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