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