1/*
2 * Copyright (C) 2004-2009, 2011  Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2002  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* $Id: interfacemgr.c,v 1.95.426.2 2011/03/12 04:59:14 tbox Exp $ */
19
20/*! \file */
21
22#include <config.h>
23
24#include <isc/interfaceiter.h>
25#include <isc/string.h>
26#include <isc/task.h>
27#include <isc/util.h>
28
29#include <dns/acl.h>
30#include <dns/dispatch.h>
31
32#include <named/client.h>
33#include <named/log.h>
34#include <named/interfacemgr.h>
35
36#define IFMGR_MAGIC			ISC_MAGIC('I', 'F', 'M', 'G')
37#define NS_INTERFACEMGR_VALID(t)	ISC_MAGIC_VALID(t, IFMGR_MAGIC)
38
39#define IFMGR_COMMON_LOGARGS \
40	ns_g_lctx, NS_LOGCATEGORY_NETWORK, NS_LOGMODULE_INTERFACEMGR
41
42/*% nameserver interface manager structure */
43struct ns_interfacemgr {
44	unsigned int		magic;		/*%< Magic number. */
45	int			references;
46	isc_mutex_t		lock;
47	isc_mem_t *		mctx;		/*%< Memory context. */
48	isc_taskmgr_t *		taskmgr;	/*%< Task manager. */
49	isc_socketmgr_t *	socketmgr;	/*%< Socket manager. */
50	dns_dispatchmgr_t *	dispatchmgr;
51	unsigned int		generation;	/*%< Current generation no. */
52	ns_listenlist_t *	listenon4;
53	ns_listenlist_t *	listenon6;
54	dns_aclenv_t		aclenv;		/*%< Localhost/localnets ACLs */
55	ISC_LIST(ns_interface_t) interfaces;	/*%< List of interfaces. */
56	ISC_LIST(isc_sockaddr_t) listenon;
57};
58
59static void
60purge_old_interfaces(ns_interfacemgr_t *mgr);
61
62static void
63clearlistenon(ns_interfacemgr_t *mgr);
64
65isc_result_t
66ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
67		       isc_socketmgr_t *socketmgr,
68		       dns_dispatchmgr_t *dispatchmgr,
69		       ns_interfacemgr_t **mgrp)
70{
71	isc_result_t result;
72	ns_interfacemgr_t *mgr;
73
74	REQUIRE(mctx != NULL);
75	REQUIRE(mgrp != NULL);
76	REQUIRE(*mgrp == NULL);
77
78	mgr = isc_mem_get(mctx, sizeof(*mgr));
79	if (mgr == NULL)
80		return (ISC_R_NOMEMORY);
81
82	result = isc_mutex_init(&mgr->lock);
83	if (result != ISC_R_SUCCESS)
84		goto cleanup_mem;
85
86	mgr->mctx = mctx;
87	mgr->taskmgr = taskmgr;
88	mgr->socketmgr = socketmgr;
89	mgr->dispatchmgr = dispatchmgr;
90	mgr->generation = 1;
91	mgr->listenon4 = NULL;
92	mgr->listenon6 = NULL;
93
94	ISC_LIST_INIT(mgr->interfaces);
95	ISC_LIST_INIT(mgr->listenon);
96
97	/*
98	 * The listen-on lists are initially empty.
99	 */
100	result = ns_listenlist_create(mctx, &mgr->listenon4);
101	if (result != ISC_R_SUCCESS)
102		goto cleanup_mem;
103	ns_listenlist_attach(mgr->listenon4, &mgr->listenon6);
104
105	result = dns_aclenv_init(mctx, &mgr->aclenv);
106	if (result != ISC_R_SUCCESS)
107		goto cleanup_listenon;
108
109	mgr->references = 1;
110	mgr->magic = IFMGR_MAGIC;
111	*mgrp = mgr;
112	return (ISC_R_SUCCESS);
113
114 cleanup_listenon:
115	ns_listenlist_detach(&mgr->listenon4);
116	ns_listenlist_detach(&mgr->listenon6);
117 cleanup_mem:
118	isc_mem_put(mctx, mgr, sizeof(*mgr));
119	return (result);
120}
121
122static void
123ns_interfacemgr_destroy(ns_interfacemgr_t *mgr) {
124	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
125	dns_aclenv_destroy(&mgr->aclenv);
126	ns_listenlist_detach(&mgr->listenon4);
127	ns_listenlist_detach(&mgr->listenon6);
128	clearlistenon(mgr);
129	DESTROYLOCK(&mgr->lock);
130	mgr->magic = 0;
131	isc_mem_put(mgr->mctx, mgr, sizeof(*mgr));
132}
133
134dns_aclenv_t *
135ns_interfacemgr_getaclenv(ns_interfacemgr_t *mgr) {
136	return (&mgr->aclenv);
137}
138
139void
140ns_interfacemgr_attach(ns_interfacemgr_t *source, ns_interfacemgr_t **target) {
141	REQUIRE(NS_INTERFACEMGR_VALID(source));
142	LOCK(&source->lock);
143	INSIST(source->references > 0);
144	source->references++;
145	UNLOCK(&source->lock);
146	*target = source;
147}
148
149void
150ns_interfacemgr_detach(ns_interfacemgr_t **targetp) {
151	isc_result_t need_destroy = ISC_FALSE;
152	ns_interfacemgr_t *target = *targetp;
153	REQUIRE(target != NULL);
154	REQUIRE(NS_INTERFACEMGR_VALID(target));
155	LOCK(&target->lock);
156	REQUIRE(target->references > 0);
157	target->references--;
158	if (target->references == 0)
159		need_destroy = ISC_TRUE;
160	UNLOCK(&target->lock);
161	if (need_destroy)
162		ns_interfacemgr_destroy(target);
163	*targetp = NULL;
164}
165
166void
167ns_interfacemgr_shutdown(ns_interfacemgr_t *mgr) {
168	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
169
170	/*%
171	 * Shut down and detach all interfaces.
172	 * By incrementing the generation count, we make purge_old_interfaces()
173	 * consider all interfaces "old".
174	 */
175	mgr->generation++;
176	purge_old_interfaces(mgr);
177}
178
179
180static isc_result_t
181ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
182		    const char *name, ns_interface_t **ifpret)
183{
184	ns_interface_t *ifp;
185	isc_result_t result;
186
187	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
188	ifp = isc_mem_get(mgr->mctx, sizeof(*ifp));
189	if (ifp == NULL)
190		return (ISC_R_NOMEMORY);
191	ifp->mgr = NULL;
192	ifp->generation = mgr->generation;
193	ifp->addr = *addr;
194	ifp->flags = 0;
195	strncpy(ifp->name, name, sizeof(ifp->name));
196	ifp->name[sizeof(ifp->name)-1] = '\0';
197	ifp->clientmgr = NULL;
198
199	result = isc_mutex_init(&ifp->lock);
200	if (result != ISC_R_SUCCESS)
201		goto lock_create_failure;
202
203	result = ns_clientmgr_create(mgr->mctx, mgr->taskmgr,
204				     ns_g_timermgr,
205				     &ifp->clientmgr);
206	if (result != ISC_R_SUCCESS) {
207		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
208			      "ns_clientmgr_create() failed: %s",
209			      isc_result_totext(result));
210		goto clientmgr_create_failure;
211	}
212
213	ifp->udpdispatch = NULL;
214
215	ifp->tcpsocket = NULL;
216	/*
217	 * Create a single TCP client object.  It will replace itself
218	 * with a new one as soon as it gets a connection, so the actual
219	 * connections will be handled in parallel even though there is
220	 * only one client initially.
221	 */
222	ifp->ntcptarget = 1;
223	ifp->ntcpcurrent = 0;
224
225	ISC_LINK_INIT(ifp, link);
226
227	ns_interfacemgr_attach(mgr, &ifp->mgr);
228	ISC_LIST_APPEND(mgr->interfaces, ifp, link);
229
230	ifp->references = 1;
231	ifp->magic = IFACE_MAGIC;
232	*ifpret = ifp;
233
234	return (ISC_R_SUCCESS);
235
236 clientmgr_create_failure:
237	DESTROYLOCK(&ifp->lock);
238 lock_create_failure:
239	ifp->magic = 0;
240	isc_mem_put(mgr->mctx, ifp, sizeof(*ifp));
241
242	return (ISC_R_UNEXPECTED);
243}
244
245static isc_result_t
246ns_interface_listenudp(ns_interface_t *ifp) {
247	isc_result_t result;
248	unsigned int attrs;
249	unsigned int attrmask;
250
251	attrs = 0;
252	attrs |= DNS_DISPATCHATTR_UDP;
253	if (isc_sockaddr_pf(&ifp->addr) == AF_INET)
254		attrs |= DNS_DISPATCHATTR_IPV4;
255	else
256		attrs |= DNS_DISPATCHATTR_IPV6;
257	attrs |= DNS_DISPATCHATTR_NOLISTEN;
258	attrmask = 0;
259	attrmask |= DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP;
260	attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6;
261	result = dns_dispatch_getudp(ifp->mgr->dispatchmgr, ns_g_socketmgr,
262				     ns_g_taskmgr, &ifp->addr,
263				     4096, 1000, 32768, 8219, 8237,
264				     attrs, attrmask, &ifp->udpdispatch);
265	if (result != ISC_R_SUCCESS) {
266		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
267			      "could not listen on UDP socket: %s",
268			      isc_result_totext(result));
269		goto udp_dispatch_failure;
270	}
271
272	result = ns_clientmgr_createclients(ifp->clientmgr, ns_g_cpus,
273					    ifp, ISC_FALSE);
274	if (result != ISC_R_SUCCESS) {
275		UNEXPECTED_ERROR(__FILE__, __LINE__,
276				 "UDP ns_clientmgr_createclients(): %s",
277				 isc_result_totext(result));
278		goto addtodispatch_failure;
279	}
280	return (ISC_R_SUCCESS);
281
282 addtodispatch_failure:
283	dns_dispatch_changeattributes(ifp->udpdispatch, 0,
284				      DNS_DISPATCHATTR_NOLISTEN);
285	dns_dispatch_detach(&ifp->udpdispatch);
286 udp_dispatch_failure:
287	return (result);
288}
289
290static isc_result_t
291ns_interface_accepttcp(ns_interface_t *ifp) {
292	isc_result_t result;
293
294	/*
295	 * Open a TCP socket.
296	 */
297	result = isc_socket_create(ifp->mgr->socketmgr,
298				   isc_sockaddr_pf(&ifp->addr),
299				   isc_sockettype_tcp,
300				   &ifp->tcpsocket);
301	if (result != ISC_R_SUCCESS) {
302		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
303				 "creating TCP socket: %s",
304				 isc_result_totext(result));
305		goto tcp_socket_failure;
306	}
307	isc_socket_setname(ifp->tcpsocket, "dispatcher", NULL);
308#ifndef ISC_ALLOW_MAPPED
309	isc_socket_ipv6only(ifp->tcpsocket, ISC_TRUE);
310#endif
311	result = isc_socket_bind(ifp->tcpsocket, &ifp->addr,
312				 ISC_SOCKET_REUSEADDRESS);
313	if (result != ISC_R_SUCCESS) {
314		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
315				 "binding TCP socket: %s",
316				 isc_result_totext(result));
317		goto tcp_bind_failure;
318	}
319	result = isc_socket_listen(ifp->tcpsocket, ns_g_listen);
320	if (result != ISC_R_SUCCESS) {
321		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
322				 "listening on TCP socket: %s",
323				 isc_result_totext(result));
324		goto tcp_listen_failure;
325	}
326
327	/*
328	 * If/when there a multiple filters listen to the
329	 * result.
330	 */
331	(void)isc_socket_filter(ifp->tcpsocket, "dataready");
332
333	result = ns_clientmgr_createclients(ifp->clientmgr,
334					    ifp->ntcptarget, ifp,
335					    ISC_TRUE);
336	if (result != ISC_R_SUCCESS) {
337		UNEXPECTED_ERROR(__FILE__, __LINE__,
338				 "TCP ns_clientmgr_createclients(): %s",
339				 isc_result_totext(result));
340		goto accepttcp_failure;
341	}
342	return (ISC_R_SUCCESS);
343
344 accepttcp_failure:
345 tcp_listen_failure:
346 tcp_bind_failure:
347	isc_socket_detach(&ifp->tcpsocket);
348 tcp_socket_failure:
349	return (ISC_R_SUCCESS);
350}
351
352static isc_result_t
353ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
354		   const char *name, ns_interface_t **ifpret,
355		   isc_boolean_t accept_tcp)
356{
357	isc_result_t result;
358	ns_interface_t *ifp = NULL;
359	REQUIRE(ifpret != NULL && *ifpret == NULL);
360
361	result = ns_interface_create(mgr, addr, name, &ifp);
362	if (result != ISC_R_SUCCESS)
363		return (result);
364
365	result = ns_interface_listenudp(ifp);
366	if (result != ISC_R_SUCCESS)
367		goto cleanup_interface;
368
369	if (accept_tcp == ISC_TRUE) {
370		result = ns_interface_accepttcp(ifp);
371		if (result != ISC_R_SUCCESS) {
372			/*
373			 * XXXRTH We don't currently have a way to easily stop
374			 * dispatch service, so we currently return
375			 * ISC_R_SUCCESS (the UDP stuff will work even if TCP
376			 * creation failed).  This will be fixed later.
377			 */
378			result = ISC_R_SUCCESS;
379		}
380	}
381	*ifpret = ifp;
382	return (result);
383
384 cleanup_interface:
385	ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
386	ns_interface_detach(&ifp);
387	return (result);
388}
389
390void
391ns_interface_shutdown(ns_interface_t *ifp) {
392	if (ifp->clientmgr != NULL)
393		ns_clientmgr_destroy(&ifp->clientmgr);
394}
395
396static void
397ns_interface_destroy(ns_interface_t *ifp) {
398	isc_mem_t *mctx = ifp->mgr->mctx;
399	REQUIRE(NS_INTERFACE_VALID(ifp));
400
401	ns_interface_shutdown(ifp);
402
403	if (ifp->udpdispatch != NULL) {
404		dns_dispatch_changeattributes(ifp->udpdispatch, 0,
405					      DNS_DISPATCHATTR_NOLISTEN);
406		dns_dispatch_detach(&ifp->udpdispatch);
407	}
408	if (ifp->tcpsocket != NULL)
409		isc_socket_detach(&ifp->tcpsocket);
410
411	DESTROYLOCK(&ifp->lock);
412
413	ns_interfacemgr_detach(&ifp->mgr);
414
415	ifp->magic = 0;
416	isc_mem_put(mctx, ifp, sizeof(*ifp));
417}
418
419void
420ns_interface_attach(ns_interface_t *source, ns_interface_t **target) {
421	REQUIRE(NS_INTERFACE_VALID(source));
422	LOCK(&source->lock);
423	INSIST(source->references > 0);
424	source->references++;
425	UNLOCK(&source->lock);
426	*target = source;
427}
428
429void
430ns_interface_detach(ns_interface_t **targetp) {
431	isc_result_t need_destroy = ISC_FALSE;
432	ns_interface_t *target = *targetp;
433	REQUIRE(target != NULL);
434	REQUIRE(NS_INTERFACE_VALID(target));
435	LOCK(&target->lock);
436	REQUIRE(target->references > 0);
437	target->references--;
438	if (target->references == 0)
439		need_destroy = ISC_TRUE;
440	UNLOCK(&target->lock);
441	if (need_destroy)
442		ns_interface_destroy(target);
443	*targetp = NULL;
444}
445
446/*%
447 * Search the interface list for an interface whose address and port
448 * both match those of 'addr'.  Return a pointer to it, or NULL if not found.
449 */
450static ns_interface_t *
451find_matching_interface(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) {
452	ns_interface_t *ifp;
453	for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL;
454	     ifp = ISC_LIST_NEXT(ifp, link)) {
455		if (isc_sockaddr_equal(&ifp->addr, addr))
456			break;
457	}
458	return (ifp);
459}
460
461/*%
462 * Remove any interfaces whose generation number is not the current one.
463 */
464static void
465purge_old_interfaces(ns_interfacemgr_t *mgr) {
466	ns_interface_t *ifp, *next;
467	for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL; ifp = next) {
468		INSIST(NS_INTERFACE_VALID(ifp));
469		next = ISC_LIST_NEXT(ifp, link);
470		if (ifp->generation != mgr->generation) {
471			char sabuf[256];
472			ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
473			isc_sockaddr_format(&ifp->addr, sabuf, sizeof(sabuf));
474			isc_log_write(IFMGR_COMMON_LOGARGS,
475				      ISC_LOG_INFO,
476				      "no longer listening on %s", sabuf);
477			ns_interface_shutdown(ifp);
478			ns_interface_detach(&ifp);
479		}
480	}
481}
482
483static isc_result_t
484clearacl(isc_mem_t *mctx, dns_acl_t **aclp) {
485	dns_acl_t *newacl = NULL;
486	isc_result_t result;
487	result = dns_acl_create(mctx, 0, &newacl);
488	if (result != ISC_R_SUCCESS)
489		return (result);
490	dns_acl_detach(aclp);
491	dns_acl_attach(newacl, aclp);
492	dns_acl_detach(&newacl);
493	return (ISC_R_SUCCESS);
494}
495
496static isc_boolean_t
497listenon_is_ip6_any(ns_listenelt_t *elt) {
498	REQUIRE(elt && elt->acl);
499	return dns_acl_isany(elt->acl);
500}
501
502static isc_result_t
503setup_locals(ns_interfacemgr_t *mgr, isc_interface_t *interface) {
504	isc_result_t result;
505	unsigned int prefixlen;
506	isc_netaddr_t *netaddr;
507
508	netaddr = &interface->address;
509
510	/* First add localhost address */
511	prefixlen = (netaddr->family == AF_INET) ? 32 : 128;
512	result = dns_iptable_addprefix(mgr->aclenv.localhost->iptable,
513				       netaddr, prefixlen, ISC_TRUE);
514	if (result != ISC_R_SUCCESS)
515		return (result);
516
517	/* Then add localnets prefix */
518	result = isc_netaddr_masktoprefixlen(&interface->netmask,
519					     &prefixlen);
520
521	/* Non contiguous netmasks not allowed by IPv6 arch. */
522	if (result != ISC_R_SUCCESS && netaddr->family == AF_INET6)
523		return (result);
524
525	if (result != ISC_R_SUCCESS) {
526		isc_log_write(IFMGR_COMMON_LOGARGS,
527			      ISC_LOG_WARNING,
528			      "omitting IPv4 interface %s from "
529			      "localnets ACL: %s",
530			      interface->name,
531			      isc_result_totext(result));
532		return (ISC_R_SUCCESS);
533	}
534
535	result = dns_iptable_addprefix(mgr->aclenv.localnets->iptable,
536				       netaddr, prefixlen, ISC_TRUE);
537	if (result != ISC_R_SUCCESS)
538		return (result);
539
540	return (ISC_R_SUCCESS);
541}
542
543static void
544setup_listenon(ns_interfacemgr_t *mgr, isc_interface_t *interface,
545	       in_port_t port)
546{
547	isc_sockaddr_t *addr;
548	isc_sockaddr_t *old;
549
550	addr = isc_mem_get(mgr->mctx, sizeof(*addr));
551	if (addr == NULL)
552		return;
553
554	isc_sockaddr_fromnetaddr(addr, &interface->address, port);
555
556	for (old = ISC_LIST_HEAD(mgr->listenon);
557	     old != NULL;
558	     old = ISC_LIST_NEXT(old, link))
559		if (isc_sockaddr_equal(addr, old))
560			break;
561
562	if (old != NULL)
563		isc_mem_put(mgr->mctx, addr, sizeof(*addr));
564	else
565		ISC_LIST_APPEND(mgr->listenon, addr, link);
566}
567
568static void
569clearlistenon(ns_interfacemgr_t *mgr) {
570	isc_sockaddr_t *old;
571
572	old = ISC_LIST_HEAD(mgr->listenon);
573	while (old != NULL) {
574		ISC_LIST_UNLINK(mgr->listenon, old, link);
575		isc_mem_put(mgr->mctx, old, sizeof(*old));
576		old = ISC_LIST_HEAD(mgr->listenon);
577	}
578}
579
580static isc_result_t
581do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
582	isc_boolean_t verbose)
583{
584	isc_interfaceiter_t *iter = NULL;
585	isc_boolean_t scan_ipv4 = ISC_FALSE;
586	isc_boolean_t scan_ipv6 = ISC_FALSE;
587	isc_boolean_t adjusting = ISC_FALSE;
588	isc_boolean_t ipv6only = ISC_TRUE;
589	isc_boolean_t ipv6pktinfo = ISC_TRUE;
590	isc_result_t result;
591	isc_netaddr_t zero_address, zero_address6;
592	ns_listenelt_t *le;
593	isc_sockaddr_t listen_addr;
594	ns_interface_t *ifp;
595	isc_boolean_t log_explicit = ISC_FALSE;
596	isc_boolean_t dolistenon;
597
598	if (ext_listen != NULL)
599		adjusting = ISC_TRUE;
600
601	if (isc_net_probeipv6() == ISC_R_SUCCESS)
602		scan_ipv6 = ISC_TRUE;
603#ifdef WANT_IPV6
604	else
605		isc_log_write(IFMGR_COMMON_LOGARGS,
606			      verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
607			      "no IPv6 interfaces found");
608#endif
609
610	if (isc_net_probeipv4() == ISC_R_SUCCESS)
611		scan_ipv4 = ISC_TRUE;
612	else
613		isc_log_write(IFMGR_COMMON_LOGARGS,
614			      verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
615			      "no IPv4 interfaces found");
616
617	/*
618	 * A special, but typical case; listen-on-v6 { any; }.
619	 * When we can make the socket IPv6-only, open a single wildcard
620	 * socket for IPv6 communication.  Otherwise, make separate socket
621	 * for each IPv6 address in order to avoid accepting IPv4 packets
622	 * as the form of mapped addresses unintentionally unless explicitly
623	 * allowed.
624	 */
625#ifndef ISC_ALLOW_MAPPED
626	if (scan_ipv6 == ISC_TRUE &&
627	    isc_net_probe_ipv6only() != ISC_R_SUCCESS) {
628		ipv6only = ISC_FALSE;
629		log_explicit = ISC_TRUE;
630	}
631#endif
632	if (scan_ipv6 == ISC_TRUE &&
633	    isc_net_probe_ipv6pktinfo() != ISC_R_SUCCESS) {
634		ipv6pktinfo = ISC_FALSE;
635		log_explicit = ISC_TRUE;
636	}
637	if (scan_ipv6 == ISC_TRUE && ipv6only && ipv6pktinfo) {
638		for (le = ISC_LIST_HEAD(mgr->listenon6->elts);
639		     le != NULL;
640		     le = ISC_LIST_NEXT(le, link)) {
641			struct in6_addr in6a;
642
643			if (!listenon_is_ip6_any(le))
644				continue;
645
646			in6a = in6addr_any;
647			isc_sockaddr_fromin6(&listen_addr, &in6a, le->port);
648
649			ifp = find_matching_interface(mgr, &listen_addr);
650			if (ifp != NULL) {
651				ifp->generation = mgr->generation;
652			} else {
653				isc_log_write(IFMGR_COMMON_LOGARGS,
654					      ISC_LOG_INFO,
655					      "listening on IPv6 "
656					      "interfaces, port %u",
657					      le->port);
658				result = ns_interface_setup(mgr, &listen_addr,
659							    "<any>", &ifp,
660							    ISC_TRUE);
661				if (result == ISC_R_SUCCESS)
662					ifp->flags |= NS_INTERFACEFLAG_ANYADDR;
663				else
664					isc_log_write(IFMGR_COMMON_LOGARGS,
665						      ISC_LOG_ERROR,
666						      "listening on all IPv6 "
667						      "interfaces failed");
668				/* Continue. */
669			}
670		}
671	}
672
673	isc_netaddr_any(&zero_address);
674	isc_netaddr_any6(&zero_address6);
675
676	result = isc_interfaceiter_create(mgr->mctx, &iter);
677	if (result != ISC_R_SUCCESS)
678		return (result);
679
680	if (adjusting == ISC_FALSE) {
681		result = clearacl(mgr->mctx, &mgr->aclenv.localhost);
682		if (result != ISC_R_SUCCESS)
683			goto cleanup_iter;
684		result = clearacl(mgr->mctx, &mgr->aclenv.localnets);
685		if (result != ISC_R_SUCCESS)
686			goto cleanup_iter;
687		clearlistenon(mgr);
688	}
689
690	for (result = isc_interfaceiter_first(iter);
691	     result == ISC_R_SUCCESS;
692	     result = isc_interfaceiter_next(iter))
693	{
694		isc_interface_t interface;
695		ns_listenlist_t *ll;
696		unsigned int family;
697
698		result = isc_interfaceiter_current(iter, &interface);
699		if (result != ISC_R_SUCCESS)
700			break;
701
702		family = interface.address.family;
703		if (family != AF_INET && family != AF_INET6)
704			continue;
705		if (scan_ipv4 == ISC_FALSE && family == AF_INET)
706			continue;
707		if (scan_ipv6 == ISC_FALSE && family == AF_INET6)
708			continue;
709
710		/*
711		 * Test for the address being nonzero rather than testing
712		 * INTERFACE_F_UP, because on some systems the latter
713		 * follows the media state and we could end up ignoring
714		 * the interface for an entire rescan interval due to
715		 * a temporary media glitch at rescan time.
716		 */
717		if (family == AF_INET &&
718		    isc_netaddr_equal(&interface.address, &zero_address)) {
719			continue;
720		}
721		if (family == AF_INET6 &&
722		    isc_netaddr_equal(&interface.address, &zero_address6)) {
723			continue;
724		}
725
726		if (adjusting == ISC_FALSE) {
727			result = setup_locals(mgr, &interface);
728			if (result != ISC_R_SUCCESS)
729				goto ignore_interface;
730		}
731
732		ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6;
733		dolistenon = ISC_TRUE;
734		for (le = ISC_LIST_HEAD(ll->elts);
735		     le != NULL;
736		     le = ISC_LIST_NEXT(le, link))
737		{
738			int match;
739			isc_boolean_t ipv6_wildcard = ISC_FALSE;
740			isc_netaddr_t listen_netaddr;
741			isc_sockaddr_t listen_sockaddr;
742
743			/*
744			 * Construct a socket address for this IP/port
745			 * combination.
746			 */
747			if (family == AF_INET) {
748				isc_netaddr_fromin(&listen_netaddr,
749						   &interface.address.type.in);
750			} else {
751				isc_netaddr_fromin6(&listen_netaddr,
752						    &interface.address.type.in6);
753				isc_netaddr_setzone(&listen_netaddr,
754						    interface.address.zone);
755			}
756			isc_sockaddr_fromnetaddr(&listen_sockaddr,
757						 &listen_netaddr,
758						 le->port);
759
760			/*
761			 * See if the address matches the listen-on statement;
762			 * if not, ignore the interface.
763			 */
764			(void)dns_acl_match(&listen_netaddr, NULL, le->acl,
765					    &mgr->aclenv, &match, NULL);
766			if (match <= 0)
767				continue;
768
769			if (adjusting == ISC_FALSE && dolistenon == ISC_TRUE) {
770				setup_listenon(mgr, &interface, le->port);
771				dolistenon = ISC_FALSE;
772			}
773
774			/*
775			 * The case of "any" IPv6 address will require
776			 * special considerations later, so remember it.
777			 */
778			if (family == AF_INET6 && ipv6only && ipv6pktinfo &&
779			    listenon_is_ip6_any(le))
780				ipv6_wildcard = ISC_TRUE;
781
782			/*
783			 * When adjusting interfaces with extra a listening
784			 * list, see if the address matches the extra list.
785			 * If it does, and is also covered by a wildcard
786			 * interface, we need to listen on the address
787			 * explicitly.
788			 */
789			if (adjusting == ISC_TRUE) {
790				ns_listenelt_t *ele;
791
792				match = 0;
793				for (ele = ISC_LIST_HEAD(ext_listen->elts);
794				     ele != NULL;
795				     ele = ISC_LIST_NEXT(ele, link)) {
796					(void)dns_acl_match(&listen_netaddr,
797							    NULL, ele->acl,
798							    NULL, &match, NULL);
799					if (match > 0 &&
800					    (ele->port == le->port ||
801					    ele->port == 0))
802						break;
803					else
804						match = 0;
805				}
806				if (ipv6_wildcard == ISC_TRUE && match == 0)
807					continue;
808			}
809
810			ifp = find_matching_interface(mgr, &listen_sockaddr);
811			if (ifp != NULL) {
812				ifp->generation = mgr->generation;
813			} else {
814				char sabuf[ISC_SOCKADDR_FORMATSIZE];
815
816				if (adjusting == ISC_FALSE &&
817				    ipv6_wildcard == ISC_TRUE)
818					continue;
819
820				if (log_explicit && family == AF_INET6 &&
821				    !adjusting && listenon_is_ip6_any(le)) {
822					isc_log_write(IFMGR_COMMON_LOGARGS,
823						      verbose ? ISC_LOG_INFO :
824							      ISC_LOG_DEBUG(1),
825						      "IPv6 socket API is "
826						      "incomplete; explicitly "
827						      "binding to each IPv6 "
828						      "address separately");
829					log_explicit = ISC_FALSE;
830				}
831				isc_sockaddr_format(&listen_sockaddr,
832						    sabuf, sizeof(sabuf));
833				isc_log_write(IFMGR_COMMON_LOGARGS,
834					      ISC_LOG_INFO,
835					      "%s"
836					      "listening on %s interface "
837					      "%s, %s",
838					      (adjusting == ISC_TRUE) ?
839					      "additionally " : "",
840					      (family == AF_INET) ?
841					      "IPv4" : "IPv6",
842					      interface.name, sabuf);
843
844				result = ns_interface_setup(mgr,
845							    &listen_sockaddr,
846							    interface.name,
847							    &ifp,
848							    (adjusting == ISC_TRUE) ?
849							    ISC_FALSE :
850							    ISC_TRUE);
851
852				if (result != ISC_R_SUCCESS) {
853					isc_log_write(IFMGR_COMMON_LOGARGS,
854						      ISC_LOG_ERROR,
855						      "creating %s interface "
856						      "%s failed; interface "
857						      "ignored",
858						      (family == AF_INET) ?
859						      "IPv4" : "IPv6",
860						      interface.name);
861				}
862				/* Continue. */
863			}
864
865		}
866		continue;
867
868	ignore_interface:
869		isc_log_write(IFMGR_COMMON_LOGARGS,
870			      ISC_LOG_ERROR,
871			      "ignoring %s interface %s: %s",
872			      (family == AF_INET) ? "IPv4" : "IPv6",
873			      interface.name, isc_result_totext(result));
874		continue;
875	}
876	if (result != ISC_R_NOMORE)
877		UNEXPECTED_ERROR(__FILE__, __LINE__,
878				 "interface iteration failed: %s",
879				 isc_result_totext(result));
880	else
881		result = ISC_R_SUCCESS;
882 cleanup_iter:
883	isc_interfaceiter_destroy(&iter);
884	return (result);
885}
886
887static void
888ns_interfacemgr_scan0(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
889		      isc_boolean_t verbose)
890{
891	isc_boolean_t purge = ISC_TRUE;
892
893	REQUIRE(NS_INTERFACEMGR_VALID(mgr));
894
895	mgr->generation++;	/* Increment the generation count. */
896
897	if (do_scan(mgr, ext_listen, verbose) != ISC_R_SUCCESS)
898		purge = ISC_FALSE;
899
900	/*
901	 * Now go through the interface list and delete anything that
902	 * does not have the current generation number.  This is
903	 * how we catch interfaces that go away or change their
904	 * addresses.
905	 */
906	if (purge)
907		purge_old_interfaces(mgr);
908
909	/*
910	 * Warn if we are not listening on any interface, unless
911	 * we're in lwresd-only mode, in which case that is to
912	 * be expected.
913	 */
914	if (ext_listen == NULL &&
915	    ISC_LIST_EMPTY(mgr->interfaces) && ! ns_g_lwresdonly) {
916		isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
917			      "not listening on any interfaces");
918	}
919}
920
921void
922ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
923	ns_interfacemgr_scan0(mgr, NULL, verbose);
924}
925
926void
927ns_interfacemgr_adjust(ns_interfacemgr_t *mgr, ns_listenlist_t *list,
928		       isc_boolean_t verbose)
929{
930	ns_interfacemgr_scan0(mgr, list, verbose);
931}
932
933void
934ns_interfacemgr_setlistenon4(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
935	LOCK(&mgr->lock);
936	ns_listenlist_detach(&mgr->listenon4);
937	ns_listenlist_attach(value, &mgr->listenon4);
938	UNLOCK(&mgr->lock);
939}
940
941void
942ns_interfacemgr_setlistenon6(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
943	LOCK(&mgr->lock);
944	ns_listenlist_detach(&mgr->listenon6);
945	ns_listenlist_attach(value, &mgr->listenon6);
946	UNLOCK(&mgr->lock);
947}
948
949void
950ns_interfacemgr_dumprecursing(FILE *f, ns_interfacemgr_t *mgr) {
951	ns_interface_t *interface;
952
953	LOCK(&mgr->lock);
954	interface = ISC_LIST_HEAD(mgr->interfaces);
955	while (interface != NULL) {
956		if (interface->clientmgr != NULL)
957			ns_client_dumprecursing(f, interface->clientmgr);
958		interface = ISC_LIST_NEXT(interface, link);
959	}
960	UNLOCK(&mgr->lock);
961}
962
963isc_boolean_t
964ns_interfacemgr_listeningon(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) {
965	isc_sockaddr_t *old;
966
967	for (old = ISC_LIST_HEAD(mgr->listenon);
968	     old != NULL;
969	     old = ISC_LIST_NEXT(old, link))
970		if (isc_sockaddr_equal(old, addr))
971			return (ISC_TRUE);
972	return (ISC_FALSE);
973}
974