2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000, 2001, 2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and 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.
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.
18 /* $Id: lwresd.c,v 1.37.2.3 2004/03/09 06:09:19 marka Exp $ */
21 * Main program for the Lightweight Resolver Daemon.
23 * To paraphrase the old saying about X11, "It's not a lightweight deamon
24 * for resolvers, it's a deamon for lightweight resolvers".
33 #include <isc/magic.h>
36 #include <isc/print.h>
37 #include <isc/socket.h>
41 #include <isccfg/cfg.h>
44 #include <dns/result.h>
47 #include <named/config.h>
48 #include <named/globals.h>
49 #include <named/log.h>
50 #include <named/lwaddr.h>
51 #include <named/lwresd.h>
52 #include <named/lwdclient.h>
53 #include <named/lwsearch.h>
54 #include <named/server.h>
56 #define LWRESD_MAGIC ISC_MAGIC('L', 'W', 'R', 'D')
57 #define VALID_LWRESD(l) ISC_MAGIC_VALID(l, LWRESD_MAGIC)
59 #define LWRESLISTENER_MAGIC ISC_MAGIC('L', 'W', 'R', 'L')
60 #define VALID_LWRESLISTENER(l) ISC_MAGIC_VALID(l, LWRESLISTENER_MAGIC)
63 * The total number of clients we can handle will be NTASKS * NRECVS.
65 #define NTASKS 2 /* tasks to create to handle lwres queries */
66 #define NRECVS 2 /* max clients per task */
68 typedef ISC_LIST(ns_lwreslistener_t) ns_lwreslistenerlist_t;
70 static ns_lwreslistenerlist_t listeners;
71 static isc_mutex_t listeners_lock;
72 static isc_once_t once = ISC_ONCE_INIT;
76 initialize_mutex(void) {
77 RUNTIME_CHECK(isc_mutex_init(&listeners_lock) == ISC_R_SUCCESS);
82 * Wrappers around our memory management stuff, for the lwres functions.
85 ns__lwresd_memalloc(void *arg, size_t size) {
86 return (isc_mem_get(arg, size));
90 ns__lwresd_memfree(void *arg, void *mem, size_t size) {
91 isc_mem_put(arg, mem, size);
97 if (result != ISC_R_SUCCESS) goto cleanup; \
101 buffer_putstr(isc_buffer_t *b, const char *s) {
102 unsigned int len = strlen(s);
103 if (isc_buffer_availablelength(b) <= len)
104 return (ISC_R_NOSPACE);
105 isc_buffer_putmem(b, (const unsigned char *)s, len);
106 return (ISC_R_SUCCESS);
110 * Convert a resolv.conf file into a config structure.
113 ns_lwresd_parseeresolvconf(isc_mem_t *mctx, cfg_parser_t *pctx,
119 lwres_context_t *lwctx = NULL;
120 lwres_conf_t *lwc = NULL;
125 lwres_result_t lwresult;
128 lwresult = lwres_context_create(&lwctx, mctx, ns__lwresd_memalloc,
130 LWRES_CONTEXT_SERVERMODE);
131 if (lwresult != LWRES_R_SUCCESS) {
132 result = ISC_R_NOMEMORY;
136 lwresult = lwres_conf_parse(lwctx, lwresd_g_resolvconffile);
137 if (lwresult != LWRES_R_SUCCESS) {
138 result = DNS_R_SYNTAX;
142 lwc = lwres_conf_get(lwctx);
145 isc_buffer_init(&b, text, sizeof(text));
147 CHECK(buffer_putstr(&b, "options {\n"));
150 * Build the list of forwarders.
152 if (lwc->nsnext > 0) {
153 CHECK(buffer_putstr(&b, "\tforwarders {\n"));
155 for (i = 0 ; i < lwc->nsnext ; i++) {
156 CHECK(lwaddr_sockaddr_fromlwresaddr(
158 &lwc->nameservers[i],
160 isc_netaddr_fromsockaddr(&na, &sa);
161 CHECK(buffer_putstr(&b, "\t\t"));
162 CHECK(isc_netaddr_totext(&na, &b));
163 CHECK(buffer_putstr(&b, ";\n"));
165 CHECK(buffer_putstr(&b, "\t};\n"));
171 if (lwc->sortlistnxt > 0) {
172 CHECK(buffer_putstr(&b, "\tsortlist {\n"));
173 CHECK(buffer_putstr(&b, "\t\t{\n"));
174 CHECK(buffer_putstr(&b, "\t\t\tany;\n"));
175 CHECK(buffer_putstr(&b, "\t\t\t{\n"));
176 for (i = 0 ; i < lwc->sortlistnxt; i++) {
177 lwres_addr_t *lwaddr = &lwc->sortlist[i].addr;
178 lwres_addr_t *lwmask = &lwc->sortlist[i].mask;
181 CHECK(lwaddr_sockaddr_fromlwresaddr(&sa, lwmask, 0));
182 isc_netaddr_fromsockaddr(&na, &sa);
183 result = isc_netaddr_masktoprefixlen(&na, &mask);
184 if (result != ISC_R_SUCCESS) {
185 char addrtext[ISC_NETADDR_FORMATSIZE];
186 isc_netaddr_format(&na, addrtext,
188 isc_log_write(ns_g_lctx,
189 NS_LOGCATEGORY_GENERAL,
192 "processing sortlist: '%s' is "
193 "not a valid netmask",
198 CHECK(lwaddr_sockaddr_fromlwresaddr(&sa, lwaddr, 0));
199 isc_netaddr_fromsockaddr(&na, &sa);
201 CHECK(buffer_putstr(&b, "\t\t\t\t"));
202 CHECK(isc_netaddr_totext(&na, &b));
203 snprintf(str, sizeof(str), "%u", mask);
204 CHECK(buffer_putstr(&b, "/"));
205 CHECK(buffer_putstr(&b, str));
206 CHECK(buffer_putstr(&b, ";\n"));
208 CHECK(buffer_putstr(&b, "\t\t\t};\n"));
209 CHECK(buffer_putstr(&b, "\t\t};\n"));
210 CHECK(buffer_putstr(&b, "\t};\n"));
213 CHECK(buffer_putstr(&b, "};\n\n"));
215 CHECK(buffer_putstr(&b, "lwres {\n"));
218 * Build the search path
220 if (lwc->searchnxt > 0) {
221 if (lwc->searchnxt > 0) {
222 CHECK(buffer_putstr(&b, "\tsearch {\n"));
223 for (i = 0; i < lwc->searchnxt; i++) {
224 CHECK(buffer_putstr(&b, "\t\t\""));
225 CHECK(buffer_putstr(&b, lwc->search[i]));
226 CHECK(buffer_putstr(&b, "\";\n"));
228 CHECK(buffer_putstr(&b, "\t};\n"));
233 * Build the ndots line
235 if (lwc->ndots != 1) {
236 CHECK(buffer_putstr(&b, "\tndots "));
237 snprintf(str, sizeof(str), "%u", lwc->ndots);
238 CHECK(buffer_putstr(&b, str));
239 CHECK(buffer_putstr(&b, ";\n"));
243 * Build the listen-on line
245 if (lwc->lwnext > 0) {
246 CHECK(buffer_putstr(&b, "\tlisten-on {\n"));
248 for (i = 0 ; i < lwc->lwnext ; i++) {
249 CHECK(lwaddr_sockaddr_fromlwresaddr(&sa,
252 isc_netaddr_fromsockaddr(&na, &sa);
253 CHECK(buffer_putstr(&b, "\t\t"));
254 CHECK(isc_netaddr_totext(&na, &b));
255 CHECK(buffer_putstr(&b, ";\n"));
257 CHECK(buffer_putstr(&b, "\t};\n"));
260 CHECK(buffer_putstr(&b, "};\n"));
264 (int)isc_buffer_usedlength(&b),
265 (char *)isc_buffer_base(&b));
268 lwres_conf_clear(lwctx);
269 lwres_context_destroy(&lwctx);
271 return (cfg_parse_buffer(pctx, &b, &cfg_type_namedconf, configp));
276 lwres_conf_clear(lwctx);
277 lwres_context_destroy(&lwctx);
285 * Handle lwresd manager objects
288 ns_lwdmanager_create(isc_mem_t *mctx, cfg_obj_t *lwres,
289 ns_lwresd_t **lwresdp)
293 dns_rdataclass_t vclass;
294 cfg_obj_t *obj, *viewobj, *searchobj;
295 cfg_listelt_t *element;
298 INSIST(lwresdp != NULL && *lwresdp == NULL);
300 lwresd = isc_mem_get(mctx, sizeof(ns_lwresd_t));
302 return (ISC_R_NOMEMORY);
305 isc_mem_attach(mctx, &lwresd->mctx);
307 lwresd->search = NULL;
311 (void)cfg_map_get(lwres, "ndots", &obj);
313 lwresd->ndots = cfg_obj_asuint32(obj);
317 RUNTIME_CHECK(isc_mutex_init(&lwresd->lock) == ISC_R_SUCCESS);
319 lwresd->shutting_down = ISC_FALSE;
322 (void)cfg_map_get(lwres, "view", &viewobj);
323 if (viewobj != NULL) {
324 vname = cfg_obj_asstring(cfg_tuple_get(viewobj, "name"));
325 obj = cfg_tuple_get(viewobj, "class");
326 result = ns_config_getclass(obj, dns_rdataclass_in, &vclass);
327 if (result != ISC_R_SUCCESS)
331 vclass = dns_rdataclass_in;
334 result = dns_viewlist_find(&ns_g_server->viewlist, vname, vclass,
336 if (result != ISC_R_SUCCESS) {
337 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
338 NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
339 "couldn't find view %s", vname);
344 cfg_map_get(lwres, "search", &searchobj);
345 if (searchobj != NULL) {
346 lwresd->search = NULL;
347 result = ns_lwsearchlist_create(lwresd->mctx,
349 if (result != ISC_R_SUCCESS) {
350 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
351 NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
352 "couldn't create searchlist");
355 for (element = cfg_list_first(searchobj);
357 element = cfg_list_next(element))
361 isc_buffer_t namebuf;
362 dns_fixedname_t fname;
365 search = cfg_listelt_value(element);
366 searchstr = cfg_obj_asstring(search);
368 dns_fixedname_init(&fname);
369 name = dns_fixedname_name(&fname);
370 isc_buffer_init(&namebuf, searchstr,
372 isc_buffer_add(&namebuf, strlen(searchstr));
373 result = dns_name_fromtext(name, &namebuf,
374 dns_rootname, ISC_FALSE,
376 if (result != ISC_R_SUCCESS) {
377 isc_log_write(ns_g_lctx,
378 NS_LOGCATEGORY_GENERAL,
381 "invalid name %s in searchlist",
386 result = ns_lwsearchlist_append(lwresd->search, name);
387 if (result != ISC_R_SUCCESS) {
388 isc_log_write(ns_g_lctx,
389 NS_LOGCATEGORY_GENERAL,
392 "couldn't update searchlist");
398 lwresd->magic = LWRESD_MAGIC;
401 return (ISC_R_SUCCESS);
404 if (lwresd->view != NULL)
405 dns_view_detach(&lwresd->view);
406 if (lwresd->search != NULL)
407 ns_lwsearchlist_detach(&lwresd->search);
408 if (lwresd->mctx != NULL)
409 isc_mem_detach(&lwresd->mctx);
414 ns_lwdmanager_attach(ns_lwresd_t *source, ns_lwresd_t **targetp) {
415 INSIST(VALID_LWRESD(source));
416 INSIST(targetp != NULL && *targetp == NULL);
420 UNLOCK(&source->lock);
426 ns_lwdmanager_detach(ns_lwresd_t **lwresdp) {
429 isc_boolean_t done = ISC_FALSE;
431 INSIST(lwresdp != NULL && *lwresdp != NULL);
432 INSIST(VALID_LWRESD(*lwresdp));
438 INSIST(lwresd->refs > 0);
440 if (lwresd->refs == 0)
442 UNLOCK(&lwresd->lock);
447 dns_view_detach(&lwresd->view);
448 if (lwresd->search != NULL)
449 ns_lwsearchlist_detach(&lwresd->search);
452 isc_mem_put(mctx, lwresd, sizeof(*lwresd));
453 isc_mem_detach(&mctx);
458 * Handle listener objects
461 ns_lwreslistener_attach(ns_lwreslistener_t *source,
462 ns_lwreslistener_t **targetp)
464 INSIST(VALID_LWRESLISTENER(source));
465 INSIST(targetp != NULL && *targetp == NULL);
469 UNLOCK(&source->lock);
475 ns_lwreslistener_detach(ns_lwreslistener_t **listenerp) {
476 ns_lwreslistener_t *listener;
478 isc_boolean_t done = ISC_FALSE;
480 INSIST(listenerp != NULL && *listenerp != NULL);
481 INSIST(VALID_LWRESLISTENER(*listenerp));
483 listener = *listenerp;
485 LOCK(&listener->lock);
486 INSIST(listener->refs > 0);
488 if (listener->refs == 0)
490 UNLOCK(&listener->lock);
495 if (listener->manager != NULL)
496 ns_lwdmanager_detach(&listener->manager);
498 if (listener->sock != NULL)
499 isc_socket_detach(&listener->sock);
502 mctx = listener->mctx;
503 isc_mem_put(mctx, listener, sizeof(*listener));
504 isc_mem_detach(&mctx);
509 listener_create(isc_mem_t *mctx, ns_lwresd_t *lwresd,
510 ns_lwreslistener_t **listenerp)
512 ns_lwreslistener_t *listener;
514 REQUIRE(listenerp != NULL && *listenerp == NULL);
516 listener = isc_mem_get(mctx, sizeof(ns_lwreslistener_t));
517 if (listener == NULL)
518 return (ISC_R_NOMEMORY);
519 RUNTIME_CHECK(isc_mutex_init(&listener->lock) == ISC_R_SUCCESS);
521 listener->magic = LWRESLISTENER_MAGIC;
524 listener->sock = NULL;
526 listener->manager = NULL;
527 ns_lwdmanager_attach(lwresd, &listener->manager);
529 listener->mctx = NULL;
530 isc_mem_attach(mctx, &listener->mctx);
532 ISC_LINK_INIT(listener, link);
533 ISC_LIST_INIT(listener->cmgrs);
535 *listenerp = listener;
536 return (ISC_R_SUCCESS);
540 listener_bind(ns_lwreslistener_t *listener, isc_sockaddr_t *address) {
541 isc_socket_t *sock = NULL;
542 isc_result_t result = ISC_R_SUCCESS;
545 pf = isc_sockaddr_pf(address);
546 if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) ||
547 (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS))
548 return (ISC_R_FAMILYNOSUPPORT);
550 listener->address = *address;
552 if (isc_sockaddr_getport(&listener->address) == 0) {
554 port = lwresd_g_listenport;
556 port = LWRES_UDP_PORT;
557 isc_sockaddr_setport(&listener->address, port);
561 result = isc_socket_create(ns_g_socketmgr, pf,
562 isc_sockettype_udp, &sock);
563 if (result != ISC_R_SUCCESS) {
564 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
565 NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
566 "failed to create lwres socket: %s",
567 isc_result_totext(result));
571 result = isc_socket_bind(sock, &listener->address);
572 if (result != ISC_R_SUCCESS) {
573 char socktext[ISC_SOCKADDR_FORMATSIZE];
574 isc_sockaddr_format(&listener->address, socktext,
576 isc_socket_detach(&sock);
577 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
578 NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
579 "failed to add lwres socket: %s: %s",
580 socktext, isc_result_totext(result));
583 listener->sock = sock;
584 return (ISC_R_SUCCESS);
588 listener_copysock(ns_lwreslistener_t *oldlistener,
589 ns_lwreslistener_t *newlistener)
591 newlistener->address = oldlistener->address;
592 isc_socket_attach(oldlistener->sock, &newlistener->sock);
596 listener_startclients(ns_lwreslistener_t *listener) {
597 ns_lwdclientmgr_t *cm;
602 * Create the client managers.
604 result = ISC_R_SUCCESS;
605 for (i = 0 ; i < NTASKS && result == ISC_R_SUCCESS; i++)
606 result = ns_lwdclientmgr_create(listener, NRECVS,
610 * Ensure that we have created at least one.
612 if (ISC_LIST_EMPTY(listener->cmgrs))
616 * Walk the list of clients and start each one up.
618 LOCK(&listener->lock);
619 cm = ISC_LIST_HEAD(listener->cmgrs);
621 ns_lwdclient_startrecv(cm);
622 cm = ISC_LIST_NEXT(cm, link);
624 UNLOCK(&listener->lock);
626 return (ISC_R_SUCCESS);
630 listener_shutdown(ns_lwreslistener_t *listener) {
631 ns_lwdclientmgr_t *cm;
633 cm = ISC_LIST_HEAD(listener->cmgrs);
635 isc_task_shutdown(cm->task);
636 cm = ISC_LIST_NEXT(cm, link);
641 find_listener(isc_sockaddr_t *address, ns_lwreslistener_t **listenerp) {
642 ns_lwreslistener_t *listener;
644 INSIST(listenerp != NULL && *listenerp == NULL);
646 for (listener = ISC_LIST_HEAD(listeners);
648 listener = ISC_LIST_NEXT(listener, link))
650 if (!isc_sockaddr_equal(address, &listener->address))
652 *listenerp = listener;
653 return (ISC_R_SUCCESS);
655 return (ISC_R_NOTFOUND);
659 ns_lwreslistener_unlinkcm(ns_lwreslistener_t *listener, ns_lwdclientmgr_t *cm)
661 REQUIRE(VALID_LWRESLISTENER(listener));
663 LOCK(&listener->lock);
664 ISC_LIST_UNLINK(listener->cmgrs, cm, link);
665 UNLOCK(&listener->lock);
669 ns_lwreslistener_linkcm(ns_lwreslistener_t *listener, ns_lwdclientmgr_t *cm) {
670 REQUIRE(VALID_LWRESLISTENER(listener));
673 * This does no locking, since it's called early enough that locking
676 ISC_LIST_APPEND(listener->cmgrs, cm, link);
680 configure_listener(isc_sockaddr_t *address, ns_lwresd_t *lwresd,
681 isc_mem_t *mctx, ns_lwreslistenerlist_t *newlisteners)
683 ns_lwreslistener_t *listener, *oldlistener = NULL;
684 char socktext[ISC_SOCKADDR_FORMATSIZE];
687 (void)find_listener(address, &oldlistener);
689 result = listener_create(mctx, lwresd, &listener);
690 if (result != ISC_R_SUCCESS) {
691 isc_sockaddr_format(address, socktext, sizeof(socktext));
692 isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
693 NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
694 "lwres failed to configure %s: %s",
695 socktext, isc_result_totext(result));
700 * If there's already a listener, don't rebind the socket.
702 if (oldlistener == NULL) {
703 result = listener_bind(listener, address);
704 if (result != ISC_R_SUCCESS) {
705 ns_lwreslistener_detach(&listener);
706 return (ISC_R_SUCCESS);
709 listener_copysock(oldlistener, listener);
711 result = listener_startclients(listener);
712 if (result != ISC_R_SUCCESS) {
713 isc_sockaddr_format(address, socktext, sizeof(socktext));
714 isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
715 NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
716 "lwres: failed to start %s: %s", socktext,
717 isc_result_totext(result));
718 ns_lwreslistener_detach(&listener);
719 return (ISC_R_SUCCESS);
722 if (oldlistener != NULL) {
724 * Remove the old listener from the old list and shut it down.
726 ISC_LIST_UNLINK(listeners, oldlistener, link);
727 listener_shutdown(oldlistener);
728 ns_lwreslistener_detach(&oldlistener);
730 isc_sockaddr_format(address, socktext, sizeof(socktext));
731 isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
732 NS_LOGMODULE_LWRESD, ISC_LOG_NOTICE,
733 "lwres listening on %s", socktext);
736 ISC_LIST_APPEND(*newlisteners, listener, link);
741 ns_lwresd_configure(isc_mem_t *mctx, cfg_obj_t *config) {
742 cfg_obj_t *lwreslist = NULL;
743 cfg_obj_t *lwres = NULL;
744 cfg_obj_t *listenerslist = NULL;
745 cfg_listelt_t *element = NULL;
746 ns_lwreslistener_t *listener;
747 ns_lwreslistenerlist_t newlisteners;
749 char socktext[ISC_SOCKADDR_FORMATSIZE];
750 isc_sockaddr_t *addrs = NULL;
751 ns_lwresd_t *lwresd = NULL;
752 isc_uint32_t count = 0;
754 REQUIRE(mctx != NULL);
755 REQUIRE(config != NULL);
757 RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS);
759 ISC_LIST_INIT(newlisteners);
761 result = cfg_map_get(config, "lwres", &lwreslist);
762 if (result != ISC_R_SUCCESS)
763 return (ISC_R_SUCCESS);
765 LOCK(&listeners_lock);
767 * Run through the new lwres address list, noting sockets that
768 * are already being listened on and moving them to the new list.
770 * Identifying duplicates addr/port combinations is left to either
771 * the underlying config code, or to the bind attempt getting an
772 * address-in-use error.
774 for (element = cfg_list_first(lwreslist);
776 element = cfg_list_next(element))
780 lwres = cfg_listelt_value(element);
781 CHECK(ns_lwdmanager_create(mctx, lwres, &lwresd));
783 port = lwresd_g_listenport;
785 port = LWRES_UDP_PORT;
787 listenerslist = NULL;
788 cfg_map_get(lwres, "listen-on", &listenerslist);
789 if (listenerslist == NULL) {
790 struct in_addr localhost;
791 isc_sockaddr_t address;
793 localhost.s_addr = htonl(INADDR_LOOPBACK);
794 isc_sockaddr_fromin(&address, &localhost, port);
795 CHECK(configure_listener(&address, lwresd, mctx,
800 CHECK(ns_config_getiplist(config, listenerslist,
801 port, mctx, &addrs, &count));
802 for (i = 0; i < count; i++)
803 CHECK(configure_listener(&addrs[i], lwresd,
804 mctx, &newlisteners));
805 ns_config_putiplist(mctx, &addrs, count);
807 ns_lwdmanager_detach(&lwresd);
811 * Shutdown everything on the listeners list, and remove them from
812 * the list. Then put all of the new listeners on it.
815 while (!ISC_LIST_EMPTY(listeners)) {
816 listener = ISC_LIST_HEAD(listeners);
817 ISC_LIST_UNLINK(listeners, listener, link);
819 isc_sockaddr_format(&listener->address,
820 socktext, sizeof(socktext));
822 listener_shutdown(listener);
823 ns_lwreslistener_detach(&listener);
825 isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
826 NS_LOGMODULE_LWRESD, ISC_LOG_NOTICE,
827 "lwres no longer listening on %s", socktext);
831 ISC_LIST_APPENDLIST(listeners, newlisteners, link);
834 ns_config_putiplist(mctx, &addrs, count);
837 ns_lwdmanager_detach(&lwresd);
839 UNLOCK(&listeners_lock);
845 ns_lwresd_shutdown(void) {
846 ns_lwreslistener_t *listener;
848 RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS);
850 while (!ISC_LIST_EMPTY(listeners)) {
851 listener = ISC_LIST_HEAD(listeners);
852 ISC_LIST_UNLINK(listeners, listener, link);
853 ns_lwreslistener_detach(&listener);