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