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