diff --git a/CHANGES b/CHANGES index e53f29c569..40d037642e 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,5 @@ +1360. [func] Listen-on-v6 now supports specific addresses. + 1359. [bug] remove IF_RUNNING test when scanning interfaces. 1358. [func] log the reason for rejecting a server when resolving diff --git a/bin/named/interfacemgr.c b/bin/named/interfacemgr.c index 16702e4254..3861794991 100644 --- a/bin/named/interfacemgr.c +++ b/bin/named/interfacemgr.c @@ -15,7 +15,7 @@ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: interfacemgr.c,v 1.67 2002/05/27 00:40:16 marka Exp $ */ +/* $Id: interfacemgr.c,v 1.68 2002/08/16 23:46:11 marka Exp $ */ #include @@ -478,13 +478,75 @@ clearacl(isc_mem_t *mctx, dns_acl_t **aclp) { return (ISC_R_SUCCESS); } +static isc_boolean_t +listenon_is_ip6_any(ns_listenelt_t *elt) { + if (elt->acl->length != 1) + return (ISC_FALSE); + if (elt->acl->elements[0].negative == ISC_FALSE && + elt->acl->elements[0].type == dns_aclelementtype_any) + return (ISC_TRUE); /* listen-on-v6 { any; } */ + return (ISC_FALSE); /* All others */ +} + static isc_result_t -do_ipv4(ns_interfacemgr_t *mgr) { +do_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) { isc_interfaceiter_t *iter = NULL; + isc_boolean_t scan_ipv4 = ISC_FALSE; + isc_boolean_t scan_ipv6 = ISC_FALSE; + isc_boolean_t setup_ipv6 = ISC_TRUE; isc_result_t result; - isc_netaddr_t zero_address; + isc_netaddr_t zero_address, zero_address6; + ns_listenelt_t *le; + isc_sockaddr_t listen_addr; + ns_interface_t *ifp; + + if (isc_net_probeipv6() == ISC_R_SUCCESS) + scan_ipv6 = ISC_TRUE; +#ifdef WANT_IPV6 + else + isc_log_write(IFMGR_COMMON_LOGARGS, + verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1), + "no IPv6 interfaces found"); +#endif + + if (isc_net_probeipv4() == ISC_R_SUCCESS) + scan_ipv4 = ISC_TRUE; + else + isc_log_write(IFMGR_COMMON_LOGARGS, + verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1), + "no IPv4 interfaces found"); + + /* A special, but typical case; listen-on-v6 { any; } */ + /* XXXJT fix when we probe for IPV6_V6ONLY */ + if (scan_ipv6 == ISC_TRUE && + (le = ISC_LIST_HEAD(mgr->listenon6->elts)) != NULL && + listenon_is_ip6_any(le)) { + struct in6_addr in6a; + + in6a = in6addr_any; + isc_sockaddr_fromin6(&listen_addr, &in6a, le->port); + + ifp = find_matching_interface(mgr, &listen_addr); + if (ifp != NULL) { + ifp->generation = mgr->generation; + } else { + isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_INFO, + "listening on IPv6 interfaces, port %u", + le->port); + result = ns_interface_setup(mgr, &listen_addr, + "", &ifp); + if (result == ISC_R_SUCCESS) + setup_ipv6 = ISC_FALSE; + else + isc_log_write(IFMGR_COMMON_LOGARGS, + ISC_LOG_ERROR, + "listening on all IPv6 " + "interfaces failed"); + } + } isc_netaddr_any(&zero_address); + isc_netaddr_any6(&zero_address6); result = isc_interfaceiter_create(mgr->mctx, &iter); if (result != ISC_R_SUCCESS) @@ -501,17 +563,22 @@ do_ipv4(ns_interfacemgr_t *mgr) { result == ISC_R_SUCCESS; result = isc_interfaceiter_next(iter)) { - ns_interface_t *ifp; isc_interface_t interface; - ns_listenelt_t *le; + ns_listenlist_t *ll; dns_aclelement_t elt; unsigned int prefixlen; + unsigned int family; result = isc_interfaceiter_current(iter, &interface); if (result != ISC_R_SUCCESS) break; - if (interface.address.family != AF_INET) + family = interface.address.family; + if (family != AF_INET && family != AF_INET6) + continue; + if (scan_ipv4 == ISC_FALSE && family == AF_INET) + continue; + if (scan_ipv6 == ISC_FALSE && family == AF_INET6) continue; /* @@ -521,19 +588,30 @@ do_ipv4(ns_interfacemgr_t *mgr) { * the interface for an entire rescan interval due to * a temporary media glitch at rescan time. */ - if (isc_netaddr_equal(&interface.address, &zero_address)) + if (family == AF_INET && + isc_netaddr_equal(&interface.address, &zero_address)) { continue; + } + if (family == AF_INET6 && + isc_netaddr_equal(&interface.address, &zero_address6)) { + continue; + } elt.type = dns_aclelementtype_ipprefix; elt.negative = ISC_FALSE; elt.u.ip_prefix.address = interface.address; - elt.u.ip_prefix.prefixlen = 32; + elt.u.ip_prefix.prefixlen = (family == AF_INET) ? 32 : 128; result = dns_acl_appendelement(mgr->aclenv.localhost, &elt); if (result != ISC_R_SUCCESS) goto ignore_interface; result = isc_netaddr_masktoprefixlen(&interface.netmask, &prefixlen); + + /* Non contigious netmasks not allowed by IPv6 arch. */ + if (result != ISC_R_SUCCESS && family == AF_INET6) + goto ignore_interface; + if (result != ISC_R_SUCCESS) { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING, @@ -550,7 +628,15 @@ do_ipv4(ns_interfacemgr_t *mgr) { goto ignore_interface; } - for (le = ISC_LIST_HEAD(mgr->listenon4->elts); + /* + * If we've made a wildcard AF_INET6 socket, silently skip all + * IPv6 addresses to bind. + */ + if (family == AF_INET6 && setup_ipv6 == ISC_FALSE) + continue; + + ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6; + for (le = ISC_LIST_HEAD(ll->elts); le != NULL; le = ISC_LIST_NEXT(le, link)) { @@ -562,8 +648,13 @@ do_ipv4(ns_interfacemgr_t *mgr) { * Construct a socket address for this IP/port * combination. */ - isc_netaddr_fromin(&listen_netaddr, - &interface.address.type.in); + if (family == AF_INET) { + isc_netaddr_fromin(&listen_netaddr, + &interface.address.type.in); + } else { + isc_netaddr_fromin6(&listen_netaddr, + &interface.address.type.in6); + } isc_sockaddr_fromnetaddr(&listen_sockaddr, &listen_netaddr, le->port); @@ -587,8 +678,11 @@ do_ipv4(ns_interfacemgr_t *mgr) { sabuf, sizeof(sabuf)); isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_INFO, - "listening on IPv4 interface " - "%s, %s", interface.name, sabuf); + "listening on %s interface " + "%s, %s", + (family == AF_INET) ? + "IPv4" : "IPv6", + interface.name, sabuf); result = ns_interface_setup(mgr, &listen_sockaddr, @@ -596,10 +690,13 @@ do_ipv4(ns_interfacemgr_t *mgr) { &ifp); if (result != ISC_R_SUCCESS) { isc_log_write(IFMGR_COMMON_LOGARGS, - ISC_LOG_ERROR, - "creating IPv4 interface %s " - "failed; interface ignored", - interface.name); + ISC_LOG_ERROR, + "creating %s interface " + "%s failed; interface " + "ignored", + (family == AF_INET) ? + "IPv4" : "IPv6", + interface.name); } /* Continue. */ } @@ -610,13 +707,14 @@ do_ipv4(ns_interfacemgr_t *mgr) { ignore_interface: isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, - "ignoring IPv4 interface %s: %s", + "ignoring %s interface %s: %s", + (family == AF_INET) ? "IPv4" : "IPv6", interface.name, isc_result_totext(result)); continue; } if (result != ISC_R_NOMORE) UNEXPECTED_ERROR(__FILE__, __LINE__, - "IPv4: interface iteration failed: %s", + "interface iteration failed: %s", isc_result_totext(result)); else result = ISC_R_SUCCESS; @@ -625,74 +723,6 @@ do_ipv4(ns_interfacemgr_t *mgr) { return (result); } -static isc_boolean_t -listenon_is_ip6_none(ns_listenelt_t *elt) { - if (elt->acl->length == 0) - return (ISC_TRUE); /* listen-on-v6 { } */ - if (elt->acl->length > 1) - return (ISC_FALSE); /* listen-on-v6 { ...; ...; } */ - if (elt->acl->elements[0].negative == ISC_TRUE && - elt->acl->elements[0].type == dns_aclelementtype_any) - return (ISC_TRUE); /* listen-on-v6 { none; } */ - return (ISC_FALSE); /* All others */ -} - -static isc_boolean_t -listenon_is_ip6_any(ns_listenelt_t *elt) { - if (elt->acl->length != 1) - return (ISC_FALSE); - if (elt->acl->elements[0].negative == ISC_FALSE && - elt->acl->elements[0].type == dns_aclelementtype_any) - return (ISC_TRUE); /* listen-on-v6 { any; } */ - return (ISC_FALSE); /* All others */ -} - -static isc_result_t -do_ipv6(ns_interfacemgr_t *mgr) { - isc_result_t result; - ns_interface_t *ifp; - isc_sockaddr_t listen_addr; - struct in6_addr in6a; - ns_listenelt_t *le; - - for (le = ISC_LIST_HEAD(mgr->listenon6->elts); - le != NULL; - le = ISC_LIST_NEXT(le, link)) - { - if (listenon_is_ip6_none(le)) - continue; - if (! listenon_is_ip6_any(le)) { - isc_log_write(IFMGR_COMMON_LOGARGS, - ISC_LOG_ERROR, - "bad IPv6 listen-on list: " - "must be 'any' or 'none'"); - return (ISC_R_FAILURE); - } - - in6a = in6addr_any; - isc_sockaddr_fromin6(&listen_addr, &in6a, le->port); - - ifp = find_matching_interface(mgr, &listen_addr); - if (ifp != NULL) { - ifp->generation = mgr->generation; - } else { - isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_INFO, - "listening on IPv6 interfaces, port %u", - le->port); - result = ns_interface_setup(mgr, &listen_addr, - "", &ifp); - if (result != ISC_R_SUCCESS) { - isc_log_write(IFMGR_COMMON_LOGARGS, - ISC_LOG_ERROR, - "listening on IPv6 interfaces " - "failed"); - /* Continue. */ - } - } - } - return (ISC_R_SUCCESS); -} - void ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) { isc_boolean_t purge = ISC_TRUE; @@ -701,24 +731,8 @@ ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) { mgr->generation++; /* Increment the generation count. */ - if (isc_net_probeipv6() == ISC_R_SUCCESS) { - if (do_ipv6(mgr) != ISC_R_SUCCESS) - purge = ISC_FALSE; - } -#ifdef WANT_IPV6 - else - isc_log_write(IFMGR_COMMON_LOGARGS, - verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1), - "no IPv6 interfaces found"); -#endif - - if (isc_net_probeipv4() == ISC_R_SUCCESS) { - if (do_ipv4(mgr) != ISC_R_SUCCESS) - purge = ISC_FALSE; - } else - isc_log_write(IFMGR_COMMON_LOGARGS, - verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1), - "no IPv4 interfaces found"); + if (do_scan(mgr, verbose) != ISC_R_SUCCESS) + purge = ISC_FALSE; /* * Now go through the interface list and delete anything that