1*00b67f09SDavid van Moolenbroek /*	$NetBSD: interfacemgr.c,v 1.10 2015/07/08 17:28:55 christos Exp $	*/
2*00b67f09SDavid van Moolenbroek 
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek  * Copyright (C) 2004-2009, 2011-2015  Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek  * Copyright (C) 1999-2002  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: interfacemgr.c,v 1.101 2011/11/09 18:44:03 each Exp  */
21*00b67f09SDavid van Moolenbroek 
22*00b67f09SDavid van Moolenbroek /*! \file */
23*00b67f09SDavid van Moolenbroek 
24*00b67f09SDavid van Moolenbroek #include <config.h>
25*00b67f09SDavid van Moolenbroek 
26*00b67f09SDavid van Moolenbroek #include <isc/interfaceiter.h>
27*00b67f09SDavid van Moolenbroek #include <isc/os.h>
28*00b67f09SDavid van Moolenbroek #include <isc/string.h>
29*00b67f09SDavid van Moolenbroek #include <isc/task.h>
30*00b67f09SDavid van Moolenbroek #include <isc/util.h>
31*00b67f09SDavid van Moolenbroek 
32*00b67f09SDavid van Moolenbroek #include <dns/acl.h>
33*00b67f09SDavid van Moolenbroek #include <dns/dispatch.h>
34*00b67f09SDavid van Moolenbroek 
35*00b67f09SDavid van Moolenbroek #include <named/client.h>
36*00b67f09SDavid van Moolenbroek #include <named/log.h>
37*00b67f09SDavid van Moolenbroek #include <named/interfacemgr.h>
38*00b67f09SDavid van Moolenbroek #include <named/server.h>
39*00b67f09SDavid van Moolenbroek 
40*00b67f09SDavid van Moolenbroek #ifdef HAVE_NET_ROUTE_H
41*00b67f09SDavid van Moolenbroek #include <net/route.h>
42*00b67f09SDavid van Moolenbroek #if defined(RTM_VERSION) && defined(RTM_NEWADDR) && defined(RTM_DELADDR)
43*00b67f09SDavid van Moolenbroek #define USE_ROUTE_SOCKET 1
44*00b67f09SDavid van Moolenbroek #define ROUTE_SOCKET_PROTOCOL PF_ROUTE
45*00b67f09SDavid van Moolenbroek #define MSGHDR rt_msghdr
46*00b67f09SDavid van Moolenbroek #define MSGTYPE rtm_type
47*00b67f09SDavid van Moolenbroek #endif
48*00b67f09SDavid van Moolenbroek #endif
49*00b67f09SDavid van Moolenbroek 
50*00b67f09SDavid van Moolenbroek #if defined(HAVE_LINUX_NETLINK_H) && defined(HAVE_LINUX_RTNETLINK_H)
51*00b67f09SDavid van Moolenbroek #include <linux/netlink.h>
52*00b67f09SDavid van Moolenbroek #include <linux/rtnetlink.h>
53*00b67f09SDavid van Moolenbroek #if defined(RTM_NEWADDR) && defined(RTM_DELADDR)
54*00b67f09SDavid van Moolenbroek #define USE_ROUTE_SOCKET 1
55*00b67f09SDavid van Moolenbroek #define ROUTE_SOCKET_PROTOCOL PF_NETLINK
56*00b67f09SDavid van Moolenbroek #define MSGHDR nlmsghdr
57*00b67f09SDavid van Moolenbroek #define MSGTYPE nlmsg_type
58*00b67f09SDavid van Moolenbroek #endif
59*00b67f09SDavid van Moolenbroek #endif
60*00b67f09SDavid van Moolenbroek 
61*00b67f09SDavid van Moolenbroek #ifdef TUNE_LARGE
62*00b67f09SDavid van Moolenbroek #define UDPBUFFERS 32768
63*00b67f09SDavid van Moolenbroek #else
64*00b67f09SDavid van Moolenbroek #define UDPBUFFERS 1000
65*00b67f09SDavid van Moolenbroek #endif /* TUNE_LARGE */
66*00b67f09SDavid van Moolenbroek 
67*00b67f09SDavid van Moolenbroek #define IFMGR_MAGIC			ISC_MAGIC('I', 'F', 'M', 'G')
68*00b67f09SDavid van Moolenbroek #define NS_INTERFACEMGR_VALID(t)	ISC_MAGIC_VALID(t, IFMGR_MAGIC)
69*00b67f09SDavid van Moolenbroek 
70*00b67f09SDavid van Moolenbroek #define IFMGR_COMMON_LOGARGS \
71*00b67f09SDavid van Moolenbroek 	ns_g_lctx, NS_LOGCATEGORY_NETWORK, NS_LOGMODULE_INTERFACEMGR
72*00b67f09SDavid van Moolenbroek 
73*00b67f09SDavid van Moolenbroek /*% nameserver interface manager structure */
74*00b67f09SDavid van Moolenbroek struct ns_interfacemgr {
75*00b67f09SDavid van Moolenbroek 	unsigned int		magic;		/*%< Magic number. */
76*00b67f09SDavid van Moolenbroek 	int			references;
77*00b67f09SDavid van Moolenbroek 	isc_mutex_t		lock;
78*00b67f09SDavid van Moolenbroek 	isc_mem_t *		mctx;		/*%< Memory context. */
79*00b67f09SDavid van Moolenbroek 	isc_taskmgr_t *		taskmgr;	/*%< Task manager. */
80*00b67f09SDavid van Moolenbroek 	isc_socketmgr_t *	socketmgr;	/*%< Socket manager. */
81*00b67f09SDavid van Moolenbroek 	dns_dispatchmgr_t *	dispatchmgr;
82*00b67f09SDavid van Moolenbroek 	unsigned int		generation;	/*%< Current generation no. */
83*00b67f09SDavid van Moolenbroek 	ns_listenlist_t *	listenon4;
84*00b67f09SDavid van Moolenbroek 	ns_listenlist_t *	listenon6;
85*00b67f09SDavid van Moolenbroek 	dns_aclenv_t		aclenv;		/*%< Localhost/localnets ACLs */
86*00b67f09SDavid van Moolenbroek 	ISC_LIST(ns_interface_t) interfaces;	/*%< List of interfaces. */
87*00b67f09SDavid van Moolenbroek 	ISC_LIST(isc_sockaddr_t) listenon;
88*00b67f09SDavid van Moolenbroek #ifdef USE_ROUTE_SOCKET
89*00b67f09SDavid van Moolenbroek 	isc_task_t *		task;
90*00b67f09SDavid van Moolenbroek 	isc_socket_t *		route;
91*00b67f09SDavid van Moolenbroek 	unsigned char		buf[2048];
92*00b67f09SDavid van Moolenbroek #endif
93*00b67f09SDavid van Moolenbroek };
94*00b67f09SDavid van Moolenbroek 
95*00b67f09SDavid van Moolenbroek static void
96*00b67f09SDavid van Moolenbroek purge_old_interfaces(ns_interfacemgr_t *mgr);
97*00b67f09SDavid van Moolenbroek 
98*00b67f09SDavid van Moolenbroek static void
99*00b67f09SDavid van Moolenbroek clearlistenon(ns_interfacemgr_t *mgr);
100*00b67f09SDavid van Moolenbroek 
101*00b67f09SDavid van Moolenbroek #ifdef USE_ROUTE_SOCKET
102*00b67f09SDavid van Moolenbroek static void
route_event(isc_task_t * task,isc_event_t * event)103*00b67f09SDavid van Moolenbroek route_event(isc_task_t *task, isc_event_t *event) {
104*00b67f09SDavid van Moolenbroek 	isc_socketevent_t *sevent = NULL;
105*00b67f09SDavid van Moolenbroek 	ns_interfacemgr_t *mgr = NULL;
106*00b67f09SDavid van Moolenbroek 	isc_region_t r;
107*00b67f09SDavid van Moolenbroek 	isc_result_t result;
108*00b67f09SDavid van Moolenbroek 	struct MSGHDR *rtm;
109*00b67f09SDavid van Moolenbroek 	isc_boolean_t done = ISC_TRUE;
110*00b67f09SDavid van Moolenbroek 
111*00b67f09SDavid van Moolenbroek 	UNUSED(task);
112*00b67f09SDavid van Moolenbroek 
113*00b67f09SDavid van Moolenbroek 	REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE);
114*00b67f09SDavid van Moolenbroek 	mgr = event->ev_arg;
115*00b67f09SDavid van Moolenbroek 	sevent = (isc_socketevent_t *)event;
116*00b67f09SDavid van Moolenbroek 
117*00b67f09SDavid van Moolenbroek 	if (sevent->result != ISC_R_SUCCESS) {
118*00b67f09SDavid van Moolenbroek 		if (sevent->result != ISC_R_CANCELED)
119*00b67f09SDavid van Moolenbroek 			isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
120*00b67f09SDavid van Moolenbroek 				      "automatic interface scanning "
121*00b67f09SDavid van Moolenbroek 				      "terminated: %s",
122*00b67f09SDavid van Moolenbroek 				      isc_result_totext(sevent->result));
123*00b67f09SDavid van Moolenbroek 		ns_interfacemgr_detach(&mgr);
124*00b67f09SDavid van Moolenbroek 		isc_event_free(&event);
125*00b67f09SDavid van Moolenbroek 		return;
126*00b67f09SDavid van Moolenbroek 	}
127*00b67f09SDavid van Moolenbroek 
128*00b67f09SDavid van Moolenbroek 	rtm = (struct MSGHDR *)mgr->buf;
129*00b67f09SDavid van Moolenbroek #ifdef RTM_VERSION
130*00b67f09SDavid van Moolenbroek 	if (rtm->rtm_version != RTM_VERSION) {
131*00b67f09SDavid van Moolenbroek 		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
132*00b67f09SDavid van Moolenbroek 			      "automatic interface rescanning disabled: "
133*00b67f09SDavid van Moolenbroek 			      "rtm->rtm_version mismatch (%u != %u) "
134*00b67f09SDavid van Moolenbroek 			      "recompile required", rtm->rtm_version,
135*00b67f09SDavid van Moolenbroek 			      RTM_VERSION);
136*00b67f09SDavid van Moolenbroek 		ns_interfacemgr_detach(&mgr);
137*00b67f09SDavid van Moolenbroek 		isc_event_free(&event);
138*00b67f09SDavid van Moolenbroek 		return;
139*00b67f09SDavid van Moolenbroek 	}
140*00b67f09SDavid van Moolenbroek #endif
141*00b67f09SDavid van Moolenbroek 
142*00b67f09SDavid van Moolenbroek 	switch (rtm->MSGTYPE) {
143*00b67f09SDavid van Moolenbroek 	case RTM_NEWADDR:
144*00b67f09SDavid van Moolenbroek 	case RTM_DELADDR:
145*00b67f09SDavid van Moolenbroek 		if (mgr->route != NULL && ns_g_server->interface_auto)
146*00b67f09SDavid van Moolenbroek 			ns_server_scan_interfaces(ns_g_server);
147*00b67f09SDavid van Moolenbroek 		break;
148*00b67f09SDavid van Moolenbroek 	default:
149*00b67f09SDavid van Moolenbroek 		break;
150*00b67f09SDavid van Moolenbroek 	}
151*00b67f09SDavid van Moolenbroek 
152*00b67f09SDavid van Moolenbroek 	LOCK(&mgr->lock);
153*00b67f09SDavid van Moolenbroek 	if (mgr->route != NULL) {
154*00b67f09SDavid van Moolenbroek 		/*
155*00b67f09SDavid van Moolenbroek 		 * Look for next route event.
156*00b67f09SDavid van Moolenbroek 		 */
157*00b67f09SDavid van Moolenbroek 		r.base = mgr->buf;
158*00b67f09SDavid van Moolenbroek 		r.length = sizeof(mgr->buf);
159*00b67f09SDavid van Moolenbroek 		result = isc_socket_recv(mgr->route, &r, 1, mgr->task,
160*00b67f09SDavid van Moolenbroek 					 route_event, mgr);
161*00b67f09SDavid van Moolenbroek 		if (result == ISC_R_SUCCESS)
162*00b67f09SDavid van Moolenbroek 			done = ISC_FALSE;
163*00b67f09SDavid van Moolenbroek 	}
164*00b67f09SDavid van Moolenbroek 	UNLOCK(&mgr->lock);
165*00b67f09SDavid van Moolenbroek 
166*00b67f09SDavid van Moolenbroek 	if (done)
167*00b67f09SDavid van Moolenbroek 		ns_interfacemgr_detach(&mgr);
168*00b67f09SDavid van Moolenbroek 	isc_event_free(&event);
169*00b67f09SDavid van Moolenbroek 	return;
170*00b67f09SDavid van Moolenbroek }
171*00b67f09SDavid van Moolenbroek #endif
172*00b67f09SDavid van Moolenbroek 
173*00b67f09SDavid van Moolenbroek isc_result_t
ns_interfacemgr_create(isc_mem_t * mctx,isc_taskmgr_t * taskmgr,isc_socketmgr_t * socketmgr,dns_dispatchmgr_t * dispatchmgr,isc_task_t * task,ns_interfacemgr_t ** mgrp)174*00b67f09SDavid van Moolenbroek ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
175*00b67f09SDavid van Moolenbroek 		       isc_socketmgr_t *socketmgr,
176*00b67f09SDavid van Moolenbroek 		       dns_dispatchmgr_t *dispatchmgr,
177*00b67f09SDavid van Moolenbroek 		       isc_task_t *task, ns_interfacemgr_t **mgrp)
178*00b67f09SDavid van Moolenbroek {
179*00b67f09SDavid van Moolenbroek 	isc_result_t result;
180*00b67f09SDavid van Moolenbroek 	ns_interfacemgr_t *mgr;
181*00b67f09SDavid van Moolenbroek 
182*00b67f09SDavid van Moolenbroek #ifndef USE_ROUTE_SOCKET
183*00b67f09SDavid van Moolenbroek 	UNUSED(task);
184*00b67f09SDavid van Moolenbroek #endif
185*00b67f09SDavid van Moolenbroek 
186*00b67f09SDavid van Moolenbroek 	REQUIRE(mctx != NULL);
187*00b67f09SDavid van Moolenbroek 	REQUIRE(mgrp != NULL);
188*00b67f09SDavid van Moolenbroek 	REQUIRE(*mgrp == NULL);
189*00b67f09SDavid van Moolenbroek 
190*00b67f09SDavid van Moolenbroek 	mgr = isc_mem_get(mctx, sizeof(*mgr));
191*00b67f09SDavid van Moolenbroek 	if (mgr == NULL)
192*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
193*00b67f09SDavid van Moolenbroek 
194*00b67f09SDavid van Moolenbroek 	mgr->mctx = NULL;
195*00b67f09SDavid van Moolenbroek 	isc_mem_attach(mctx, &mgr->mctx);
196*00b67f09SDavid van Moolenbroek 
197*00b67f09SDavid van Moolenbroek 	result = isc_mutex_init(&mgr->lock);
198*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
199*00b67f09SDavid van Moolenbroek 		goto cleanup_mem;
200*00b67f09SDavid van Moolenbroek 
201*00b67f09SDavid van Moolenbroek 	mgr->taskmgr = taskmgr;
202*00b67f09SDavid van Moolenbroek 	mgr->socketmgr = socketmgr;
203*00b67f09SDavid van Moolenbroek 	mgr->dispatchmgr = dispatchmgr;
204*00b67f09SDavid van Moolenbroek 	mgr->generation = 1;
205*00b67f09SDavid van Moolenbroek 	mgr->listenon4 = NULL;
206*00b67f09SDavid van Moolenbroek 	mgr->listenon6 = NULL;
207*00b67f09SDavid van Moolenbroek 
208*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(mgr->interfaces);
209*00b67f09SDavid van Moolenbroek 	ISC_LIST_INIT(mgr->listenon);
210*00b67f09SDavid van Moolenbroek 
211*00b67f09SDavid van Moolenbroek 	/*
212*00b67f09SDavid van Moolenbroek 	 * The listen-on lists are initially empty.
213*00b67f09SDavid van Moolenbroek 	 */
214*00b67f09SDavid van Moolenbroek 	result = ns_listenlist_create(mctx, &mgr->listenon4);
215*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
216*00b67f09SDavid van Moolenbroek 		goto cleanup_mem;
217*00b67f09SDavid van Moolenbroek 	ns_listenlist_attach(mgr->listenon4, &mgr->listenon6);
218*00b67f09SDavid van Moolenbroek 
219*00b67f09SDavid van Moolenbroek 	result = dns_aclenv_init(mctx, &mgr->aclenv);
220*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
221*00b67f09SDavid van Moolenbroek 		goto cleanup_listenon;
222*00b67f09SDavid van Moolenbroek #ifdef HAVE_GEOIP
223*00b67f09SDavid van Moolenbroek 	mgr->aclenv.geoip = ns_g_geoip;
224*00b67f09SDavid van Moolenbroek #endif
225*00b67f09SDavid van Moolenbroek 
226*00b67f09SDavid van Moolenbroek #ifdef USE_ROUTE_SOCKET
227*00b67f09SDavid van Moolenbroek 	mgr->route = NULL;
228*00b67f09SDavid van Moolenbroek 	result = isc_socket_create(mgr->socketmgr, ROUTE_SOCKET_PROTOCOL,
229*00b67f09SDavid van Moolenbroek 				   isc_sockettype_raw, &mgr->route);
230*00b67f09SDavid van Moolenbroek 	switch (result) {
231*00b67f09SDavid van Moolenbroek 	case ISC_R_NOPERM:
232*00b67f09SDavid van Moolenbroek 	case ISC_R_SUCCESS:
233*00b67f09SDavid van Moolenbroek 	case ISC_R_NOTIMPLEMENTED:
234*00b67f09SDavid van Moolenbroek 	case ISC_R_FAMILYNOSUPPORT:
235*00b67f09SDavid van Moolenbroek 	    break;
236*00b67f09SDavid van Moolenbroek 	default:
237*00b67f09SDavid van Moolenbroek 		goto cleanup_aclenv;
238*00b67f09SDavid van Moolenbroek 	}
239*00b67f09SDavid van Moolenbroek 
240*00b67f09SDavid van Moolenbroek 	mgr->task = NULL;
241*00b67f09SDavid van Moolenbroek 	if (mgr->route != NULL)
242*00b67f09SDavid van Moolenbroek 		isc_task_attach(task, &mgr->task);
243*00b67f09SDavid van Moolenbroek 	mgr->references = (mgr->route != NULL) ? 2 : 1;
244*00b67f09SDavid van Moolenbroek #else
245*00b67f09SDavid van Moolenbroek 	mgr->references = 1;
246*00b67f09SDavid van Moolenbroek #endif
247*00b67f09SDavid van Moolenbroek 	mgr->magic = IFMGR_MAGIC;
248*00b67f09SDavid van Moolenbroek 	*mgrp = mgr;
249*00b67f09SDavid van Moolenbroek 
250*00b67f09SDavid van Moolenbroek #ifdef USE_ROUTE_SOCKET
251*00b67f09SDavid van Moolenbroek 	if (mgr->route != NULL) {
252*00b67f09SDavid van Moolenbroek 		isc_region_t r = { mgr->buf, sizeof(mgr->buf) };
253*00b67f09SDavid van Moolenbroek 
254*00b67f09SDavid van Moolenbroek 		result = isc_socket_recv(mgr->route, &r, 1, mgr->task,
255*00b67f09SDavid van Moolenbroek 					 route_event, mgr);
256*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
257*00b67f09SDavid van Moolenbroek 			isc_task_detach(&mgr->task);
258*00b67f09SDavid van Moolenbroek 			isc_socket_detach(&mgr->route);
259*00b67f09SDavid van Moolenbroek 			ns_interfacemgr_detach(&mgr);
260*00b67f09SDavid van Moolenbroek 		}
261*00b67f09SDavid van Moolenbroek 	}
262*00b67f09SDavid van Moolenbroek #endif
263*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
264*00b67f09SDavid van Moolenbroek 
265*00b67f09SDavid van Moolenbroek #ifdef USE_ROUTE_SOCKET
266*00b67f09SDavid van Moolenbroek  cleanup_aclenv:
267*00b67f09SDavid van Moolenbroek 	dns_aclenv_destroy(&mgr->aclenv);
268*00b67f09SDavid van Moolenbroek #endif
269*00b67f09SDavid van Moolenbroek  cleanup_listenon:
270*00b67f09SDavid van Moolenbroek 	ns_listenlist_detach(&mgr->listenon4);
271*00b67f09SDavid van Moolenbroek 	ns_listenlist_detach(&mgr->listenon6);
272*00b67f09SDavid van Moolenbroek  cleanup_mem:
273*00b67f09SDavid van Moolenbroek 	isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr));
274*00b67f09SDavid van Moolenbroek 	return (result);
275*00b67f09SDavid van Moolenbroek }
276*00b67f09SDavid van Moolenbroek 
277*00b67f09SDavid van Moolenbroek static void
ns_interfacemgr_destroy(ns_interfacemgr_t * mgr)278*00b67f09SDavid van Moolenbroek ns_interfacemgr_destroy(ns_interfacemgr_t *mgr) {
279*00b67f09SDavid van Moolenbroek 	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
280*00b67f09SDavid van Moolenbroek 
281*00b67f09SDavid van Moolenbroek #ifdef USE_ROUTE_SOCKET
282*00b67f09SDavid van Moolenbroek 	if (mgr->route != NULL)
283*00b67f09SDavid van Moolenbroek 		isc_socket_detach(&mgr->route);
284*00b67f09SDavid van Moolenbroek 	if (mgr->task != NULL)
285*00b67f09SDavid van Moolenbroek 		isc_task_detach(&mgr->task);
286*00b67f09SDavid van Moolenbroek #endif
287*00b67f09SDavid van Moolenbroek 	dns_aclenv_destroy(&mgr->aclenv);
288*00b67f09SDavid van Moolenbroek 	ns_listenlist_detach(&mgr->listenon4);
289*00b67f09SDavid van Moolenbroek 	ns_listenlist_detach(&mgr->listenon6);
290*00b67f09SDavid van Moolenbroek 	clearlistenon(mgr);
291*00b67f09SDavid van Moolenbroek 	DESTROYLOCK(&mgr->lock);
292*00b67f09SDavid van Moolenbroek 	mgr->magic = 0;
293*00b67f09SDavid van Moolenbroek 	isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr));
294*00b67f09SDavid van Moolenbroek }
295*00b67f09SDavid van Moolenbroek 
296*00b67f09SDavid van Moolenbroek dns_aclenv_t *
ns_interfacemgr_getaclenv(ns_interfacemgr_t * mgr)297*00b67f09SDavid van Moolenbroek ns_interfacemgr_getaclenv(ns_interfacemgr_t *mgr) {
298*00b67f09SDavid van Moolenbroek 	return (&mgr->aclenv);
299*00b67f09SDavid van Moolenbroek }
300*00b67f09SDavid van Moolenbroek 
301*00b67f09SDavid van Moolenbroek void
ns_interfacemgr_attach(ns_interfacemgr_t * source,ns_interfacemgr_t ** target)302*00b67f09SDavid van Moolenbroek ns_interfacemgr_attach(ns_interfacemgr_t *source, ns_interfacemgr_t **target) {
303*00b67f09SDavid van Moolenbroek 	REQUIRE(NS_INTERFACEMGR_VALID(source));
304*00b67f09SDavid van Moolenbroek 	LOCK(&source->lock);
305*00b67f09SDavid van Moolenbroek 	INSIST(source->references > 0);
306*00b67f09SDavid van Moolenbroek 	source->references++;
307*00b67f09SDavid van Moolenbroek 	UNLOCK(&source->lock);
308*00b67f09SDavid van Moolenbroek 	*target = source;
309*00b67f09SDavid van Moolenbroek }
310*00b67f09SDavid van Moolenbroek 
311*00b67f09SDavid van Moolenbroek void
ns_interfacemgr_detach(ns_interfacemgr_t ** targetp)312*00b67f09SDavid van Moolenbroek ns_interfacemgr_detach(ns_interfacemgr_t **targetp) {
313*00b67f09SDavid van Moolenbroek 	isc_result_t need_destroy = ISC_FALSE;
314*00b67f09SDavid van Moolenbroek 	ns_interfacemgr_t *target = *targetp;
315*00b67f09SDavid van Moolenbroek 	REQUIRE(target != NULL);
316*00b67f09SDavid van Moolenbroek 	REQUIRE(NS_INTERFACEMGR_VALID(target));
317*00b67f09SDavid van Moolenbroek 	LOCK(&target->lock);
318*00b67f09SDavid van Moolenbroek 	REQUIRE(target->references > 0);
319*00b67f09SDavid van Moolenbroek 	target->references--;
320*00b67f09SDavid van Moolenbroek 	if (target->references == 0)
321*00b67f09SDavid van Moolenbroek 		need_destroy = ISC_TRUE;
322*00b67f09SDavid van Moolenbroek 	UNLOCK(&target->lock);
323*00b67f09SDavid van Moolenbroek 	if (need_destroy)
324*00b67f09SDavid van Moolenbroek 		ns_interfacemgr_destroy(target);
325*00b67f09SDavid van Moolenbroek 	*targetp = NULL;
326*00b67f09SDavid van Moolenbroek }
327*00b67f09SDavid van Moolenbroek 
328*00b67f09SDavid van Moolenbroek void
ns_interfacemgr_shutdown(ns_interfacemgr_t * mgr)329*00b67f09SDavid van Moolenbroek ns_interfacemgr_shutdown(ns_interfacemgr_t *mgr) {
330*00b67f09SDavid van Moolenbroek 	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
331*00b67f09SDavid van Moolenbroek 
332*00b67f09SDavid van Moolenbroek 	/*%
333*00b67f09SDavid van Moolenbroek 	 * Shut down and detach all interfaces.
334*00b67f09SDavid van Moolenbroek 	 * By incrementing the generation count, we make purge_old_interfaces()
335*00b67f09SDavid van Moolenbroek 	 * consider all interfaces "old".
336*00b67f09SDavid van Moolenbroek 	 */
337*00b67f09SDavid van Moolenbroek 	mgr->generation++;
338*00b67f09SDavid van Moolenbroek #ifdef USE_ROUTE_SOCKET
339*00b67f09SDavid van Moolenbroek 	LOCK(&mgr->lock);
340*00b67f09SDavid van Moolenbroek 	if (mgr->route != NULL) {
341*00b67f09SDavid van Moolenbroek 		isc_socket_cancel(mgr->route, mgr->task, ISC_SOCKCANCEL_RECV);
342*00b67f09SDavid van Moolenbroek 		isc_socket_detach(&mgr->route);
343*00b67f09SDavid van Moolenbroek 		isc_task_detach(&mgr->task);
344*00b67f09SDavid van Moolenbroek 	}
345*00b67f09SDavid van Moolenbroek 	UNLOCK(&mgr->lock);
346*00b67f09SDavid van Moolenbroek #endif
347*00b67f09SDavid van Moolenbroek 	purge_old_interfaces(mgr);
348*00b67f09SDavid van Moolenbroek }
349*00b67f09SDavid van Moolenbroek 
350*00b67f09SDavid van Moolenbroek 
351*00b67f09SDavid van Moolenbroek static isc_result_t
ns_interface_create(ns_interfacemgr_t * mgr,isc_sockaddr_t * addr,const char * name,ns_interface_t ** ifpret)352*00b67f09SDavid van Moolenbroek ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
353*00b67f09SDavid van Moolenbroek 		    const char *name, ns_interface_t **ifpret)
354*00b67f09SDavid van Moolenbroek {
355*00b67f09SDavid van Moolenbroek 	ns_interface_t *ifp;
356*00b67f09SDavid van Moolenbroek 	isc_result_t result;
357*00b67f09SDavid van Moolenbroek 	int disp;
358*00b67f09SDavid van Moolenbroek 
359*00b67f09SDavid van Moolenbroek 	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
360*00b67f09SDavid van Moolenbroek 
361*00b67f09SDavid van Moolenbroek 	ifp = isc_mem_get(mgr->mctx, sizeof(*ifp));
362*00b67f09SDavid van Moolenbroek 	if (ifp == NULL)
363*00b67f09SDavid van Moolenbroek 		return (ISC_R_NOMEMORY);
364*00b67f09SDavid van Moolenbroek 
365*00b67f09SDavid van Moolenbroek 	ifp->mgr = NULL;
366*00b67f09SDavid van Moolenbroek 	ifp->generation = mgr->generation;
367*00b67f09SDavid van Moolenbroek 	ifp->addr = *addr;
368*00b67f09SDavid van Moolenbroek 	ifp->flags = 0;
369*00b67f09SDavid van Moolenbroek 	strncpy(ifp->name, name, sizeof(ifp->name));
370*00b67f09SDavid van Moolenbroek 	ifp->name[sizeof(ifp->name)-1] = '\0';
371*00b67f09SDavid van Moolenbroek 	ifp->clientmgr = NULL;
372*00b67f09SDavid van Moolenbroek 
373*00b67f09SDavid van Moolenbroek 	result = isc_mutex_init(&ifp->lock);
374*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
375*00b67f09SDavid van Moolenbroek 		goto lock_create_failure;
376*00b67f09SDavid van Moolenbroek 
377*00b67f09SDavid van Moolenbroek 	result = ns_clientmgr_create(mgr->mctx, mgr->taskmgr,
378*00b67f09SDavid van Moolenbroek 				     ns_g_timermgr,
379*00b67f09SDavid van Moolenbroek 				     &ifp->clientmgr);
380*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
381*00b67f09SDavid van Moolenbroek 		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
382*00b67f09SDavid van Moolenbroek 			      "ns_clientmgr_create() failed: %s",
383*00b67f09SDavid van Moolenbroek 			      isc_result_totext(result));
384*00b67f09SDavid van Moolenbroek 		goto clientmgr_create_failure;
385*00b67f09SDavid van Moolenbroek 	}
386*00b67f09SDavid van Moolenbroek 
387*00b67f09SDavid van Moolenbroek 	for (disp = 0; disp < MAX_UDP_DISPATCH; disp++)
388*00b67f09SDavid van Moolenbroek 		ifp->udpdispatch[disp] = NULL;
389*00b67f09SDavid van Moolenbroek 
390*00b67f09SDavid van Moolenbroek 	ifp->tcpsocket = NULL;
391*00b67f09SDavid van Moolenbroek 
392*00b67f09SDavid van Moolenbroek 	/*
393*00b67f09SDavid van Moolenbroek 	 * Create a single TCP client object.  It will replace itself
394*00b67f09SDavid van Moolenbroek 	 * with a new one as soon as it gets a connection, so the actual
395*00b67f09SDavid van Moolenbroek 	 * connections will be handled in parallel even though there is
396*00b67f09SDavid van Moolenbroek 	 * only one client initially.
397*00b67f09SDavid van Moolenbroek 	 */
398*00b67f09SDavid van Moolenbroek 	ifp->ntcptarget = 1;
399*00b67f09SDavid van Moolenbroek 	ifp->ntcpcurrent = 0;
400*00b67f09SDavid van Moolenbroek 	ifp->nudpdispatch = 0;
401*00b67f09SDavid van Moolenbroek 
402*00b67f09SDavid van Moolenbroek 	ifp->dscp = -1;
403*00b67f09SDavid van Moolenbroek 
404*00b67f09SDavid van Moolenbroek 	ISC_LINK_INIT(ifp, link);
405*00b67f09SDavid van Moolenbroek 
406*00b67f09SDavid van Moolenbroek 	ns_interfacemgr_attach(mgr, &ifp->mgr);
407*00b67f09SDavid van Moolenbroek 	ISC_LIST_APPEND(mgr->interfaces, ifp, link);
408*00b67f09SDavid van Moolenbroek 
409*00b67f09SDavid van Moolenbroek 	ifp->references = 1;
410*00b67f09SDavid van Moolenbroek 	ifp->magic = IFACE_MAGIC;
411*00b67f09SDavid van Moolenbroek 	*ifpret = ifp;
412*00b67f09SDavid van Moolenbroek 
413*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
414*00b67f09SDavid van Moolenbroek 
415*00b67f09SDavid van Moolenbroek  clientmgr_create_failure:
416*00b67f09SDavid van Moolenbroek 	DESTROYLOCK(&ifp->lock);
417*00b67f09SDavid van Moolenbroek 
418*00b67f09SDavid van Moolenbroek  lock_create_failure:
419*00b67f09SDavid van Moolenbroek 	ifp->magic = 0;
420*00b67f09SDavid van Moolenbroek 	isc_mem_put(mgr->mctx, ifp, sizeof(*ifp));
421*00b67f09SDavid van Moolenbroek 
422*00b67f09SDavid van Moolenbroek 	return (ISC_R_UNEXPECTED);
423*00b67f09SDavid van Moolenbroek }
424*00b67f09SDavid van Moolenbroek 
425*00b67f09SDavid van Moolenbroek static isc_result_t
ns_interface_listenudp(ns_interface_t * ifp)426*00b67f09SDavid van Moolenbroek ns_interface_listenudp(ns_interface_t *ifp) {
427*00b67f09SDavid van Moolenbroek 	isc_result_t result;
428*00b67f09SDavid van Moolenbroek 	unsigned int attrs;
429*00b67f09SDavid van Moolenbroek 	unsigned int attrmask;
430*00b67f09SDavid van Moolenbroek 	int disp, i;
431*00b67f09SDavid van Moolenbroek 
432*00b67f09SDavid van Moolenbroek 	attrs = 0;
433*00b67f09SDavid van Moolenbroek 	attrs |= DNS_DISPATCHATTR_UDP;
434*00b67f09SDavid van Moolenbroek 	if (isc_sockaddr_pf(&ifp->addr) == AF_INET)
435*00b67f09SDavid van Moolenbroek 		attrs |= DNS_DISPATCHATTR_IPV4;
436*00b67f09SDavid van Moolenbroek 	else
437*00b67f09SDavid van Moolenbroek 		attrs |= DNS_DISPATCHATTR_IPV6;
438*00b67f09SDavid van Moolenbroek 	attrs |= DNS_DISPATCHATTR_NOLISTEN;
439*00b67f09SDavid van Moolenbroek 	attrmask = 0;
440*00b67f09SDavid van Moolenbroek 	attrmask |= DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP;
441*00b67f09SDavid van Moolenbroek 	attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6;
442*00b67f09SDavid van Moolenbroek 
443*00b67f09SDavid van Moolenbroek 	ifp->nudpdispatch = ISC_MIN(ns_g_udpdisp, MAX_UDP_DISPATCH);
444*00b67f09SDavid van Moolenbroek 	for (disp = 0; disp < ifp->nudpdispatch; disp++) {
445*00b67f09SDavid van Moolenbroek 		result = dns_dispatch_getudp_dup(ifp->mgr->dispatchmgr,
446*00b67f09SDavid van Moolenbroek 						 ns_g_socketmgr,
447*00b67f09SDavid van Moolenbroek 						 ns_g_taskmgr, &ifp->addr,
448*00b67f09SDavid van Moolenbroek 						 4096, UDPBUFFERS,
449*00b67f09SDavid van Moolenbroek 						 32768, 8219, 8237,
450*00b67f09SDavid van Moolenbroek 						 attrs, attrmask,
451*00b67f09SDavid van Moolenbroek 						 &ifp->udpdispatch[disp],
452*00b67f09SDavid van Moolenbroek 						 disp == 0
453*00b67f09SDavid van Moolenbroek 						    ? NULL
454*00b67f09SDavid van Moolenbroek 						    : ifp->udpdispatch[0]);
455*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
456*00b67f09SDavid van Moolenbroek 			isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
457*00b67f09SDavid van Moolenbroek 				      "could not listen on UDP socket: %s",
458*00b67f09SDavid van Moolenbroek 				      isc_result_totext(result));
459*00b67f09SDavid van Moolenbroek 			goto udp_dispatch_failure;
460*00b67f09SDavid van Moolenbroek 		}
461*00b67f09SDavid van Moolenbroek 
462*00b67f09SDavid van Moolenbroek 	}
463*00b67f09SDavid van Moolenbroek 
464*00b67f09SDavid van Moolenbroek 	result = ns_clientmgr_createclients(ifp->clientmgr, ifp->nudpdispatch,
465*00b67f09SDavid van Moolenbroek 					    ifp, ISC_FALSE);
466*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
467*00b67f09SDavid van Moolenbroek 		UNEXPECTED_ERROR(__FILE__, __LINE__,
468*00b67f09SDavid van Moolenbroek 				 "UDP ns_clientmgr_createclients(): %s",
469*00b67f09SDavid van Moolenbroek 				 isc_result_totext(result));
470*00b67f09SDavid van Moolenbroek 		goto addtodispatch_failure;
471*00b67f09SDavid van Moolenbroek 	}
472*00b67f09SDavid van Moolenbroek 
473*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
474*00b67f09SDavid van Moolenbroek 
475*00b67f09SDavid van Moolenbroek  addtodispatch_failure:
476*00b67f09SDavid van Moolenbroek 	for (i = disp - 1; i <= 0; i--) {
477*00b67f09SDavid van Moolenbroek 		dns_dispatch_changeattributes(ifp->udpdispatch[i], 0,
478*00b67f09SDavid van Moolenbroek 					      DNS_DISPATCHATTR_NOLISTEN);
479*00b67f09SDavid van Moolenbroek 		dns_dispatch_detach(&(ifp->udpdispatch[i]));
480*00b67f09SDavid van Moolenbroek 	}
481*00b67f09SDavid van Moolenbroek 	ifp->nudpdispatch = 0;
482*00b67f09SDavid van Moolenbroek 
483*00b67f09SDavid van Moolenbroek  udp_dispatch_failure:
484*00b67f09SDavid van Moolenbroek 	return (result);
485*00b67f09SDavid van Moolenbroek }
486*00b67f09SDavid van Moolenbroek 
487*00b67f09SDavid van Moolenbroek static isc_result_t
ns_interface_accepttcp(ns_interface_t * ifp)488*00b67f09SDavid van Moolenbroek ns_interface_accepttcp(ns_interface_t *ifp) {
489*00b67f09SDavid van Moolenbroek 	isc_result_t result;
490*00b67f09SDavid van Moolenbroek 
491*00b67f09SDavid van Moolenbroek 	/*
492*00b67f09SDavid van Moolenbroek 	 * Open a TCP socket.
493*00b67f09SDavid van Moolenbroek 	 */
494*00b67f09SDavid van Moolenbroek 	result = isc_socket_create(ifp->mgr->socketmgr,
495*00b67f09SDavid van Moolenbroek 				   isc_sockaddr_pf(&ifp->addr),
496*00b67f09SDavid van Moolenbroek 				   isc_sockettype_tcp,
497*00b67f09SDavid van Moolenbroek 				   &ifp->tcpsocket);
498*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
499*00b67f09SDavid van Moolenbroek 		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
500*00b67f09SDavid van Moolenbroek 				 "creating TCP socket: %s",
501*00b67f09SDavid van Moolenbroek 				 isc_result_totext(result));
502*00b67f09SDavid van Moolenbroek 		goto tcp_socket_failure;
503*00b67f09SDavid van Moolenbroek 	}
504*00b67f09SDavid van Moolenbroek 	isc_socket_setname(ifp->tcpsocket, "dispatcher", NULL);
505*00b67f09SDavid van Moolenbroek #ifndef ISC_ALLOW_MAPPED
506*00b67f09SDavid van Moolenbroek 	isc_socket_ipv6only(ifp->tcpsocket, ISC_TRUE);
507*00b67f09SDavid van Moolenbroek #endif
508*00b67f09SDavid van Moolenbroek 	result = isc_socket_bind(ifp->tcpsocket, &ifp->addr,
509*00b67f09SDavid van Moolenbroek 				 ISC_SOCKET_REUSEADDRESS);
510*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
511*00b67f09SDavid van Moolenbroek 		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
512*00b67f09SDavid van Moolenbroek 				 "binding TCP socket: %s",
513*00b67f09SDavid van Moolenbroek 				 isc_result_totext(result));
514*00b67f09SDavid van Moolenbroek 		goto tcp_bind_failure;
515*00b67f09SDavid van Moolenbroek 	}
516*00b67f09SDavid van Moolenbroek 
517*00b67f09SDavid van Moolenbroek 	if (ifp->dscp != -1)
518*00b67f09SDavid van Moolenbroek 		isc_socket_dscp(ifp->tcpsocket, ifp->dscp);
519*00b67f09SDavid van Moolenbroek 
520*00b67f09SDavid van Moolenbroek 	result = isc_socket_listen(ifp->tcpsocket, ns_g_listen);
521*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
522*00b67f09SDavid van Moolenbroek 		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
523*00b67f09SDavid van Moolenbroek 				 "listening on TCP socket: %s",
524*00b67f09SDavid van Moolenbroek 				 isc_result_totext(result));
525*00b67f09SDavid van Moolenbroek 		goto tcp_listen_failure;
526*00b67f09SDavid van Moolenbroek 	}
527*00b67f09SDavid van Moolenbroek 
528*00b67f09SDavid van Moolenbroek 	/*
529*00b67f09SDavid van Moolenbroek 	 * If/when there a multiple filters listen to the
530*00b67f09SDavid van Moolenbroek 	 * result.
531*00b67f09SDavid van Moolenbroek 	 */
532*00b67f09SDavid van Moolenbroek 	(void)isc_socket_filter(ifp->tcpsocket, "dataready");
533*00b67f09SDavid van Moolenbroek 
534*00b67f09SDavid van Moolenbroek 	result = ns_clientmgr_createclients(ifp->clientmgr,
535*00b67f09SDavid van Moolenbroek 					    ifp->ntcptarget, ifp,
536*00b67f09SDavid van Moolenbroek 					    ISC_TRUE);
537*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
538*00b67f09SDavid van Moolenbroek 		UNEXPECTED_ERROR(__FILE__, __LINE__,
539*00b67f09SDavid van Moolenbroek 				 "TCP ns_clientmgr_createclients(): %s",
540*00b67f09SDavid van Moolenbroek 				 isc_result_totext(result));
541*00b67f09SDavid van Moolenbroek 		goto accepttcp_failure;
542*00b67f09SDavid van Moolenbroek 	}
543*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
544*00b67f09SDavid van Moolenbroek 
545*00b67f09SDavid van Moolenbroek  accepttcp_failure:
546*00b67f09SDavid van Moolenbroek  tcp_listen_failure:
547*00b67f09SDavid van Moolenbroek  tcp_bind_failure:
548*00b67f09SDavid van Moolenbroek 	isc_socket_detach(&ifp->tcpsocket);
549*00b67f09SDavid van Moolenbroek  tcp_socket_failure:
550*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
551*00b67f09SDavid van Moolenbroek }
552*00b67f09SDavid van Moolenbroek 
553*00b67f09SDavid van Moolenbroek static isc_result_t
ns_interface_setup(ns_interfacemgr_t * mgr,isc_sockaddr_t * addr,const char * name,ns_interface_t ** ifpret,isc_boolean_t accept_tcp,isc_dscp_t dscp)554*00b67f09SDavid van Moolenbroek ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
555*00b67f09SDavid van Moolenbroek 		   const char *name, ns_interface_t **ifpret,
556*00b67f09SDavid van Moolenbroek 		   isc_boolean_t accept_tcp, isc_dscp_t dscp)
557*00b67f09SDavid van Moolenbroek {
558*00b67f09SDavid van Moolenbroek 	isc_result_t result;
559*00b67f09SDavid van Moolenbroek 	ns_interface_t *ifp = NULL;
560*00b67f09SDavid van Moolenbroek 	REQUIRE(ifpret != NULL && *ifpret == NULL);
561*00b67f09SDavid van Moolenbroek 
562*00b67f09SDavid van Moolenbroek 	result = ns_interface_create(mgr, addr, name, &ifp);
563*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
564*00b67f09SDavid van Moolenbroek 		return (result);
565*00b67f09SDavid van Moolenbroek 
566*00b67f09SDavid van Moolenbroek 	ifp->dscp = dscp;
567*00b67f09SDavid van Moolenbroek 
568*00b67f09SDavid van Moolenbroek 	result = ns_interface_listenudp(ifp);
569*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
570*00b67f09SDavid van Moolenbroek 		goto cleanup_interface;
571*00b67f09SDavid van Moolenbroek 
572*00b67f09SDavid van Moolenbroek 	if (!ns_g_notcp && accept_tcp == ISC_TRUE) {
573*00b67f09SDavid van Moolenbroek 		result = ns_interface_accepttcp(ifp);
574*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS) {
575*00b67f09SDavid van Moolenbroek 			/*
576*00b67f09SDavid van Moolenbroek 			 * XXXRTH We don't currently have a way to easily stop
577*00b67f09SDavid van Moolenbroek 			 * dispatch service, so we currently return
578*00b67f09SDavid van Moolenbroek 			 * ISC_R_SUCCESS (the UDP stuff will work even if TCP
579*00b67f09SDavid van Moolenbroek 			 * creation failed).  This will be fixed later.
580*00b67f09SDavid van Moolenbroek 			 */
581*00b67f09SDavid van Moolenbroek 			result = ISC_R_SUCCESS;
582*00b67f09SDavid van Moolenbroek 		}
583*00b67f09SDavid van Moolenbroek 	}
584*00b67f09SDavid van Moolenbroek 	*ifpret = ifp;
585*00b67f09SDavid van Moolenbroek 	return (result);
586*00b67f09SDavid van Moolenbroek 
587*00b67f09SDavid van Moolenbroek  cleanup_interface:
588*00b67f09SDavid van Moolenbroek 	ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
589*00b67f09SDavid van Moolenbroek 	ns_interface_detach(&ifp);
590*00b67f09SDavid van Moolenbroek 	return (result);
591*00b67f09SDavid van Moolenbroek }
592*00b67f09SDavid van Moolenbroek 
593*00b67f09SDavid van Moolenbroek void
ns_interface_shutdown(ns_interface_t * ifp)594*00b67f09SDavid van Moolenbroek ns_interface_shutdown(ns_interface_t *ifp) {
595*00b67f09SDavid van Moolenbroek 	if (ifp->clientmgr != NULL)
596*00b67f09SDavid van Moolenbroek 		ns_clientmgr_destroy(&ifp->clientmgr);
597*00b67f09SDavid van Moolenbroek }
598*00b67f09SDavid van Moolenbroek 
599*00b67f09SDavid van Moolenbroek static void
ns_interface_destroy(ns_interface_t * ifp)600*00b67f09SDavid van Moolenbroek ns_interface_destroy(ns_interface_t *ifp) {
601*00b67f09SDavid van Moolenbroek 	isc_mem_t *mctx = ifp->mgr->mctx;
602*00b67f09SDavid van Moolenbroek 	int disp;
603*00b67f09SDavid van Moolenbroek 
604*00b67f09SDavid van Moolenbroek 	REQUIRE(NS_INTERFACE_VALID(ifp));
605*00b67f09SDavid van Moolenbroek 
606*00b67f09SDavid van Moolenbroek 	ns_interface_shutdown(ifp);
607*00b67f09SDavid van Moolenbroek 
608*00b67f09SDavid van Moolenbroek 	for (disp = 0; disp < ifp->nudpdispatch; disp++)
609*00b67f09SDavid van Moolenbroek 		if (ifp->udpdispatch[disp] != NULL) {
610*00b67f09SDavid van Moolenbroek 			dns_dispatch_changeattributes(ifp->udpdispatch[disp], 0,
611*00b67f09SDavid van Moolenbroek 						    DNS_DISPATCHATTR_NOLISTEN);
612*00b67f09SDavid van Moolenbroek 			dns_dispatch_detach(&(ifp->udpdispatch[disp]));
613*00b67f09SDavid van Moolenbroek 		}
614*00b67f09SDavid van Moolenbroek 
615*00b67f09SDavid van Moolenbroek 	if (ifp->tcpsocket != NULL)
616*00b67f09SDavid van Moolenbroek 		isc_socket_detach(&ifp->tcpsocket);
617*00b67f09SDavid van Moolenbroek 
618*00b67f09SDavid van Moolenbroek 	DESTROYLOCK(&ifp->lock);
619*00b67f09SDavid van Moolenbroek 
620*00b67f09SDavid van Moolenbroek 	ns_interfacemgr_detach(&ifp->mgr);
621*00b67f09SDavid van Moolenbroek 
622*00b67f09SDavid van Moolenbroek 	ifp->magic = 0;
623*00b67f09SDavid van Moolenbroek 	isc_mem_put(mctx, ifp, sizeof(*ifp));
624*00b67f09SDavid van Moolenbroek }
625*00b67f09SDavid van Moolenbroek 
626*00b67f09SDavid van Moolenbroek void
ns_interface_attach(ns_interface_t * source,ns_interface_t ** target)627*00b67f09SDavid van Moolenbroek ns_interface_attach(ns_interface_t *source, ns_interface_t **target) {
628*00b67f09SDavid van Moolenbroek 	REQUIRE(NS_INTERFACE_VALID(source));
629*00b67f09SDavid van Moolenbroek 	LOCK(&source->lock);
630*00b67f09SDavid van Moolenbroek 	INSIST(source->references > 0);
631*00b67f09SDavid van Moolenbroek 	source->references++;
632*00b67f09SDavid van Moolenbroek 	UNLOCK(&source->lock);
633*00b67f09SDavid van Moolenbroek 	*target = source;
634*00b67f09SDavid van Moolenbroek }
635*00b67f09SDavid van Moolenbroek 
636*00b67f09SDavid van Moolenbroek void
ns_interface_detach(ns_interface_t ** targetp)637*00b67f09SDavid van Moolenbroek ns_interface_detach(ns_interface_t **targetp) {
638*00b67f09SDavid van Moolenbroek 	isc_result_t need_destroy = ISC_FALSE;
639*00b67f09SDavid van Moolenbroek 	ns_interface_t *target = *targetp;
640*00b67f09SDavid van Moolenbroek 	REQUIRE(target != NULL);
641*00b67f09SDavid van Moolenbroek 	REQUIRE(NS_INTERFACE_VALID(target));
642*00b67f09SDavid van Moolenbroek 	LOCK(&target->lock);
643*00b67f09SDavid van Moolenbroek 	REQUIRE(target->references > 0);
644*00b67f09SDavid van Moolenbroek 	target->references--;
645*00b67f09SDavid van Moolenbroek 	if (target->references == 0)
646*00b67f09SDavid van Moolenbroek 		need_destroy = ISC_TRUE;
647*00b67f09SDavid van Moolenbroek 	UNLOCK(&target->lock);
648*00b67f09SDavid van Moolenbroek 	if (need_destroy)
649*00b67f09SDavid van Moolenbroek 		ns_interface_destroy(target);
650*00b67f09SDavid van Moolenbroek 	*targetp = NULL;
651*00b67f09SDavid van Moolenbroek }
652*00b67f09SDavid van Moolenbroek 
653*00b67f09SDavid van Moolenbroek /*%
654*00b67f09SDavid van Moolenbroek  * Search the interface list for an interface whose address and port
655*00b67f09SDavid van Moolenbroek  * both match those of 'addr'.  Return a pointer to it, or NULL if not found.
656*00b67f09SDavid van Moolenbroek  */
657*00b67f09SDavid van Moolenbroek static ns_interface_t *
find_matching_interface(ns_interfacemgr_t * mgr,isc_sockaddr_t * addr)658*00b67f09SDavid van Moolenbroek find_matching_interface(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) {
659*00b67f09SDavid van Moolenbroek 	ns_interface_t *ifp;
660*00b67f09SDavid van Moolenbroek 	for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL;
661*00b67f09SDavid van Moolenbroek 	     ifp = ISC_LIST_NEXT(ifp, link)) {
662*00b67f09SDavid van Moolenbroek 		if (isc_sockaddr_equal(&ifp->addr, addr))
663*00b67f09SDavid van Moolenbroek 			break;
664*00b67f09SDavid van Moolenbroek 	}
665*00b67f09SDavid van Moolenbroek 	return (ifp);
666*00b67f09SDavid van Moolenbroek }
667*00b67f09SDavid van Moolenbroek 
668*00b67f09SDavid van Moolenbroek /*%
669*00b67f09SDavid van Moolenbroek  * Remove any interfaces whose generation number is not the current one.
670*00b67f09SDavid van Moolenbroek  */
671*00b67f09SDavid van Moolenbroek static void
purge_old_interfaces(ns_interfacemgr_t * mgr)672*00b67f09SDavid van Moolenbroek purge_old_interfaces(ns_interfacemgr_t *mgr) {
673*00b67f09SDavid van Moolenbroek 	ns_interface_t *ifp, *next;
674*00b67f09SDavid van Moolenbroek 	for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL; ifp = next) {
675*00b67f09SDavid van Moolenbroek 		INSIST(NS_INTERFACE_VALID(ifp));
676*00b67f09SDavid van Moolenbroek 		next = ISC_LIST_NEXT(ifp, link);
677*00b67f09SDavid van Moolenbroek 		if (ifp->generation != mgr->generation) {
678*00b67f09SDavid van Moolenbroek 			char sabuf[256];
679*00b67f09SDavid van Moolenbroek 			ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
680*00b67f09SDavid van Moolenbroek 			isc_sockaddr_format(&ifp->addr, sabuf, sizeof(sabuf));
681*00b67f09SDavid van Moolenbroek 			isc_log_write(IFMGR_COMMON_LOGARGS,
682*00b67f09SDavid van Moolenbroek 				      ISC_LOG_INFO,
683*00b67f09SDavid van Moolenbroek 				      "no longer listening on %s", sabuf);
684*00b67f09SDavid van Moolenbroek 			ns_interface_shutdown(ifp);
685*00b67f09SDavid van Moolenbroek 			ns_interface_detach(&ifp);
686*00b67f09SDavid van Moolenbroek 		}
687*00b67f09SDavid van Moolenbroek 	}
688*00b67f09SDavid van Moolenbroek }
689*00b67f09SDavid van Moolenbroek 
690*00b67f09SDavid van Moolenbroek static isc_result_t
clearacl(isc_mem_t * mctx,dns_acl_t ** aclp)691*00b67f09SDavid van Moolenbroek clearacl(isc_mem_t *mctx, dns_acl_t **aclp) {
692*00b67f09SDavid van Moolenbroek 	dns_acl_t *newacl = NULL;
693*00b67f09SDavid van Moolenbroek 	isc_result_t result;
694*00b67f09SDavid van Moolenbroek 	result = dns_acl_create(mctx, 0, &newacl);
695*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
696*00b67f09SDavid van Moolenbroek 		return (result);
697*00b67f09SDavid van Moolenbroek 	dns_acl_detach(aclp);
698*00b67f09SDavid van Moolenbroek 	dns_acl_attach(newacl, aclp);
699*00b67f09SDavid van Moolenbroek 	dns_acl_detach(&newacl);
700*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
701*00b67f09SDavid van Moolenbroek }
702*00b67f09SDavid van Moolenbroek 
703*00b67f09SDavid van Moolenbroek static isc_boolean_t
listenon_is_ip6_any(ns_listenelt_t * elt)704*00b67f09SDavid van Moolenbroek listenon_is_ip6_any(ns_listenelt_t *elt) {
705*00b67f09SDavid van Moolenbroek 	REQUIRE(elt && elt->acl);
706*00b67f09SDavid van Moolenbroek 	return dns_acl_isany(elt->acl);
707*00b67f09SDavid van Moolenbroek }
708*00b67f09SDavid van Moolenbroek 
709*00b67f09SDavid van Moolenbroek static isc_result_t
setup_locals(ns_interfacemgr_t * mgr,isc_interface_t * interface)710*00b67f09SDavid van Moolenbroek setup_locals(ns_interfacemgr_t *mgr, isc_interface_t *interface) {
711*00b67f09SDavid van Moolenbroek 	isc_result_t result;
712*00b67f09SDavid van Moolenbroek 	unsigned int prefixlen;
713*00b67f09SDavid van Moolenbroek 	isc_netaddr_t *netaddr;
714*00b67f09SDavid van Moolenbroek 
715*00b67f09SDavid van Moolenbroek 	netaddr = &interface->address;
716*00b67f09SDavid van Moolenbroek 
717*00b67f09SDavid van Moolenbroek 	/* First add localhost address */
718*00b67f09SDavid van Moolenbroek 	prefixlen = (netaddr->family == AF_INET) ? 32 : 128;
719*00b67f09SDavid van Moolenbroek 	result = dns_iptable_addprefix(mgr->aclenv.localhost->iptable,
720*00b67f09SDavid van Moolenbroek 				       netaddr, prefixlen, ISC_TRUE);
721*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
722*00b67f09SDavid van Moolenbroek 		return (result);
723*00b67f09SDavid van Moolenbroek 
724*00b67f09SDavid van Moolenbroek 	/* Then add localnets prefix */
725*00b67f09SDavid van Moolenbroek 	result = isc_netaddr_masktoprefixlen(&interface->netmask,
726*00b67f09SDavid van Moolenbroek 					     &prefixlen);
727*00b67f09SDavid van Moolenbroek 
728*00b67f09SDavid van Moolenbroek 	/* Non contiguous netmasks not allowed by IPv6 arch. */
729*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS && netaddr->family == AF_INET6)
730*00b67f09SDavid van Moolenbroek 		return (result);
731*00b67f09SDavid van Moolenbroek 
732*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS) {
733*00b67f09SDavid van Moolenbroek 		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
734*00b67f09SDavid van Moolenbroek 			      "omitting IPv4 interface %s from "
735*00b67f09SDavid van Moolenbroek 			      "localnets ACL: %s", interface->name,
736*00b67f09SDavid van Moolenbroek 			      isc_result_totext(result));
737*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
738*00b67f09SDavid van Moolenbroek 	}
739*00b67f09SDavid van Moolenbroek 
740*00b67f09SDavid van Moolenbroek 	if (prefixlen == 0U) {
741*00b67f09SDavid van Moolenbroek 		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
742*00b67f09SDavid van Moolenbroek 			      "omitting %s interface %s from localnets ACL: "
743*00b67f09SDavid van Moolenbroek 			      "zero prefix length detected",
744*00b67f09SDavid van Moolenbroek 			      (netaddr->family == AF_INET) ? "IPv4" : "IPv6",
745*00b67f09SDavid van Moolenbroek 			      interface->name);
746*00b67f09SDavid van Moolenbroek 		return (ISC_R_SUCCESS);
747*00b67f09SDavid van Moolenbroek 	}
748*00b67f09SDavid van Moolenbroek 
749*00b67f09SDavid van Moolenbroek 	result = dns_iptable_addprefix(mgr->aclenv.localnets->iptable,
750*00b67f09SDavid van Moolenbroek 				       netaddr, prefixlen, ISC_TRUE);
751*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
752*00b67f09SDavid van Moolenbroek 		return (result);
753*00b67f09SDavid van Moolenbroek 
754*00b67f09SDavid van Moolenbroek 	return (ISC_R_SUCCESS);
755*00b67f09SDavid van Moolenbroek }
756*00b67f09SDavid van Moolenbroek 
757*00b67f09SDavid van Moolenbroek static void
setup_listenon(ns_interfacemgr_t * mgr,isc_interface_t * interface,in_port_t port)758*00b67f09SDavid van Moolenbroek setup_listenon(ns_interfacemgr_t *mgr, isc_interface_t *interface,
759*00b67f09SDavid van Moolenbroek 	       in_port_t port)
760*00b67f09SDavid van Moolenbroek {
761*00b67f09SDavid van Moolenbroek 	isc_sockaddr_t *addr;
762*00b67f09SDavid van Moolenbroek 	isc_sockaddr_t *old;
763*00b67f09SDavid van Moolenbroek 
764*00b67f09SDavid van Moolenbroek 	addr = isc_mem_get(mgr->mctx, sizeof(*addr));
765*00b67f09SDavid van Moolenbroek 	if (addr == NULL)
766*00b67f09SDavid van Moolenbroek 		return;
767*00b67f09SDavid van Moolenbroek 
768*00b67f09SDavid van Moolenbroek 	isc_sockaddr_fromnetaddr(addr, &interface->address, port);
769*00b67f09SDavid van Moolenbroek 
770*00b67f09SDavid van Moolenbroek 	for (old = ISC_LIST_HEAD(mgr->listenon);
771*00b67f09SDavid van Moolenbroek 	     old != NULL;
772*00b67f09SDavid van Moolenbroek 	     old = ISC_LIST_NEXT(old, link))
773*00b67f09SDavid van Moolenbroek 		if (isc_sockaddr_equal(addr, old))
774*00b67f09SDavid van Moolenbroek 			break;
775*00b67f09SDavid van Moolenbroek 
776*00b67f09SDavid van Moolenbroek 	if (old != NULL)
777*00b67f09SDavid van Moolenbroek 		isc_mem_put(mgr->mctx, addr, sizeof(*addr));
778*00b67f09SDavid van Moolenbroek 	else
779*00b67f09SDavid van Moolenbroek 		ISC_LIST_APPEND(mgr->listenon, addr, link);
780*00b67f09SDavid van Moolenbroek }
781*00b67f09SDavid van Moolenbroek 
782*00b67f09SDavid van Moolenbroek static void
clearlistenon(ns_interfacemgr_t * mgr)783*00b67f09SDavid van Moolenbroek clearlistenon(ns_interfacemgr_t *mgr) {
784*00b67f09SDavid van Moolenbroek 	isc_sockaddr_t *old;
785*00b67f09SDavid van Moolenbroek 
786*00b67f09SDavid van Moolenbroek 	old = ISC_LIST_HEAD(mgr->listenon);
787*00b67f09SDavid van Moolenbroek 	while (old != NULL) {
788*00b67f09SDavid van Moolenbroek 		ISC_LIST_UNLINK(mgr->listenon, old, link);
789*00b67f09SDavid van Moolenbroek 		isc_mem_put(mgr->mctx, old, sizeof(*old));
790*00b67f09SDavid van Moolenbroek 		old = ISC_LIST_HEAD(mgr->listenon);
791*00b67f09SDavid van Moolenbroek 	}
792*00b67f09SDavid van Moolenbroek }
793*00b67f09SDavid van Moolenbroek 
794*00b67f09SDavid van Moolenbroek static isc_result_t
do_scan(ns_interfacemgr_t * mgr,ns_listenlist_t * ext_listen,isc_boolean_t verbose)795*00b67f09SDavid van Moolenbroek do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
796*00b67f09SDavid van Moolenbroek 	isc_boolean_t verbose)
797*00b67f09SDavid van Moolenbroek {
798*00b67f09SDavid van Moolenbroek 	isc_interfaceiter_t *iter = NULL;
799*00b67f09SDavid van Moolenbroek 	isc_boolean_t scan_ipv4 = ISC_FALSE;
800*00b67f09SDavid van Moolenbroek 	isc_boolean_t scan_ipv6 = ISC_FALSE;
801*00b67f09SDavid van Moolenbroek 	isc_boolean_t adjusting = ISC_FALSE;
802*00b67f09SDavid van Moolenbroek 	isc_boolean_t ipv6only = ISC_TRUE;
803*00b67f09SDavid van Moolenbroek 	isc_boolean_t ipv6pktinfo = ISC_TRUE;
804*00b67f09SDavid van Moolenbroek 	isc_result_t result;
805*00b67f09SDavid van Moolenbroek 	isc_netaddr_t zero_address, zero_address6;
806*00b67f09SDavid van Moolenbroek 	ns_listenelt_t *le;
807*00b67f09SDavid van Moolenbroek 	isc_sockaddr_t listen_addr;
808*00b67f09SDavid van Moolenbroek 	ns_interface_t *ifp;
809*00b67f09SDavid van Moolenbroek 	isc_boolean_t log_explicit = ISC_FALSE;
810*00b67f09SDavid van Moolenbroek 	isc_boolean_t dolistenon;
811*00b67f09SDavid van Moolenbroek 	char sabuf[ISC_SOCKADDR_FORMATSIZE];
812*00b67f09SDavid van Moolenbroek 
813*00b67f09SDavid van Moolenbroek 	if (ext_listen != NULL)
814*00b67f09SDavid van Moolenbroek 		adjusting = ISC_TRUE;
815*00b67f09SDavid van Moolenbroek 
816*00b67f09SDavid van Moolenbroek 	if (isc_net_probeipv6() == ISC_R_SUCCESS)
817*00b67f09SDavid van Moolenbroek 		scan_ipv6 = ISC_TRUE;
818*00b67f09SDavid van Moolenbroek #ifdef WANT_IPV6
819*00b67f09SDavid van Moolenbroek 	else if (!ns_g_disable6)
820*00b67f09SDavid van Moolenbroek 		isc_log_write(IFMGR_COMMON_LOGARGS,
821*00b67f09SDavid van Moolenbroek 			      verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
822*00b67f09SDavid van Moolenbroek 			      "no IPv6 interfaces found");
823*00b67f09SDavid van Moolenbroek #endif
824*00b67f09SDavid van Moolenbroek 
825*00b67f09SDavid van Moolenbroek 	if (isc_net_probeipv4() == ISC_R_SUCCESS)
826*00b67f09SDavid van Moolenbroek 		scan_ipv4 = ISC_TRUE;
827*00b67f09SDavid van Moolenbroek 	else if (!ns_g_disable4)
828*00b67f09SDavid van Moolenbroek 		isc_log_write(IFMGR_COMMON_LOGARGS,
829*00b67f09SDavid van Moolenbroek 			      verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
830*00b67f09SDavid van Moolenbroek 			      "no IPv4 interfaces found");
831*00b67f09SDavid van Moolenbroek 
832*00b67f09SDavid van Moolenbroek 	/*
833*00b67f09SDavid van Moolenbroek 	 * A special, but typical case; listen-on-v6 { any; }.
834*00b67f09SDavid van Moolenbroek 	 * When we can make the socket IPv6-only, open a single wildcard
835*00b67f09SDavid van Moolenbroek 	 * socket for IPv6 communication.  Otherwise, make separate socket
836*00b67f09SDavid van Moolenbroek 	 * for each IPv6 address in order to avoid accepting IPv4 packets
837*00b67f09SDavid van Moolenbroek 	 * as the form of mapped addresses unintentionally unless explicitly
838*00b67f09SDavid van Moolenbroek 	 * allowed.
839*00b67f09SDavid van Moolenbroek 	 */
840*00b67f09SDavid van Moolenbroek #ifndef ISC_ALLOW_MAPPED
841*00b67f09SDavid van Moolenbroek 	if (scan_ipv6 == ISC_TRUE &&
842*00b67f09SDavid van Moolenbroek 	    isc_net_probe_ipv6only() != ISC_R_SUCCESS) {
843*00b67f09SDavid van Moolenbroek 		ipv6only = ISC_FALSE;
844*00b67f09SDavid van Moolenbroek 		log_explicit = ISC_TRUE;
845*00b67f09SDavid van Moolenbroek 	}
846*00b67f09SDavid van Moolenbroek #endif
847*00b67f09SDavid van Moolenbroek 	if (scan_ipv6 == ISC_TRUE &&
848*00b67f09SDavid van Moolenbroek 	    isc_net_probe_ipv6pktinfo() != ISC_R_SUCCESS) {
849*00b67f09SDavid van Moolenbroek 		ipv6pktinfo = ISC_FALSE;
850*00b67f09SDavid van Moolenbroek 		log_explicit = ISC_TRUE;
851*00b67f09SDavid van Moolenbroek 	}
852*00b67f09SDavid van Moolenbroek 	if (scan_ipv6 == ISC_TRUE && ipv6only && ipv6pktinfo) {
853*00b67f09SDavid van Moolenbroek 		for (le = ISC_LIST_HEAD(mgr->listenon6->elts);
854*00b67f09SDavid van Moolenbroek 		     le != NULL;
855*00b67f09SDavid van Moolenbroek 		     le = ISC_LIST_NEXT(le, link)) {
856*00b67f09SDavid van Moolenbroek 			struct in6_addr in6a;
857*00b67f09SDavid van Moolenbroek 
858*00b67f09SDavid van Moolenbroek 			if (!listenon_is_ip6_any(le))
859*00b67f09SDavid van Moolenbroek 				continue;
860*00b67f09SDavid van Moolenbroek 
861*00b67f09SDavid van Moolenbroek 			in6a = in6addr_any;
862*00b67f09SDavid van Moolenbroek 			isc_sockaddr_fromin6(&listen_addr, &in6a, le->port);
863*00b67f09SDavid van Moolenbroek 
864*00b67f09SDavid van Moolenbroek 			ifp = find_matching_interface(mgr, &listen_addr);
865*00b67f09SDavid van Moolenbroek 			if (ifp != NULL) {
866*00b67f09SDavid van Moolenbroek 				ifp->generation = mgr->generation;
867*00b67f09SDavid van Moolenbroek 				if (le->dscp != -1 && ifp->dscp == -1)
868*00b67f09SDavid van Moolenbroek 					ifp->dscp = le->dscp;
869*00b67f09SDavid van Moolenbroek 				else if (le->dscp != ifp->dscp) {
870*00b67f09SDavid van Moolenbroek 					isc_sockaddr_format(&listen_addr,
871*00b67f09SDavid van Moolenbroek 							    sabuf,
872*00b67f09SDavid van Moolenbroek 							    sizeof(sabuf));
873*00b67f09SDavid van Moolenbroek 					isc_log_write(IFMGR_COMMON_LOGARGS,
874*00b67f09SDavid van Moolenbroek 						      ISC_LOG_WARNING,
875*00b67f09SDavid van Moolenbroek 						      "%s: conflicting DSCP "
876*00b67f09SDavid van Moolenbroek 						      "values, using %d",
877*00b67f09SDavid van Moolenbroek 						      sabuf, ifp->dscp);
878*00b67f09SDavid van Moolenbroek 				}
879*00b67f09SDavid van Moolenbroek 			} else {
880*00b67f09SDavid van Moolenbroek 				isc_log_write(IFMGR_COMMON_LOGARGS,
881*00b67f09SDavid van Moolenbroek 					      ISC_LOG_INFO,
882*00b67f09SDavid van Moolenbroek 					      "listening on IPv6 "
883*00b67f09SDavid van Moolenbroek 					      "interfaces, port %u",
884*00b67f09SDavid van Moolenbroek 					      le->port);
885*00b67f09SDavid van Moolenbroek 				result = ns_interface_setup(mgr, &listen_addr,
886*00b67f09SDavid van Moolenbroek 							    "<any>", &ifp,
887*00b67f09SDavid van Moolenbroek 							    ISC_TRUE,
888*00b67f09SDavid van Moolenbroek 							    le->dscp);
889*00b67f09SDavid van Moolenbroek 				if (result == ISC_R_SUCCESS)
890*00b67f09SDavid van Moolenbroek 					ifp->flags |= NS_INTERFACEFLAG_ANYADDR;
891*00b67f09SDavid van Moolenbroek 				else
892*00b67f09SDavid van Moolenbroek 					isc_log_write(IFMGR_COMMON_LOGARGS,
893*00b67f09SDavid van Moolenbroek 						      ISC_LOG_ERROR,
894*00b67f09SDavid van Moolenbroek 						      "listening on all IPv6 "
895*00b67f09SDavid van Moolenbroek 						      "interfaces failed");
896*00b67f09SDavid van Moolenbroek 				/* Continue. */
897*00b67f09SDavid van Moolenbroek 			}
898*00b67f09SDavid van Moolenbroek 		}
899*00b67f09SDavid van Moolenbroek 	}
900*00b67f09SDavid van Moolenbroek 
901*00b67f09SDavid van Moolenbroek 	isc_netaddr_any(&zero_address);
902*00b67f09SDavid van Moolenbroek 	isc_netaddr_any6(&zero_address6);
903*00b67f09SDavid van Moolenbroek 
904*00b67f09SDavid van Moolenbroek 	result = isc_interfaceiter_create(mgr->mctx, &iter);
905*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_SUCCESS)
906*00b67f09SDavid van Moolenbroek 		return (result);
907*00b67f09SDavid van Moolenbroek 
908*00b67f09SDavid van Moolenbroek 	if (adjusting == ISC_FALSE) {
909*00b67f09SDavid van Moolenbroek 		result = clearacl(mgr->mctx, &mgr->aclenv.localhost);
910*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
911*00b67f09SDavid van Moolenbroek 			goto cleanup_iter;
912*00b67f09SDavid van Moolenbroek 		result = clearacl(mgr->mctx, &mgr->aclenv.localnets);
913*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
914*00b67f09SDavid van Moolenbroek 			goto cleanup_iter;
915*00b67f09SDavid van Moolenbroek 		clearlistenon(mgr);
916*00b67f09SDavid van Moolenbroek 	}
917*00b67f09SDavid van Moolenbroek 
918*00b67f09SDavid van Moolenbroek 	for (result = isc_interfaceiter_first(iter);
919*00b67f09SDavid van Moolenbroek 	     result == ISC_R_SUCCESS;
920*00b67f09SDavid van Moolenbroek 	     result = isc_interfaceiter_next(iter))
921*00b67f09SDavid van Moolenbroek 	{
922*00b67f09SDavid van Moolenbroek 		isc_interface_t interface;
923*00b67f09SDavid van Moolenbroek 		ns_listenlist_t *ll;
924*00b67f09SDavid van Moolenbroek 		unsigned int family;
925*00b67f09SDavid van Moolenbroek 
926*00b67f09SDavid van Moolenbroek 		result = isc_interfaceiter_current(iter, &interface);
927*00b67f09SDavid van Moolenbroek 		if (result != ISC_R_SUCCESS)
928*00b67f09SDavid van Moolenbroek 			break;
929*00b67f09SDavid van Moolenbroek 
930*00b67f09SDavid van Moolenbroek 		family = interface.address.family;
931*00b67f09SDavid van Moolenbroek 		if (family != AF_INET && family != AF_INET6)
932*00b67f09SDavid van Moolenbroek 			continue;
933*00b67f09SDavid van Moolenbroek 		if (scan_ipv4 == ISC_FALSE && family == AF_INET)
934*00b67f09SDavid van Moolenbroek 			continue;
935*00b67f09SDavid van Moolenbroek 		if (scan_ipv6 == ISC_FALSE && family == AF_INET6)
936*00b67f09SDavid van Moolenbroek 			continue;
937*00b67f09SDavid van Moolenbroek 
938*00b67f09SDavid van Moolenbroek 		/*
939*00b67f09SDavid van Moolenbroek 		 * Test for the address being nonzero rather than testing
940*00b67f09SDavid van Moolenbroek 		 * INTERFACE_F_UP, because on some systems the latter
941*00b67f09SDavid van Moolenbroek 		 * follows the media state and we could end up ignoring
942*00b67f09SDavid van Moolenbroek 		 * the interface for an entire rescan interval due to
943*00b67f09SDavid van Moolenbroek 		 * a temporary media glitch at rescan time.
944*00b67f09SDavid van Moolenbroek 		 */
945*00b67f09SDavid van Moolenbroek 		if (family == AF_INET &&
946*00b67f09SDavid van Moolenbroek 		    isc_netaddr_equal(&interface.address, &zero_address)) {
947*00b67f09SDavid van Moolenbroek 			continue;
948*00b67f09SDavid van Moolenbroek 		}
949*00b67f09SDavid van Moolenbroek 		if (family == AF_INET6 &&
950*00b67f09SDavid van Moolenbroek 		    isc_netaddr_equal(&interface.address, &zero_address6)) {
951*00b67f09SDavid van Moolenbroek 			continue;
952*00b67f09SDavid van Moolenbroek 		}
953*00b67f09SDavid van Moolenbroek 
954*00b67f09SDavid van Moolenbroek 		if (adjusting == ISC_FALSE) {
955*00b67f09SDavid van Moolenbroek 			result = setup_locals(mgr, &interface);
956*00b67f09SDavid van Moolenbroek 			if (result != ISC_R_SUCCESS)
957*00b67f09SDavid van Moolenbroek 				goto ignore_interface;
958*00b67f09SDavid van Moolenbroek 		}
959*00b67f09SDavid van Moolenbroek 
960*00b67f09SDavid van Moolenbroek 		ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6;
961*00b67f09SDavid van Moolenbroek 		dolistenon = ISC_TRUE;
962*00b67f09SDavid van Moolenbroek 		for (le = ISC_LIST_HEAD(ll->elts);
963*00b67f09SDavid van Moolenbroek 		     le != NULL;
964*00b67f09SDavid van Moolenbroek 		     le = ISC_LIST_NEXT(le, link))
965*00b67f09SDavid van Moolenbroek 		{
966*00b67f09SDavid van Moolenbroek 			int match;
967*00b67f09SDavid van Moolenbroek 			isc_boolean_t ipv6_wildcard = ISC_FALSE;
968*00b67f09SDavid van Moolenbroek 			isc_netaddr_t listen_netaddr;
969*00b67f09SDavid van Moolenbroek 			isc_sockaddr_t listen_sockaddr;
970*00b67f09SDavid van Moolenbroek 
971*00b67f09SDavid van Moolenbroek 			/*
972*00b67f09SDavid van Moolenbroek 			 * Construct a socket address for this IP/port
973*00b67f09SDavid van Moolenbroek 			 * combination.
974*00b67f09SDavid van Moolenbroek 			 */
975*00b67f09SDavid van Moolenbroek 			if (family == AF_INET) {
976*00b67f09SDavid van Moolenbroek 				isc_netaddr_fromin(&listen_netaddr,
977*00b67f09SDavid van Moolenbroek 						   &interface.address.type.in);
978*00b67f09SDavid van Moolenbroek 			} else {
979*00b67f09SDavid van Moolenbroek 				isc_netaddr_fromin6(&listen_netaddr,
980*00b67f09SDavid van Moolenbroek 						    &interface.address.type.in6);
981*00b67f09SDavid van Moolenbroek 				isc_netaddr_setzone(&listen_netaddr,
982*00b67f09SDavid van Moolenbroek 						    interface.address.zone);
983*00b67f09SDavid van Moolenbroek 			}
984*00b67f09SDavid van Moolenbroek 			isc_sockaddr_fromnetaddr(&listen_sockaddr,
985*00b67f09SDavid van Moolenbroek 						 &listen_netaddr,
986*00b67f09SDavid van Moolenbroek 						 le->port);
987*00b67f09SDavid van Moolenbroek 
988*00b67f09SDavid van Moolenbroek 			/*
989*00b67f09SDavid van Moolenbroek 			 * See if the address matches the listen-on statement;
990*00b67f09SDavid van Moolenbroek 			 * if not, ignore the interface.
991*00b67f09SDavid van Moolenbroek 			 */
992*00b67f09SDavid van Moolenbroek 			(void)dns_acl_match(&listen_netaddr, NULL, le->acl,
993*00b67f09SDavid van Moolenbroek 					    &mgr->aclenv, &match, NULL);
994*00b67f09SDavid van Moolenbroek 			if (match <= 0)
995*00b67f09SDavid van Moolenbroek 				continue;
996*00b67f09SDavid van Moolenbroek 
997*00b67f09SDavid van Moolenbroek 			if (adjusting == ISC_FALSE && dolistenon == ISC_TRUE) {
998*00b67f09SDavid van Moolenbroek 				setup_listenon(mgr, &interface, le->port);
999*00b67f09SDavid van Moolenbroek 				dolistenon = ISC_FALSE;
1000*00b67f09SDavid van Moolenbroek 			}
1001*00b67f09SDavid van Moolenbroek 
1002*00b67f09SDavid van Moolenbroek 			/*
1003*00b67f09SDavid van Moolenbroek 			 * The case of "any" IPv6 address will require
1004*00b67f09SDavid van Moolenbroek 			 * special considerations later, so remember it.
1005*00b67f09SDavid van Moolenbroek 			 */
1006*00b67f09SDavid van Moolenbroek 			if (family == AF_INET6 && ipv6only && ipv6pktinfo &&
1007*00b67f09SDavid van Moolenbroek 			    listenon_is_ip6_any(le))
1008*00b67f09SDavid van Moolenbroek 				ipv6_wildcard = ISC_TRUE;
1009*00b67f09SDavid van Moolenbroek 
1010*00b67f09SDavid van Moolenbroek 			/*
1011*00b67f09SDavid van Moolenbroek 			 * When adjusting interfaces with extra a listening
1012*00b67f09SDavid van Moolenbroek 			 * list, see if the address matches the extra list.
1013*00b67f09SDavid van Moolenbroek 			 * If it does, and is also covered by a wildcard
1014*00b67f09SDavid van Moolenbroek 			 * interface, we need to listen on the address
1015*00b67f09SDavid van Moolenbroek 			 * explicitly.
1016*00b67f09SDavid van Moolenbroek 			 */
1017*00b67f09SDavid van Moolenbroek 			if (adjusting == ISC_TRUE) {
1018*00b67f09SDavid van Moolenbroek 				ns_listenelt_t *ele;
1019*00b67f09SDavid van Moolenbroek 
1020*00b67f09SDavid van Moolenbroek 				match = 0;
1021*00b67f09SDavid van Moolenbroek 				for (ele = ISC_LIST_HEAD(ext_listen->elts);
1022*00b67f09SDavid van Moolenbroek 				     ele != NULL;
1023*00b67f09SDavid van Moolenbroek 				     ele = ISC_LIST_NEXT(ele, link)) {
1024*00b67f09SDavid van Moolenbroek 					(void)dns_acl_match(&listen_netaddr,
1025*00b67f09SDavid van Moolenbroek 							    NULL, ele->acl,
1026*00b67f09SDavid van Moolenbroek 							    NULL, &match, NULL);
1027*00b67f09SDavid van Moolenbroek 					if (match > 0 &&
1028*00b67f09SDavid van Moolenbroek 					    (ele->port == le->port ||
1029*00b67f09SDavid van Moolenbroek 					    ele->port == 0))
1030*00b67f09SDavid van Moolenbroek 						break;
1031*00b67f09SDavid van Moolenbroek 					else
1032*00b67f09SDavid van Moolenbroek 						match = 0;
1033*00b67f09SDavid van Moolenbroek 				}
1034*00b67f09SDavid van Moolenbroek 				if (ipv6_wildcard == ISC_TRUE && match == 0)
1035*00b67f09SDavid van Moolenbroek 					continue;
1036*00b67f09SDavid van Moolenbroek 			}
1037*00b67f09SDavid van Moolenbroek 
1038*00b67f09SDavid van Moolenbroek 			ifp = find_matching_interface(mgr, &listen_sockaddr);
1039*00b67f09SDavid van Moolenbroek 			if (ifp != NULL) {
1040*00b67f09SDavid van Moolenbroek 				ifp->generation = mgr->generation;
1041*00b67f09SDavid van Moolenbroek 				if (le->dscp != -1 && ifp->dscp == -1)
1042*00b67f09SDavid van Moolenbroek 					ifp->dscp = le->dscp;
1043*00b67f09SDavid van Moolenbroek 				else if (le->dscp != ifp->dscp) {
1044*00b67f09SDavid van Moolenbroek 					isc_sockaddr_format(&listen_sockaddr,
1045*00b67f09SDavid van Moolenbroek 							    sabuf,
1046*00b67f09SDavid van Moolenbroek 							    sizeof(sabuf));
1047*00b67f09SDavid van Moolenbroek 					isc_log_write(IFMGR_COMMON_LOGARGS,
1048*00b67f09SDavid van Moolenbroek 						      ISC_LOG_WARNING,
1049*00b67f09SDavid van Moolenbroek 						      "%s: conflicting DSCP "
1050*00b67f09SDavid van Moolenbroek 						      "values, using %d",
1051*00b67f09SDavid van Moolenbroek 						      sabuf, ifp->dscp);
1052*00b67f09SDavid van Moolenbroek 				}
1053*00b67f09SDavid van Moolenbroek 			} else {
1054*00b67f09SDavid van Moolenbroek 				if (adjusting == ISC_FALSE &&
1055*00b67f09SDavid van Moolenbroek 				    ipv6_wildcard == ISC_TRUE)
1056*00b67f09SDavid van Moolenbroek 					continue;
1057*00b67f09SDavid van Moolenbroek 
1058*00b67f09SDavid van Moolenbroek 				if (log_explicit && family == AF_INET6 &&
1059*00b67f09SDavid van Moolenbroek 				    !adjusting && listenon_is_ip6_any(le)) {
1060*00b67f09SDavid van Moolenbroek 					isc_log_write(IFMGR_COMMON_LOGARGS,
1061*00b67f09SDavid van Moolenbroek 						      verbose ? ISC_LOG_INFO :
1062*00b67f09SDavid van Moolenbroek 							      ISC_LOG_DEBUG(1),
1063*00b67f09SDavid van Moolenbroek 						      "IPv6 socket API is "
1064*00b67f09SDavid van Moolenbroek 						      "incomplete; explicitly "
1065*00b67f09SDavid van Moolenbroek 						      "binding to each IPv6 "
1066*00b67f09SDavid van Moolenbroek 						      "address separately");
1067*00b67f09SDavid van Moolenbroek 					log_explicit = ISC_FALSE;
1068*00b67f09SDavid van Moolenbroek 				}
1069*00b67f09SDavid van Moolenbroek 				isc_sockaddr_format(&listen_sockaddr,
1070*00b67f09SDavid van Moolenbroek 						    sabuf, sizeof(sabuf));
1071*00b67f09SDavid van Moolenbroek 				isc_log_write(IFMGR_COMMON_LOGARGS,
1072*00b67f09SDavid van Moolenbroek 					      ISC_LOG_INFO,
1073*00b67f09SDavid van Moolenbroek 					      "%s"
1074*00b67f09SDavid van Moolenbroek 					      "listening on %s interface "
1075*00b67f09SDavid van Moolenbroek 					      "%s, %s",
1076*00b67f09SDavid van Moolenbroek 					      (adjusting == ISC_TRUE) ?
1077*00b67f09SDavid van Moolenbroek 					      "additionally " : "",
1078*00b67f09SDavid van Moolenbroek 					      (family == AF_INET) ?
1079*00b67f09SDavid van Moolenbroek 					      "IPv4" : "IPv6",
1080*00b67f09SDavid van Moolenbroek 					      interface.name, sabuf);
1081*00b67f09SDavid van Moolenbroek 
1082*00b67f09SDavid van Moolenbroek 				result = ns_interface_setup(mgr,
1083*00b67f09SDavid van Moolenbroek 						    &listen_sockaddr,
1084*00b67f09SDavid van Moolenbroek 						    interface.name,
1085*00b67f09SDavid van Moolenbroek 						    &ifp,
1086*00b67f09SDavid van Moolenbroek 						    (adjusting == ISC_TRUE) ?
1087*00b67f09SDavid van Moolenbroek 						    ISC_FALSE : ISC_TRUE,
1088*00b67f09SDavid van Moolenbroek 						    le->dscp);
1089*00b67f09SDavid van Moolenbroek 
1090*00b67f09SDavid van Moolenbroek 				if (result != ISC_R_SUCCESS) {
1091*00b67f09SDavid van Moolenbroek 					isc_log_write(IFMGR_COMMON_LOGARGS,
1092*00b67f09SDavid van Moolenbroek 						      ISC_LOG_ERROR,
1093*00b67f09SDavid van Moolenbroek 						      "creating %s interface "
1094*00b67f09SDavid van Moolenbroek 						      "%s failed; interface "
1095*00b67f09SDavid van Moolenbroek 						      "ignored",
1096*00b67f09SDavid van Moolenbroek 						      (family == AF_INET) ?
1097*00b67f09SDavid van Moolenbroek 						      "IPv4" : "IPv6",
1098*00b67f09SDavid van Moolenbroek 						      interface.name);
1099*00b67f09SDavid van Moolenbroek 				}
1100*00b67f09SDavid van Moolenbroek 				/* Continue. */
1101*00b67f09SDavid van Moolenbroek 			}
1102*00b67f09SDavid van Moolenbroek 
1103*00b67f09SDavid van Moolenbroek 		}
1104*00b67f09SDavid van Moolenbroek 		continue;
1105*00b67f09SDavid van Moolenbroek 
1106*00b67f09SDavid van Moolenbroek 	ignore_interface:
1107*00b67f09SDavid van Moolenbroek 		isc_log_write(IFMGR_COMMON_LOGARGS,
1108*00b67f09SDavid van Moolenbroek 			      ISC_LOG_ERROR,
1109*00b67f09SDavid van Moolenbroek 			      "ignoring %s interface %s: %s",
1110*00b67f09SDavid van Moolenbroek 			      (family == AF_INET) ? "IPv4" : "IPv6",
1111*00b67f09SDavid van Moolenbroek 			      interface.name, isc_result_totext(result));
1112*00b67f09SDavid van Moolenbroek 		continue;
1113*00b67f09SDavid van Moolenbroek 	}
1114*00b67f09SDavid van Moolenbroek 	if (result != ISC_R_NOMORE)
1115*00b67f09SDavid van Moolenbroek 		UNEXPECTED_ERROR(__FILE__, __LINE__,
1116*00b67f09SDavid van Moolenbroek 				 "interface iteration failed: %s",
1117*00b67f09SDavid van Moolenbroek 				 isc_result_totext(result));
1118*00b67f09SDavid van Moolenbroek 	else
1119*00b67f09SDavid van Moolenbroek 		result = ISC_R_SUCCESS;
1120*00b67f09SDavid van Moolenbroek  cleanup_iter:
1121*00b67f09SDavid van Moolenbroek 	isc_interfaceiter_destroy(&iter);
1122*00b67f09SDavid van Moolenbroek 	return (result);
1123*00b67f09SDavid van Moolenbroek }
1124*00b67f09SDavid van Moolenbroek 
1125*00b67f09SDavid van Moolenbroek static void
ns_interfacemgr_scan0(ns_interfacemgr_t * mgr,ns_listenlist_t * ext_listen,isc_boolean_t verbose)1126*00b67f09SDavid van Moolenbroek ns_interfacemgr_scan0(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
1127*00b67f09SDavid van Moolenbroek 		      isc_boolean_t verbose)
1128*00b67f09SDavid van Moolenbroek {
1129*00b67f09SDavid van Moolenbroek 	isc_boolean_t purge = ISC_TRUE;
1130*00b67f09SDavid van Moolenbroek 
1131*00b67f09SDavid van Moolenbroek 	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
1132*00b67f09SDavid van Moolenbroek 
1133*00b67f09SDavid van Moolenbroek 	mgr->generation++;	/* Increment the generation count. */
1134*00b67f09SDavid van Moolenbroek 
1135*00b67f09SDavid van Moolenbroek 	if (do_scan(mgr, ext_listen, verbose) != ISC_R_SUCCESS)
1136*00b67f09SDavid van Moolenbroek 		purge = ISC_FALSE;
1137*00b67f09SDavid van Moolenbroek 
1138*00b67f09SDavid van Moolenbroek 	/*
1139*00b67f09SDavid van Moolenbroek 	 * Now go through the interface list and delete anything that
1140*00b67f09SDavid van Moolenbroek 	 * does not have the current generation number.  This is
1141*00b67f09SDavid van Moolenbroek 	 * how we catch interfaces that go away or change their
1142*00b67f09SDavid van Moolenbroek 	 * addresses.
1143*00b67f09SDavid van Moolenbroek 	 */
1144*00b67f09SDavid van Moolenbroek 	if (purge)
1145*00b67f09SDavid van Moolenbroek 		purge_old_interfaces(mgr);
1146*00b67f09SDavid van Moolenbroek 
1147*00b67f09SDavid van Moolenbroek 	/*
1148*00b67f09SDavid van Moolenbroek 	 * Warn if we are not listening on any interface, unless
1149*00b67f09SDavid van Moolenbroek 	 * we're in lwresd-only mode, in which case that is to
1150*00b67f09SDavid van Moolenbroek 	 * be expected.
1151*00b67f09SDavid van Moolenbroek 	 */
1152*00b67f09SDavid van Moolenbroek 	if (ext_listen == NULL &&
1153*00b67f09SDavid van Moolenbroek 	    ISC_LIST_EMPTY(mgr->interfaces) && ! ns_g_lwresdonly) {
1154*00b67f09SDavid van Moolenbroek 		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
1155*00b67f09SDavid van Moolenbroek 			      "not listening on any interfaces");
1156*00b67f09SDavid van Moolenbroek 	}
1157*00b67f09SDavid van Moolenbroek }
1158*00b67f09SDavid van Moolenbroek 
1159*00b67f09SDavid van Moolenbroek void
ns_interfacemgr_scan(ns_interfacemgr_t * mgr,isc_boolean_t verbose)1160*00b67f09SDavid van Moolenbroek ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
1161*00b67f09SDavid van Moolenbroek 	ns_interfacemgr_scan0(mgr, NULL, verbose);
1162*00b67f09SDavid van Moolenbroek }
1163*00b67f09SDavid van Moolenbroek 
1164*00b67f09SDavid van Moolenbroek void
ns_interfacemgr_adjust(ns_interfacemgr_t * mgr,ns_listenlist_t * list,isc_boolean_t verbose)1165*00b67f09SDavid van Moolenbroek ns_interfacemgr_adjust(ns_interfacemgr_t *mgr, ns_listenlist_t *list,
1166*00b67f09SDavid van Moolenbroek 		       isc_boolean_t verbose)
1167*00b67f09SDavid van Moolenbroek {
1168*00b67f09SDavid van Moolenbroek 	ns_interfacemgr_scan0(mgr, list, verbose);
1169*00b67f09SDavid van Moolenbroek }
1170*00b67f09SDavid van Moolenbroek 
1171*00b67f09SDavid van Moolenbroek void
ns_interfacemgr_setlistenon4(ns_interfacemgr_t * mgr,ns_listenlist_t * value)1172*00b67f09SDavid van Moolenbroek ns_interfacemgr_setlistenon4(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
1173*00b67f09SDavid van Moolenbroek 	LOCK(&mgr->lock);
1174*00b67f09SDavid van Moolenbroek 	ns_listenlist_detach(&mgr->listenon4);
1175*00b67f09SDavid van Moolenbroek 	ns_listenlist_attach(value, &mgr->listenon4);
1176*00b67f09SDavid van Moolenbroek 	UNLOCK(&mgr->lock);
1177*00b67f09SDavid van Moolenbroek }
1178*00b67f09SDavid van Moolenbroek 
1179*00b67f09SDavid van Moolenbroek void
ns_interfacemgr_setlistenon6(ns_interfacemgr_t * mgr,ns_listenlist_t * value)1180*00b67f09SDavid van Moolenbroek ns_interfacemgr_setlistenon6(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
1181*00b67f09SDavid van Moolenbroek 	LOCK(&mgr->lock);
1182*00b67f09SDavid van Moolenbroek 	ns_listenlist_detach(&mgr->listenon6);
1183*00b67f09SDavid van Moolenbroek 	ns_listenlist_attach(value, &mgr->listenon6);
1184*00b67f09SDavid van Moolenbroek 	UNLOCK(&mgr->lock);
1185*00b67f09SDavid van Moolenbroek }
1186*00b67f09SDavid van Moolenbroek 
1187*00b67f09SDavid van Moolenbroek void
ns_interfacemgr_dumprecursing(FILE * f,ns_interfacemgr_t * mgr)1188*00b67f09SDavid van Moolenbroek ns_interfacemgr_dumprecursing(FILE *f, ns_interfacemgr_t *mgr) {
1189*00b67f09SDavid van Moolenbroek 	ns_interface_t *interface;
1190*00b67f09SDavid van Moolenbroek 
1191*00b67f09SDavid van Moolenbroek 	LOCK(&mgr->lock);
1192*00b67f09SDavid van Moolenbroek 	interface = ISC_LIST_HEAD(mgr->interfaces);
1193*00b67f09SDavid van Moolenbroek 	while (interface != NULL) {
1194*00b67f09SDavid van Moolenbroek 		if (interface->clientmgr != NULL)
1195*00b67f09SDavid van Moolenbroek 			ns_client_dumprecursing(f, interface->clientmgr);
1196*00b67f09SDavid van Moolenbroek 		interface = ISC_LIST_NEXT(interface, link);
1197*00b67f09SDavid van Moolenbroek 	}
1198*00b67f09SDavid van Moolenbroek 	UNLOCK(&mgr->lock);
1199*00b67f09SDavid van Moolenbroek }
1200*00b67f09SDavid van Moolenbroek 
1201*00b67f09SDavid van Moolenbroek isc_boolean_t
ns_interfacemgr_listeningon(ns_interfacemgr_t * mgr,isc_sockaddr_t * addr)1202*00b67f09SDavid van Moolenbroek ns_interfacemgr_listeningon(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) {
1203*00b67f09SDavid van Moolenbroek 	isc_sockaddr_t *old;
1204*00b67f09SDavid van Moolenbroek 
1205*00b67f09SDavid van Moolenbroek 	for (old = ISC_LIST_HEAD(mgr->listenon);
1206*00b67f09SDavid van Moolenbroek 	     old != NULL;
1207*00b67f09SDavid van Moolenbroek 	     old = ISC_LIST_NEXT(old, link))
1208*00b67f09SDavid van Moolenbroek 		if (isc_sockaddr_equal(old, addr))
1209*00b67f09SDavid van Moolenbroek 			return (ISC_TRUE);
1210*00b67f09SDavid van Moolenbroek 	return (ISC_FALSE);
1211*00b67f09SDavid van Moolenbroek }
1212