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