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