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