]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
developer: jinmei
authorMark Andrews <marka@isc.org>
Fri, 30 Aug 2002 02:05:30 +0000 (02:05 +0000)
committerMark Andrews <marka@isc.org>
Fri, 30 Aug 2002 02:05:30 +0000 (02:05 +0000)
reviewer: marka
1371    [bug]           notify-source-v6, transfer-source-v6 and
                        query-source-v6 with explict addresses and using the
                        same ports as named was listening on could interfere
                        with nameds ability to answer queries sent to those
                        addresses.

CHANGES
bin/named/include/named/interfacemgr.h
bin/named/interfacemgr.c
bin/named/server.c

diff --git a/CHANGES b/CHANGES
index 8238110f917c972427b5bfcc55264eb386a31f1f..5f9a6180302dda6e80260fc993989a02ee36c6f0 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,9 @@
+1371   [bug]           notify-source-v6, transfer-source-v6 and
+                       query-source-v6 with explict addresses and using the
+                       same ports as named was listening on could interfere
+                       with nameds ability to answer queries sent to those
+                       addresses.
+
 1370.  [bug]           dig '+[no]recurse' was incorrectly documented.
 
 1369.  [bug]           Adding an NS record as the lexicographically last
index c8b1a47a80b15d30a24063b8a96a9957fb96057d..5ddb8f1303c7c6f4a9d577a64e5ceae7e1efd72b 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: interfacemgr.h,v 1.23 2001/08/28 03:58:00 marka Exp $ */
+/* $Id: interfacemgr.h,v 1.24 2002/08/30 02:05:30 marka Exp $ */
 
 #ifndef NAMED_INTERFACEMGR_H
 #define NAMED_INTERFACEMGR_H 1
@@ -120,6 +120,20 @@ ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose);
  * in named.conf.
  */
 
+void
+ns_interfacemgr_adjust(ns_interfacemgr_t *mgr, ns_listenlist_t *list,
+                      isc_boolean_t verbose);
+/*
+ * Similar to ns_interfacemgr_scan(), but this function also tries to see the
+ * need for an explicit listen-on when a list element in 'list' is going to
+ * override an already-listening a wildcard interface.
+ *
+ * This function does not update localhost and localnets ACLs.
+ *
+ * This should be called once on server startup, after configuring views and
+ * zones.
+ */
+
 void
 ns_interfacemgr_setlistenon4(ns_interfacemgr_t *mgr, ns_listenlist_t *value);
 /*
index c538e2a1286d9c40d639857548d7a9cc5a8300e3..1183fad5f0f3499569aba1e6e8e26bbe98ae72ac 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: interfacemgr.c,v 1.69 2002/08/17 03:00:49 marka Exp $ */
+/* $Id: interfacemgr.c,v 1.70 2002/08/30 02:05:29 marka Exp $ */
 
 #include <config.h>
 
@@ -339,7 +339,8 @@ ns_interface_accepttcp(ns_interface_t *ifp) {
 
 static isc_result_t
 ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
-                  const char *name, ns_interface_t **ifpret)
+                  const char *name, ns_interface_t **ifpret,
+                  isc_boolean_t accept_tcp)
 {
        isc_result_t result;
        ns_interface_t *ifp = NULL;
@@ -353,15 +354,17 @@ ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
        if (result != ISC_R_SUCCESS)
                goto cleanup_interface;
 
-       result = ns_interface_accepttcp(ifp);
-       if (result != ISC_R_SUCCESS) {
-               /*
-                * XXXRTH We don't currently have a way to easily stop dispatch
-                * service, so we return currently return ISC_R_SUCCESS (the
-                * UDP stuff will work even if TCP creation failed).  This will
-                * be fixed later.
-                */
-               result = ISC_R_SUCCESS;
+       if (accept_tcp == ISC_TRUE) {
+               result = ns_interface_accepttcp(ifp);
+               if (result != ISC_R_SUCCESS) {
+                       /*
+                        * XXXRTH We don't currently have a way to easily stop
+                        * dispatch service, so we return currently return
+                        * ISC_R_SUCCESS (the UDP stuff will work even if TCP
+                        * creation failed).  This will be fixed later.
+                        */
+                       result = ISC_R_SUCCESS;
+               }
        }
        *ifpret = ifp;
        return (ISC_R_SUCCESS);
@@ -489,16 +492,65 @@ listenon_is_ip6_any(ns_listenelt_t *elt) {
 }
 
 static isc_result_t
-do_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
+setup_locals(ns_interfacemgr_t *mgr, isc_interface_t *interface) {
+       isc_result_t result;
+       dns_aclelement_t elt;
+       unsigned int family;
+       unsigned int prefixlen;
+
+       family = interface->address.family;
+       
+       elt.type = dns_aclelementtype_ipprefix;
+       elt.negative = ISC_FALSE;
+       elt.u.ip_prefix.address = interface->address;
+       elt.u.ip_prefix.prefixlen = (family == AF_INET) ? 32 : 128;
+       result = dns_acl_appendelement(mgr->aclenv.localhost, &elt);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+
+       result = isc_netaddr_masktoprefixlen(&interface->netmask,
+                                            &prefixlen);
+
+       /* Non contigious netmasks not allowed by IPv6 arch. */
+       if (result != ISC_R_SUCCESS && family == AF_INET6)
+               return (result);
+
+       if (result != ISC_R_SUCCESS) {
+               isc_log_write(IFMGR_COMMON_LOGARGS,
+                             ISC_LOG_WARNING,
+                             "omitting IPv4 interface %s from "
+                             "localnets ACL: %s",
+                             interface->name,
+                             isc_result_totext(result));
+       } else {
+               elt.u.ip_prefix.prefixlen = prefixlen;
+               /* XXX suppress duplicates */
+               result = dns_acl_appendelement(mgr->aclenv.localnets,
+                                              &elt);
+               if (result != ISC_R_SUCCESS)
+                       return (result);
+       }
+
+       return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
+       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 adjusting = ISC_FALSE;
        isc_result_t result;
        isc_netaddr_t zero_address, zero_address6;
        ns_listenelt_t *le;
        isc_sockaddr_t listen_addr;
        ns_interface_t *ifp;
 
+       if (ext_listen != NULL)
+               adjusting = ISC_TRUE;
+
        if (isc_net_probeipv6() == ISC_R_SUCCESS)
                scan_ipv6 = ISC_TRUE;
 #ifdef WANT_IPV6
@@ -539,7 +591,8 @@ do_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
                                              "interfaces, port %u",
                                              le->port);
                                result = ns_interface_setup(mgr, &listen_addr,
-                                                           "<any>", &ifp);
+                                                           "<any>", &ifp,
+                                                           ISC_TRUE);
                                if (result != ISC_R_SUCCESS)
                                        isc_log_write(IFMGR_COMMON_LOGARGS,
                                                      ISC_LOG_ERROR,
@@ -557,12 +610,14 @@ do_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
        if (result != ISC_R_SUCCESS)
                return (result);
 
-       result = clearacl(mgr->mctx, &mgr->aclenv.localhost);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_iter;
-       result = clearacl(mgr->mctx, &mgr->aclenv.localnets);
-       if (result != ISC_R_SUCCESS)
-               goto cleanup_iter;
+       if (adjusting == ISC_FALSE) {
+               result = clearacl(mgr->mctx, &mgr->aclenv.localhost);
+               if (result != ISC_R_SUCCESS)
+                       goto cleanup_iter;
+               result = clearacl(mgr->mctx, &mgr->aclenv.localnets);
+               if (result != ISC_R_SUCCESS)
+                       goto cleanup_iter;
+       }
 
        for (result = isc_interfaceiter_first(iter);
             result == ISC_R_SUCCESS;
@@ -570,8 +625,6 @@ do_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
        {
                isc_interface_t interface;
                ns_listenlist_t *ll;
-               dns_aclelement_t elt;
-               unsigned int prefixlen;
                unsigned int family; 
 
                result = isc_interfaceiter_current(iter, &interface);
@@ -602,33 +655,8 @@ do_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
                        continue;
                }
 
-               elt.type = dns_aclelementtype_ipprefix;
-               elt.negative = ISC_FALSE;
-               elt.u.ip_prefix.address = interface.address;
-               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,
-                                     "omitting IPv4 interface %s from "
-                                     "localnets ACL: %s",
-                                     interface.name,
-                                     isc_result_totext(result));
-               } else {
-                       elt.u.ip_prefix.prefixlen = prefixlen;
-                       /* XXX suppress duplicates */
-                       result = dns_acl_appendelement(mgr->aclenv.localnets,
-                                                      &elt);
+               if (adjusting == ISC_FALSE) {
+                       result = setup_locals(mgr, &interface);
                        if (result != ISC_R_SUCCESS)
                                goto ignore_interface;
                }
@@ -639,13 +667,10 @@ do_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
                     le = ISC_LIST_NEXT(le, link))
                {
                        int match;
+                       isc_boolean_t ipv6_wildcard = ISC_FALSE;
                        isc_netaddr_t listen_netaddr;
                        isc_sockaddr_t listen_sockaddr;
 
-                       /* the case of "any" IPv6 address was already done. */
-                       if (family == AF_INET6 && listenon_is_ip6_any(le))
-                               continue;
-
                        /*
                         * Construct a socket address for this IP/port
                         * combination.
@@ -671,17 +696,58 @@ do_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
                        if (match <= 0)
                                continue;
 
+                       /*
+                        * The case of "any" IPv6 address will require
+                        * special considerations later, so remember it.
+                        */
+                       if (family == AF_INET6 && listenon_is_ip6_any(le))
+                               ipv6_wildcard = ISC_TRUE;
+
+                       /*
+                        * When adjusting interfaces with extra a listening
+                        * list, see if the address matches the extra list.
+                        * If it does, and is also covered by a wildcard
+                        * interface, we need to listen on the address
+                        * explicitly.
+                        */
+                       if (adjusting == ISC_TRUE) {
+                               ns_listenelt_t *ele;
+
+                               match = 0;
+                               for (ele = ISC_LIST_HEAD(ext_listen->elts);
+                                    ele != NULL;
+                                    ele = ISC_LIST_NEXT(ele, link)) {
+                                       dns_acl_match(&listen_netaddr, NULL,
+                                                     ele->acl, NULL,
+                                                     &match, NULL);
+                                       if (match > 0 && ele->port == le->port)
+                                               break;
+                                       else
+                                               match = 0;
+                               }
+                               if (ipv6_wildcard == ISC_TRUE && match == 0)
+                                       continue;
+                       }
+
                        ifp = find_matching_interface(mgr, &listen_sockaddr);
                        if (ifp != NULL) {
                                ifp->generation = mgr->generation;
                        } else {
                                char sabuf[ISC_SOCKADDR_FORMATSIZE];
+
+                               if (adjusting == ISC_FALSE &&
+                                   ipv6_wildcard == ISC_TRUE)
+                                       continue;
+
                                isc_sockaddr_format(&listen_sockaddr,
                                                    sabuf, sizeof(sabuf));
                                isc_log_write(IFMGR_COMMON_LOGARGS,
                                              ISC_LOG_INFO,
+                                             "%s"
                                              "listening on %s interface "
                                              "%s, %s",
+                                             (adjusting == ISC_TRUE) ?
+                                             "additionally " : "",
                                              (family == AF_INET) ?
                                              "IPv4" : "IPv6",
                                              interface.name, sabuf);
@@ -689,7 +755,11 @@ do_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
                                result = ns_interface_setup(mgr,
                                                            &listen_sockaddr,
                                                            interface.name,
-                                                           &ifp);
+                                                           &ifp,
+                                                           (adjusting == ISC_TRUE) ?
+                                                           ISC_FALSE :
+                                                           ISC_TRUE);
+
                                if (result != ISC_R_SUCCESS) {
                                        isc_log_write(IFMGR_COMMON_LOGARGS,
                                                      ISC_LOG_ERROR,
@@ -725,15 +795,17 @@ do_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
        return (result);
 }
 
-void
-ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
+static void
+ns_interfacemgr_scan0(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
+                     isc_boolean_t verbose)
+{
        isc_boolean_t purge = ISC_TRUE;
 
        REQUIRE(NS_INTERFACEMGR_VALID(mgr));
 
        mgr->generation++;      /* Increment the generation count. */
 
-       if (do_scan(mgr, verbose) != ISC_R_SUCCESS)
+       if (do_scan(mgr, ext_listen, verbose) != ISC_R_SUCCESS)
                purge = ISC_FALSE;
 
        /*
@@ -750,9 +822,23 @@ ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
         * we're in lwresd-only mode, in which case that is to 
         * be expected.
         */
-       if (ISC_LIST_EMPTY(mgr->interfaces) && ! ns_g_lwresdonly)
+       if (ext_listen == NULL &&
+           ISC_LIST_EMPTY(mgr->interfaces) && ! ns_g_lwresdonly) {
                isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
                              "not listening on any interfaces");
+       }
+}
+
+void
+ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
+       ns_interfacemgr_scan0(mgr, NULL, verbose);
+}
+
+void
+ns_interfacemgr_adjust(ns_interfacemgr_t *mgr, ns_listenlist_t *list,
+                      isc_boolean_t verbose)
+{
+       ns_interfacemgr_scan0(mgr, list, verbose);
 }
 
 void
@@ -770,4 +856,3 @@ ns_interfacemgr_setlistenon6(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
        ns_listenlist_attach(value, &mgr->listenon6);
        UNLOCK(&mgr->lock);
 }
-
index 6a68971d2730fbfbf9880921f13c649826391f4b..fe38b2f43ef8a2f03a1b5670d3d5e3cc9d0e46cd 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: server.c,v 1.382 2002/08/17 00:23:19 marka Exp $ */
+/* $Id: server.c,v 1.383 2002/08/30 02:05:29 marka Exp $ */
 
 #include <config.h>
 
@@ -1400,6 +1400,132 @@ scan_interfaces(ns_server_t *server, isc_boolean_t verbose) {
        server->aclenv.match_mapped = match_mapped;
 }
 
+static isc_result_t
+add_listenelt(isc_mem_t *mctx, ns_listenlist_t *list, isc_sockaddr_t *addr) {
+       ns_listenelt_t *lelt = NULL;
+       dns_acl_t *src_acl = NULL;
+       dns_aclelement_t aelt;
+       isc_result_t result;
+       isc_sockaddr_t any_sa6;
+
+       REQUIRE(isc_sockaddr_pf(addr) == AF_INET6);
+
+       isc_sockaddr_any6(&any_sa6);
+       if (!isc_sockaddr_equal(&any_sa6, addr)) {
+               aelt.type = dns_aclelementtype_ipprefix;
+               aelt.negative = ISC_FALSE;
+               aelt.u.ip_prefix.prefixlen = 128;
+               isc_netaddr_fromin6(&aelt.u.ip_prefix.address,
+                                   &addr->type.sin6.sin6_addr);
+
+               result = dns_acl_create(mctx, 1, &src_acl);
+               if (result != ISC_R_SUCCESS)
+                       return (result);
+               result = dns_acl_appendelement(src_acl, &aelt);
+               if (result != ISC_R_SUCCESS)
+                       goto clean;
+
+               result = ns_listenelt_create(mctx, isc_sockaddr_getport(addr),
+                                            src_acl, &lelt);
+               if (result != ISC_R_SUCCESS)
+                       goto clean;
+               ISC_LIST_APPEND(list->elts, lelt, link);
+       }
+
+       return (ISC_R_SUCCESS);
+
+ clean:
+       INSIST(lelt == NULL);
+       if (src_acl != NULL)
+               dns_acl_detach(&src_acl);
+
+       return (result);
+}
+
+/*
+ * Make a list of xxx-source addresses and call ns_interfacemgr_adjust()
+ * to update the listening interfaces accordingly.
+ * We currently only consider IPv6, because this only affects IPv6 wildcard
+ * sockets.
+ */
+static void
+adjust_interfaces(ns_server_t *server, isc_mem_t *mctx) {
+       isc_result_t result;
+       ns_listenlist_t *list = NULL;
+       dns_view_t *view;
+       dns_zone_t *zone, *next;
+       isc_sockaddr_t addr, *addrp;
+
+       result = ns_listenlist_create(mctx, &list);
+       if (result != ISC_R_SUCCESS)
+               return;
+
+       for (view = ISC_LIST_HEAD(server->viewlist);
+            view != NULL;
+            view = ISC_LIST_NEXT(view, link)) {
+               dns_dispatch_t *dispatch6;
+
+               dispatch6 = dns_resolver_dispatchv6(view->resolver);
+               INSIST(dispatch6 != NULL);
+               result = dns_dispatch_getlocaladdress(dispatch6, &addr);
+               if (result != ISC_R_SUCCESS)
+                       goto fail;
+               result = add_listenelt(mctx, list, &addr);
+               if (result != ISC_R_SUCCESS)
+                       goto fail;
+       }
+
+       zone = NULL;
+       for (result = dns_zone_first(server->zonemgr, &zone);
+            result == ISC_R_SUCCESS;
+            next = NULL, result = dns_zone_next(zone, &next), zone = next) {
+               dns_view_t *zoneview;
+
+               /*
+                * At this point the zone list may contain a stale zone
+                * just removed from the configuration.  To see the validity,
+                * check if the corresponding view is in our current view list.
+                */
+               zoneview = dns_zone_getview(zone);
+               INSIST(zoneview != NULL);
+               for (view = ISC_LIST_HEAD(server->viewlist);
+                    view != NULL && view != zoneview;
+                    view = ISC_LIST_NEXT(view, link))
+                       ;
+               if (view == NULL)
+                       continue;
+
+               addrp = dns_zone_getnotifysrc6(zone);
+               INSIST(addrp != NULL);
+               result = add_listenelt(mctx, list, addrp);
+               if (result != ISC_R_SUCCESS)
+                       goto fail;
+
+               addrp = dns_zone_getxfrsource6(zone);
+               INSIST(addrp != NULL);
+               result = add_listenelt(mctx, list, addrp);
+               if (result != ISC_R_SUCCESS)
+                       goto fail;
+       }
+
+       ns_interfacemgr_adjust(server->interfacemgr, list, ISC_TRUE);
+       
+ clean:
+       ns_listenlist_detach(&list);
+       return;
+
+ fail:
+       /*
+        * Even when we failed the procedure, most of other interfaces
+        * should work correctly.  We therefore just warn it.
+        */
+       isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL,
+                     NS_LOGMODULE_SERVER, ISC_LOG_WARNING,
+                     "could not adjust the listen-on list; "
+                     "some interfaces may not work");
+       goto clean;
+}
+
 /*
  * This event callback is invoked to do periodic network
  * interface scanning.
@@ -2060,6 +2186,12 @@ load_configuration(const char *filename, ns_server_t *server,
 
        }
 
+       /*
+        * Adjust the listening interfaces in accordance with the source
+        * addresses specified in views and zones.
+        */
+       adjust_interfaces(server, ns_g_mctx);
+
        if (dispatchv4 != NULL)
                dns_dispatch_detach(&dispatchv4);
        if (dispatchv6 != NULL)