lwresd.c revision 222395
1/* 2 * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 2000-2003 Internet Software Consortium. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15 * PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* $Id: lwresd.c,v 1.58 2008-07-23 23:27:54 marka Exp $ */ 19 20/*! \file 21 * \brief 22 * Main program for the Lightweight Resolver Daemon. 23 * 24 * To paraphrase the old saying about X11, "It's not a lightweight deamon 25 * for resolvers, it's a deamon for lightweight resolvers". 26 */ 27 28#include <config.h> 29 30#include <stdlib.h> 31#include <string.h> 32 33#include <isc/list.h> 34#include <isc/magic.h> 35#include <isc/mem.h> 36#include <isc/once.h> 37#include <isc/print.h> 38#include <isc/socket.h> 39#include <isc/task.h> 40#include <isc/util.h> 41 42#include <isccfg/namedconf.h> 43 44#include <dns/log.h> 45#include <dns/result.h> 46#include <dns/view.h> 47 48#include <named/config.h> 49#include <named/globals.h> 50#include <named/log.h> 51#include <named/lwaddr.h> 52#include <named/lwresd.h> 53#include <named/lwdclient.h> 54#include <named/lwsearch.h> 55#include <named/server.h> 56 57#define LWRESD_MAGIC ISC_MAGIC('L', 'W', 'R', 'D') 58#define VALID_LWRESD(l) ISC_MAGIC_VALID(l, LWRESD_MAGIC) 59 60#define LWRESLISTENER_MAGIC ISC_MAGIC('L', 'W', 'R', 'L') 61#define VALID_LWRESLISTENER(l) ISC_MAGIC_VALID(l, LWRESLISTENER_MAGIC) 62 63/*! 64 * The total number of clients we can handle will be NTASKS * NRECVS. 65 */ 66#define NTASKS 2 /*%< tasks to create to handle lwres queries */ 67#define NRECVS 2 /*%< max clients per task */ 68 69typedef ISC_LIST(ns_lwreslistener_t) ns_lwreslistenerlist_t; 70 71static ns_lwreslistenerlist_t listeners; 72static isc_mutex_t listeners_lock; 73static isc_once_t once = ISC_ONCE_INIT; 74 75 76static void 77initialize_mutex(void) { 78 RUNTIME_CHECK(isc_mutex_init(&listeners_lock) == ISC_R_SUCCESS); 79} 80 81 82/*% 83 * Wrappers around our memory management stuff, for the lwres functions. 84 */ 85void * 86ns__lwresd_memalloc(void *arg, size_t size) { 87 return (isc_mem_get(arg, size)); 88} 89 90void 91ns__lwresd_memfree(void *arg, void *mem, size_t size) { 92 isc_mem_put(arg, mem, size); 93} 94 95 96#define CHECK(op) \ 97 do { result = (op); \ 98 if (result != ISC_R_SUCCESS) goto cleanup; \ 99 } while (0) 100 101static isc_result_t 102buffer_putstr(isc_buffer_t *b, const char *s) { 103 unsigned int len = strlen(s); 104 if (isc_buffer_availablelength(b) <= len) 105 return (ISC_R_NOSPACE); 106 isc_buffer_putmem(b, (const unsigned char *)s, len); 107 return (ISC_R_SUCCESS); 108} 109 110/* 111 * Convert a resolv.conf file into a config structure. 112 */ 113isc_result_t 114ns_lwresd_parseeresolvconf(isc_mem_t *mctx, cfg_parser_t *pctx, 115 cfg_obj_t **configp) 116{ 117 char text[4096]; 118 char str[16]; 119 isc_buffer_t b; 120 lwres_context_t *lwctx = NULL; 121 lwres_conf_t *lwc = NULL; 122 isc_sockaddr_t sa; 123 isc_netaddr_t na; 124 int i; 125 isc_result_t result; 126 lwres_result_t lwresult; 127 128 lwctx = NULL; 129 lwresult = lwres_context_create(&lwctx, mctx, ns__lwresd_memalloc, 130 ns__lwresd_memfree, 131 LWRES_CONTEXT_SERVERMODE); 132 if (lwresult != LWRES_R_SUCCESS) { 133 result = ISC_R_NOMEMORY; 134 goto cleanup; 135 } 136 137 lwresult = lwres_conf_parse(lwctx, lwresd_g_resolvconffile); 138 if (lwresult != LWRES_R_SUCCESS) { 139 result = DNS_R_SYNTAX; 140 goto cleanup; 141 } 142 143 lwc = lwres_conf_get(lwctx); 144 INSIST(lwc != NULL); 145 146 isc_buffer_init(&b, text, sizeof(text)); 147 148 CHECK(buffer_putstr(&b, "options {\n")); 149 150 /* 151 * Build the list of forwarders. 152 */ 153 if (lwc->nsnext > 0) { 154 CHECK(buffer_putstr(&b, "\tforwarders {\n")); 155 156 for (i = 0; i < lwc->nsnext; i++) { 157 CHECK(lwaddr_sockaddr_fromlwresaddr( 158 &sa, 159 &lwc->nameservers[i], 160 ns_g_port)); 161 isc_netaddr_fromsockaddr(&na, &sa); 162 CHECK(buffer_putstr(&b, "\t\t")); 163 CHECK(isc_netaddr_totext(&na, &b)); 164 CHECK(buffer_putstr(&b, ";\n")); 165 } 166 CHECK(buffer_putstr(&b, "\t};\n")); 167 } 168 169 /* 170 * Build the sortlist 171 */ 172 if (lwc->sortlistnxt > 0) { 173 CHECK(buffer_putstr(&b, "\tsortlist {\n")); 174 CHECK(buffer_putstr(&b, "\t\t{\n")); 175 CHECK(buffer_putstr(&b, "\t\t\tany;\n")); 176 CHECK(buffer_putstr(&b, "\t\t\t{\n")); 177 for (i = 0; i < lwc->sortlistnxt; i++) { 178 lwres_addr_t *lwaddr = &lwc->sortlist[i].addr; 179 lwres_addr_t *lwmask = &lwc->sortlist[i].mask; 180 unsigned int mask; 181 182 CHECK(lwaddr_sockaddr_fromlwresaddr(&sa, lwmask, 0)); 183 isc_netaddr_fromsockaddr(&na, &sa); 184 result = isc_netaddr_masktoprefixlen(&na, &mask); 185 if (result != ISC_R_SUCCESS) { 186 char addrtext[ISC_NETADDR_FORMATSIZE]; 187 isc_netaddr_format(&na, addrtext, 188 sizeof(addrtext)); 189 isc_log_write(ns_g_lctx, 190 NS_LOGCATEGORY_GENERAL, 191 NS_LOGMODULE_LWRESD, 192 ISC_LOG_ERROR, 193 "processing sortlist: '%s' is " 194 "not a valid netmask", 195 addrtext); 196 goto cleanup; 197 } 198 199 CHECK(lwaddr_sockaddr_fromlwresaddr(&sa, lwaddr, 0)); 200 isc_netaddr_fromsockaddr(&na, &sa); 201 202 CHECK(buffer_putstr(&b, "\t\t\t\t")); 203 CHECK(isc_netaddr_totext(&na, &b)); 204 snprintf(str, sizeof(str), "%u", mask); 205 CHECK(buffer_putstr(&b, "/")); 206 CHECK(buffer_putstr(&b, str)); 207 CHECK(buffer_putstr(&b, ";\n")); 208 } 209 CHECK(buffer_putstr(&b, "\t\t\t};\n")); 210 CHECK(buffer_putstr(&b, "\t\t};\n")); 211 CHECK(buffer_putstr(&b, "\t};\n")); 212 } 213 214 CHECK(buffer_putstr(&b, "};\n\n")); 215 216 CHECK(buffer_putstr(&b, "lwres {\n")); 217 218 /* 219 * Build the search path 220 */ 221 if (lwc->searchnxt > 0) { 222 if (lwc->searchnxt > 0) { 223 CHECK(buffer_putstr(&b, "\tsearch {\n")); 224 for (i = 0; i < lwc->searchnxt; i++) { 225 CHECK(buffer_putstr(&b, "\t\t\"")); 226 CHECK(buffer_putstr(&b, lwc->search[i])); 227 CHECK(buffer_putstr(&b, "\";\n")); 228 } 229 CHECK(buffer_putstr(&b, "\t};\n")); 230 } 231 } 232 233 /* 234 * Build the ndots line 235 */ 236 if (lwc->ndots != 1) { 237 CHECK(buffer_putstr(&b, "\tndots ")); 238 snprintf(str, sizeof(str), "%u", lwc->ndots); 239 CHECK(buffer_putstr(&b, str)); 240 CHECK(buffer_putstr(&b, ";\n")); 241 } 242 243 /* 244 * Build the listen-on line 245 */ 246 if (lwc->lwnext > 0) { 247 CHECK(buffer_putstr(&b, "\tlisten-on {\n")); 248 249 for (i = 0; i < lwc->lwnext; i++) { 250 CHECK(lwaddr_sockaddr_fromlwresaddr(&sa, 251 &lwc->lwservers[i], 252 0)); 253 isc_netaddr_fromsockaddr(&na, &sa); 254 CHECK(buffer_putstr(&b, "\t\t")); 255 CHECK(isc_netaddr_totext(&na, &b)); 256 CHECK(buffer_putstr(&b, ";\n")); 257 } 258 CHECK(buffer_putstr(&b, "\t};\n")); 259 } 260 261 CHECK(buffer_putstr(&b, "};\n")); 262 263#if 0 264 printf("%.*s\n", 265 (int)isc_buffer_usedlength(&b), 266 (char *)isc_buffer_base(&b)); 267#endif 268 269 lwres_conf_clear(lwctx); 270 lwres_context_destroy(&lwctx); 271 272 return (cfg_parse_buffer(pctx, &b, &cfg_type_namedconf, configp)); 273 274 cleanup: 275 276 if (lwctx != NULL) { 277 lwres_conf_clear(lwctx); 278 lwres_context_destroy(&lwctx); 279 } 280 281 return (result); 282} 283 284 285/* 286 * Handle lwresd manager objects 287 */ 288isc_result_t 289ns_lwdmanager_create(isc_mem_t *mctx, const cfg_obj_t *lwres, 290 ns_lwresd_t **lwresdp) 291{ 292 ns_lwresd_t *lwresd; 293 const char *vname; 294 dns_rdataclass_t vclass; 295 const cfg_obj_t *obj, *viewobj, *searchobj; 296 const cfg_listelt_t *element; 297 isc_result_t result; 298 299 INSIST(lwresdp != NULL && *lwresdp == NULL); 300 301 lwresd = isc_mem_get(mctx, sizeof(ns_lwresd_t)); 302 if (lwresd == NULL) 303 return (ISC_R_NOMEMORY); 304 305 lwresd->mctx = NULL; 306 isc_mem_attach(mctx, &lwresd->mctx); 307 lwresd->view = NULL; 308 lwresd->search = NULL; 309 lwresd->refs = 1; 310 311 obj = NULL; 312 (void)cfg_map_get(lwres, "ndots", &obj); 313 if (obj != NULL) 314 lwresd->ndots = cfg_obj_asuint32(obj); 315 else 316 lwresd->ndots = 1; 317 318 RUNTIME_CHECK(isc_mutex_init(&lwresd->lock) == ISC_R_SUCCESS); 319 320 lwresd->shutting_down = ISC_FALSE; 321 322 viewobj = NULL; 323 (void)cfg_map_get(lwres, "view", &viewobj); 324 if (viewobj != NULL) { 325 vname = cfg_obj_asstring(cfg_tuple_get(viewobj, "name")); 326 obj = cfg_tuple_get(viewobj, "class"); 327 result = ns_config_getclass(obj, dns_rdataclass_in, &vclass); 328 if (result != ISC_R_SUCCESS) 329 goto fail; 330 } else { 331 vname = "_default"; 332 vclass = dns_rdataclass_in; 333 } 334 335 result = dns_viewlist_find(&ns_g_server->viewlist, vname, vclass, 336 &lwresd->view); 337 if (result != ISC_R_SUCCESS) { 338 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 339 NS_LOGMODULE_LWRESD, ISC_LOG_WARNING, 340 "couldn't find view %s", vname); 341 goto fail; 342 } 343 344 searchobj = NULL; 345 (void)cfg_map_get(lwres, "search", &searchobj); 346 if (searchobj != NULL) { 347 lwresd->search = NULL; 348 result = ns_lwsearchlist_create(lwresd->mctx, 349 &lwresd->search); 350 if (result != ISC_R_SUCCESS) { 351 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 352 NS_LOGMODULE_LWRESD, ISC_LOG_WARNING, 353 "couldn't create searchlist"); 354 goto fail; 355 } 356 for (element = cfg_list_first(searchobj); 357 element != NULL; 358 element = cfg_list_next(element)) 359 { 360 const cfg_obj_t *search; 361 const char *searchstr; 362 isc_buffer_t namebuf; 363 dns_fixedname_t fname; 364 dns_name_t *name; 365 366 search = cfg_listelt_value(element); 367 searchstr = cfg_obj_asstring(search); 368 369 dns_fixedname_init(&fname); 370 name = dns_fixedname_name(&fname); 371 isc_buffer_init(&namebuf, searchstr, 372 strlen(searchstr)); 373 isc_buffer_add(&namebuf, strlen(searchstr)); 374 result = dns_name_fromtext(name, &namebuf, 375 dns_rootname, ISC_FALSE, 376 NULL); 377 if (result != ISC_R_SUCCESS) { 378 isc_log_write(ns_g_lctx, 379 NS_LOGCATEGORY_GENERAL, 380 NS_LOGMODULE_LWRESD, 381 ISC_LOG_WARNING, 382 "invalid name %s in searchlist", 383 searchstr); 384 continue; 385 } 386 387 result = ns_lwsearchlist_append(lwresd->search, name); 388 if (result != ISC_R_SUCCESS) { 389 isc_log_write(ns_g_lctx, 390 NS_LOGCATEGORY_GENERAL, 391 NS_LOGMODULE_LWRESD, 392 ISC_LOG_WARNING, 393 "couldn't update searchlist"); 394 goto fail; 395 } 396 } 397 } 398 399 lwresd->magic = LWRESD_MAGIC; 400 401 *lwresdp = lwresd; 402 return (ISC_R_SUCCESS); 403 404 fail: 405 if (lwresd->view != NULL) 406 dns_view_detach(&lwresd->view); 407 if (lwresd->search != NULL) 408 ns_lwsearchlist_detach(&lwresd->search); 409 if (lwresd->mctx != NULL) 410 isc_mem_detach(&lwresd->mctx); 411 isc_mem_put(mctx, lwresd, sizeof(ns_lwresd_t)); 412 return (result); 413} 414 415void 416ns_lwdmanager_attach(ns_lwresd_t *source, ns_lwresd_t **targetp) { 417 INSIST(VALID_LWRESD(source)); 418 INSIST(targetp != NULL && *targetp == NULL); 419 420 LOCK(&source->lock); 421 source->refs++; 422 UNLOCK(&source->lock); 423 424 *targetp = source; 425} 426 427void 428ns_lwdmanager_detach(ns_lwresd_t **lwresdp) { 429 ns_lwresd_t *lwresd; 430 isc_mem_t *mctx; 431 isc_boolean_t done = ISC_FALSE; 432 433 INSIST(lwresdp != NULL && *lwresdp != NULL); 434 INSIST(VALID_LWRESD(*lwresdp)); 435 436 lwresd = *lwresdp; 437 *lwresdp = NULL; 438 439 LOCK(&lwresd->lock); 440 INSIST(lwresd->refs > 0); 441 lwresd->refs--; 442 if (lwresd->refs == 0) 443 done = ISC_TRUE; 444 UNLOCK(&lwresd->lock); 445 446 if (!done) 447 return; 448 449 dns_view_detach(&lwresd->view); 450 if (lwresd->search != NULL) 451 ns_lwsearchlist_detach(&lwresd->search); 452 mctx = lwresd->mctx; 453 lwresd->magic = 0; 454 isc_mem_put(mctx, lwresd, sizeof(*lwresd)); 455 isc_mem_detach(&mctx); 456} 457 458 459/* 460 * Handle listener objects 461 */ 462void 463ns_lwreslistener_attach(ns_lwreslistener_t *source, 464 ns_lwreslistener_t **targetp) 465{ 466 INSIST(VALID_LWRESLISTENER(source)); 467 INSIST(targetp != NULL && *targetp == NULL); 468 469 LOCK(&source->lock); 470 source->refs++; 471 UNLOCK(&source->lock); 472 473 *targetp = source; 474} 475 476void 477ns_lwreslistener_detach(ns_lwreslistener_t **listenerp) { 478 ns_lwreslistener_t *listener; 479 isc_mem_t *mctx; 480 isc_boolean_t done = ISC_FALSE; 481 482 INSIST(listenerp != NULL && *listenerp != NULL); 483 INSIST(VALID_LWRESLISTENER(*listenerp)); 484 485 listener = *listenerp; 486 487 LOCK(&listener->lock); 488 INSIST(listener->refs > 0); 489 listener->refs--; 490 if (listener->refs == 0) 491 done = ISC_TRUE; 492 UNLOCK(&listener->lock); 493 494 if (!done) 495 return; 496 497 if (listener->manager != NULL) 498 ns_lwdmanager_detach(&listener->manager); 499 500 if (listener->sock != NULL) 501 isc_socket_detach(&listener->sock); 502 503 listener->magic = 0; 504 mctx = listener->mctx; 505 isc_mem_put(mctx, listener, sizeof(*listener)); 506 isc_mem_detach(&mctx); 507 listenerp = NULL; 508} 509 510static isc_result_t 511listener_create(isc_mem_t *mctx, ns_lwresd_t *lwresd, 512 ns_lwreslistener_t **listenerp) 513{ 514 ns_lwreslistener_t *listener; 515 isc_result_t result; 516 517 REQUIRE(listenerp != NULL && *listenerp == NULL); 518 519 listener = isc_mem_get(mctx, sizeof(ns_lwreslistener_t)); 520 if (listener == NULL) 521 return (ISC_R_NOMEMORY); 522 523 result = isc_mutex_init(&listener->lock); 524 if (result != ISC_R_SUCCESS) { 525 isc_mem_put(mctx, listener, sizeof(ns_lwreslistener_t)); 526 return (result); 527 } 528 529 listener->magic = LWRESLISTENER_MAGIC; 530 listener->refs = 1; 531 532 listener->sock = NULL; 533 534 listener->manager = NULL; 535 ns_lwdmanager_attach(lwresd, &listener->manager); 536 537 listener->mctx = NULL; 538 isc_mem_attach(mctx, &listener->mctx); 539 540 ISC_LINK_INIT(listener, link); 541 ISC_LIST_INIT(listener->cmgrs); 542 543 *listenerp = listener; 544 return (ISC_R_SUCCESS); 545} 546 547static isc_result_t 548listener_bind(ns_lwreslistener_t *listener, isc_sockaddr_t *address) { 549 isc_socket_t *sock = NULL; 550 isc_result_t result = ISC_R_SUCCESS; 551 int pf; 552 553 pf = isc_sockaddr_pf(address); 554 if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) || 555 (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS)) 556 return (ISC_R_FAMILYNOSUPPORT); 557 558 listener->address = *address; 559 560 if (isc_sockaddr_getport(&listener->address) == 0) { 561 in_port_t port; 562 port = lwresd_g_listenport; 563 if (port == 0) 564 port = LWRES_UDP_PORT; 565 isc_sockaddr_setport(&listener->address, port); 566 } 567 568 sock = NULL; 569 result = isc_socket_create(ns_g_socketmgr, pf, 570 isc_sockettype_udp, &sock); 571 if (result != ISC_R_SUCCESS) { 572 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 573 NS_LOGMODULE_LWRESD, ISC_LOG_WARNING, 574 "failed to create lwres socket: %s", 575 isc_result_totext(result)); 576 return (result); 577 } 578 579 result = isc_socket_bind(sock, &listener->address, 580 ISC_SOCKET_REUSEADDRESS); 581 if (result != ISC_R_SUCCESS) { 582 char socktext[ISC_SOCKADDR_FORMATSIZE]; 583 isc_sockaddr_format(&listener->address, socktext, 584 sizeof(socktext)); 585 isc_socket_detach(&sock); 586 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 587 NS_LOGMODULE_LWRESD, ISC_LOG_WARNING, 588 "failed to add lwres socket: %s: %s", 589 socktext, isc_result_totext(result)); 590 return (result); 591 } 592 listener->sock = sock; 593 return (ISC_R_SUCCESS); 594} 595 596static void 597listener_copysock(ns_lwreslistener_t *oldlistener, 598 ns_lwreslistener_t *newlistener) 599{ 600 newlistener->address = oldlistener->address; 601 isc_socket_attach(oldlistener->sock, &newlistener->sock); 602} 603 604static isc_result_t 605listener_startclients(ns_lwreslistener_t *listener) { 606 ns_lwdclientmgr_t *cm; 607 unsigned int i; 608 isc_result_t result; 609 610 /* 611 * Create the client managers. 612 */ 613 result = ISC_R_SUCCESS; 614 for (i = 0; i < NTASKS && result == ISC_R_SUCCESS; i++) 615 result = ns_lwdclientmgr_create(listener, NRECVS, 616 ns_g_taskmgr); 617 618 /* 619 * Ensure that we have created at least one. 620 */ 621 if (ISC_LIST_EMPTY(listener->cmgrs)) 622 return (result); 623 624 /* 625 * Walk the list of clients and start each one up. 626 */ 627 LOCK(&listener->lock); 628 cm = ISC_LIST_HEAD(listener->cmgrs); 629 while (cm != NULL) { 630 result = ns_lwdclient_startrecv(cm); 631 if (result != ISC_R_SUCCESS) 632 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, 633 NS_LOGMODULE_LWRESD, ISC_LOG_ERROR, 634 "could not start lwres " 635 "client handler: %s", 636 isc_result_totext(result)); 637 cm = ISC_LIST_NEXT(cm, link); 638 } 639 UNLOCK(&listener->lock); 640 641 return (ISC_R_SUCCESS); 642} 643 644static void 645listener_shutdown(ns_lwreslistener_t *listener) { 646 ns_lwdclientmgr_t *cm; 647 648 cm = ISC_LIST_HEAD(listener->cmgrs); 649 while (cm != NULL) { 650 isc_task_shutdown(cm->task); 651 cm = ISC_LIST_NEXT(cm, link); 652 } 653} 654 655static isc_result_t 656find_listener(isc_sockaddr_t *address, ns_lwreslistener_t **listenerp) { 657 ns_lwreslistener_t *listener; 658 659 INSIST(listenerp != NULL && *listenerp == NULL); 660 661 for (listener = ISC_LIST_HEAD(listeners); 662 listener != NULL; 663 listener = ISC_LIST_NEXT(listener, link)) 664 { 665 if (!isc_sockaddr_equal(address, &listener->address)) 666 continue; 667 *listenerp = listener; 668 return (ISC_R_SUCCESS); 669 } 670 return (ISC_R_NOTFOUND); 671} 672 673void 674ns_lwreslistener_unlinkcm(ns_lwreslistener_t *listener, ns_lwdclientmgr_t *cm) 675{ 676 REQUIRE(VALID_LWRESLISTENER(listener)); 677 678 LOCK(&listener->lock); 679 ISC_LIST_UNLINK(listener->cmgrs, cm, link); 680 UNLOCK(&listener->lock); 681} 682 683void 684ns_lwreslistener_linkcm(ns_lwreslistener_t *listener, ns_lwdclientmgr_t *cm) { 685 REQUIRE(VALID_LWRESLISTENER(listener)); 686 687 /* 688 * This does no locking, since it's called early enough that locking 689 * isn't needed. 690 */ 691 ISC_LIST_APPEND(listener->cmgrs, cm, link); 692} 693 694static isc_result_t 695configure_listener(isc_sockaddr_t *address, ns_lwresd_t *lwresd, 696 isc_mem_t *mctx, ns_lwreslistenerlist_t *newlisteners) 697{ 698 ns_lwreslistener_t *listener, *oldlistener = NULL; 699 char socktext[ISC_SOCKADDR_FORMATSIZE]; 700 isc_result_t result; 701 702 (void)find_listener(address, &oldlistener); 703 listener = NULL; 704 result = listener_create(mctx, lwresd, &listener); 705 if (result != ISC_R_SUCCESS) { 706 isc_sockaddr_format(address, socktext, sizeof(socktext)); 707 isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL, 708 NS_LOGMODULE_LWRESD, ISC_LOG_WARNING, 709 "lwres failed to configure %s: %s", 710 socktext, isc_result_totext(result)); 711 return (result); 712 } 713 714 /* 715 * If there's already a listener, don't rebind the socket. 716 */ 717 if (oldlistener == NULL) { 718 result = listener_bind(listener, address); 719 if (result != ISC_R_SUCCESS) { 720 ns_lwreslistener_detach(&listener); 721 return (ISC_R_SUCCESS); 722 } 723 } else 724 listener_copysock(oldlistener, listener); 725 726 result = listener_startclients(listener); 727 if (result != ISC_R_SUCCESS) { 728 isc_sockaddr_format(address, socktext, sizeof(socktext)); 729 isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL, 730 NS_LOGMODULE_LWRESD, ISC_LOG_WARNING, 731 "lwres: failed to start %s: %s", socktext, 732 isc_result_totext(result)); 733 ns_lwreslistener_detach(&listener); 734 return (ISC_R_SUCCESS); 735 } 736 737 if (oldlistener != NULL) { 738 /* 739 * Remove the old listener from the old list and shut it down. 740 */ 741 ISC_LIST_UNLINK(listeners, oldlistener, link); 742 listener_shutdown(oldlistener); 743 ns_lwreslistener_detach(&oldlistener); 744 } else { 745 isc_sockaddr_format(address, socktext, sizeof(socktext)); 746 isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL, 747 NS_LOGMODULE_LWRESD, ISC_LOG_NOTICE, 748 "lwres listening on %s", socktext); 749 } 750 751 ISC_LIST_APPEND(*newlisteners, listener, link); 752 return (result); 753} 754 755isc_result_t 756ns_lwresd_configure(isc_mem_t *mctx, const cfg_obj_t *config) { 757 const cfg_obj_t *lwreslist = NULL; 758 const cfg_obj_t *lwres = NULL; 759 const cfg_obj_t *listenerslist = NULL; 760 const cfg_listelt_t *element = NULL; 761 ns_lwreslistener_t *listener; 762 ns_lwreslistenerlist_t newlisteners; 763 isc_result_t result; 764 char socktext[ISC_SOCKADDR_FORMATSIZE]; 765 isc_sockaddr_t *addrs = NULL; 766 ns_lwresd_t *lwresd = NULL; 767 isc_uint32_t count = 0; 768 769 REQUIRE(mctx != NULL); 770 REQUIRE(config != NULL); 771 772 RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS); 773 774 ISC_LIST_INIT(newlisteners); 775 776 result = cfg_map_get(config, "lwres", &lwreslist); 777 if (result != ISC_R_SUCCESS) 778 return (ISC_R_SUCCESS); 779 780 LOCK(&listeners_lock); 781 /* 782 * Run through the new lwres address list, noting sockets that 783 * are already being listened on and moving them to the new list. 784 * 785 * Identifying duplicates addr/port combinations is left to either 786 * the underlying config code, or to the bind attempt getting an 787 * address-in-use error. 788 */ 789 for (element = cfg_list_first(lwreslist); 790 element != NULL; 791 element = cfg_list_next(element)) 792 { 793 in_port_t port; 794 795 lwres = cfg_listelt_value(element); 796 CHECK(ns_lwdmanager_create(mctx, lwres, &lwresd)); 797 798 port = lwresd_g_listenport; 799 if (port == 0) 800 port = LWRES_UDP_PORT; 801 802 listenerslist = NULL; 803 (void)cfg_map_get(lwres, "listen-on", &listenerslist); 804 if (listenerslist == NULL) { 805 struct in_addr localhost; 806 isc_sockaddr_t address; 807 808 localhost.s_addr = htonl(INADDR_LOOPBACK); 809 isc_sockaddr_fromin(&address, &localhost, port); 810 CHECK(configure_listener(&address, lwresd, mctx, 811 &newlisteners)); 812 } else { 813 isc_uint32_t i; 814 815 CHECK(ns_config_getiplist(config, listenerslist, 816 port, mctx, &addrs, &count)); 817 for (i = 0; i < count; i++) 818 CHECK(configure_listener(&addrs[i], lwresd, 819 mctx, &newlisteners)); 820 ns_config_putiplist(mctx, &addrs, count); 821 } 822 ns_lwdmanager_detach(&lwresd); 823 } 824 825 /* 826 * Shutdown everything on the listeners list, and remove them from 827 * the list. Then put all of the new listeners on it. 828 */ 829 830 while (!ISC_LIST_EMPTY(listeners)) { 831 listener = ISC_LIST_HEAD(listeners); 832 ISC_LIST_UNLINK(listeners, listener, link); 833 834 isc_sockaddr_format(&listener->address, 835 socktext, sizeof(socktext)); 836 837 listener_shutdown(listener); 838 ns_lwreslistener_detach(&listener); 839 840 isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL, 841 NS_LOGMODULE_LWRESD, ISC_LOG_NOTICE, 842 "lwres no longer listening on %s", socktext); 843 } 844 845 cleanup: 846 ISC_LIST_APPENDLIST(listeners, newlisteners, link); 847 848 if (addrs != NULL) 849 ns_config_putiplist(mctx, &addrs, count); 850 851 if (lwresd != NULL) 852 ns_lwdmanager_detach(&lwresd); 853 854 UNLOCK(&listeners_lock); 855 856 return (result); 857} 858 859void 860ns_lwresd_shutdown(void) { 861 ns_lwreslistener_t *listener; 862 863 RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS); 864 865 while (!ISC_LIST_EMPTY(listeners)) { 866 listener = ISC_LIST_HEAD(listeners); 867 ISC_LIST_UNLINK(listeners, listener, link); 868 ns_lwreslistener_detach(&listener); 869 } 870} 871