PageRenderTime 95ms CodeModel.GetById 53ms app.highlight 35ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/bind9/bin/named/lwresd.c

https://bitbucket.org/freebsd/freebsd-head/
C | 869 lines | 639 code | 145 blank | 85 comment | 149 complexity | 3c669f7465d2206e3b7bd5de3be549bb MD5 | raw file
  1/*
  2 * Copyright (C) 2004-2009  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
 69typedef ISC_LIST(ns_lwreslistener_t) ns_lwreslistenerlist_t;
 70
 71static ns_lwreslistenerlist_t listeners;
 72static isc_mutex_t listeners_lock;
 73static isc_once_t once = ISC_ONCE_INIT;
 74
 75
 76static void
 77initialize_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 */
 85void *
 86ns__lwresd_memalloc(void *arg, size_t size) {
 87	return (isc_mem_get(arg, size));
 88}
 89
 90void
 91ns__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
101static isc_result_t
102buffer_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 */
113isc_result_t
114ns_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 */
288isc_result_t
289ns_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_init(&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
414void
415ns_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
426void
427ns_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 */
461void
462ns_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
475void
476ns_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
509static isc_result_t
510listener_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
546static isc_result_t
547listener_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
595static void
596listener_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
603static isc_result_t
604listener_startclients(ns_lwreslistener_t *listener) {
605	ns_lwdclientmgr_t *cm;
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		result = ns_lwdclient_startrecv(cm);
630		if (result != ISC_R_SUCCESS)
631			isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
632				      NS_LOGMODULE_LWRESD, ISC_LOG_ERROR,
633				      "could not start lwres "
634				      "client handler: %s",
635				      isc_result_totext(result));
636		cm = ISC_LIST_NEXT(cm, link);
637	}
638	UNLOCK(&listener->lock);
639
640	return (ISC_R_SUCCESS);
641}
642
643static void
644listener_shutdown(ns_lwreslistener_t *listener) {
645	ns_lwdclientmgr_t *cm;
646
647	cm = ISC_LIST_HEAD(listener->cmgrs);
648	while (cm != NULL) {
649		isc_task_shutdown(cm->task);
650		cm = ISC_LIST_NEXT(cm, link);
651	}
652}
653
654static isc_result_t
655find_listener(isc_sockaddr_t *address, ns_lwreslistener_t **listenerp) {
656	ns_lwreslistener_t *listener;
657
658	INSIST(listenerp != NULL && *listenerp == NULL);
659
660	for (listener = ISC_LIST_HEAD(listeners);
661	     listener != NULL;
662	     listener = ISC_LIST_NEXT(listener, link))
663	{
664		if (!isc_sockaddr_equal(address, &listener->address))
665			continue;
666		*listenerp = listener;
667		return (ISC_R_SUCCESS);
668	}
669	return (ISC_R_NOTFOUND);
670}
671
672void
673ns_lwreslistener_unlinkcm(ns_lwreslistener_t *listener, ns_lwdclientmgr_t *cm)
674{
675	REQUIRE(VALID_LWRESLISTENER(listener));
676
677	LOCK(&listener->lock);
678	ISC_LIST_UNLINK(listener->cmgrs, cm, link);
679	UNLOCK(&listener->lock);
680}
681
682void
683ns_lwreslistener_linkcm(ns_lwreslistener_t *listener, ns_lwdclientmgr_t *cm) {
684	REQUIRE(VALID_LWRESLISTENER(listener));
685
686	/*
687	 * This does no locking, since it's called early enough that locking
688	 * isn't needed.
689	 */
690	ISC_LIST_APPEND(listener->cmgrs, cm, link);
691}
692
693static isc_result_t
694configure_listener(isc_sockaddr_t *address, ns_lwresd_t *lwresd,
695		   isc_mem_t *mctx, ns_lwreslistenerlist_t *newlisteners)
696{
697	ns_lwreslistener_t *listener, *oldlistener = NULL;
698	char socktext[ISC_SOCKADDR_FORMATSIZE];
699	isc_result_t result;
700
701	(void)find_listener(address, &oldlistener);
702	listener = NULL;
703	result = listener_create(mctx, lwresd, &listener);
704	if (result != ISC_R_SUCCESS) {
705		isc_sockaddr_format(address, socktext, sizeof(socktext));
706		isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
707			      NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
708			      "lwres failed to configure %s: %s",
709			      socktext, isc_result_totext(result));
710		return (result);
711	}
712
713	/*
714	 * If there's already a listener, don't rebind the socket.
715	 */
716	if (oldlistener == NULL) {
717		result = listener_bind(listener, address);
718		if (result != ISC_R_SUCCESS) {
719			ns_lwreslistener_detach(&listener);
720			return (ISC_R_SUCCESS);
721		}
722	} else
723		listener_copysock(oldlistener, listener);
724
725	result = listener_startclients(listener);
726	if (result != ISC_R_SUCCESS) {
727		isc_sockaddr_format(address, socktext, sizeof(socktext));
728		isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
729			      NS_LOGMODULE_LWRESD, ISC_LOG_WARNING,
730			      "lwres: failed to start %s: %s", socktext,
731			      isc_result_totext(result));
732		ns_lwreslistener_detach(&listener);
733		return (ISC_R_SUCCESS);
734	}
735
736	if (oldlistener != NULL) {
737		/*
738		 * Remove the old listener from the old list and shut it down.
739		 */
740		ISC_LIST_UNLINK(listeners, oldlistener, link);
741		listener_shutdown(oldlistener);
742		ns_lwreslistener_detach(&oldlistener);
743	} else {
744		isc_sockaddr_format(address, socktext, sizeof(socktext));
745		isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
746			      NS_LOGMODULE_LWRESD, ISC_LOG_NOTICE,
747			      "lwres listening on %s", socktext);
748	}
749
750	ISC_LIST_APPEND(*newlisteners, listener, link);
751	return (result);
752}
753
754isc_result_t
755ns_lwresd_configure(isc_mem_t *mctx, const cfg_obj_t *config) {
756	const cfg_obj_t *lwreslist = NULL;
757	const cfg_obj_t *lwres = NULL;
758	const cfg_obj_t *listenerslist = NULL;
759	const cfg_listelt_t *element = NULL;
760	ns_lwreslistener_t *listener;
761	ns_lwreslistenerlist_t newlisteners;
762	isc_result_t result;
763	char socktext[ISC_SOCKADDR_FORMATSIZE];
764	isc_sockaddr_t *addrs = NULL;
765	ns_lwresd_t *lwresd = NULL;
766	isc_uint32_t count = 0;
767
768	REQUIRE(mctx != NULL);
769	REQUIRE(config != NULL);
770
771	RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS);
772
773	ISC_LIST_INIT(newlisteners);
774
775	result = cfg_map_get(config, "lwres", &lwreslist);
776	if (result != ISC_R_SUCCESS)
777		return (ISC_R_SUCCESS);
778
779	LOCK(&listeners_lock);
780	/*
781	 * Run through the new lwres address list, noting sockets that
782	 * are already being listened on and moving them to the new list.
783	 *
784	 * Identifying duplicates addr/port combinations is left to either
785	 * the underlying config code, or to the bind attempt getting an
786	 * address-in-use error.
787	 */
788	for (element = cfg_list_first(lwreslist);
789	     element != NULL;
790	     element = cfg_list_next(element))
791	{
792		in_port_t port;
793
794		lwres = cfg_listelt_value(element);
795		CHECK(ns_lwdmanager_create(mctx, lwres, &lwresd));
796
797		port = lwresd_g_listenport;
798		if (port == 0)
799			port = LWRES_UDP_PORT;
800
801		listenerslist = NULL;
802		(void)cfg_map_get(lwres, "listen-on", &listenerslist);
803		if (listenerslist == NULL) {
804			struct in_addr localhost;
805			isc_sockaddr_t address;
806
807			localhost.s_addr = htonl(INADDR_LOOPBACK);
808			isc_sockaddr_fromin(&address, &localhost, port);
809			CHECK(configure_listener(&address, lwresd, mctx,
810						 &newlisteners));
811		} else {
812			isc_uint32_t i;
813
814			CHECK(ns_config_getiplist(config, listenerslist,
815						  port, mctx, &addrs, &count));
816			for (i = 0; i < count; i++)
817				CHECK(configure_listener(&addrs[i], lwresd,
818							 mctx, &newlisteners));
819			ns_config_putiplist(mctx, &addrs, count);
820		}
821		ns_lwdmanager_detach(&lwresd);
822	}
823
824	/*
825	 * Shutdown everything on the listeners list, and remove them from
826	 * the list.  Then put all of the new listeners on it.
827	 */
828
829	while (!ISC_LIST_EMPTY(listeners)) {
830		listener = ISC_LIST_HEAD(listeners);
831		ISC_LIST_UNLINK(listeners, listener, link);
832
833		isc_sockaddr_format(&listener->address,
834				    socktext, sizeof(socktext));
835
836		listener_shutdown(listener);
837		ns_lwreslistener_detach(&listener);
838
839		isc_log_write(ns_g_lctx, ISC_LOGCATEGORY_GENERAL,
840			      NS_LOGMODULE_LWRESD, ISC_LOG_NOTICE,
841			      "lwres no longer listening on %s", socktext);
842	}
843
844 cleanup:
845	ISC_LIST_APPENDLIST(listeners, newlisteners, link);
846
847	if (addrs != NULL)
848		ns_config_putiplist(mctx, &addrs, count);
849
850	if (lwresd != NULL)
851		ns_lwdmanager_detach(&lwresd);
852
853	UNLOCK(&listeners_lock);
854
855	return (result);
856}
857
858void
859ns_lwresd_shutdown(void) {
860	ns_lwreslistener_t *listener;
861
862	RUNTIME_CHECK(isc_once_do(&once, initialize_mutex) == ISC_R_SUCCESS);
863
864	while (!ISC_LIST_EMPTY(listeners)) {
865		listener = ISC_LIST_HEAD(listeners);
866		ISC_LIST_UNLINK(listeners, listener, link);
867		ns_lwreslistener_detach(&listener);
868	}
869}