]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bind9/bin/named/lwresd.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / bind9 / bin / named / lwresd.c
1 /*
2  * Copyright (C) 2004-2009  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.60 2009/09/02 23:48:01 tbox 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
69 typedef ISC_LIST(ns_lwreslistener_t) ns_lwreslistenerlist_t;
70
71 static ns_lwreslistenerlist_t listeners;
72 static isc_mutex_t listeners_lock;
73 static isc_once_t once = ISC_ONCE_INIT;
74
75
76 static void
77 initialize_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  */
85 void *
86 ns__lwresd_memalloc(void *arg, size_t size) {
87         return (isc_mem_get(arg, size));
88 }
89
90 void
91 ns__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
101 static isc_result_t
102 buffer_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  */
113 isc_result_t
114 ns_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  */
288 isc_result_t
289 ns_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, 0, NULL);
376                         if (result != ISC_R_SUCCESS) {
377                                 isc_log_write(ns_g_lctx,
378                                               NS_LOGCATEGORY_GENERAL,
379                                               NS_LOGMODULE_LWRESD,
380                                               ISC_LOG_WARNING,
381                                               "invalid name %s in searchlist",
382                                               searchstr);
383                                 continue;
384                         }
385
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,
390                                               NS_LOGMODULE_LWRESD,
391                                               ISC_LOG_WARNING,
392                                               "couldn't update searchlist");
393                                 goto fail;
394                         }
395                 }
396         }
397
398         lwresd->magic = LWRESD_MAGIC;
399
400         *lwresdp = lwresd;
401         return (ISC_R_SUCCESS);
402
403  fail:
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);
410         isc_mem_put(mctx, lwresd, sizeof(ns_lwresd_t));
411         return (result);
412 }
413
414 void
415 ns_lwdmanager_attach(ns_lwresd_t *source, ns_lwresd_t **targetp) {
416         INSIST(VALID_LWRESD(source));
417         INSIST(targetp != NULL && *targetp == NULL);
418
419         LOCK(&source->lock);
420         source->refs++;
421         UNLOCK(&source->lock);
422
423         *targetp = source;
424 }
425
426 void
427 ns_lwdmanager_detach(ns_lwresd_t **lwresdp) {
428         ns_lwresd_t *lwresd;
429         isc_mem_t *mctx;
430         isc_boolean_t done = ISC_FALSE;
431
432         INSIST(lwresdp != NULL && *lwresdp != NULL);
433         INSIST(VALID_LWRESD(*lwresdp));
434
435         lwresd = *lwresdp;
436         *lwresdp = NULL;
437
438         LOCK(&lwresd->lock);
439         INSIST(lwresd->refs > 0);
440         lwresd->refs--;
441         if (lwresd->refs == 0)
442                 done = ISC_TRUE;
443         UNLOCK(&lwresd->lock);
444
445         if (!done)
446                 return;
447
448         dns_view_detach(&lwresd->view);
449         if (lwresd->search != NULL)
450                 ns_lwsearchlist_detach(&lwresd->search);
451         mctx = lwresd->mctx;
452         lwresd->magic = 0;
453         isc_mem_put(mctx, lwresd, sizeof(*lwresd));
454         isc_mem_detach(&mctx);
455 }
456
457
458 /*
459  * Handle listener objects
460  */
461 void
462 ns_lwreslistener_attach(ns_lwreslistener_t *source,
463                         ns_lwreslistener_t **targetp)
464 {
465         INSIST(VALID_LWRESLISTENER(source));
466         INSIST(targetp != NULL && *targetp == NULL);
467
468         LOCK(&source->lock);
469         source->refs++;
470         UNLOCK(&source->lock);
471
472         *targetp = source;
473 }
474
475 void
476 ns_lwreslistener_detach(ns_lwreslistener_t **listenerp) {
477         ns_lwreslistener_t *listener;
478         isc_mem_t *mctx;
479         isc_boolean_t done = ISC_FALSE;
480
481         INSIST(listenerp != NULL && *listenerp != NULL);
482         INSIST(VALID_LWRESLISTENER(*listenerp));
483
484         listener = *listenerp;
485
486         LOCK(&listener->lock);
487         INSIST(listener->refs > 0);
488         listener->refs--;
489         if (listener->refs == 0)
490                 done = ISC_TRUE;
491         UNLOCK(&listener->lock);
492
493         if (!done)
494                 return;
495
496         if (listener->manager != NULL)
497                 ns_lwdmanager_detach(&listener->manager);
498
499         if (listener->sock != NULL)
500                 isc_socket_detach(&listener->sock);
501
502         listener->magic = 0;
503         mctx = listener->mctx;
504         isc_mem_put(mctx, listener, sizeof(*listener));
505         isc_mem_detach(&mctx);
506         listenerp = NULL;
507 }
508
509 static isc_result_t
510 listener_create(isc_mem_t *mctx, ns_lwresd_t *lwresd,
511                 ns_lwreslistener_t **listenerp)
512 {
513         ns_lwreslistener_t *listener;
514         isc_result_t result;
515
516         REQUIRE(listenerp != NULL && *listenerp == NULL);
517
518         listener = isc_mem_get(mctx, sizeof(ns_lwreslistener_t));
519         if (listener == NULL)
520                 return (ISC_R_NOMEMORY);
521
522         result = isc_mutex_init(&listener->lock);
523         if (result != ISC_R_SUCCESS) {
524                 isc_mem_put(mctx, listener, sizeof(ns_lwreslistener_t));
525                 return (result);
526         }
527
528         listener->magic = LWRESLISTENER_MAGIC;
529         listener->refs = 1;
530
531         listener->sock = NULL;
532
533         listener->manager = NULL;
534         ns_lwdmanager_attach(lwresd, &listener->manager);
535
536         listener->mctx = NULL;
537         isc_mem_attach(mctx, &listener->mctx);
538
539         ISC_LINK_INIT(listener, link);
540         ISC_LIST_INIT(listener->cmgrs);
541
542         *listenerp = listener;
543         return (ISC_R_SUCCESS);
544 }
545
546 static isc_result_t
547 listener_bind(ns_lwreslistener_t *listener, isc_sockaddr_t *address) {
548         isc_socket_t *sock = NULL;
549         isc_result_t result = ISC_R_SUCCESS;
550         int pf;
551
552         pf = isc_sockaddr_pf(address);
553         if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) ||
554             (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS))
555                 return (ISC_R_FAMILYNOSUPPORT);
556
557         listener->address = *address;
558
559         if (isc_sockaddr_getport(&listener->address) == 0) {
560                 in_port_t port;
561                 port = lwresd_g_listenport;
562                 if (port == 0)
563                         port = LWRES_UDP_PORT;
564                 isc_sockaddr_setport(&listener->address, port);
565         }
566
567         sock = NULL;
568         result = isc_socket_create(ns_g_socketmgr, pf,
569                                    isc_sockettype_udp, &sock);
570         if (result != ISC_R_SUCCESS) {
571                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
572                               NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
573                               "failed to create lwres socket: %s",
574                               isc_result_totext(result));
575                 return (result);
576         }
577
578         result = isc_socket_bind(sock, &listener->address,
579                                  ISC_SOCKET_REUSEADDRESS);
580         if (result != ISC_R_SUCCESS) {
581                 char socktext[ISC_SOCKADDR_FORMATSIZE];
582                 isc_sockaddr_format(&listener->address, socktext,
583                                     sizeof(socktext));
584                 isc_socket_detach(&sock);
585                 isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
586                               NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
587                               "failed to add lwres socket: %s: %s",
588                               socktext, isc_result_totext(result));
589                 return (result);
590         }
591         listener->sock = sock;
592         return (ISC_R_SUCCESS);
593 }
594
595 static void
596 listener_copysock(ns_lwreslistener_t *oldlistener,
597                   ns_lwreslistener_t *newlistener)
598 {
599         newlistener->address = oldlistener->address;
600         isc_socket_attach(oldlistener->sock, &newlistener->sock);
601 }
602
603 static isc_result_t
604 listener_startclients(ns_lwreslistener_t *listener) {
605         ns_lwdclientmgr_t *cm;
606         unsigned int i;
607         isc_result_t result;
608
609         /*
610          * Create the client managers.
611          */
612         result = ISC_R_SUCCESS;
613         for (i = 0; i < NTASKS && result == ISC_R_SUCCESS; i++)
614                 result = ns_lwdclientmgr_create(listener, NRECVS,
615                                                 ns_g_taskmgr);
616
617         /*
618          * Ensure that we have created at least one.
619          */
620         if (ISC_LIST_EMPTY(listener->cmgrs))
621                 return (result);
622
623         /*
624          * Walk the list of clients and start each one up.
625          */
626         LOCK(&listener->lock);
627         cm = ISC_LIST_HEAD(listener->cmgrs);
628         while (cm != NULL) {
629                 result = ns_lwdclient_startrecv(cm);
630                 if (result != ISC_R_SUCCESS)
631                         isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
632                                       NS_LOGMODULE_LWRESD, ISC_LOG_ERROR,
633                                       "could not start lwres "
634                                       "client handler: %s",
635                                       isc_result_totext(result));
636                 cm = ISC_LIST_NEXT(cm, link);
637         }
638         UNLOCK(&listener->lock);
639
640         return (ISC_R_SUCCESS);
641 }
642
643 static void
644 listener_shutdown(ns_lwreslistener_t *listener) {
645         ns_lwdclientmgr_t *cm;
646
647         cm = ISC_LIST_HEAD(listener->cmgrs);
648         while (cm != NULL) {
649                 isc_task_shutdown(cm->task);
650                 cm = ISC_LIST_NEXT(cm, link);
651         }
652 }
653
654 static isc_result_t
655 find_listener(isc_sockaddr_t *address, ns_lwreslistener_t **listenerp) {
656         ns_lwreslistener_t *listener;
657
658         INSIST(listenerp != NULL && *listenerp == NULL);
659
660         for (listener = ISC_LIST_HEAD(listeners);
661              listener != NULL;
662              listener = ISC_LIST_NEXT(listener, link))
663         {
664                 if (!isc_sockaddr_equal(address, &listener->address))
665                         continue;
666                 *listenerp = listener;
667                 return (ISC_R_SUCCESS);
668         }
669         return (ISC_R_NOTFOUND);
670 }
671
672 void
673 ns_lwreslistener_unlinkcm(ns_lwreslistener_t *listener, ns_lwdclientmgr_t *cm)
674 {
675         REQUIRE(VALID_LWRESLISTENER(listener));
676
677         LOCK(&listener->lock);
678         ISC_LIST_UNLINK(listener->cmgrs, cm, link);
679         UNLOCK(&listener->lock);
680 }
681
682 void
683 ns_lwreslistener_linkcm(ns_lwreslistener_t *listener, ns_lwdclientmgr_t *cm) {
684         REQUIRE(VALID_LWRESLISTENER(listener));
685
686         /*
687          * This does no locking, since it's called early enough that locking
688          * isn't needed.
689          */
690         ISC_LIST_APPEND(listener->cmgrs, cm, link);
691 }
692
693 static isc_result_t
694 configure_listener(isc_sockaddr_t *address, ns_lwresd_t *lwresd,
695                    isc_mem_t *mctx, ns_lwreslistenerlist_t *newlisteners)
696 {
697         ns_lwreslistener_t *listener, *oldlistener = NULL;
698         char socktext[ISC_SOCKADDR_FORMATSIZE];
699         isc_result_t result;
700
701         (void)find_listener(address, &oldlistener);
702         listener = NULL;
703         result = listener_create(mctx, lwresd, &listener);
704         if (result != ISC_R_SUCCESS) {
705                 isc_sockaddr_format(address, socktext, sizeof(socktext));
706                 isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
707                               NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
708                               "lwres failed to configure %s: %s",
709                               socktext, isc_result_totext(result));
710                 return (result);
711         }
712
713         /*
714          * If there's already a listener, don't rebind the socket.
715          */
716         if (oldlistener == NULL) {
717                 result = listener_bind(listener, address);
718                 if (result != ISC_R_SUCCESS) {
719                         ns_lwreslistener_detach(&listener);
720                         return (ISC_R_SUCCESS);
721                 }
722         } else
723                 listener_copysock(oldlistener, listener);
724
725         result = listener_startclients(listener);
726         if (result != ISC_R_SUCCESS) {
727                 isc_sockaddr_format(address, socktext, sizeof(socktext));
728                 isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
729                               NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
730                               "lwres: failed to start %s: %s", socktext,
731                               isc_result_totext(result));
732                 ns_lwreslistener_detach(&listener);
733                 return (ISC_R_SUCCESS);
734         }
735
736         if (oldlistener != NULL) {
737                 /*
738                  * Remove the old listener from the old list and shut it down.
739                  */
740                 ISC_LIST_UNLINK(listeners, oldlistener, link);
741                 listener_shutdown(oldlistener);
742                 ns_lwreslistener_detach(&oldlistener);
743         } else {
744                 isc_sockaddr_format(address, socktext, sizeof(socktext));
745                 isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
746                               NS_LOGMODULE_LWRESD, ISC_LOG_NOTICE,
747                               "lwres listening on %s", socktext);
748         }
749
750         ISC_LIST_APPEND(*newlisteners, listener, link);
751         return (result);
752 }
753
754 isc_result_t
755 ns_lwresd_configure(isc_mem_t *mctx, const cfg_obj_t *config) {
756         const cfg_obj_t *lwreslist = NULL;
757         const cfg_obj_t *lwres = NULL;
758         const cfg_obj_t *listenerslist = NULL;
759         const cfg_listelt_t *element = NULL;
760         ns_lwreslistener_t *listener;
761         ns_lwreslistenerlist_t newlisteners;
762         isc_result_t result;
763         char socktext[ISC_SOCKADDR_FORMATSIZE];
764         isc_sockaddr_t *addrs = NULL;
765         ns_lwresd_t *lwresd = NULL;
766         isc_uint32_t count = 0;
767
768         REQUIRE(mctx != NULL);
769         REQUIRE(config != NULL);
770
771         RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS);
772
773         ISC_LIST_INIT(newlisteners);
774
775         result = cfg_map_get(config, "lwres", &lwreslist);
776         if (result != ISC_R_SUCCESS)
777                 return (ISC_R_SUCCESS);
778
779         LOCK(&listeners_lock);
780         /*
781          * Run through the new lwres address list, noting sockets that
782          * are already being listened on and moving them to the new list.
783          *
784          * Identifying duplicates addr/port combinations is left to either
785          * the underlying config code, or to the bind attempt getting an
786          * address-in-use error.
787          */
788         for (element = cfg_list_first(lwreslist);
789              element != NULL;
790              element = cfg_list_next(element))
791         {
792                 in_port_t port;
793
794                 lwres = cfg_listelt_value(element);
795                 CHECK(ns_lwdmanager_create(mctx, lwres, &lwresd));
796
797                 port = lwresd_g_listenport;
798                 if (port == 0)
799                         port = LWRES_UDP_PORT;
800
801                 listenerslist = NULL;
802                 (void)cfg_map_get(lwres, "listen-on", &listenerslist);
803                 if (listenerslist == NULL) {
804                         struct in_addr localhost;
805                         isc_sockaddr_t address;
806
807                         localhost.s_addr = htonl(INADDR_LOOPBACK);
808                         isc_sockaddr_fromin(&address, &localhost, port);
809                         CHECK(configure_listener(&address, lwresd, mctx,
810                                                  &newlisteners));
811                 } else {
812                         isc_uint32_t i;
813
814                         CHECK(ns_config_getiplist(config, listenerslist,
815                                                   port, mctx, &addrs, &count));
816                         for (i = 0; i < count; i++)
817                                 CHECK(configure_listener(&addrs[i], lwresd,
818                                                          mctx, &newlisteners));
819                         ns_config_putiplist(mctx, &addrs, count);
820                 }
821                 ns_lwdmanager_detach(&lwresd);
822         }
823
824         /*
825          * Shutdown everything on the listeners list, and remove them from
826          * the list.  Then put all of the new listeners on it.
827          */
828
829         while (!ISC_LIST_EMPTY(listeners)) {
830                 listener = ISC_LIST_HEAD(listeners);
831                 ISC_LIST_UNLINK(listeners, listener, link);
832
833                 isc_sockaddr_format(&listener->address,
834                                     socktext, sizeof(socktext));
835
836                 listener_shutdown(listener);
837                 ns_lwreslistener_detach(&listener);
838
839                 isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
840                               NS_LOGMODULE_LWRESD, ISC_LOG_NOTICE,
841                               "lwres no longer listening on %s", socktext);
842         }
843
844  cleanup:
845         ISC_LIST_APPENDLIST(listeners, newlisteners, link);
846
847         if (addrs != NULL)
848                 ns_config_putiplist(mctx, &addrs, count);
849
850         if (lwresd != NULL)
851                 ns_lwdmanager_detach(&lwresd);
852
853         UNLOCK(&listeners_lock);
854
855         return (result);
856 }
857
858 void
859 ns_lwresd_shutdown(void) {
860         ns_lwreslistener_t *listener;
861
862         RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS);
863
864         while (!ISC_LIST_EMPTY(listeners)) {
865                 listener = ISC_LIST_HEAD(listeners);
866                 ISC_LIST_UNLINK(listeners, listener, link);
867                 ns_lwreslistener_detach(&listener);
868         }
869 }