Import bind-9.3.4
[dragonfly.git] / contrib / bind-9.3 / bin / named / interfacemgr.c
bloba3410567e631164a242380e0a6644bce9dd42ea4
1 /*
2 * Copyright (C) 2004, 2006 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 1999-2002 Internet Software Consortium.
5 * Permission to use, copy, modify, and 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.
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.
18 /* $Id: interfacemgr.c,v 1.59.2.5.8.18 2006/07/19 00:16:28 marka Exp $ */
20 #include <config.h>
22 #include <isc/interfaceiter.h>
23 #include <isc/string.h>
24 #include <isc/task.h>
25 #include <isc/util.h>
27 #include <dns/acl.h>
28 #include <dns/dispatch.h>
30 #include <named/client.h>
31 #include <named/log.h>
32 #include <named/interfacemgr.h>
34 #define IFMGR_MAGIC ISC_MAGIC('I', 'F', 'M', 'G')
35 #define NS_INTERFACEMGR_VALID(t) ISC_MAGIC_VALID(t, IFMGR_MAGIC)
37 #define IFMGR_COMMON_LOGARGS \
38 ns_g_lctx, NS_LOGCATEGORY_NETWORK, NS_LOGMODULE_INTERFACEMGR
40 struct ns_interfacemgr {
41 unsigned int magic; /* Magic number. */
42 int references;
43 isc_mutex_t lock;
44 isc_mem_t * mctx; /* Memory context. */
45 isc_taskmgr_t * taskmgr; /* Task manager. */
46 isc_socketmgr_t * socketmgr; /* Socket manager. */
47 dns_dispatchmgr_t * dispatchmgr;
48 unsigned int generation; /* Current generation no. */
49 ns_listenlist_t * listenon4;
50 ns_listenlist_t * listenon6;
51 dns_aclenv_t aclenv; /* Localhost/localnets ACLs */
52 ISC_LIST(ns_interface_t) interfaces; /* List of interfaces. */
55 static void
56 purge_old_interfaces(ns_interfacemgr_t *mgr);
58 isc_result_t
59 ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
60 isc_socketmgr_t *socketmgr,
61 dns_dispatchmgr_t *dispatchmgr,
62 ns_interfacemgr_t **mgrp)
64 isc_result_t result;
65 ns_interfacemgr_t *mgr;
67 REQUIRE(mctx != NULL);
68 REQUIRE(mgrp != NULL);
69 REQUIRE(*mgrp == NULL);
71 mgr = isc_mem_get(mctx, sizeof(*mgr));
72 if (mgr == NULL)
73 return (ISC_R_NOMEMORY);
75 result = isc_mutex_init(&mgr->lock);
76 if (result != ISC_R_SUCCESS)
77 goto cleanup_mem;
79 mgr->mctx = mctx;
80 mgr->taskmgr = taskmgr;
81 mgr->socketmgr = socketmgr;
82 mgr->dispatchmgr = dispatchmgr;
83 mgr->generation = 1;
84 mgr->listenon4 = NULL;
85 mgr->listenon6 = NULL;
87 ISC_LIST_INIT(mgr->interfaces);
90 * The listen-on lists are initially empty.
92 result = ns_listenlist_create(mctx, &mgr->listenon4);
93 if (result != ISC_R_SUCCESS)
94 goto cleanup_mem;
95 ns_listenlist_attach(mgr->listenon4, &mgr->listenon6);
97 result = dns_aclenv_init(mctx, &mgr->aclenv);
98 if (result != ISC_R_SUCCESS)
99 goto cleanup_listenon;
101 mgr->references = 1;
102 mgr->magic = IFMGR_MAGIC;
103 *mgrp = mgr;
104 return (ISC_R_SUCCESS);
106 cleanup_listenon:
107 ns_listenlist_detach(&mgr->listenon4);
108 ns_listenlist_detach(&mgr->listenon6);
109 cleanup_mem:
110 isc_mem_put(mctx, mgr, sizeof(*mgr));
111 return (result);
114 static void
115 ns_interfacemgr_destroy(ns_interfacemgr_t *mgr) {
116 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
117 dns_aclenv_destroy(&mgr->aclenv);
118 ns_listenlist_detach(&mgr->listenon4);
119 ns_listenlist_detach(&mgr->listenon6);
120 DESTROYLOCK(&mgr->lock);
121 mgr->magic = 0;
122 isc_mem_put(mgr->mctx, mgr, sizeof(*mgr));
125 dns_aclenv_t *
126 ns_interfacemgr_getaclenv(ns_interfacemgr_t *mgr) {
127 return (&mgr->aclenv);
130 void
131 ns_interfacemgr_attach(ns_interfacemgr_t *source, ns_interfacemgr_t **target) {
132 REQUIRE(NS_INTERFACEMGR_VALID(source));
133 LOCK(&source->lock);
134 INSIST(source->references > 0);
135 source->references++;
136 UNLOCK(&source->lock);
137 *target = source;
140 void
141 ns_interfacemgr_detach(ns_interfacemgr_t **targetp) {
142 isc_result_t need_destroy = ISC_FALSE;
143 ns_interfacemgr_t *target = *targetp;
144 REQUIRE(target != NULL);
145 REQUIRE(NS_INTERFACEMGR_VALID(target));
146 LOCK(&target->lock);
147 REQUIRE(target->references > 0);
148 target->references--;
149 if (target->references == 0)
150 need_destroy = ISC_TRUE;
151 UNLOCK(&target->lock);
152 if (need_destroy)
153 ns_interfacemgr_destroy(target);
154 *targetp = NULL;
157 void
158 ns_interfacemgr_shutdown(ns_interfacemgr_t *mgr) {
159 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
162 * Shut down and detach all interfaces.
163 * By incrementing the generation count, we make purge_old_interfaces()
164 * consider all interfaces "old".
166 mgr->generation++;
167 purge_old_interfaces(mgr);
171 static isc_result_t
172 ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
173 const char *name, ns_interface_t **ifpret)
175 ns_interface_t *ifp;
176 isc_result_t result;
178 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
179 ifp = isc_mem_get(mgr->mctx, sizeof(*ifp));
180 if (ifp == NULL)
181 return (ISC_R_NOMEMORY);
182 ifp->mgr = NULL;
183 ifp->generation = mgr->generation;
184 ifp->addr = *addr;
185 ifp->flags = 0;
186 strncpy(ifp->name, name, sizeof(ifp->name));
187 ifp->name[sizeof(ifp->name)-1] = '\0';
188 ifp->clientmgr = NULL;
190 result = isc_mutex_init(&ifp->lock);
191 if (result != ISC_R_SUCCESS)
192 goto lock_create_failure;
194 result = ns_clientmgr_create(mgr->mctx, mgr->taskmgr,
195 ns_g_timermgr,
196 &ifp->clientmgr);
197 if (result != ISC_R_SUCCESS) {
198 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
199 "ns_clientmgr_create() failed: %s",
200 isc_result_totext(result));
201 goto clientmgr_create_failure;
204 ifp->udpdispatch = NULL;
206 ifp->tcpsocket = NULL;
208 * Create a single TCP client object. It will replace itself
209 * with a new one as soon as it gets a connection, so the actual
210 * connections will be handled in parallel even though there is
211 * only one client initially.
213 ifp->ntcptarget = 1;
214 ifp->ntcpcurrent = 0;
216 ISC_LINK_INIT(ifp, link);
218 ns_interfacemgr_attach(mgr, &ifp->mgr);
219 ISC_LIST_APPEND(mgr->interfaces, ifp, link);
221 ifp->references = 1;
222 ifp->magic = IFACE_MAGIC;
223 *ifpret = ifp;
225 return (ISC_R_SUCCESS);
227 clientmgr_create_failure:
228 DESTROYLOCK(&ifp->lock);
229 lock_create_failure:
230 ifp->magic = 0;
231 isc_mem_put(mgr->mctx, ifp, sizeof(*ifp));
233 return (ISC_R_UNEXPECTED);
236 static isc_result_t
237 ns_interface_listenudp(ns_interface_t *ifp) {
238 isc_result_t result;
239 unsigned int attrs;
240 unsigned int attrmask;
242 attrs = 0;
243 attrs |= DNS_DISPATCHATTR_UDP;
244 if (isc_sockaddr_pf(&ifp->addr) == AF_INET)
245 attrs |= DNS_DISPATCHATTR_IPV4;
246 else
247 attrs |= DNS_DISPATCHATTR_IPV6;
248 attrs |= DNS_DISPATCHATTR_NOLISTEN;
249 attrmask = 0;
250 attrmask |= DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP;
251 attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6;
252 result = dns_dispatch_getudp(ifp->mgr->dispatchmgr, ns_g_socketmgr,
253 ns_g_taskmgr, &ifp->addr,
254 4096, 1000, 32768, 8219, 8237,
255 attrs, attrmask, &ifp->udpdispatch);
256 if (result != ISC_R_SUCCESS) {
257 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
258 "could not listen on UDP socket: %s",
259 isc_result_totext(result));
260 goto udp_dispatch_failure;
263 result = ns_clientmgr_createclients(ifp->clientmgr, ns_g_cpus,
264 ifp, ISC_FALSE);
265 if (result != ISC_R_SUCCESS) {
266 UNEXPECTED_ERROR(__FILE__, __LINE__,
267 "UDP ns_clientmgr_createclients(): %s",
268 isc_result_totext(result));
269 goto addtodispatch_failure;
271 return (ISC_R_SUCCESS);
273 addtodispatch_failure:
274 dns_dispatch_changeattributes(ifp->udpdispatch, 0,
275 DNS_DISPATCHATTR_NOLISTEN);
276 dns_dispatch_detach(&ifp->udpdispatch);
277 udp_dispatch_failure:
278 return (result);
281 static isc_result_t
282 ns_interface_accepttcp(ns_interface_t *ifp) {
283 isc_result_t result;
286 * Open a TCP socket.
288 result = isc_socket_create(ifp->mgr->socketmgr,
289 isc_sockaddr_pf(&ifp->addr),
290 isc_sockettype_tcp,
291 &ifp->tcpsocket);
292 if (result != ISC_R_SUCCESS) {
293 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
294 "creating TCP socket: %s",
295 isc_result_totext(result));
296 goto tcp_socket_failure;
298 #ifndef ISC_ALLOW_MAPPED
299 isc_socket_ipv6only(ifp->tcpsocket, ISC_TRUE);
300 #endif
301 result = isc_socket_bind(ifp->tcpsocket, &ifp->addr);
302 if (result != ISC_R_SUCCESS) {
303 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
304 "binding TCP socket: %s",
305 isc_result_totext(result));
306 goto tcp_bind_failure;
308 result = isc_socket_listen(ifp->tcpsocket, ns_g_listen);
309 if (result != ISC_R_SUCCESS) {
310 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
311 "listening on TCP socket: %s",
312 isc_result_totext(result));
313 goto tcp_listen_failure;
317 * If/when there a multiple filters listen to the
318 * result.
320 (void)isc_socket_filter(ifp->tcpsocket, "dataready");
322 result = ns_clientmgr_createclients(ifp->clientmgr,
323 ifp->ntcptarget, ifp,
324 ISC_TRUE);
325 if (result != ISC_R_SUCCESS) {
326 UNEXPECTED_ERROR(__FILE__, __LINE__,
327 "TCP ns_clientmgr_createclients(): %s",
328 isc_result_totext(result));
329 goto accepttcp_failure;
331 return (ISC_R_SUCCESS);
333 accepttcp_failure:
334 tcp_listen_failure:
335 tcp_bind_failure:
336 isc_socket_detach(&ifp->tcpsocket);
337 tcp_socket_failure:
338 return (ISC_R_SUCCESS);
341 static isc_result_t
342 ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
343 const char *name, ns_interface_t **ifpret,
344 isc_boolean_t accept_tcp)
346 isc_result_t result;
347 ns_interface_t *ifp = NULL;
348 REQUIRE(ifpret != NULL && *ifpret == NULL);
350 result = ns_interface_create(mgr, addr, name, &ifp);
351 if (result != ISC_R_SUCCESS)
352 return (result);
354 result = ns_interface_listenudp(ifp);
355 if (result != ISC_R_SUCCESS)
356 goto cleanup_interface;
358 if (accept_tcp == ISC_TRUE) {
359 result = ns_interface_accepttcp(ifp);
360 if (result != ISC_R_SUCCESS) {
362 * XXXRTH We don't currently have a way to easily stop
363 * dispatch service, so we currently return
364 * ISC_R_SUCCESS (the UDP stuff will work even if TCP
365 * creation failed). This will be fixed later.
367 result = ISC_R_SUCCESS;
370 *ifpret = ifp;
371 return (ISC_R_SUCCESS);
373 cleanup_interface:
374 ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
375 ns_interface_detach(&ifp);
376 return (result);
379 void
380 ns_interface_shutdown(ns_interface_t *ifp) {
381 if (ifp->clientmgr != NULL)
382 ns_clientmgr_destroy(&ifp->clientmgr);
385 static void
386 ns_interface_destroy(ns_interface_t *ifp) {
387 isc_mem_t *mctx = ifp->mgr->mctx;
388 REQUIRE(NS_INTERFACE_VALID(ifp));
390 ns_interface_shutdown(ifp);
392 if (ifp->udpdispatch != NULL) {
393 dns_dispatch_changeattributes(ifp->udpdispatch, 0,
394 DNS_DISPATCHATTR_NOLISTEN);
395 dns_dispatch_detach(&ifp->udpdispatch);
397 if (ifp->tcpsocket != NULL)
398 isc_socket_detach(&ifp->tcpsocket);
400 DESTROYLOCK(&ifp->lock);
402 ns_interfacemgr_detach(&ifp->mgr);
404 ifp->magic = 0;
405 isc_mem_put(mctx, ifp, sizeof(*ifp));
408 void
409 ns_interface_attach(ns_interface_t *source, ns_interface_t **target) {
410 REQUIRE(NS_INTERFACE_VALID(source));
411 LOCK(&source->lock);
412 INSIST(source->references > 0);
413 source->references++;
414 UNLOCK(&source->lock);
415 *target = source;
418 void
419 ns_interface_detach(ns_interface_t **targetp) {
420 isc_result_t need_destroy = ISC_FALSE;
421 ns_interface_t *target = *targetp;
422 REQUIRE(target != NULL);
423 REQUIRE(NS_INTERFACE_VALID(target));
424 LOCK(&target->lock);
425 REQUIRE(target->references > 0);
426 target->references--;
427 if (target->references == 0)
428 need_destroy = ISC_TRUE;
429 UNLOCK(&target->lock);
430 if (need_destroy)
431 ns_interface_destroy(target);
432 *targetp = NULL;
436 * Search the interface list for an interface whose address and port
437 * both match those of 'addr'. Return a pointer to it, or NULL if not found.
439 static ns_interface_t *
440 find_matching_interface(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) {
441 ns_interface_t *ifp;
442 for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL;
443 ifp = ISC_LIST_NEXT(ifp, link)) {
444 if (isc_sockaddr_equal(&ifp->addr, addr))
445 break;
447 return (ifp);
451 * Remove any interfaces whose generation number is not the current one.
453 static void
454 purge_old_interfaces(ns_interfacemgr_t *mgr) {
455 ns_interface_t *ifp, *next;
456 for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL; ifp = next) {
457 INSIST(NS_INTERFACE_VALID(ifp));
458 next = ISC_LIST_NEXT(ifp, link);
459 if (ifp->generation != mgr->generation) {
460 char sabuf[256];
461 ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
462 isc_sockaddr_format(&ifp->addr, sabuf, sizeof(sabuf));
463 isc_log_write(IFMGR_COMMON_LOGARGS,
464 ISC_LOG_INFO,
465 "no longer listening on %s", sabuf);
466 ns_interface_shutdown(ifp);
467 ns_interface_detach(&ifp);
472 static isc_result_t
473 clearacl(isc_mem_t *mctx, dns_acl_t **aclp) {
474 dns_acl_t *newacl = NULL;
475 isc_result_t result;
476 result = dns_acl_create(mctx, 10, &newacl);
477 if (result != ISC_R_SUCCESS)
478 return (result);
479 dns_acl_detach(aclp);
480 dns_acl_attach(newacl, aclp);
481 dns_acl_detach(&newacl);
482 return (ISC_R_SUCCESS);
485 static isc_boolean_t
486 listenon_is_ip6_any(ns_listenelt_t *elt) {
487 if (elt->acl->length != 1)
488 return (ISC_FALSE);
489 if (elt->acl->elements[0].negative == ISC_FALSE &&
490 elt->acl->elements[0].type == dns_aclelementtype_any)
491 return (ISC_TRUE); /* listen-on-v6 { any; } */
492 return (ISC_FALSE); /* All others */
495 static isc_result_t
496 setup_locals(ns_interfacemgr_t *mgr, isc_interface_t *interface) {
497 isc_result_t result;
498 dns_aclelement_t elt;
499 unsigned int family;
500 unsigned int prefixlen;
502 family = interface->address.family;
504 elt.type = dns_aclelementtype_ipprefix;
505 elt.negative = ISC_FALSE;
506 elt.u.ip_prefix.address = interface->address;
507 elt.u.ip_prefix.prefixlen = (family == AF_INET) ? 32 : 128;
508 result = dns_acl_appendelement(mgr->aclenv.localhost, &elt);
509 if (result != ISC_R_SUCCESS)
510 return (result);
512 result = isc_netaddr_masktoprefixlen(&interface->netmask,
513 &prefixlen);
515 /* Non contigious netmasks not allowed by IPv6 arch. */
516 if (result != ISC_R_SUCCESS && family == AF_INET6)
517 return (result);
519 if (result != ISC_R_SUCCESS) {
520 isc_log_write(IFMGR_COMMON_LOGARGS,
521 ISC_LOG_WARNING,
522 "omitting IPv4 interface %s from "
523 "localnets ACL: %s",
524 interface->name,
525 isc_result_totext(result));
526 } else {
527 elt.u.ip_prefix.prefixlen = prefixlen;
528 if (dns_acl_elementmatch(mgr->aclenv.localnets, &elt,
529 NULL) == ISC_R_NOTFOUND) {
530 result = dns_acl_appendelement(mgr->aclenv.localnets,
531 &elt);
532 if (result != ISC_R_SUCCESS)
533 return (result);
537 return (ISC_R_SUCCESS);
540 static isc_result_t
541 do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
542 isc_boolean_t verbose)
544 isc_interfaceiter_t *iter = NULL;
545 isc_boolean_t scan_ipv4 = ISC_FALSE;
546 isc_boolean_t scan_ipv6 = ISC_FALSE;
547 isc_boolean_t adjusting = ISC_FALSE;
548 isc_boolean_t ipv6only = ISC_TRUE;
549 isc_boolean_t ipv6pktinfo = ISC_TRUE;
550 isc_result_t result;
551 isc_netaddr_t zero_address, zero_address6;
552 ns_listenelt_t *le;
553 isc_sockaddr_t listen_addr;
554 ns_interface_t *ifp;
555 isc_boolean_t log_explicit = ISC_FALSE;
557 if (ext_listen != NULL)
558 adjusting = ISC_TRUE;
560 if (isc_net_probeipv6() == ISC_R_SUCCESS)
561 scan_ipv6 = ISC_TRUE;
562 #ifdef WANT_IPV6
563 else
564 isc_log_write(IFMGR_COMMON_LOGARGS,
565 verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
566 "no IPv6 interfaces found");
567 #endif
569 if (isc_net_probeipv4() == ISC_R_SUCCESS)
570 scan_ipv4 = ISC_TRUE;
571 else
572 isc_log_write(IFMGR_COMMON_LOGARGS,
573 verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
574 "no IPv4 interfaces found");
577 * A special, but typical case; listen-on-v6 { any; }.
578 * When we can make the socket IPv6-only, open a single wildcard
579 * socket for IPv6 communication. Otherwise, make separate socket
580 * for each IPv6 address in order to avoid accepting IPv4 packets
581 * as the form of mapped addresses unintentionally unless explicitly
582 * allowed.
584 #ifndef ISC_ALLOW_MAPPED
585 if (scan_ipv6 == ISC_TRUE &&
586 isc_net_probe_ipv6only() != ISC_R_SUCCESS) {
587 ipv6only = ISC_FALSE;
588 log_explicit = ISC_TRUE;
590 #endif
591 if (scan_ipv6 == ISC_TRUE &&
592 isc_net_probe_ipv6pktinfo() != ISC_R_SUCCESS) {
593 ipv6pktinfo = ISC_FALSE;
594 log_explicit = ISC_TRUE;
596 if (scan_ipv6 == ISC_TRUE && ipv6only && ipv6pktinfo) {
597 for (le = ISC_LIST_HEAD(mgr->listenon6->elts);
598 le != NULL;
599 le = ISC_LIST_NEXT(le, link)) {
600 struct in6_addr in6a;
602 if (!listenon_is_ip6_any(le))
603 continue;
605 in6a = in6addr_any;
606 isc_sockaddr_fromin6(&listen_addr, &in6a, le->port);
608 ifp = find_matching_interface(mgr, &listen_addr);
609 if (ifp != NULL) {
610 ifp->generation = mgr->generation;
611 } else {
612 isc_log_write(IFMGR_COMMON_LOGARGS,
613 ISC_LOG_INFO,
614 "listening on IPv6 "
615 "interfaces, port %u",
616 le->port);
617 result = ns_interface_setup(mgr, &listen_addr,
618 "<any>", &ifp,
619 ISC_TRUE);
620 if (result == ISC_R_SUCCESS)
621 ifp->flags |= NS_INTERFACEFLAG_ANYADDR;
622 else
623 isc_log_write(IFMGR_COMMON_LOGARGS,
624 ISC_LOG_ERROR,
625 "listening on all IPv6 "
626 "interfaces failed");
627 /* Continue. */
632 isc_netaddr_any(&zero_address);
633 isc_netaddr_any6(&zero_address6);
635 result = isc_interfaceiter_create(mgr->mctx, &iter);
636 if (result != ISC_R_SUCCESS)
637 return (result);
639 if (adjusting == ISC_FALSE) {
640 result = clearacl(mgr->mctx, &mgr->aclenv.localhost);
641 if (result != ISC_R_SUCCESS)
642 goto cleanup_iter;
643 result = clearacl(mgr->mctx, &mgr->aclenv.localnets);
644 if (result != ISC_R_SUCCESS)
645 goto cleanup_iter;
648 for (result = isc_interfaceiter_first(iter);
649 result == ISC_R_SUCCESS;
650 result = isc_interfaceiter_next(iter))
652 isc_interface_t interface;
653 ns_listenlist_t *ll;
654 unsigned int family;
656 result = isc_interfaceiter_current(iter, &interface);
657 if (result != ISC_R_SUCCESS)
658 break;
660 family = interface.address.family;
661 if (family != AF_INET && family != AF_INET6)
662 continue;
663 if (scan_ipv4 == ISC_FALSE && family == AF_INET)
664 continue;
665 if (scan_ipv6 == ISC_FALSE && family == AF_INET6)
666 continue;
669 * Test for the address being nonzero rather than testing
670 * INTERFACE_F_UP, because on some systems the latter
671 * follows the media state and we could end up ignoring
672 * the interface for an entire rescan interval due to
673 * a temporary media glitch at rescan time.
675 if (family == AF_INET &&
676 isc_netaddr_equal(&interface.address, &zero_address)) {
677 continue;
679 if (family == AF_INET6 &&
680 isc_netaddr_equal(&interface.address, &zero_address6)) {
681 continue;
684 if (adjusting == ISC_FALSE) {
685 result = setup_locals(mgr, &interface);
686 if (result != ISC_R_SUCCESS)
687 goto ignore_interface;
690 ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6;
691 for (le = ISC_LIST_HEAD(ll->elts);
692 le != NULL;
693 le = ISC_LIST_NEXT(le, link))
695 int match;
696 isc_boolean_t ipv6_wildcard = ISC_FALSE;
697 isc_netaddr_t listen_netaddr;
698 isc_sockaddr_t listen_sockaddr;
701 * Construct a socket address for this IP/port
702 * combination.
704 if (family == AF_INET) {
705 isc_netaddr_fromin(&listen_netaddr,
706 &interface.address.type.in);
707 } else {
708 isc_netaddr_fromin6(&listen_netaddr,
709 &interface.address.type.in6);
710 isc_netaddr_setzone(&listen_netaddr,
711 interface.address.zone);
713 isc_sockaddr_fromnetaddr(&listen_sockaddr,
714 &listen_netaddr,
715 le->port);
718 * See if the address matches the listen-on statement;
719 * if not, ignore the interface.
721 (void)dns_acl_match(&listen_netaddr, NULL, le->acl,
722 &mgr->aclenv, &match, NULL);
723 if (match <= 0)
724 continue;
727 * The case of "any" IPv6 address will require
728 * special considerations later, so remember it.
730 if (family == AF_INET6 && ipv6only && ipv6pktinfo &&
731 listenon_is_ip6_any(le))
732 ipv6_wildcard = ISC_TRUE;
735 * When adjusting interfaces with extra a listening
736 * list, see if the address matches the extra list.
737 * If it does, and is also covered by a wildcard
738 * interface, we need to listen on the address
739 * explicitly.
741 if (adjusting == ISC_TRUE) {
742 ns_listenelt_t *ele;
744 match = 0;
745 for (ele = ISC_LIST_HEAD(ext_listen->elts);
746 ele != NULL;
747 ele = ISC_LIST_NEXT(ele, link)) {
748 (void)dns_acl_match(&listen_netaddr,
749 NULL, ele->acl,
750 NULL, &match, NULL);
751 if (match > 0 && ele->port == le->port)
752 break;
753 else
754 match = 0;
756 if (ipv6_wildcard == ISC_TRUE && match == 0)
757 continue;
760 ifp = find_matching_interface(mgr, &listen_sockaddr);
761 if (ifp != NULL) {
762 ifp->generation = mgr->generation;
763 } else {
764 char sabuf[ISC_SOCKADDR_FORMATSIZE];
766 if (adjusting == ISC_FALSE &&
767 ipv6_wildcard == ISC_TRUE)
768 continue;
770 if (log_explicit && family == AF_INET6 &&
771 !adjusting && listenon_is_ip6_any(le)) {
772 isc_log_write(IFMGR_COMMON_LOGARGS,
773 verbose ? ISC_LOG_INFO :
774 ISC_LOG_DEBUG(1),
775 "IPv6 socket API is "
776 "incomplete; explicitly "
777 "binding to each IPv6 "
778 "address separately");
779 log_explicit = ISC_FALSE;
781 isc_sockaddr_format(&listen_sockaddr,
782 sabuf, sizeof(sabuf));
783 isc_log_write(IFMGR_COMMON_LOGARGS,
784 ISC_LOG_INFO,
785 "%s"
786 "listening on %s interface "
787 "%s, %s",
788 (adjusting == ISC_TRUE) ?
789 "additionally " : "",
790 (family == AF_INET) ?
791 "IPv4" : "IPv6",
792 interface.name, sabuf);
794 result = ns_interface_setup(mgr,
795 &listen_sockaddr,
796 interface.name,
797 &ifp,
798 (adjusting == ISC_TRUE) ?
799 ISC_FALSE :
800 ISC_TRUE);
802 if (result != ISC_R_SUCCESS) {
803 isc_log_write(IFMGR_COMMON_LOGARGS,
804 ISC_LOG_ERROR,
805 "creating %s interface "
806 "%s failed; interface "
807 "ignored",
808 (family == AF_INET) ?
809 "IPv4" : "IPv6",
810 interface.name);
812 /* Continue. */
816 continue;
818 ignore_interface:
819 isc_log_write(IFMGR_COMMON_LOGARGS,
820 ISC_LOG_ERROR,
821 "ignoring %s interface %s: %s",
822 (family == AF_INET) ? "IPv4" : "IPv6",
823 interface.name, isc_result_totext(result));
824 continue;
826 if (result != ISC_R_NOMORE)
827 UNEXPECTED_ERROR(__FILE__, __LINE__,
828 "interface iteration failed: %s",
829 isc_result_totext(result));
830 else
831 result = ISC_R_SUCCESS;
832 cleanup_iter:
833 isc_interfaceiter_destroy(&iter);
834 return (result);
837 static void
838 ns_interfacemgr_scan0(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
839 isc_boolean_t verbose)
841 isc_boolean_t purge = ISC_TRUE;
843 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
845 mgr->generation++; /* Increment the generation count. */
847 if (do_scan(mgr, ext_listen, verbose) != ISC_R_SUCCESS)
848 purge = ISC_FALSE;
851 * Now go through the interface list and delete anything that
852 * does not have the current generation number. This is
853 * how we catch interfaces that go away or change their
854 * addresses.
856 if (purge)
857 purge_old_interfaces(mgr);
860 * Warn if we are not listening on any interface, unless
861 * we're in lwresd-only mode, in which case that is to
862 * be expected.
864 if (ext_listen == NULL &&
865 ISC_LIST_EMPTY(mgr->interfaces) && ! ns_g_lwresdonly) {
866 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
867 "not listening on any interfaces");
871 void
872 ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
873 ns_interfacemgr_scan0(mgr, NULL, verbose);
876 void
877 ns_interfacemgr_adjust(ns_interfacemgr_t *mgr, ns_listenlist_t *list,
878 isc_boolean_t verbose)
880 ns_interfacemgr_scan0(mgr, list, verbose);
883 void
884 ns_interfacemgr_setlistenon4(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
885 LOCK(&mgr->lock);
886 ns_listenlist_detach(&mgr->listenon4);
887 ns_listenlist_attach(value, &mgr->listenon4);
888 UNLOCK(&mgr->lock);
891 void
892 ns_interfacemgr_setlistenon6(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
893 LOCK(&mgr->lock);
894 ns_listenlist_detach(&mgr->listenon6);
895 ns_listenlist_attach(value, &mgr->listenon6);
896 UNLOCK(&mgr->lock);
899 void
900 ns_interfacemgr_dumprecursing(FILE *f, ns_interfacemgr_t *mgr) {
901 ns_interface_t *interface;
903 LOCK(&mgr->lock);
904 interface = ISC_LIST_HEAD(mgr->interfaces);
905 while (interface != NULL) {
906 if (interface->clientmgr != NULL)
907 ns_client_dumprecursing(f, interface->clientmgr);
908 interface = ISC_LIST_NEXT(interface, link);
910 UNLOCK(&mgr->lock);