2 * Copyright (C) 2004 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.7 2004/08/10 04:58:00 jinmei Exp $ */
22 #include <isc/interfaceiter.h>
23 #include <isc/string.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. */
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. */
56 purge_old_interfaces(ns_interfacemgr_t *mgr);
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)
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));
73 return (ISC_R_NOMEMORY);
75 result = isc_mutex_init(&mgr->lock);
76 if (result != ISC_R_SUCCESS)
80 mgr->taskmgr = taskmgr;
81 mgr->socketmgr = socketmgr;
82 mgr->dispatchmgr = dispatchmgr;
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)
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;
102 mgr->magic = IFMGR_MAGIC;
104 return (ISC_R_SUCCESS);
107 ns_listenlist_detach(&mgr->listenon4);
108 ns_listenlist_detach(&mgr->listenon6);
110 isc_mem_put(mctx, mgr, sizeof(*mgr));
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);
122 isc_mem_put(mgr->mctx, mgr, sizeof *mgr);
126 ns_interfacemgr_getaclenv(ns_interfacemgr_t *mgr) {
127 return (&mgr->aclenv);
131 ns_interfacemgr_attach(ns_interfacemgr_t *source, ns_interfacemgr_t **target) {
132 REQUIRE(NS_INTERFACEMGR_VALID(source));
134 INSIST(source->references > 0);
135 source->references++;
136 UNLOCK(&source->lock);
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));
147 REQUIRE(target->references > 0);
148 target->references--;
149 if (target->references == 0)
150 need_destroy = ISC_TRUE;
151 UNLOCK(&target->lock);
153 ns_interfacemgr_destroy(target);
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".
167 purge_old_interfaces(mgr);
172 ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
173 const char *name, ns_interface_t **ifpret)
178 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
179 ifp = isc_mem_get(mgr->mctx, sizeof(*ifp));
181 return (ISC_R_NOMEMORY);
183 ifp->generation = mgr->generation;
185 strncpy(ifp->name, name, sizeof(ifp->name));
186 ifp->name[sizeof(ifp->name)-1] = '\0';
187 ifp->clientmgr = NULL;
189 result = isc_mutex_init(&ifp->lock);
190 if (result != ISC_R_SUCCESS)
191 goto lock_create_failure;
193 result = ns_clientmgr_create(mgr->mctx, mgr->taskmgr,
196 if (result != ISC_R_SUCCESS) {
197 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
198 "ns_clientmgr_create() failed: %s",
199 isc_result_totext(result));
200 goto clientmgr_create_failure;
203 ifp->udpdispatch = NULL;
205 ifp->tcpsocket = NULL;
207 * Create a single TCP client object. It will replace itself
208 * with a new one as soon as it gets a connection, so the actual
209 * connections will be handled in parallel even though there is
210 * only one client initially.
213 ifp->ntcpcurrent = 0;
215 ISC_LINK_INIT(ifp, link);
217 ns_interfacemgr_attach(mgr, &ifp->mgr);
218 ISC_LIST_APPEND(mgr->interfaces, ifp, link);
221 ifp->magic = IFACE_MAGIC;
224 return (ISC_R_SUCCESS);
226 clientmgr_create_failure:
227 DESTROYLOCK(&ifp->lock);
230 isc_mem_put(mgr->mctx, ifp, sizeof(*ifp));
232 return (ISC_R_UNEXPECTED);
236 ns_interface_listenudp(ns_interface_t *ifp) {
239 unsigned int attrmask;
242 attrs |= DNS_DISPATCHATTR_UDP;
243 if (isc_sockaddr_pf(&ifp->addr) == AF_INET)
244 attrs |= DNS_DISPATCHATTR_IPV4;
246 attrs |= DNS_DISPATCHATTR_IPV6;
247 attrs |= DNS_DISPATCHATTR_NOLISTEN;
249 attrmask |= DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP;
250 attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6;
251 result = dns_dispatch_getudp(ifp->mgr->dispatchmgr, ns_g_socketmgr,
252 ns_g_taskmgr, &ifp->addr,
253 4096, 1000, 32768, 8219, 8237,
254 attrs, attrmask, &ifp->udpdispatch);
255 if (result != ISC_R_SUCCESS) {
256 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
257 "could not listen on UDP socket: %s",
258 isc_result_totext(result));
259 goto udp_dispatch_failure;
262 result = ns_clientmgr_createclients(ifp->clientmgr, ns_g_cpus,
264 if (result != ISC_R_SUCCESS) {
265 UNEXPECTED_ERROR(__FILE__, __LINE__,
266 "UDP ns_clientmgr_createclients(): %s",
267 isc_result_totext(result));
268 goto addtodispatch_failure;
270 return (ISC_R_SUCCESS);
272 addtodispatch_failure:
273 dns_dispatch_changeattributes(ifp->udpdispatch, 0,
274 DNS_DISPATCHATTR_NOLISTEN);
275 dns_dispatch_detach(&ifp->udpdispatch);
276 udp_dispatch_failure:
281 ns_interface_accepttcp(ns_interface_t *ifp) {
287 result = isc_socket_create(ifp->mgr->socketmgr,
288 isc_sockaddr_pf(&ifp->addr),
291 if (result != ISC_R_SUCCESS) {
292 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
293 "creating TCP socket: %s",
294 isc_result_totext(result));
295 goto tcp_socket_failure;
297 result = isc_socket_bind(ifp->tcpsocket, &ifp->addr);
298 if (result != ISC_R_SUCCESS) {
299 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
300 "binding TCP socket: %s",
301 isc_result_totext(result));
302 goto tcp_bind_failure;
304 result = isc_socket_listen(ifp->tcpsocket, 3);
305 if (result != ISC_R_SUCCESS) {
306 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
307 "listening on TCP socket: %s",
308 isc_result_totext(result));
309 goto tcp_listen_failure;
312 result = ns_clientmgr_createclients(ifp->clientmgr,
313 ifp->ntcptarget, ifp,
315 if (result != ISC_R_SUCCESS) {
316 UNEXPECTED_ERROR(__FILE__, __LINE__,
317 "TCP ns_clientmgr_createclients(): %s",
318 isc_result_totext(result));
319 goto accepttcp_failure;
321 return (ISC_R_SUCCESS);
326 isc_socket_detach(&ifp->tcpsocket);
328 return (ISC_R_SUCCESS);
332 ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
333 const char *name, ns_interface_t **ifpret)
336 ns_interface_t *ifp = NULL;
337 REQUIRE(ifpret != NULL && *ifpret == NULL);
339 result = ns_interface_create(mgr, addr, name, &ifp);
340 if (result != ISC_R_SUCCESS)
343 result = ns_interface_listenudp(ifp);
344 if (result != ISC_R_SUCCESS)
345 goto cleanup_interface;
347 result = ns_interface_accepttcp(ifp);
348 if (result != ISC_R_SUCCESS) {
350 * XXXRTH We don't currently have a way to easily stop dispatch
351 * service, so we currently return ISC_R_SUCCESS (the UDP stuff
352 * will work even if TCP creation failed). This will be fixed
355 result = ISC_R_SUCCESS;
358 return (ISC_R_SUCCESS);
361 ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
362 ns_interface_detach(&ifp);
367 ns_interface_shutdown(ns_interface_t *ifp) {
368 if (ifp->clientmgr != NULL)
369 ns_clientmgr_destroy(&ifp->clientmgr);
373 ns_interface_destroy(ns_interface_t *ifp) {
374 isc_mem_t *mctx = ifp->mgr->mctx;
375 REQUIRE(NS_INTERFACE_VALID(ifp));
377 ns_interface_shutdown(ifp);
379 if (ifp->udpdispatch != NULL) {
380 dns_dispatch_changeattributes(ifp->udpdispatch, 0,
381 DNS_DISPATCHATTR_NOLISTEN);
382 dns_dispatch_detach(&ifp->udpdispatch);
384 if (ifp->tcpsocket != NULL)
385 isc_socket_detach(&ifp->tcpsocket);
387 DESTROYLOCK(&ifp->lock);
389 ns_interfacemgr_detach(&ifp->mgr);
392 isc_mem_put(mctx, ifp, sizeof(*ifp));
396 ns_interface_attach(ns_interface_t *source, ns_interface_t **target) {
397 REQUIRE(NS_INTERFACE_VALID(source));
399 INSIST(source->references > 0);
400 source->references++;
401 UNLOCK(&source->lock);
406 ns_interface_detach(ns_interface_t **targetp) {
407 isc_result_t need_destroy = ISC_FALSE;
408 ns_interface_t *target = *targetp;
409 REQUIRE(target != NULL);
410 REQUIRE(NS_INTERFACE_VALID(target));
412 REQUIRE(target->references > 0);
413 target->references--;
414 if (target->references == 0)
415 need_destroy = ISC_TRUE;
416 UNLOCK(&target->lock);
418 ns_interface_destroy(target);
423 * Search the interface list for an interface whose address and port
424 * both match those of 'addr'. Return a pointer to it, or NULL if not found.
426 static ns_interface_t *
427 find_matching_interface(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) {
429 for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL;
430 ifp = ISC_LIST_NEXT(ifp, link)) {
431 if (isc_sockaddr_equal(&ifp->addr, addr))
438 * Remove any interfaces whose generation number is not the current one.
441 purge_old_interfaces(ns_interfacemgr_t *mgr) {
442 ns_interface_t *ifp, *next;
443 for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL; ifp = next) {
444 INSIST(NS_INTERFACE_VALID(ifp));
445 next = ISC_LIST_NEXT(ifp, link);
446 if (ifp->generation != mgr->generation) {
448 ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
449 isc_sockaddr_format(&ifp->addr, sabuf, sizeof(sabuf));
450 isc_log_write(IFMGR_COMMON_LOGARGS,
452 "no longer listening on %s", sabuf);
453 ns_interface_shutdown(ifp);
454 ns_interface_detach(&ifp);
460 clearacl(isc_mem_t *mctx, dns_acl_t **aclp) {
461 dns_acl_t *newacl = NULL;
463 result = dns_acl_create(mctx, 10, &newacl);
464 if (result != ISC_R_SUCCESS)
466 dns_acl_detach(aclp);
467 dns_acl_attach(newacl, aclp);
468 dns_acl_detach(&newacl);
469 return (ISC_R_SUCCESS);
473 do_ipv4(ns_interfacemgr_t *mgr) {
474 isc_interfaceiter_t *iter = NULL;
477 result = isc_interfaceiter_create(mgr->mctx, &iter);
478 if (result != ISC_R_SUCCESS)
481 result = clearacl(mgr->mctx, &mgr->aclenv.localhost);
482 if (result != ISC_R_SUCCESS)
484 result = clearacl(mgr->mctx, &mgr->aclenv.localnets);
485 if (result != ISC_R_SUCCESS)
488 for (result = isc_interfaceiter_first(iter);
489 result == ISC_R_SUCCESS;
490 result = isc_interfaceiter_next(iter))
493 isc_interface_t interface;
495 dns_aclelement_t elt;
496 unsigned int prefixlen;
498 result = isc_interfaceiter_current(iter, &interface);
499 if (result != ISC_R_SUCCESS)
502 if (interface.address.family != AF_INET)
505 if ((interface.flags & INTERFACE_F_UP) == 0)
508 elt.type = dns_aclelementtype_ipprefix;
509 elt.negative = ISC_FALSE;
510 elt.u.ip_prefix.address = interface.address;
511 elt.u.ip_prefix.prefixlen = 32;
512 result = dns_acl_appendelement(mgr->aclenv.localhost, &elt);
513 if (result != ISC_R_SUCCESS)
514 goto ignore_interface;
516 result = isc_netaddr_masktoprefixlen(&interface.netmask,
518 if (result != ISC_R_SUCCESS) {
519 isc_log_write(IFMGR_COMMON_LOGARGS,
521 "omitting IPv4 interface %s from "
524 isc_result_totext(result));
526 elt.u.ip_prefix.prefixlen = prefixlen;
527 /* XXX suppress duplicates */
528 result = dns_acl_appendelement(mgr->aclenv.localnets,
530 if (result != ISC_R_SUCCESS)
531 goto ignore_interface;
534 for (le = ISC_LIST_HEAD(mgr->listenon4->elts);
536 le = ISC_LIST_NEXT(le, link))
539 isc_netaddr_t listen_netaddr;
540 isc_sockaddr_t listen_sockaddr;
543 * Construct a socket address for this IP/port
546 isc_netaddr_fromin(&listen_netaddr,
547 &interface.address.type.in);
548 isc_sockaddr_fromnetaddr(&listen_sockaddr,
553 * See if the address matches the listen-on statement;
554 * if not, ignore the interface.
556 result = dns_acl_match(&listen_netaddr, NULL,
557 le->acl, &mgr->aclenv,
562 ifp = find_matching_interface(mgr, &listen_sockaddr);
564 ifp->generation = mgr->generation;
566 char sabuf[ISC_SOCKADDR_FORMATSIZE];
567 isc_sockaddr_format(&listen_sockaddr,
568 sabuf, sizeof(sabuf));
569 isc_log_write(IFMGR_COMMON_LOGARGS,
571 "listening on IPv4 interface "
572 "%s, %s", interface.name, sabuf);
574 result = ns_interface_setup(mgr,
578 if (result != ISC_R_SUCCESS) {
579 isc_log_write(IFMGR_COMMON_LOGARGS,
581 "creating IPv4 interface %s "
582 "failed; interface ignored",
592 isc_log_write(IFMGR_COMMON_LOGARGS,
594 "ignoring IPv4 interface %s: %s",
595 interface.name, isc_result_totext(result));
598 if (result != ISC_R_NOMORE)
599 UNEXPECTED_ERROR(__FILE__, __LINE__,
600 "IPv4: interface iteration failed: %s",
601 isc_result_totext(result));
603 result = ISC_R_SUCCESS;
605 isc_interfaceiter_destroy(&iter);
610 listenon_is_ip6_none(ns_listenelt_t *elt) {
611 if (elt->acl->length == 0)
612 return (ISC_TRUE); /* listen-on-v6 { } */
613 if (elt->acl->length > 1)
614 return (ISC_FALSE); /* listen-on-v6 { ...; ...; } */
615 if (elt->acl->elements[0].negative == ISC_TRUE &&
616 elt->acl->elements[0].type == dns_aclelementtype_any)
617 return (ISC_TRUE); /* listen-on-v6 { none; } */
618 return (ISC_FALSE); /* All others */
622 listenon_is_ip6_any(ns_listenelt_t *elt) {
623 if (elt->acl->length != 1)
625 if (elt->acl->elements[0].negative == ISC_FALSE &&
626 elt->acl->elements[0].type == dns_aclelementtype_any)
627 return (ISC_TRUE); /* listen-on-v6 { any; } */
628 return (ISC_FALSE); /* All others */
632 do_ipv6(ns_interfacemgr_t *mgr) {
635 isc_sockaddr_t listen_addr;
636 struct in6_addr in6a;
639 for (le = ISC_LIST_HEAD(mgr->listenon6->elts);
641 le = ISC_LIST_NEXT(le, link))
643 if (listenon_is_ip6_none(le))
645 if (! listenon_is_ip6_any(le)) {
646 isc_log_write(IFMGR_COMMON_LOGARGS,
648 "bad IPv6 listen-on list: "
649 "must be 'any' or 'none'");
650 return (ISC_R_FAILURE);
654 isc_sockaddr_fromin6(&listen_addr, &in6a, le->port);
656 ifp = find_matching_interface(mgr, &listen_addr);
658 ifp->generation = mgr->generation;
660 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_INFO,
661 "listening on IPv6 interfaces, port %u",
663 result = ns_interface_setup(mgr, &listen_addr,
665 if (result != ISC_R_SUCCESS) {
666 isc_log_write(IFMGR_COMMON_LOGARGS,
668 "listening on IPv6 interfaces "
674 return (ISC_R_SUCCESS);
678 ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
679 isc_boolean_t purge = ISC_TRUE;
681 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
683 mgr->generation++; /* Increment the generation count. */
685 if (isc_net_probeipv6() == ISC_R_SUCCESS) {
686 if (do_ipv6(mgr) != ISC_R_SUCCESS)
691 isc_log_write(IFMGR_COMMON_LOGARGS,
692 verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
693 "no IPv6 interfaces found");
696 if (isc_net_probeipv4() == ISC_R_SUCCESS) {
697 if (do_ipv4(mgr) != ISC_R_SUCCESS)
700 isc_log_write(IFMGR_COMMON_LOGARGS,
701 verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
702 "no IPv4 interfaces found");
705 * Now go through the interface list and delete anything that
706 * does not have the current generation number. This is
707 * how we catch interfaces that go away or change their
711 purge_old_interfaces(mgr);
714 * Warn if we are not listening on any interface, unless
715 * we're in lwresd-only mode, in which case that is to
718 if (ISC_LIST_EMPTY(mgr->interfaces) && ! ns_g_lwresdonly)
719 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
720 "not listening on any interfaces");
724 ns_interfacemgr_setlistenon4(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
726 ns_listenlist_detach(&mgr->listenon4);
727 ns_listenlist_attach(value, &mgr->listenon4);
732 ns_interfacemgr_setlistenon6(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
734 ns_listenlist_detach(&mgr->listenon6);
735 ns_listenlist_attach(value, &mgr->listenon6);