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