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
initialize_mutex(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 *
ns__lwresd_memalloc(void * arg,size_t size)88 ns__lwresd_memalloc(void *arg, size_t size) {
89 return (isc_mem_get(arg, size));
90 }
91
92 void
ns__lwresd_memfree(void * arg,void * mem,size_t size)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
buffer_putstr(isc_buffer_t * b,const char * s)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
ns_lwresd_parseeresolvconf(isc_mem_t * mctx,cfg_parser_t * pctx,cfg_obj_t ** configp)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
ns_lwdmanager_create(isc_mem_t * mctx,const cfg_obj_t * lwres,ns_lwresd_t ** lwresdp)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
ns_lwdmanager_attach(ns_lwresd_t * source,ns_lwresd_t ** targetp)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
ns_lwdmanager_detach(ns_lwresd_t ** lwresdp)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
ns_lwreslistener_attach(ns_lwreslistener_t * source,ns_lwreslistener_t ** targetp)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
ns_lwreslistener_detach(ns_lwreslistener_t ** listenerp)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
listener_create(isc_mem_t * mctx,ns_lwresd_t * lwresd,ns_lwreslistener_t ** listenerp)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
listener_bind(ns_lwreslistener_t * listener,isc_sockaddr_t * address)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
listener_copysock(ns_lwreslistener_t * oldlistener,ns_lwreslistener_t * newlistener)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
listener_startclients(ns_lwreslistener_t * listener)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
listener_shutdown(ns_lwreslistener_t * listener)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
find_listener(isc_sockaddr_t * address,ns_lwreslistener_t ** listenerp)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
ns_lwreslistener_unlinkcm(ns_lwreslistener_t * listener,ns_lwdclientmgr_t * cm)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
ns_lwreslistener_linkcm(ns_lwreslistener_t * listener,ns_lwdclientmgr_t * cm)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
configure_listener(isc_sockaddr_t * address,ns_lwresd_t * lwresd,isc_mem_t * mctx,ns_lwreslistenerlist_t * newlisteners)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
ns_lwresd_configure(isc_mem_t * mctx,const cfg_obj_t * config)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
ns_lwresd_shutdown(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