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