No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / bind / dist / bin / named / interfacemgr.c
blobd7f17e789ede9526f03e96ab422fd90cadcf468b
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2002 Internet Software Consortium.
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.
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.
20 /* Id: interfacemgr.c,v 1.95 2009/01/17 23:47:42 tbox Exp */
22 /*! \file */
24 #include <config.h>
26 #include <isc/interfaceiter.h>
27 #include <isc/string.h>
28 #include <isc/task.h>
29 #include <isc/util.h>
31 #include <dns/acl.h>
32 #include <dns/dispatch.h>
34 #include <named/client.h>
35 #include <named/log.h>
36 #include <named/interfacemgr.h>
38 #define IFMGR_MAGIC ISC_MAGIC('I', 'F', 'M', 'G')
39 #define NS_INTERFACEMGR_VALID(t) ISC_MAGIC_VALID(t, IFMGR_MAGIC)
41 #define IFMGR_COMMON_LOGARGS \
42 ns_g_lctx, NS_LOGCATEGORY_NETWORK, NS_LOGMODULE_INTERFACEMGR
44 /*% nameserver interface manager structure */
45 struct ns_interfacemgr {
46 unsigned int magic; /*%< Magic number. */
47 int references;
48 isc_mutex_t lock;
49 isc_mem_t * mctx; /*%< Memory context. */
50 isc_taskmgr_t * taskmgr; /*%< Task manager. */
51 isc_socketmgr_t * socketmgr; /*%< Socket manager. */
52 dns_dispatchmgr_t * dispatchmgr;
53 unsigned int generation; /*%< Current generation no. */
54 ns_listenlist_t * listenon4;
55 ns_listenlist_t * listenon6;
56 dns_aclenv_t aclenv; /*%< Localhost/localnets ACLs */
57 ISC_LIST(ns_interface_t) interfaces; /*%< List of interfaces. */
58 ISC_LIST(isc_sockaddr_t) listenon;
61 static void
62 purge_old_interfaces(ns_interfacemgr_t *mgr);
64 static void
65 clearlistenon(ns_interfacemgr_t *mgr);
67 isc_result_t
68 ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
69 isc_socketmgr_t *socketmgr,
70 dns_dispatchmgr_t *dispatchmgr,
71 ns_interfacemgr_t **mgrp)
73 isc_result_t result;
74 ns_interfacemgr_t *mgr;
76 REQUIRE(mctx != NULL);
77 REQUIRE(mgrp != NULL);
78 REQUIRE(*mgrp == NULL);
80 mgr = isc_mem_get(mctx, sizeof(*mgr));
81 if (mgr == NULL)
82 return (ISC_R_NOMEMORY);
84 result = isc_mutex_init(&mgr->lock);
85 if (result != ISC_R_SUCCESS)
86 goto cleanup_mem;
88 mgr->mctx = mctx;
89 mgr->taskmgr = taskmgr;
90 mgr->socketmgr = socketmgr;
91 mgr->dispatchmgr = dispatchmgr;
92 mgr->generation = 1;
93 mgr->listenon4 = NULL;
94 mgr->listenon6 = NULL;
96 ISC_LIST_INIT(mgr->interfaces);
97 ISC_LIST_INIT(mgr->listenon);
100 * The listen-on lists are initially empty.
102 result = ns_listenlist_create(mctx, &mgr->listenon4);
103 if (result != ISC_R_SUCCESS)
104 goto cleanup_mem;
105 ns_listenlist_attach(mgr->listenon4, &mgr->listenon6);
107 result = dns_aclenv_init(mctx, &mgr->aclenv);
108 if (result != ISC_R_SUCCESS)
109 goto cleanup_listenon;
111 mgr->references = 1;
112 mgr->magic = IFMGR_MAGIC;
113 *mgrp = mgr;
114 return (ISC_R_SUCCESS);
116 cleanup_listenon:
117 ns_listenlist_detach(&mgr->listenon4);
118 ns_listenlist_detach(&mgr->listenon6);
119 cleanup_mem:
120 isc_mem_put(mctx, mgr, sizeof(*mgr));
121 return (result);
124 static void
125 ns_interfacemgr_destroy(ns_interfacemgr_t *mgr) {
126 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
127 dns_aclenv_destroy(&mgr->aclenv);
128 ns_listenlist_detach(&mgr->listenon4);
129 ns_listenlist_detach(&mgr->listenon6);
130 clearlistenon(mgr);
131 DESTROYLOCK(&mgr->lock);
132 mgr->magic = 0;
133 isc_mem_put(mgr->mctx, mgr, sizeof(*mgr));
136 dns_aclenv_t *
137 ns_interfacemgr_getaclenv(ns_interfacemgr_t *mgr) {
138 return (&mgr->aclenv);
141 void
142 ns_interfacemgr_attach(ns_interfacemgr_t *source, ns_interfacemgr_t **target) {
143 REQUIRE(NS_INTERFACEMGR_VALID(source));
144 LOCK(&source->lock);
145 INSIST(source->references > 0);
146 source->references++;
147 UNLOCK(&source->lock);
148 *target = source;
151 void
152 ns_interfacemgr_detach(ns_interfacemgr_t **targetp) {
153 isc_result_t need_destroy = ISC_FALSE;
154 ns_interfacemgr_t *target = *targetp;
155 REQUIRE(target != NULL);
156 REQUIRE(NS_INTERFACEMGR_VALID(target));
157 LOCK(&target->lock);
158 REQUIRE(target->references > 0);
159 target->references--;
160 if (target->references == 0)
161 need_destroy = ISC_TRUE;
162 UNLOCK(&target->lock);
163 if (need_destroy)
164 ns_interfacemgr_destroy(target);
165 *targetp = NULL;
168 void
169 ns_interfacemgr_shutdown(ns_interfacemgr_t *mgr) {
170 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
173 * Shut down and detach all interfaces.
174 * By incrementing the generation count, we make purge_old_interfaces()
175 * consider all interfaces "old".
177 mgr->generation++;
178 purge_old_interfaces(mgr);
182 static isc_result_t
183 ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
184 const char *name, ns_interface_t **ifpret)
186 ns_interface_t *ifp;
187 isc_result_t result;
189 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
190 ifp = isc_mem_get(mgr->mctx, sizeof(*ifp));
191 if (ifp == NULL)
192 return (ISC_R_NOMEMORY);
193 ifp->mgr = NULL;
194 ifp->generation = mgr->generation;
195 ifp->addr = *addr;
196 ifp->flags = 0;
197 strncpy(ifp->name, name, sizeof(ifp->name));
198 ifp->name[sizeof(ifp->name)-1] = '\0';
199 ifp->clientmgr = NULL;
201 result = isc_mutex_init(&ifp->lock);
202 if (result != ISC_R_SUCCESS)
203 goto lock_create_failure;
205 result = ns_clientmgr_create(mgr->mctx, mgr->taskmgr,
206 ns_g_timermgr,
207 &ifp->clientmgr);
208 if (result != ISC_R_SUCCESS) {
209 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
210 "ns_clientmgr_create() failed: %s",
211 isc_result_totext(result));
212 goto clientmgr_create_failure;
215 ifp->udpdispatch = NULL;
217 ifp->tcpsocket = NULL;
219 * Create a single TCP client object. It will replace itself
220 * with a new one as soon as it gets a connection, so the actual
221 * connections will be handled in parallel even though there is
222 * only one client initially.
224 ifp->ntcptarget = 1;
225 ifp->ntcpcurrent = 0;
227 ISC_LINK_INIT(ifp, link);
229 ns_interfacemgr_attach(mgr, &ifp->mgr);
230 ISC_LIST_APPEND(mgr->interfaces, ifp, link);
232 ifp->references = 1;
233 ifp->magic = IFACE_MAGIC;
234 *ifpret = ifp;
236 return (ISC_R_SUCCESS);
238 clientmgr_create_failure:
239 DESTROYLOCK(&ifp->lock);
240 lock_create_failure:
241 ifp->magic = 0;
242 isc_mem_put(mgr->mctx, ifp, sizeof(*ifp));
244 return (ISC_R_UNEXPECTED);
247 static isc_result_t
248 ns_interface_listenudp(ns_interface_t *ifp) {
249 isc_result_t result;
250 unsigned int attrs;
251 unsigned int attrmask;
253 attrs = 0;
254 attrs |= DNS_DISPATCHATTR_UDP;
255 if (isc_sockaddr_pf(&ifp->addr) == AF_INET)
256 attrs |= DNS_DISPATCHATTR_IPV4;
257 else
258 attrs |= DNS_DISPATCHATTR_IPV6;
259 attrs |= DNS_DISPATCHATTR_NOLISTEN;
260 attrmask = 0;
261 attrmask |= DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP;
262 attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6;
263 result = dns_dispatch_getudp(ifp->mgr->dispatchmgr, ns_g_socketmgr,
264 ns_g_taskmgr, &ifp->addr,
265 4096, 1000, 32768, 8219, 8237,
266 attrs, attrmask, &ifp->udpdispatch);
267 if (result != ISC_R_SUCCESS) {
268 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
269 "could not listen on UDP socket: %s",
270 isc_result_totext(result));
271 goto udp_dispatch_failure;
274 result = ns_clientmgr_createclients(ifp->clientmgr, ns_g_cpus,
275 ifp, ISC_FALSE);
276 if (result != ISC_R_SUCCESS) {
277 UNEXPECTED_ERROR(__FILE__, __LINE__,
278 "UDP ns_clientmgr_createclients(): %s",
279 isc_result_totext(result));
280 goto addtodispatch_failure;
282 return (ISC_R_SUCCESS);
284 addtodispatch_failure:
285 dns_dispatch_changeattributes(ifp->udpdispatch, 0,
286 DNS_DISPATCHATTR_NOLISTEN);
287 dns_dispatch_detach(&ifp->udpdispatch);
288 udp_dispatch_failure:
289 return (result);
292 static isc_result_t
293 ns_interface_accepttcp(ns_interface_t *ifp) {
294 isc_result_t result;
297 * Open a TCP socket.
299 result = isc_socket_create(ifp->mgr->socketmgr,
300 isc_sockaddr_pf(&ifp->addr),
301 isc_sockettype_tcp,
302 &ifp->tcpsocket);
303 if (result != ISC_R_SUCCESS) {
304 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
305 "creating TCP socket: %s",
306 isc_result_totext(result));
307 goto tcp_socket_failure;
309 isc_socket_setname(ifp->tcpsocket, "dispatcher", NULL);
310 #ifndef ISC_ALLOW_MAPPED
311 isc_socket_ipv6only(ifp->tcpsocket, ISC_TRUE);
312 #endif
313 result = isc_socket_bind(ifp->tcpsocket, &ifp->addr,
314 ISC_SOCKET_REUSEADDRESS);
315 if (result != ISC_R_SUCCESS) {
316 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
317 "binding TCP socket: %s",
318 isc_result_totext(result));
319 goto tcp_bind_failure;
321 result = isc_socket_listen(ifp->tcpsocket, ns_g_listen);
322 if (result != ISC_R_SUCCESS) {
323 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
324 "listening on TCP socket: %s",
325 isc_result_totext(result));
326 goto tcp_listen_failure;
330 * If/when there a multiple filters listen to the
331 * result.
333 (void)isc_socket_filter(ifp->tcpsocket, "dataready");
335 result = ns_clientmgr_createclients(ifp->clientmgr,
336 ifp->ntcptarget, ifp,
337 ISC_TRUE);
338 if (result != ISC_R_SUCCESS) {
339 UNEXPECTED_ERROR(__FILE__, __LINE__,
340 "TCP ns_clientmgr_createclients(): %s",
341 isc_result_totext(result));
342 goto accepttcp_failure;
344 return (ISC_R_SUCCESS);
346 accepttcp_failure:
347 tcp_listen_failure:
348 tcp_bind_failure:
349 isc_socket_detach(&ifp->tcpsocket);
350 tcp_socket_failure:
351 return (ISC_R_SUCCESS);
354 static isc_result_t
355 ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
356 const char *name, ns_interface_t **ifpret,
357 isc_boolean_t accept_tcp)
359 isc_result_t result;
360 ns_interface_t *ifp = NULL;
361 REQUIRE(ifpret != NULL && *ifpret == NULL);
363 result = ns_interface_create(mgr, addr, name, &ifp);
364 if (result != ISC_R_SUCCESS)
365 return (result);
367 result = ns_interface_listenudp(ifp);
368 if (result != ISC_R_SUCCESS)
369 goto cleanup_interface;
371 if (accept_tcp == ISC_TRUE) {
372 result = ns_interface_accepttcp(ifp);
373 if (result != ISC_R_SUCCESS) {
375 * XXXRTH We don't currently have a way to easily stop
376 * dispatch service, so we currently return
377 * ISC_R_SUCCESS (the UDP stuff will work even if TCP
378 * creation failed). This will be fixed later.
380 result = ISC_R_SUCCESS;
383 *ifpret = ifp;
384 return (ISC_R_SUCCESS);
386 cleanup_interface:
387 ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
388 ns_interface_detach(&ifp);
389 return (result);
392 void
393 ns_interface_shutdown(ns_interface_t *ifp) {
394 if (ifp->clientmgr != NULL)
395 ns_clientmgr_destroy(&ifp->clientmgr);
398 static void
399 ns_interface_destroy(ns_interface_t *ifp) {
400 isc_mem_t *mctx = ifp->mgr->mctx;
401 REQUIRE(NS_INTERFACE_VALID(ifp));
403 ns_interface_shutdown(ifp);
405 if (ifp->udpdispatch != NULL) {
406 dns_dispatch_changeattributes(ifp->udpdispatch, 0,
407 DNS_DISPATCHATTR_NOLISTEN);
408 dns_dispatch_detach(&ifp->udpdispatch);
410 if (ifp->tcpsocket != NULL)
411 isc_socket_detach(&ifp->tcpsocket);
413 DESTROYLOCK(&ifp->lock);
415 ns_interfacemgr_detach(&ifp->mgr);
417 ifp->magic = 0;
418 isc_mem_put(mctx, ifp, sizeof(*ifp));
421 void
422 ns_interface_attach(ns_interface_t *source, ns_interface_t **target) {
423 REQUIRE(NS_INTERFACE_VALID(source));
424 LOCK(&source->lock);
425 INSIST(source->references > 0);
426 source->references++;
427 UNLOCK(&source->lock);
428 *target = source;
431 void
432 ns_interface_detach(ns_interface_t **targetp) {
433 isc_result_t need_destroy = ISC_FALSE;
434 ns_interface_t *target = *targetp;
435 REQUIRE(target != NULL);
436 REQUIRE(NS_INTERFACE_VALID(target));
437 LOCK(&target->lock);
438 REQUIRE(target->references > 0);
439 target->references--;
440 if (target->references == 0)
441 need_destroy = ISC_TRUE;
442 UNLOCK(&target->lock);
443 if (need_destroy)
444 ns_interface_destroy(target);
445 *targetp = NULL;
449 * Search the interface list for an interface whose address and port
450 * both match those of 'addr'. Return a pointer to it, or NULL if not found.
452 static ns_interface_t *
453 find_matching_interface(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) {
454 ns_interface_t *ifp;
455 for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL;
456 ifp = ISC_LIST_NEXT(ifp, link)) {
457 if (isc_sockaddr_equal(&ifp->addr, addr))
458 break;
460 return (ifp);
464 * Remove any interfaces whose generation number is not the current one.
466 static void
467 purge_old_interfaces(ns_interfacemgr_t *mgr) {
468 ns_interface_t *ifp, *next;
469 for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL; ifp = next) {
470 INSIST(NS_INTERFACE_VALID(ifp));
471 next = ISC_LIST_NEXT(ifp, link);
472 if (ifp->generation != mgr->generation) {
473 char sabuf[256];
474 ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
475 isc_sockaddr_format(&ifp->addr, sabuf, sizeof(sabuf));
476 isc_log_write(IFMGR_COMMON_LOGARGS,
477 ISC_LOG_INFO,
478 "no longer listening on %s", sabuf);
479 ns_interface_shutdown(ifp);
480 ns_interface_detach(&ifp);
485 static isc_result_t
486 clearacl(isc_mem_t *mctx, dns_acl_t **aclp) {
487 dns_acl_t *newacl = NULL;
488 isc_result_t result;
489 result = dns_acl_create(mctx, 0, &newacl);
490 if (result != ISC_R_SUCCESS)
491 return (result);
492 dns_acl_detach(aclp);
493 dns_acl_attach(newacl, aclp);
494 dns_acl_detach(&newacl);
495 return (ISC_R_SUCCESS);
498 static isc_boolean_t
499 listenon_is_ip6_any(ns_listenelt_t *elt) {
500 REQUIRE(elt && elt->acl);
501 return dns_acl_isany(elt->acl);
504 static isc_result_t
505 setup_locals(ns_interfacemgr_t *mgr, isc_interface_t *interface) {
506 isc_result_t result;
507 unsigned int prefixlen;
508 isc_netaddr_t *netaddr;
510 netaddr = &interface->address;
512 /* First add localhost address */
513 prefixlen = (netaddr->family == AF_INET) ? 32 : 128;
514 result = dns_iptable_addprefix(mgr->aclenv.localhost->iptable,
515 netaddr, prefixlen, ISC_TRUE);
516 if (result != ISC_R_SUCCESS)
517 return (result);
519 /* Then add localnets prefix */
520 result = isc_netaddr_masktoprefixlen(&interface->netmask,
521 &prefixlen);
523 /* Non contiguous netmasks not allowed by IPv6 arch. */
524 if (result != ISC_R_SUCCESS && netaddr->family == AF_INET6)
525 return (result);
527 if (result != ISC_R_SUCCESS) {
528 isc_log_write(IFMGR_COMMON_LOGARGS,
529 ISC_LOG_WARNING,
530 "omitting IPv4 interface %s from "
531 "localnets ACL: %s",
532 interface->name,
533 isc_result_totext(result));
534 return (ISC_R_SUCCESS);
537 result = dns_iptable_addprefix(mgr->aclenv.localnets->iptable,
538 netaddr, prefixlen, ISC_TRUE);
539 if (result != ISC_R_SUCCESS)
540 return (result);
542 return (ISC_R_SUCCESS);
545 static void
546 setup_listenon(ns_interfacemgr_t *mgr, isc_interface_t *interface,
547 in_port_t port)
549 isc_sockaddr_t *addr;
550 isc_sockaddr_t *old;
552 addr = isc_mem_get(mgr->mctx, sizeof(*addr));
553 if (addr == NULL)
554 return;
556 isc_sockaddr_fromnetaddr(addr, &interface->address, port);
558 for (old = ISC_LIST_HEAD(mgr->listenon);
559 old != NULL;
560 old = ISC_LIST_NEXT(old, link))
561 if (isc_sockaddr_equal(addr, old))
562 break;
564 if (old != NULL)
565 isc_mem_put(mgr->mctx, addr, sizeof(*addr));
566 else
567 ISC_LIST_APPEND(mgr->listenon, addr, link);
570 static void
571 clearlistenon(ns_interfacemgr_t *mgr) {
572 isc_sockaddr_t *old;
574 old = ISC_LIST_HEAD(mgr->listenon);
575 while (old != NULL) {
576 ISC_LIST_UNLINK(mgr->listenon, old, link);
577 isc_mem_put(mgr->mctx, old, sizeof(*old));
578 old = ISC_LIST_HEAD(mgr->listenon);
582 static isc_result_t
583 do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
584 isc_boolean_t verbose)
586 isc_interfaceiter_t *iter = NULL;
587 isc_boolean_t scan_ipv4 = ISC_FALSE;
588 isc_boolean_t scan_ipv6 = ISC_FALSE;
589 isc_boolean_t adjusting = ISC_FALSE;
590 isc_boolean_t ipv6only = ISC_TRUE;
591 isc_boolean_t ipv6pktinfo = ISC_TRUE;
592 isc_result_t result;
593 isc_netaddr_t zero_address, zero_address6;
594 ns_listenelt_t *le;
595 isc_sockaddr_t listen_addr;
596 ns_interface_t *ifp;
597 isc_boolean_t log_explicit = ISC_FALSE;
598 isc_boolean_t dolistenon;
600 if (ext_listen != NULL)
601 adjusting = ISC_TRUE;
603 if (isc_net_probeipv6() == ISC_R_SUCCESS)
604 scan_ipv6 = ISC_TRUE;
605 #ifdef WANT_IPV6
606 else
607 isc_log_write(IFMGR_COMMON_LOGARGS,
608 verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
609 "no IPv6 interfaces found");
610 #endif
612 if (isc_net_probeipv4() == ISC_R_SUCCESS)
613 scan_ipv4 = ISC_TRUE;
614 else
615 isc_log_write(IFMGR_COMMON_LOGARGS,
616 verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
617 "no IPv4 interfaces found");
620 * A special, but typical case; listen-on-v6 { any; }.
621 * When we can make the socket IPv6-only, open a single wildcard
622 * socket for IPv6 communication. Otherwise, make separate socket
623 * for each IPv6 address in order to avoid accepting IPv4 packets
624 * as the form of mapped addresses unintentionally unless explicitly
625 * allowed.
627 #ifndef ISC_ALLOW_MAPPED
628 if (scan_ipv6 == ISC_TRUE &&
629 isc_net_probe_ipv6only() != ISC_R_SUCCESS) {
630 ipv6only = ISC_FALSE;
631 log_explicit = ISC_TRUE;
633 #endif
634 if (scan_ipv6 == ISC_TRUE &&
635 isc_net_probe_ipv6pktinfo() != ISC_R_SUCCESS) {
636 ipv6pktinfo = ISC_FALSE;
637 log_explicit = ISC_TRUE;
639 if (scan_ipv6 == ISC_TRUE && ipv6only && ipv6pktinfo) {
640 for (le = ISC_LIST_HEAD(mgr->listenon6->elts);
641 le != NULL;
642 le = ISC_LIST_NEXT(le, link)) {
643 struct in6_addr in6a;
645 if (!listenon_is_ip6_any(le))
646 continue;
648 in6a = in6addr_any;
649 isc_sockaddr_fromin6(&listen_addr, &in6a, le->port);
651 ifp = find_matching_interface(mgr, &listen_addr);
652 if (ifp != NULL) {
653 ifp->generation = mgr->generation;
654 } else {
655 isc_log_write(IFMGR_COMMON_LOGARGS,
656 ISC_LOG_INFO,
657 "listening on IPv6 "
658 "interfaces, port %u",
659 le->port);
660 result = ns_interface_setup(mgr, &listen_addr,
661 "<any>", &ifp,
662 ISC_TRUE);
663 if (result == ISC_R_SUCCESS)
664 ifp->flags |= NS_INTERFACEFLAG_ANYADDR;
665 else
666 isc_log_write(IFMGR_COMMON_LOGARGS,
667 ISC_LOG_ERROR,
668 "listening on all IPv6 "
669 "interfaces failed");
670 /* Continue. */
675 isc_netaddr_any(&zero_address);
676 isc_netaddr_any6(&zero_address6);
678 result = isc_interfaceiter_create(mgr->mctx, &iter);
679 if (result != ISC_R_SUCCESS)
680 return (result);
682 if (adjusting == ISC_FALSE) {
683 result = clearacl(mgr->mctx, &mgr->aclenv.localhost);
684 if (result != ISC_R_SUCCESS)
685 goto cleanup_iter;
686 result = clearacl(mgr->mctx, &mgr->aclenv.localnets);
687 if (result != ISC_R_SUCCESS)
688 goto cleanup_iter;
689 clearlistenon(mgr);
692 for (result = isc_interfaceiter_first(iter);
693 result == ISC_R_SUCCESS;
694 result = isc_interfaceiter_next(iter))
696 isc_interface_t interface;
697 ns_listenlist_t *ll;
698 unsigned int family;
700 result = isc_interfaceiter_current(iter, &interface);
701 if (result != ISC_R_SUCCESS)
702 break;
704 family = interface.address.family;
705 if (family != AF_INET && family != AF_INET6)
706 continue;
707 if (scan_ipv4 == ISC_FALSE && family == AF_INET)
708 continue;
709 if (scan_ipv6 == ISC_FALSE && family == AF_INET6)
710 continue;
713 * Test for the address being nonzero rather than testing
714 * INTERFACE_F_UP, because on some systems the latter
715 * follows the media state and we could end up ignoring
716 * the interface for an entire rescan interval due to
717 * a temporary media glitch at rescan time.
719 if (family == AF_INET &&
720 isc_netaddr_equal(&interface.address, &zero_address)) {
721 continue;
723 if (family == AF_INET6 &&
724 isc_netaddr_equal(&interface.address, &zero_address6)) {
725 continue;
728 if (adjusting == ISC_FALSE) {
729 result = setup_locals(mgr, &interface);
730 if (result != ISC_R_SUCCESS)
731 goto ignore_interface;
734 ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6;
735 dolistenon = ISC_TRUE;
736 for (le = ISC_LIST_HEAD(ll->elts);
737 le != NULL;
738 le = ISC_LIST_NEXT(le, link))
740 int match;
741 isc_boolean_t ipv6_wildcard = ISC_FALSE;
742 isc_netaddr_t listen_netaddr;
743 isc_sockaddr_t listen_sockaddr;
746 * Construct a socket address for this IP/port
747 * combination.
749 if (family == AF_INET) {
750 isc_netaddr_fromin(&listen_netaddr,
751 &interface.address.type.in);
752 } else {
753 isc_netaddr_fromin6(&listen_netaddr,
754 &interface.address.type.in6);
755 isc_netaddr_setzone(&listen_netaddr,
756 interface.address.zone);
758 isc_sockaddr_fromnetaddr(&listen_sockaddr,
759 &listen_netaddr,
760 le->port);
763 * See if the address matches the listen-on statement;
764 * if not, ignore the interface.
766 (void)dns_acl_match(&listen_netaddr, NULL, le->acl,
767 &mgr->aclenv, &match, NULL);
768 if (match <= 0)
769 continue;
771 if (adjusting == ISC_FALSE && dolistenon == ISC_TRUE) {
772 setup_listenon(mgr, &interface, le->port);
773 dolistenon = ISC_FALSE;
777 * The case of "any" IPv6 address will require
778 * special considerations later, so remember it.
780 if (family == AF_INET6 && ipv6only && ipv6pktinfo &&
781 listenon_is_ip6_any(le))
782 ipv6_wildcard = ISC_TRUE;
785 * When adjusting interfaces with extra a listening
786 * list, see if the address matches the extra list.
787 * If it does, and is also covered by a wildcard
788 * interface, we need to listen on the address
789 * explicitly.
791 if (adjusting == ISC_TRUE) {
792 ns_listenelt_t *ele;
794 match = 0;
795 for (ele = ISC_LIST_HEAD(ext_listen->elts);
796 ele != NULL;
797 ele = ISC_LIST_NEXT(ele, link)) {
798 (void)dns_acl_match(&listen_netaddr,
799 NULL, ele->acl,
800 NULL, &match, NULL);
801 if (match > 0 &&
802 (ele->port == le->port ||
803 ele->port == 0))
804 break;
805 else
806 match = 0;
808 if (ipv6_wildcard == ISC_TRUE && match == 0)
809 continue;
812 ifp = find_matching_interface(mgr, &listen_sockaddr);
813 if (ifp != NULL) {
814 ifp->generation = mgr->generation;
815 } else {
816 char sabuf[ISC_SOCKADDR_FORMATSIZE];
818 if (adjusting == ISC_FALSE &&
819 ipv6_wildcard == ISC_TRUE)
820 continue;
822 if (log_explicit && family == AF_INET6 &&
823 !adjusting && listenon_is_ip6_any(le)) {
824 isc_log_write(IFMGR_COMMON_LOGARGS,
825 verbose ? ISC_LOG_INFO :
826 ISC_LOG_DEBUG(1),
827 "IPv6 socket API is "
828 "incomplete; explicitly "
829 "binding to each IPv6 "
830 "address separately");
831 log_explicit = ISC_FALSE;
833 isc_sockaddr_format(&listen_sockaddr,
834 sabuf, sizeof(sabuf));
835 isc_log_write(IFMGR_COMMON_LOGARGS,
836 ISC_LOG_INFO,
837 "%s"
838 "listening on %s interface "
839 "%s, %s",
840 (adjusting == ISC_TRUE) ?
841 "additionally " : "",
842 (family == AF_INET) ?
843 "IPv4" : "IPv6",
844 interface.name, sabuf);
846 result = ns_interface_setup(mgr,
847 &listen_sockaddr,
848 interface.name,
849 &ifp,
850 (adjusting == ISC_TRUE) ?
851 ISC_FALSE :
852 ISC_TRUE);
854 if (result != ISC_R_SUCCESS) {
855 isc_log_write(IFMGR_COMMON_LOGARGS,
856 ISC_LOG_ERROR,
857 "creating %s interface "
858 "%s failed; interface "
859 "ignored",
860 (family == AF_INET) ?
861 "IPv4" : "IPv6",
862 interface.name);
864 /* Continue. */
868 continue;
870 ignore_interface:
871 isc_log_write(IFMGR_COMMON_LOGARGS,
872 ISC_LOG_ERROR,
873 "ignoring %s interface %s: %s",
874 (family == AF_INET) ? "IPv4" : "IPv6",
875 interface.name, isc_result_totext(result));
876 continue;
878 if (result != ISC_R_NOMORE)
879 UNEXPECTED_ERROR(__FILE__, __LINE__,
880 "interface iteration failed: %s",
881 isc_result_totext(result));
882 else
883 result = ISC_R_SUCCESS;
884 cleanup_iter:
885 isc_interfaceiter_destroy(&iter);
886 return (result);
889 static void
890 ns_interfacemgr_scan0(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
891 isc_boolean_t verbose)
893 isc_boolean_t purge = ISC_TRUE;
895 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
897 mgr->generation++; /* Increment the generation count. */
899 if (do_scan(mgr, ext_listen, verbose) != ISC_R_SUCCESS)
900 purge = ISC_FALSE;
903 * Now go through the interface list and delete anything that
904 * does not have the current generation number. This is
905 * how we catch interfaces that go away or change their
906 * addresses.
908 if (purge)
909 purge_old_interfaces(mgr);
912 * Warn if we are not listening on any interface, unless
913 * we're in lwresd-only mode, in which case that is to
914 * be expected.
916 if (ext_listen == NULL &&
917 ISC_LIST_EMPTY(mgr->interfaces) && ! ns_g_lwresdonly) {
918 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
919 "not listening on any interfaces");
923 void
924 ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
925 ns_interfacemgr_scan0(mgr, NULL, verbose);
928 void
929 ns_interfacemgr_adjust(ns_interfacemgr_t *mgr, ns_listenlist_t *list,
930 isc_boolean_t verbose)
932 ns_interfacemgr_scan0(mgr, list, verbose);
935 void
936 ns_interfacemgr_setlistenon4(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
937 LOCK(&mgr->lock);
938 ns_listenlist_detach(&mgr->listenon4);
939 ns_listenlist_attach(value, &mgr->listenon4);
940 UNLOCK(&mgr->lock);
943 void
944 ns_interfacemgr_setlistenon6(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
945 LOCK(&mgr->lock);
946 ns_listenlist_detach(&mgr->listenon6);
947 ns_listenlist_attach(value, &mgr->listenon6);
948 UNLOCK(&mgr->lock);
951 void
952 ns_interfacemgr_dumprecursing(FILE *f, ns_interfacemgr_t *mgr) {
953 ns_interface_t *interface;
955 LOCK(&mgr->lock);
956 interface = ISC_LIST_HEAD(mgr->interfaces);
957 while (interface != NULL) {
958 if (interface->clientmgr != NULL)
959 ns_client_dumprecursing(f, interface->clientmgr);
960 interface = ISC_LIST_NEXT(interface, link);
962 UNLOCK(&mgr->lock);
965 isc_boolean_t
966 ns_interfacemgr_listeningon(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) {
967 isc_sockaddr_t *old;
969 old = ISC_LIST_HEAD(mgr->listenon);
970 for (old = ISC_LIST_HEAD(mgr->listenon);
971 old != NULL;
972 old = ISC_LIST_NEXT(old, link))
973 if (isc_sockaddr_equal(old, addr))
974 return (ISC_TRUE);
975 return (ISC_FALSE);