interfacemgr.c revision 1.16
1/*	$NetBSD: interfacemgr.c,v 1.16 2024/02/21 22:52:46 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 MSGHDR	rt_msghdr
41#define MSGTYPE rtm_type
42#endif /* if defined(RTM_VERSION) && defined(RTM_NEWADDR) && \
43	* defined(RTM_DELADDR) */
44#endif /* ifdef HAVE_NET_ROUTE_H */
45
46#if defined(HAVE_LINUX_NETLINK_H) && defined(HAVE_LINUX_RTNETLINK_H)
47#define LINUX_NETLINK_AVAILABLE
48#include <linux/netlink.h>
49#include <linux/rtnetlink.h>
50#if defined(RTM_NEWADDR) && defined(RTM_DELADDR)
51#define MSGHDR	nlmsghdr
52#define MSGTYPE nlmsg_type
53#endif /* if defined(RTM_NEWADDR) && defined(RTM_DELADDR) */
54#endif /* if defined(HAVE_LINUX_NETLINK_H) && defined(HAVE_LINUX_RTNETLINK_H) \
55	*/
56
57#define LISTENING(ifp) (((ifp)->flags & NS_INTERFACEFLAG_LISTENING) != 0)
58
59#ifdef TUNE_LARGE
60#define UDPBUFFERS 32768
61#else /* ifdef TUNE_LARGE */
62#define UDPBUFFERS 1000
63#endif /* TUNE_LARGE */
64
65#define IFMGR_MAGIC		 ISC_MAGIC('I', 'F', 'M', 'G')
66#define NS_INTERFACEMGR_VALID(t) ISC_MAGIC_VALID(t, IFMGR_MAGIC)
67
68#define IFMGR_COMMON_LOGARGS \
69	ns_lctx, NS_LOGCATEGORY_NETWORK, NS_LOGMODULE_INTERFACEMGR
70
71/*% nameserver interface manager structure */
72struct ns_interfacemgr {
73	unsigned int magic; /*%< Magic number */
74	isc_refcount_t references;
75	isc_mutex_t lock;
76	isc_mem_t *mctx;	  /*%< Memory context */
77	ns_server_t *sctx;	  /*%< Server context */
78	isc_taskmgr_t *taskmgr;	  /*%< Task manager */
79	isc_task_t *task;	  /*%< Task */
80	isc_timermgr_t *timermgr; /*%< Timer manager */
81	isc_nm_t *nm;		  /*%< Net manager */
82	int ncpus;		  /*%< Number of workers */
83	dns_dispatchmgr_t *dispatchmgr;
84	unsigned int generation; /*%< Current generation no */
85	ns_listenlist_t *listenon4;
86	ns_listenlist_t *listenon6;
87	dns_aclenv_t *aclenv;		     /*%< Localhost/localnets ACLs */
88	ISC_LIST(ns_interface_t) interfaces; /*%< List of interfaces */
89	ISC_LIST(isc_sockaddr_t) listenon;
90	int backlog;		     /*%< Listen queue size */
91	atomic_bool shuttingdown;    /*%< Interfacemgr shutting down */
92	ns_clientmgr_t **clientmgrs; /*%< Client managers */
93	isc_nmhandle_t *route;
94};
95
96static void
97purge_old_interfaces(ns_interfacemgr_t *mgr);
98
99static void
100clearlistenon(ns_interfacemgr_t *mgr);
101
102static bool
103need_rescan(ns_interfacemgr_t *mgr, struct MSGHDR *rtm, size_t len) {
104	if (rtm->MSGTYPE != RTM_NEWADDR && rtm->MSGTYPE != RTM_DELADDR) {
105		return (false);
106	}
107
108#ifndef LINUX_NETLINK_AVAILABLE
109	UNUSED(mgr);
110	UNUSED(len);
111	/* On most systems, any NEWADDR or DELADDR means we rescan */
112	return (true);
113#else  /* LINUX_NETLINK_AVAILABLE */
114	/* ...but on linux we need to check the messages more carefully */
115	for (struct MSGHDR *nlh = rtm;
116	     NLMSG_OK(nlh, len) && nlh->nlmsg_type != NLMSG_DONE;
117	     nlh = NLMSG_NEXT(nlh, len))
118	{
119		struct ifaddrmsg *ifa = (struct ifaddrmsg *)NLMSG_DATA(nlh);
120		struct rtattr *rth = IFA_RTA(ifa);
121		size_t rtl = IFA_PAYLOAD(nlh);
122
123		while (rtl > 0 && RTA_OK(rth, rtl)) {
124			/*
125			 * Look for IFA_ADDRESS to detect IPv6 interface
126			 * state changes.
127			 */
128			if (rth->rta_type == IFA_ADDRESS &&
129			    ifa->ifa_family == AF_INET6)
130			{
131				bool existed = false;
132				bool was_listening = false;
133				isc_netaddr_t addr = { 0 };
134				ns_interface_t *ifp = NULL;
135
136				isc_netaddr_fromin6(&addr, RTA_DATA(rth));
137				INSIST(isc_netaddr_getzone(&addr) == 0);
138
139				/*
140				 * Check whether we were listening on the
141				 * address. We need to do this as the
142				 * Linux kernel seems to issue messages
143				 * containing IFA_ADDRESS far more often
144				 * than the actual state changes (on
145				 * router advertisements?)
146				 */
147				LOCK(&mgr->lock);
148				for (ifp = ISC_LIST_HEAD(mgr->interfaces);
149				     ifp != NULL;
150				     ifp = ISC_LIST_NEXT(ifp, link))
151				{
152					isc_netaddr_t tmp = { 0 };
153					isc_netaddr_fromsockaddr(&tmp,
154								 &ifp->addr);
155					if (tmp.family != AF_INET6) {
156						continue;
157					}
158
159					/*
160					 * We have to nullify the zone (IPv6
161					 * scope ID) because we haven't got one
162					 * from the kernel. Otherwise match
163					 * could fail even for an existing
164					 * address.
165					 */
166					isc_netaddr_setzone(&tmp, 0);
167					if (isc_netaddr_equal(&tmp, &addr)) {
168						was_listening = LISTENING(ifp);
169						existed = true;
170						break;
171					}
172				}
173				UNLOCK(&mgr->lock);
174
175				/*
176				 * Do rescan if the state of the interface
177				 * has changed.
178				 */
179				if ((!existed && rtm->MSGTYPE == RTM_NEWADDR) ||
180				    (existed && was_listening &&
181				     rtm->MSGTYPE == RTM_DELADDR))
182				{
183					return (true);
184				}
185			} else if (rth->rta_type == IFA_ADDRESS &&
186				   ifa->ifa_family == AF_INET)
187			{
188				/*
189				 * It seems that the IPv4 P2P link state
190				 * has changed.
191				 */
192				return (true);
193			} else if (rth->rta_type == IFA_LOCAL) {
194				/*
195				 * Local address state has changed - do
196				 * rescan.
197				 */
198				return (true);
199			}
200			rth = RTA_NEXT(rth, rtl);
201		}
202	}
203#endif /* LINUX_NETLINK_AVAILABLE */
204
205	return (false);
206}
207
208static void
209route_recv(isc_nmhandle_t *handle, isc_result_t eresult, isc_region_t *region,
210	   void *arg) {
211	ns_interfacemgr_t *mgr = (ns_interfacemgr_t *)arg;
212	struct MSGHDR *rtm = NULL;
213	size_t rtmlen;
214
215	isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_DEBUG(9), "route_recv: %s",
216		      isc_result_totext(eresult));
217
218	if (handle == NULL) {
219		return;
220	}
221
222	if (eresult != ISC_R_SUCCESS) {
223		if (eresult != ISC_R_CANCELED && eresult != ISC_R_SHUTTINGDOWN)
224		{
225			isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
226				      "automatic interface scanning "
227				      "terminated: %s",
228				      isc_result_totext(eresult));
229		}
230		isc_nmhandle_detach(&mgr->route);
231		ns_interfacemgr_detach(&mgr);
232		return;
233	}
234
235	rtm = (struct MSGHDR *)region->base;
236	rtmlen = region->length;
237
238#ifdef RTM_VERSION
239	if (rtm->rtm_version != RTM_VERSION) {
240		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
241			      "automatic interface rescanning disabled: "
242			      "rtm->rtm_version mismatch (%u != %u) "
243			      "recompile required",
244			      rtm->rtm_version, RTM_VERSION);
245		isc_nmhandle_detach(&mgr->route);
246		ns_interfacemgr_detach(&mgr);
247		return;
248	}
249#endif /* ifdef RTM_VERSION */
250
251	REQUIRE(mgr->route != NULL);
252
253	if (need_rescan(mgr, rtm, rtmlen) && mgr->sctx->interface_auto) {
254		ns_interfacemgr_scan(mgr, false, false);
255	}
256
257	isc_nm_read(handle, route_recv, mgr);
258	return;
259}
260
261static void
262route_connected(isc_nmhandle_t *handle, isc_result_t eresult, void *arg) {
263	ns_interfacemgr_t *mgr = (ns_interfacemgr_t *)arg;
264
265	isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_DEBUG(9),
266		      "route_connected: %s", isc_result_totext(eresult));
267
268	if (eresult != ISC_R_SUCCESS) {
269		ns_interfacemgr_detach(&mgr);
270		return;
271	}
272
273	INSIST(mgr->route == NULL);
274
275	isc_nmhandle_attach(handle, &mgr->route);
276	isc_nm_read(handle, route_recv, mgr);
277}
278
279isc_result_t
280ns_interfacemgr_create(isc_mem_t *mctx, ns_server_t *sctx,
281		       isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr,
282		       isc_nm_t *nm, dns_dispatchmgr_t *dispatchmgr,
283		       isc_task_t *task, dns_geoip_databases_t *geoip,
284		       int ncpus, bool scan, ns_interfacemgr_t **mgrp) {
285	isc_result_t result;
286	ns_interfacemgr_t *mgr = NULL;
287
288	UNUSED(task);
289
290	REQUIRE(mctx != NULL);
291	REQUIRE(mgrp != NULL);
292	REQUIRE(*mgrp == NULL);
293
294	mgr = isc_mem_get(mctx, sizeof(*mgr));
295	*mgr = (ns_interfacemgr_t){ .taskmgr = taskmgr,
296				    .timermgr = timermgr,
297				    .nm = nm,
298				    .dispatchmgr = dispatchmgr,
299				    .generation = 1,
300				    .ncpus = ncpus };
301
302	isc_mem_attach(mctx, &mgr->mctx);
303	ns_server_attach(sctx, &mgr->sctx);
304
305	isc_mutex_init(&mgr->lock);
306
307	result = isc_task_create_bound(taskmgr, 0, &mgr->task, 0);
308	if (result != ISC_R_SUCCESS) {
309		goto cleanup_lock;
310	}
311
312	atomic_init(&mgr->shuttingdown, false);
313
314	ISC_LIST_INIT(mgr->interfaces);
315	ISC_LIST_INIT(mgr->listenon);
316
317	/*
318	 * The listen-on lists are initially empty.
319	 */
320	result = ns_listenlist_create(mctx, &mgr->listenon4);
321	if (result != ISC_R_SUCCESS) {
322		goto cleanup_task;
323	}
324	ns_listenlist_attach(mgr->listenon4, &mgr->listenon6);
325
326	result = dns_aclenv_create(mctx, &mgr->aclenv);
327	if (result != ISC_R_SUCCESS) {
328		goto cleanup_listenon;
329	}
330#if defined(HAVE_GEOIP2)
331	mgr->aclenv->geoip = geoip;
332#else  /* if defined(HAVE_GEOIP2) */
333	UNUSED(geoip);
334#endif /* if defined(HAVE_GEOIP2) */
335
336	isc_refcount_init(&mgr->references, 1);
337	mgr->magic = IFMGR_MAGIC;
338	*mgrp = mgr;
339
340	mgr->clientmgrs = isc_mem_get(mgr->mctx,
341				      mgr->ncpus * sizeof(mgr->clientmgrs[0]));
342	for (size_t i = 0; i < (size_t)mgr->ncpus; i++) {
343		result = ns_clientmgr_create(mgr->sctx, mgr->taskmgr,
344					     mgr->timermgr, mgr->aclenv, (int)i,
345					     &mgr->clientmgrs[i]);
346		RUNTIME_CHECK(result == ISC_R_SUCCESS);
347	}
348
349	if (scan) {
350		ns_interfacemgr_t *imgr = NULL;
351
352		ns_interfacemgr_attach(mgr, &imgr);
353
354		result = isc_nm_routeconnect(nm, route_connected, imgr, 0);
355		if (result == ISC_R_NOTIMPLEMENTED) {
356			ns_interfacemgr_detach(&imgr);
357		}
358		if (result != ISC_R_SUCCESS) {
359			isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_INFO,
360				      "unable to open route socket: %s",
361				      isc_result_totext(result));
362		}
363	}
364
365	return (ISC_R_SUCCESS);
366
367cleanup_listenon:
368	ns_listenlist_detach(&mgr->listenon4);
369	ns_listenlist_detach(&mgr->listenon6);
370cleanup_task:
371	isc_task_detach(&mgr->task);
372cleanup_lock:
373	isc_mutex_destroy(&mgr->lock);
374	ns_server_detach(&mgr->sctx);
375	isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr));
376	return (result);
377}
378
379static void
380ns_interfacemgr_destroy(ns_interfacemgr_t *mgr) {
381	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
382
383	isc_refcount_destroy(&mgr->references);
384
385	dns_aclenv_detach(&mgr->aclenv);
386	ns_listenlist_detach(&mgr->listenon4);
387	ns_listenlist_detach(&mgr->listenon6);
388	clearlistenon(mgr);
389	isc_mutex_destroy(&mgr->lock);
390	for (size_t i = 0; i < (size_t)mgr->ncpus; i++) {
391		ns_clientmgr_detach(&mgr->clientmgrs[i]);
392	}
393	isc_mem_put(mgr->mctx, mgr->clientmgrs,
394		    mgr->ncpus * sizeof(mgr->clientmgrs[0]));
395
396	if (mgr->sctx != NULL) {
397		ns_server_detach(&mgr->sctx);
398	}
399	isc_task_detach(&mgr->task);
400	mgr->magic = 0;
401	isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr));
402}
403
404void
405ns_interfacemgr_setbacklog(ns_interfacemgr_t *mgr, int backlog) {
406	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
407	LOCK(&mgr->lock);
408	mgr->backlog = backlog;
409	UNLOCK(&mgr->lock);
410}
411
412dns_aclenv_t *
413ns_interfacemgr_getaclenv(ns_interfacemgr_t *mgr) {
414	dns_aclenv_t *aclenv = NULL;
415
416	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
417
418	LOCK(&mgr->lock);
419	aclenv = mgr->aclenv;
420	UNLOCK(&mgr->lock);
421
422	return (aclenv);
423}
424
425void
426ns_interfacemgr_attach(ns_interfacemgr_t *source, ns_interfacemgr_t **target) {
427	REQUIRE(NS_INTERFACEMGR_VALID(source));
428	isc_refcount_increment(&source->references);
429	*target = source;
430}
431
432void
433ns_interfacemgr_detach(ns_interfacemgr_t **targetp) {
434	ns_interfacemgr_t *target = *targetp;
435	*targetp = NULL;
436	REQUIRE(target != NULL);
437	REQUIRE(NS_INTERFACEMGR_VALID(target));
438	if (isc_refcount_decrement(&target->references) == 1) {
439		ns_interfacemgr_destroy(target);
440	}
441}
442
443void
444ns_interfacemgr_shutdown(ns_interfacemgr_t *mgr) {
445	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
446
447	/*%
448	 * Shut down and detach all interfaces.
449	 * By incrementing the generation count, we make
450	 * purge_old_interfaces() consider all interfaces "old".
451	 */
452	mgr->generation++;
453	atomic_store(&mgr->shuttingdown, true);
454
455	purge_old_interfaces(mgr);
456
457	if (mgr->route != NULL) {
458		isc_nm_cancelread(mgr->route);
459	}
460
461	for (size_t i = 0; i < (size_t)mgr->ncpus; i++) {
462		ns_clientmgr_shutdown(mgr->clientmgrs[i]);
463	}
464}
465
466static void
467interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, const char *name,
468		 ns_interface_t **ifpret) {
469	ns_interface_t *ifp = NULL;
470
471	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
472
473	ifp = isc_mem_get(mgr->mctx, sizeof(*ifp));
474	*ifp = (ns_interface_t){ .generation = mgr->generation, .addr = *addr };
475
476	strlcpy(ifp->name, name, sizeof(ifp->name));
477
478	isc_mutex_init(&ifp->lock);
479
480	isc_refcount_init(&ifp->ntcpaccepting, 0);
481	isc_refcount_init(&ifp->ntcpactive, 0);
482
483	ISC_LINK_INIT(ifp, link);
484
485	ns_interfacemgr_attach(mgr, &ifp->mgr);
486	ifp->magic = IFACE_MAGIC;
487
488	LOCK(&mgr->lock);
489	ISC_LIST_APPEND(mgr->interfaces, ifp, link);
490	UNLOCK(&mgr->lock);
491
492	*ifpret = ifp;
493}
494
495static isc_result_t
496ns_interface_listenudp(ns_interface_t *ifp) {
497	isc_result_t result;
498
499	/* Reserve space for an ns_client_t with the netmgr handle */
500	result = isc_nm_listenudp(ifp->mgr->nm, &ifp->addr, ns__client_request,
501				  ifp, sizeof(ns_client_t),
502				  &ifp->udplistensocket);
503	return (result);
504}
505
506static isc_result_t
507ns_interface_listentcp(ns_interface_t *ifp) {
508	isc_result_t result;
509
510	result = isc_nm_listentcpdns(
511		ifp->mgr->nm, &ifp->addr, ns__client_request, ifp,
512		ns__client_tcpconn, ifp, sizeof(ns_client_t), ifp->mgr->backlog,
513		&ifp->mgr->sctx->tcpquota, &ifp->tcplistensocket);
514	if (result != ISC_R_SUCCESS) {
515		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
516			      "creating TCP socket: %s",
517			      isc_result_totext(result));
518	}
519
520	/*
521	 * We call this now to update the tcp-highwater statistic:
522	 * this is necessary because we are adding to the TCP quota just
523	 * by listening.
524	 */
525	result = ns__client_tcpconn(NULL, ISC_R_SUCCESS, ifp);
526	if (result != ISC_R_SUCCESS) {
527		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
528			      "connecting TCP socket: %s",
529			      isc_result_totext(result));
530	}
531
532	return (result);
533}
534
535/*
536 * XXXWPK we should probably pass a complete object with key, cert, and other
537 * TLS related options.
538 */
539static isc_result_t
540ns_interface_listentls(ns_interface_t *ifp, isc_tlsctx_t *sslctx) {
541	isc_result_t result;
542
543	result = isc_nm_listentlsdns(
544		ifp->mgr->nm, &ifp->addr, ns__client_request, ifp,
545		ns__client_tcpconn, ifp, sizeof(ns_client_t), ifp->mgr->backlog,
546		&ifp->mgr->sctx->tcpquota, sslctx, &ifp->tcplistensocket);
547
548	if (result != ISC_R_SUCCESS) {
549		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
550			      "creating TLS socket: %s",
551			      isc_result_totext(result));
552		return (result);
553	}
554
555	/*
556	 * We call this now to update the tcp-highwater statistic:
557	 * this is necessary because we are adding to the TCP quota just
558	 * by listening.
559	 */
560	result = ns__client_tcpconn(NULL, ISC_R_SUCCESS, ifp);
561	if (result != ISC_R_SUCCESS) {
562		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
563			      "updating TCP stats: %s",
564			      isc_result_totext(result));
565	}
566
567	return (result);
568}
569
570#ifdef HAVE_LIBNGHTTP2
571static isc_result_t
572load_http_endpoints(isc_nm_http_endpoints_t *epset, ns_interface_t *ifp,
573		    char **eps, size_t neps) {
574	isc_result_t result = ISC_R_FAILURE;
575
576	for (size_t i = 0; i < neps; i++) {
577		result = isc_nm_http_endpoints_add(epset, eps[i],
578						   ns__client_request, ifp,
579						   sizeof(ns_client_t));
580		if (result != ISC_R_SUCCESS) {
581			break;
582		}
583	}
584
585	return (result);
586}
587#endif /* HAVE_LIBNGHTTP2 */
588
589static isc_result_t
590ns_interface_listenhttp(ns_interface_t *ifp, isc_tlsctx_t *sslctx, char **eps,
591			size_t neps, uint32_t max_clients,
592			uint32_t max_concurrent_streams) {
593#if HAVE_LIBNGHTTP2
594	isc_result_t result = ISC_R_FAILURE;
595	isc_nmsocket_t *sock = NULL;
596	isc_nm_http_endpoints_t *epset = NULL;
597	isc_quota_t *quota = NULL;
598
599	epset = isc_nm_http_endpoints_new(ifp->mgr->mctx);
600
601	result = load_http_endpoints(epset, ifp, eps, neps);
602
603	if (result == ISC_R_SUCCESS) {
604		quota = isc_mem_get(ifp->mgr->mctx, sizeof(*quota));
605		isc_quota_init(quota, max_clients);
606		result = isc_nm_listenhttp(
607			ifp->mgr->nm, &ifp->addr, ifp->mgr->backlog, quota,
608			sslctx, epset, max_concurrent_streams, &sock);
609	}
610
611	isc_nm_http_endpoints_detach(&epset);
612
613	if (quota != NULL) {
614		if (result != ISC_R_SUCCESS) {
615			isc_quota_destroy(quota);
616			isc_mem_put(ifp->mgr->mctx, quota, sizeof(*quota));
617		} else {
618			ifp->http_quota = quota;
619			ns_server_append_http_quota(ifp->mgr->sctx, quota);
620		}
621	}
622
623	if (result != ISC_R_SUCCESS) {
624		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
625			      "creating %s socket: %s",
626			      sslctx ? "HTTPS" : "HTTP",
627			      isc_result_totext(result));
628		return (result);
629	}
630
631	if (sslctx) {
632		ifp->http_secure_listensocket = sock;
633	} else {
634		ifp->http_listensocket = sock;
635	}
636
637	/*
638	 * We call this now to update the tcp-highwater statistic:
639	 * this is necessary because we are adding to the TCP quota just
640	 * by listening.
641	 */
642	result = ns__client_tcpconn(NULL, ISC_R_SUCCESS, ifp);
643	if (result != ISC_R_SUCCESS) {
644		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
645			      "updating TCP stats: %s",
646			      isc_result_totext(result));
647	}
648
649	return (result);
650#else
651	UNUSED(ifp);
652	UNUSED(sslctx);
653	UNUSED(eps);
654	UNUSED(neps);
655	UNUSED(max_clients);
656	UNUSED(max_concurrent_streams);
657	return (ISC_R_NOTIMPLEMENTED);
658#endif
659}
660
661static isc_result_t
662interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, const char *name,
663		ns_interface_t **ifpret, ns_listenelt_t *elt,
664		bool *addr_in_use) {
665	isc_result_t result;
666	ns_interface_t *ifp = NULL;
667
668	REQUIRE(ifpret != NULL);
669	REQUIRE(addr_in_use == NULL || !*addr_in_use);
670
671	ifp = *ifpret;
672
673	if (ifp == NULL) {
674		interface_create(mgr, addr, name, &ifp);
675	} else {
676		REQUIRE(!LISTENING(ifp));
677	}
678
679	ifp->flags |= NS_INTERFACEFLAG_LISTENING;
680
681	if (elt->is_http) {
682		result = ns_interface_listenhttp(
683			ifp, elt->sslctx, elt->http_endpoints,
684			elt->http_endpoints_number, elt->http_max_clients,
685			elt->max_concurrent_streams);
686		if (result != ISC_R_SUCCESS) {
687			goto cleanup_interface;
688		}
689		*ifpret = ifp;
690		return (result);
691	}
692
693	if (elt->sslctx != NULL) {
694		result = ns_interface_listentls(ifp, elt->sslctx);
695		if (result != ISC_R_SUCCESS) {
696			goto cleanup_interface;
697		}
698		*ifpret = ifp;
699		return (result);
700	}
701
702	result = ns_interface_listenudp(ifp);
703	if (result != ISC_R_SUCCESS) {
704		if ((result == ISC_R_ADDRINUSE) && (addr_in_use != NULL)) {
705			*addr_in_use = true;
706		}
707		goto cleanup_interface;
708	}
709
710	if (((mgr->sctx->options & NS_SERVER_NOTCP) == 0)) {
711		result = ns_interface_listentcp(ifp);
712		if (result != ISC_R_SUCCESS) {
713			if ((result == ISC_R_ADDRINUSE) &&
714			    (addr_in_use != NULL))
715			{
716				*addr_in_use = true;
717			}
718
719			/*
720			 * XXXRTH We don't currently have a way to easily stop
721			 * dispatch service, so we currently return
722			 * ISC_R_SUCCESS (the UDP stuff will work even if TCP
723			 * creation failed).  This will be fixed later.
724			 */
725			result = ISC_R_SUCCESS;
726		}
727	}
728	*ifpret = ifp;
729	return (result);
730
731cleanup_interface:
732	ns_interface_shutdown(ifp);
733	return (result);
734}
735
736void
737ns_interface_shutdown(ns_interface_t *ifp) {
738	ifp->flags &= ~NS_INTERFACEFLAG_LISTENING;
739
740	if (ifp->udplistensocket != NULL) {
741		isc_nm_stoplistening(ifp->udplistensocket);
742		isc_nmsocket_close(&ifp->udplistensocket);
743	}
744	if (ifp->tcplistensocket != NULL) {
745		isc_nm_stoplistening(ifp->tcplistensocket);
746		isc_nmsocket_close(&ifp->tcplistensocket);
747	}
748	if (ifp->http_listensocket != NULL) {
749		isc_nm_stoplistening(ifp->http_listensocket);
750		isc_nmsocket_close(&ifp->http_listensocket);
751	}
752	if (ifp->http_secure_listensocket != NULL) {
753		isc_nm_stoplistening(ifp->http_secure_listensocket);
754		isc_nmsocket_close(&ifp->http_secure_listensocket);
755	}
756	ifp->http_quota = NULL;
757}
758
759static void
760interface_destroy(ns_interface_t **interfacep) {
761	ns_interface_t *ifp = NULL;
762	ns_interfacemgr_t *mgr = NULL;
763
764	REQUIRE(interfacep != NULL);
765
766	ifp = *interfacep;
767	*interfacep = NULL;
768
769	REQUIRE(NS_INTERFACE_VALID(ifp));
770
771	mgr = ifp->mgr;
772
773	ns_interface_shutdown(ifp);
774
775	ifp->magic = 0;
776	isc_mutex_destroy(&ifp->lock);
777	ns_interfacemgr_detach(&ifp->mgr);
778	isc_refcount_destroy(&ifp->ntcpactive);
779	isc_refcount_destroy(&ifp->ntcpaccepting);
780
781	isc_mem_put(mgr->mctx, ifp, sizeof(*ifp));
782}
783
784/*%
785 * Search the interface list for an interface whose address and port
786 * both match those of 'addr'.  Return a pointer to it, or NULL if not found.
787 */
788static ns_interface_t *
789find_matching_interface(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) {
790	ns_interface_t *ifp;
791	LOCK(&mgr->lock);
792	for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL;
793	     ifp = ISC_LIST_NEXT(ifp, link))
794	{
795		if (isc_sockaddr_equal(&ifp->addr, addr)) {
796			break;
797		}
798	}
799	UNLOCK(&mgr->lock);
800	return (ifp);
801}
802
803/*%
804 * Remove any interfaces whose generation number is not the current one.
805 */
806static void
807purge_old_interfaces(ns_interfacemgr_t *mgr) {
808	ns_interface_t *ifp = NULL, *next = NULL;
809	ISC_LIST(ns_interface_t) interfaces;
810
811	ISC_LIST_INIT(interfaces);
812
813	LOCK(&mgr->lock);
814	for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL; ifp = next) {
815		INSIST(NS_INTERFACE_VALID(ifp));
816		next = ISC_LIST_NEXT(ifp, link);
817		if (ifp->generation != mgr->generation) {
818			ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
819			ISC_LIST_APPEND(interfaces, ifp, link);
820		}
821	}
822	UNLOCK(&mgr->lock);
823
824	for (ifp = ISC_LIST_HEAD(interfaces); ifp != NULL; ifp = next) {
825		next = ISC_LIST_NEXT(ifp, link);
826		if (LISTENING(ifp)) {
827			char sabuf[256];
828			isc_sockaddr_format(&ifp->addr, sabuf, sizeof(sabuf));
829			isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_INFO,
830				      "no longer listening on %s", sabuf);
831			ns_interface_shutdown(ifp);
832		}
833		ISC_LIST_UNLINK(interfaces, ifp, link);
834		interface_destroy(&ifp);
835	}
836}
837
838static bool
839listenon_is_ip6_any(ns_listenelt_t *elt) {
840	REQUIRE(elt && elt->acl);
841	return (dns_acl_isany(elt->acl));
842}
843
844static isc_result_t
845setup_locals(isc_interface_t *interface, dns_acl_t *localhost,
846	     dns_acl_t *localnets) {
847	isc_result_t result;
848	unsigned int prefixlen;
849	isc_netaddr_t *netaddr;
850
851	netaddr = &interface->address;
852
853	/* First add localhost address */
854	prefixlen = (netaddr->family == AF_INET) ? 32 : 128;
855	result = dns_iptable_addprefix(localhost->iptable, netaddr, prefixlen,
856				       true);
857	if (result != ISC_R_SUCCESS) {
858		return (result);
859	}
860
861	/* Then add localnets prefix */
862	result = isc_netaddr_masktoprefixlen(&interface->netmask, &prefixlen);
863
864	/* Non contiguous netmasks not allowed by IPv6 arch. */
865	if (result != ISC_R_SUCCESS && netaddr->family == AF_INET6) {
866		return (result);
867	}
868
869	if (result != ISC_R_SUCCESS) {
870		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
871			      "omitting IPv4 interface %s from "
872			      "localnets ACL: %s",
873			      interface->name, isc_result_totext(result));
874		return (ISC_R_SUCCESS);
875	}
876
877	if (prefixlen == 0U) {
878		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
879			      "omitting %s interface %s from localnets ACL: "
880			      "zero prefix length detected",
881			      (netaddr->family == AF_INET) ? "IPv4" : "IPv6",
882			      interface->name);
883		return (ISC_R_SUCCESS);
884	}
885
886	result = dns_iptable_addprefix(localnets->iptable, netaddr, prefixlen,
887				       true);
888	if (result != ISC_R_SUCCESS) {
889		return (result);
890	}
891
892	return (ISC_R_SUCCESS);
893}
894
895static void
896setup_listenon(ns_interfacemgr_t *mgr, isc_interface_t *interface,
897	       in_port_t port) {
898	isc_sockaddr_t *addr;
899	isc_sockaddr_t *old;
900
901	addr = isc_mem_get(mgr->mctx, sizeof(*addr));
902
903	isc_sockaddr_fromnetaddr(addr, &interface->address, port);
904
905	LOCK(&mgr->lock);
906	for (old = ISC_LIST_HEAD(mgr->listenon); old != NULL;
907	     old = ISC_LIST_NEXT(old, link))
908	{
909		if (isc_sockaddr_equal(addr, old)) {
910			/* We found an existing address */
911			isc_mem_put(mgr->mctx, addr, sizeof(*addr));
912			goto unlock;
913		}
914	}
915
916	ISC_LIST_APPEND(mgr->listenon, addr, link);
917unlock:
918	UNLOCK(&mgr->lock);
919}
920
921static void
922clearlistenon(ns_interfacemgr_t *mgr) {
923	ISC_LIST(isc_sockaddr_t) listenon;
924	isc_sockaddr_t *old;
925
926	ISC_LIST_INIT(listenon);
927
928	LOCK(&mgr->lock);
929	ISC_LIST_MOVE(listenon, mgr->listenon);
930	UNLOCK(&mgr->lock);
931
932	old = ISC_LIST_HEAD(listenon);
933	while (old != NULL) {
934		ISC_LIST_UNLINK(listenon, old, link);
935		isc_mem_put(mgr->mctx, old, sizeof(*old));
936		old = ISC_LIST_HEAD(listenon);
937	}
938}
939
940static void
941replace_listener_tlsctx(ns_interface_t *ifp, isc_tlsctx_t *newctx) {
942	char sabuf[ISC_SOCKADDR_FORMATSIZE];
943
944	isc_sockaddr_format(&ifp->addr, sabuf, sizeof(sabuf));
945	isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_INFO,
946		      "updating TLS context on %s", sabuf);
947	if (ifp->tcplistensocket != NULL) {
948		/* 'tcplistensocket' is used for DoT */
949		isc_nmsocket_set_tlsctx(ifp->tcplistensocket, newctx);
950	} else if (ifp->http_secure_listensocket != NULL) {
951		isc_nmsocket_set_tlsctx(ifp->http_secure_listensocket, newctx);
952	}
953}
954
955#ifdef HAVE_LIBNGHTTP2
956static void
957update_http_settings(ns_interface_t *ifp, ns_listenelt_t *le) {
958	isc_result_t result;
959	isc_nmsocket_t *listener;
960	isc_nm_http_endpoints_t *epset;
961
962	REQUIRE(le->is_http);
963
964	INSIST(ifp->http_quota != NULL);
965	isc_quota_max(ifp->http_quota, le->http_max_clients);
966
967	if (ifp->http_secure_listensocket != NULL) {
968		listener = ifp->http_secure_listensocket;
969	} else {
970		INSIST(ifp->http_listensocket != NULL);
971		listener = ifp->http_listensocket;
972	}
973
974	isc_nmsocket_set_max_streams(listener, le->max_concurrent_streams);
975
976	epset = isc_nm_http_endpoints_new(ifp->mgr->mctx);
977
978	result = load_http_endpoints(epset, ifp, le->http_endpoints,
979				     le->http_endpoints_number);
980
981	if (result == ISC_R_SUCCESS) {
982		isc_nm_http_set_endpoints(listener, epset);
983	}
984
985	isc_nm_http_endpoints_detach(&epset);
986}
987#endif /* HAVE_LIBNGHTTP2 */
988
989static void
990update_listener_configuration(ns_interfacemgr_t *mgr, ns_interface_t *ifp,
991			      ns_listenelt_t *le) {
992	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
993	REQUIRE(NS_INTERFACE_VALID(ifp));
994	REQUIRE(le != NULL);
995
996	LOCK(&mgr->lock);
997	/*
998	 * We need to update the TLS contexts
999	 * inside the TLS/HTTPS listeners during
1000	 * a reconfiguration because the
1001	 * certificates could have been changed.
1002	 */
1003	if (le->sslctx != NULL) {
1004		replace_listener_tlsctx(ifp, le->sslctx);
1005	}
1006
1007#ifdef HAVE_LIBNGHTTP2
1008	/*
1009	 * Let's update HTTP listener settings
1010	 * on reconfiguration.
1011	 */
1012	if (le->is_http) {
1013		update_http_settings(ifp, le);
1014	}
1015#endif /* HAVE_LIBNGHTTP2 */
1016
1017	UNLOCK(&mgr->lock);
1018}
1019
1020static isc_result_t
1021do_scan(ns_interfacemgr_t *mgr, bool verbose, bool config) {
1022	isc_interfaceiter_t *iter = NULL;
1023	bool scan_ipv4 = false;
1024	bool scan_ipv6 = false;
1025	bool ipv6only = true;
1026	bool ipv6pktinfo = true;
1027	isc_result_t result;
1028	isc_netaddr_t zero_address, zero_address6;
1029	ns_listenelt_t *le = NULL;
1030	isc_sockaddr_t listen_addr;
1031	ns_interface_t *ifp = NULL;
1032	bool log_explicit = false;
1033	bool dolistenon;
1034	char sabuf[ISC_SOCKADDR_FORMATSIZE];
1035	bool tried_listening;
1036	bool all_addresses_in_use;
1037	dns_acl_t *localhost = NULL;
1038	dns_acl_t *localnets = NULL;
1039
1040	if (isc_net_probeipv6() == ISC_R_SUCCESS) {
1041		scan_ipv6 = true;
1042	} else if ((mgr->sctx->options & NS_SERVER_DISABLE6) == 0) {
1043		isc_log_write(IFMGR_COMMON_LOGARGS,
1044			      verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
1045			      "no IPv6 interfaces found");
1046	}
1047
1048	if (isc_net_probeipv4() == ISC_R_SUCCESS) {
1049		scan_ipv4 = true;
1050	} else if ((mgr->sctx->options & NS_SERVER_DISABLE4) == 0) {
1051		isc_log_write(IFMGR_COMMON_LOGARGS,
1052			      verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
1053			      "no IPv4 interfaces found");
1054	}
1055
1056	/*
1057	 * A special, but typical case; listen-on-v6 { any; }.
1058	 * When we can make the socket IPv6-only, open a single wildcard
1059	 * socket for IPv6 communication.  Otherwise, make separate
1060	 * socket for each IPv6 address in order to avoid accepting IPv4
1061	 * packets as the form of mapped addresses unintentionally
1062	 * unless explicitly allowed.
1063	 */
1064	if (scan_ipv6 && isc_net_probe_ipv6only() != ISC_R_SUCCESS) {
1065		ipv6only = false;
1066		log_explicit = true;
1067	}
1068	if (scan_ipv6 && isc_net_probe_ipv6pktinfo() != ISC_R_SUCCESS) {
1069		ipv6pktinfo = false;
1070		log_explicit = true;
1071	}
1072	if (scan_ipv6 && ipv6only && ipv6pktinfo) {
1073		for (le = ISC_LIST_HEAD(mgr->listenon6->elts); le != NULL;
1074		     le = ISC_LIST_NEXT(le, link))
1075		{
1076			struct in6_addr in6a;
1077
1078			if (!listenon_is_ip6_any(le)) {
1079				continue;
1080			}
1081
1082			in6a = in6addr_any;
1083			isc_sockaddr_fromin6(&listen_addr, &in6a, le->port);
1084
1085			ifp = find_matching_interface(mgr, &listen_addr);
1086			if (ifp != NULL) {
1087				ifp->generation = mgr->generation;
1088				if (LISTENING(ifp)) {
1089					if (config) {
1090						update_listener_configuration(
1091							mgr, ifp, le);
1092					}
1093					continue;
1094				}
1095			}
1096
1097			isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_INFO,
1098				      "listening on IPv6 "
1099				      "interfaces, port %u",
1100				      le->port);
1101			result = interface_setup(mgr, &listen_addr, "<any>",
1102						 &ifp, le, NULL);
1103			if (result == ISC_R_SUCCESS) {
1104				ifp->flags |= NS_INTERFACEFLAG_ANYADDR;
1105			} else {
1106				isc_log_write(IFMGR_COMMON_LOGARGS,
1107					      ISC_LOG_ERROR,
1108					      "listening on all IPv6 "
1109					      "interfaces failed");
1110			}
1111			/* Continue. */
1112		}
1113	}
1114
1115	isc_netaddr_any(&zero_address);
1116	isc_netaddr_any6(&zero_address6);
1117
1118	result = isc_interfaceiter_create(mgr->mctx, &iter);
1119	if (result != ISC_R_SUCCESS) {
1120		return (result);
1121	}
1122
1123	result = dns_acl_create(mgr->mctx, 0, &localhost);
1124	if (result != ISC_R_SUCCESS) {
1125		goto cleanup_iter;
1126	}
1127	result = dns_acl_create(mgr->mctx, 0, &localnets);
1128	if (result != ISC_R_SUCCESS) {
1129		goto cleanup_localhost;
1130	}
1131
1132	clearlistenon(mgr);
1133
1134	tried_listening = false;
1135	all_addresses_in_use = true;
1136	for (result = isc_interfaceiter_first(iter); result == ISC_R_SUCCESS;
1137	     result = isc_interfaceiter_next(iter))
1138	{
1139		isc_interface_t interface;
1140		ns_listenlist_t *ll = NULL;
1141		unsigned int family;
1142
1143		result = isc_interfaceiter_current(iter, &interface);
1144		if (result != ISC_R_SUCCESS) {
1145			break;
1146		}
1147
1148		family = interface.address.family;
1149		if (family != AF_INET && family != AF_INET6) {
1150			continue;
1151		}
1152		if (!scan_ipv4 && family == AF_INET) {
1153			continue;
1154		}
1155		if (!scan_ipv6 && family == AF_INET6) {
1156			continue;
1157		}
1158
1159		/*
1160		 * Test for the address being nonzero rather than testing
1161		 * INTERFACE_F_UP, because on some systems the latter
1162		 * follows the media state and we could end up ignoring
1163		 * the interface for an entire rescan interval due to
1164		 * a temporary media glitch at rescan time.
1165		 */
1166		if (family == AF_INET &&
1167		    isc_netaddr_equal(&interface.address, &zero_address))
1168		{
1169			continue;
1170		}
1171		if (family == AF_INET6 &&
1172		    isc_netaddr_equal(&interface.address, &zero_address6))
1173		{
1174			continue;
1175		}
1176
1177		/*
1178		 * If running with -T fixedlocal, then we only
1179		 * want 127.0.0.1 and ::1 in the localhost ACL.
1180		 */
1181		if (((mgr->sctx->options & NS_SERVER_FIXEDLOCAL) != 0) &&
1182		    !isc_netaddr_isloopback(&interface.address))
1183		{
1184			goto listenon;
1185		}
1186
1187		result = setup_locals(&interface, localhost, localnets);
1188		if (result != ISC_R_SUCCESS) {
1189			goto ignore_interface;
1190		}
1191
1192	listenon:
1193		ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6;
1194		dolistenon = true;
1195		for (le = ISC_LIST_HEAD(ll->elts); le != NULL;
1196		     le = ISC_LIST_NEXT(le, link))
1197		{
1198			int match;
1199			bool addr_in_use = false;
1200			bool ipv6_wildcard = false;
1201			isc_sockaddr_t listen_sockaddr;
1202
1203			isc_sockaddr_fromnetaddr(&listen_sockaddr,
1204						 &interface.address, le->port);
1205
1206			/*
1207			 * See if the address matches the listen-on statement;
1208			 * if not, ignore the interface, but store it in
1209			 * the interface table so we know we've seen it
1210			 * before.
1211			 */
1212			(void)dns_acl_match(&interface.address, NULL, le->acl,
1213					    mgr->aclenv, &match, NULL);
1214			if (match <= 0) {
1215				ns_interface_t *new = NULL;
1216				interface_create(mgr, &listen_sockaddr,
1217						 interface.name, &new);
1218				continue;
1219			}
1220
1221			if (dolistenon) {
1222				setup_listenon(mgr, &interface, le->port);
1223				dolistenon = false;
1224			}
1225
1226			/*
1227			 * The case of "any" IPv6 address will require
1228			 * special considerations later, so remember it.
1229			 */
1230			if (family == AF_INET6 && ipv6only && ipv6pktinfo &&
1231			    listenon_is_ip6_any(le))
1232			{
1233				ipv6_wildcard = true;
1234			}
1235
1236			ifp = find_matching_interface(mgr, &listen_sockaddr);
1237			if (ifp != NULL) {
1238				ifp->generation = mgr->generation;
1239				if (LISTENING(ifp)) {
1240					if (config) {
1241						update_listener_configuration(
1242							mgr, ifp, le);
1243					}
1244					continue;
1245				}
1246			}
1247
1248			if (ipv6_wildcard) {
1249				continue;
1250			}
1251
1252			if (log_explicit && family == AF_INET6 &&
1253			    listenon_is_ip6_any(le))
1254			{
1255				isc_log_write(IFMGR_COMMON_LOGARGS,
1256					      verbose ? ISC_LOG_INFO
1257						      : ISC_LOG_DEBUG(1),
1258					      "IPv6 socket API is "
1259					      "incomplete; explicitly "
1260					      "binding to each IPv6 "
1261					      "address separately");
1262				log_explicit = false;
1263			}
1264			isc_sockaddr_format(&listen_sockaddr, sabuf,
1265					    sizeof(sabuf));
1266			isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_INFO,
1267				      "listening on %s interface "
1268				      "%s, %s",
1269				      (family == AF_INET) ? "IPv4" : "IPv6",
1270				      interface.name, sabuf);
1271
1272			result = interface_setup(mgr, &listen_sockaddr,
1273						 interface.name, &ifp, le,
1274						 &addr_in_use);
1275
1276			tried_listening = true;
1277			if (!addr_in_use) {
1278				all_addresses_in_use = false;
1279			}
1280
1281			if (result != ISC_R_SUCCESS) {
1282				isc_log_write(
1283					IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
1284					"creating %s interface "
1285					"%s failed; interface ignored",
1286					(family == AF_INET) ? "IPv4" : "IPv6",
1287					interface.name);
1288			}
1289			/* Continue. */
1290		}
1291		continue;
1292
1293	ignore_interface:
1294		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
1295			      "ignoring %s interface %s: %s",
1296			      (family == AF_INET) ? "IPv4" : "IPv6",
1297			      interface.name, isc_result_totext(result));
1298		continue;
1299	}
1300	if (result != ISC_R_NOMORE) {
1301		UNEXPECTED_ERROR("interface iteration failed: %s",
1302				 isc_result_totext(result));
1303	} else {
1304		result = ((tried_listening && all_addresses_in_use)
1305				  ? ISC_R_ADDRINUSE
1306				  : ISC_R_SUCCESS);
1307	}
1308
1309	dns_aclenv_set(mgr->aclenv, localhost, localnets);
1310
1311	/* cleanup_localnets: */
1312	dns_acl_detach(&localnets);
1313
1314cleanup_localhost:
1315	dns_acl_detach(&localhost);
1316
1317cleanup_iter:
1318	isc_interfaceiter_destroy(&iter);
1319	return (result);
1320}
1321
1322isc_result_t
1323ns_interfacemgr_scan(ns_interfacemgr_t *mgr, bool verbose, bool config) {
1324	isc_result_t result;
1325	bool purge = true;
1326
1327	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
1328	REQUIRE(isc_nm_tid() == 0);
1329
1330	mgr->generation++; /* Increment the generation count. */
1331
1332	result = do_scan(mgr, verbose, config);
1333	if ((result != ISC_R_SUCCESS) && (result != ISC_R_ADDRINUSE)) {
1334		purge = false;
1335	}
1336
1337	/*
1338	 * Now go through the interface list and delete anything that
1339	 * does not have the current generation number.  This is
1340	 * how we catch interfaces that go away or change their
1341	 * addresses.
1342	 */
1343	if (purge) {
1344		purge_old_interfaces(mgr);
1345	}
1346
1347	/*
1348	 * Warn if we are not listening on any interface.
1349	 */
1350	if (ISC_LIST_EMPTY(mgr->interfaces)) {
1351		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
1352			      "not listening on any interfaces");
1353	}
1354
1355	return (result);
1356}
1357
1358bool
1359ns_interfacemgr_islistening(ns_interfacemgr_t *mgr) {
1360	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
1361
1362	return (ISC_LIST_EMPTY(mgr->interfaces) ? false : true);
1363}
1364
1365void
1366ns_interfacemgr_setlistenon4(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
1367	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
1368
1369	LOCK(&mgr->lock);
1370	ns_listenlist_detach(&mgr->listenon4);
1371	ns_listenlist_attach(value, &mgr->listenon4);
1372	UNLOCK(&mgr->lock);
1373}
1374
1375void
1376ns_interfacemgr_setlistenon6(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
1377	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
1378
1379	LOCK(&mgr->lock);
1380	ns_listenlist_detach(&mgr->listenon6);
1381	ns_listenlist_attach(value, &mgr->listenon6);
1382	UNLOCK(&mgr->lock);
1383}
1384
1385void
1386ns_interfacemgr_dumprecursing(FILE *f, ns_interfacemgr_t *mgr) {
1387	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
1388
1389	LOCK(&mgr->lock);
1390	for (size_t i = 0; i < (size_t)mgr->ncpus; i++) {
1391		ns_client_dumprecursing(f, mgr->clientmgrs[i]);
1392	}
1393	UNLOCK(&mgr->lock);
1394}
1395
1396bool
1397ns_interfacemgr_listeningon(ns_interfacemgr_t *mgr,
1398			    const isc_sockaddr_t *addr) {
1399	isc_sockaddr_t *old;
1400	bool result = false;
1401
1402	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
1403	/*
1404	 * If the manager is shutting down it's safer to
1405	 * return true.
1406	 */
1407	if (atomic_load(&mgr->shuttingdown)) {
1408		return (true);
1409	}
1410	LOCK(&mgr->lock);
1411	for (old = ISC_LIST_HEAD(mgr->listenon); old != NULL;
1412	     old = ISC_LIST_NEXT(old, link))
1413	{
1414		if (isc_sockaddr_equal(old, addr)) {
1415			result = true;
1416			break;
1417		}
1418	}
1419	UNLOCK(&mgr->lock);
1420
1421	return (result);
1422}
1423
1424ns_server_t *
1425ns_interfacemgr_getserver(ns_interfacemgr_t *mgr) {
1426	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
1427
1428	return (mgr->sctx);
1429}
1430
1431ns_clientmgr_t *
1432ns_interfacemgr_getclientmgr(ns_interfacemgr_t *mgr) {
1433	int tid = isc_nm_tid();
1434
1435	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
1436	REQUIRE(tid >= 0);
1437	REQUIRE(tid < mgr->ncpus);
1438
1439	return (mgr->clientmgrs[tid]);
1440}
1441