]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
1394. [func] It is now possible to check if a particular element is
authorMark Andrews <marka@isc.org>
Tue, 29 Oct 2002 04:40:26 +0000 (04:40 +0000)
committerMark Andrews <marka@isc.org>
Tue, 29 Oct 2002 04:40:26 +0000 (04:40 +0000)
                        in a acl.  Remove duplicate entries from the localnets
                        acl.

1393.   [port]          Bind to individual IPv6 interfaces if IPV6_IPV6ONLY
                        is not available in the kernel to prevent accidently
                        listening on IPv4 interfaces.
developer: jinmei
reviewer: marka

CHANGES
bin/named/interfacemgr.c
doc/arm/Bv9ARM-book.xml
lib/dns/acl.c
lib/dns/include/dns/acl.h
lib/isc/unix/include/isc/net.h
lib/isc/unix/net.c
lib/isc/win32/include/isc/net.h
lib/isc/win32/net.c

diff --git a/CHANGES b/CHANGES
index 6ad3b7571b62e8a64ebdc8d86d396988e1233593..3e70a5b11e44b17df93629fcaf7dcda746da5f90 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,11 @@
+1394.  [func]          It is now possible to check if a particular element is
+                       in a acl.  Remove duplicate entries from the localnets
+                       acl.
+
+1393.  [port]          Bind to individual IPv6 interfaces if IPV6_IPV6ONLY
+                       is not available in the kernel to prevent accidently
+                       listening on IPv4 interfaces.
+
 1392.  [bug]           named-checkzone: update usage.
 
 1391.  [func]          Add support for IPv6 scoped addresses in named.
index 5069d0162ed93c6b1a5f85d1a8965474a17c71ad..67957b416ca5603152ccea580194ed1344cd5b60 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: interfacemgr.c,v 1.72 2002/10/24 03:52:31 marka Exp $ */
+/* $Id: interfacemgr.c,v 1.73 2002/10/29 04:40:23 marka Exp $ */
 
 #include <config.h>
 
@@ -524,11 +524,13 @@ setup_locals(ns_interfacemgr_t *mgr, isc_interface_t *interface) {
                              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);
+               if (dns_acl_elementmatch(mgr->aclenv.localnets, &elt,
+                                        NULL) == ISC_R_NOTFOUND) {
+                       result = dns_acl_appendelement(mgr->aclenv.localnets,
+                                                      &elt);
+                       if (result != ISC_R_SUCCESS)
+                               return (result);
+               }
        }
 
        return (ISC_R_SUCCESS);
@@ -542,6 +544,7 @@ do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
        isc_boolean_t scan_ipv4 = ISC_FALSE;
        isc_boolean_t scan_ipv6 = ISC_FALSE;
        isc_boolean_t adjusting = ISC_FALSE;
+       isc_boolean_t ipv6only = ISC_TRUE;
        isc_result_t result;
        isc_netaddr_t zero_address, zero_address6;
        ns_listenelt_t *le;
@@ -567,9 +570,25 @@ do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
                              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) {
+       /*
+        * A special, but typical case; listen-on-v6 { any; }.
+        * When we can make the socket IPv6-only, open a single wildcard
+        * socket for IPv6 communication.  Otherwise, make separate socket
+        * for each IPv6 address in order to avoid accepting IPv4 packets
+        * as the form of mapped addresses unintentionally unless explicitly
+        * allowed.
+        */
+#ifndef ISC_ALLOW_MAPPED
+       if (scan_ipv6 == ISC_TRUE &&
+           isc_net_probe_ipv6only() != ISC_R_SUCCESS) {
+               ipv6only = ISC_FALSE;
+               isc_log_write(IFMGR_COMMON_LOGARGS,
+                             verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
+                             "IPv6-only option is not available."
+                             "  use explicit binding");
+       }
+#endif
+       if (scan_ipv6 == ISC_TRUE && ipv6only) {
                for (le = ISC_LIST_HEAD(mgr->listenon6->elts);
                    le != NULL;
                    le = ISC_LIST_NEXT(le, link)) {
@@ -702,7 +721,8 @@ do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
                         * The case of "any" IPv6 address will require
                         * special considerations later, so remember it.
                         */
-                       if (family == AF_INET6 && listenon_is_ip6_any(le))
+                       if (family == AF_INET6 && ipv6only &&
+                           listenon_is_ip6_any(le))
                                ipv6_wildcard = ISC_TRUE;
 
                        /*
index c678fccdf16ceca46c849b15e3deee2c66393c29..339a4421d28cef7a715fc7a03be123e97c02eeeb 100644 (file)
@@ -2,7 +2,7 @@
 <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.0//EN"
                "http://www.oasis-open.org/docbook/xml/4.0/docbookx.dtd">
 
-<!-- File: $Id: Bv9ARM-book.xml,v 1.206 2002/10/24 03:52:32 marka Exp $ -->
+<!-- File: $Id: Bv9ARM-book.xml,v 1.207 2002/10/29 04:40:23 marka Exp $ -->
 
 <book>
 <title>BIND 9 Administrator Reference Manual</title>
@@ -3549,11 +3549,10 @@ listen-on port 1234 { !1.2.3.4; 1.2/16; };
 server will listen on port 53 on all interfaces.</para>
 
 <para>By default, the server does not bind a separate socket to each
-IPv6 interface address as it does for IPv4. Instead, it always
-listens on the IPv6 wildcard address.
-However, some particular IPv6 addresses can also be specified,
-in which case the server makes a separate socket for each specified
-address.</para>
+IPv6 interface address as it does for IPv4. Instead, it listens on the 
+IPv6 wildcard address.
+Alternatively, a list of IPv6 addresses can be specified, in which case
+the server listens on a separate socket for each specified address.</para>
 
 <para>Multiple <command>listen-on-v6</command> options can be used.
 For example,</para>
index a5083f12e8b4aa8c7ded91c4473e0485df879235..83aa5d61cdcd00971eeb7c355ea09c9f4b5a2c24 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: acl.c,v 1.23 2001/05/31 10:43:37 tale Exp $ */
+/* $Id: acl.c,v 1.24 2002/10/29 04:40:23 marka Exp $ */
 
 #include <config.h>
 
@@ -149,6 +149,29 @@ dns_acl_match(isc_netaddr_t *reqaddr,
        return (ISC_R_SUCCESS);
 }
 
+isc_result_t
+dns_acl_elementmatch(dns_acl_t *acl,
+                    dns_aclelement_t *elt,
+                    dns_aclelement_t **matchelt)
+{
+       unsigned int i;
+
+       REQUIRE(elt != NULL);
+       REQUIRE(matchelt == NULL || *matchelt == NULL);
+       
+       for (i = 0; i < acl->length; i++) {
+               dns_aclelement_t *e = &acl->elements[i];
+
+               if (dns_aclelement_equal(e, elt) == ISC_TRUE) {
+                       if (matchelt != NULL)
+                               *matchelt = e;
+                       return (ISC_R_SUCCESS);
+               }
+       }
+
+       return (ISC_R_NOTFOUND);
+}
+
 isc_boolean_t
 dns_aclelement_match(isc_netaddr_t *reqaddr,
                     dns_name_t *reqsigner,
@@ -297,8 +320,9 @@ dns_aclelement_equal(dns_aclelement_t *ea, dns_aclelement_t *eb) {
                if (ea->u.ip_prefix.prefixlen !=
                    eb->u.ip_prefix.prefixlen)
                        return (ISC_FALSE);
-               return (isc_netaddr_equal(&ea->u.ip_prefix.address,
-                                         &eb->u.ip_prefix.address));
+               return (isc_netaddr_eqprefix(&ea->u.ip_prefix.address,
+                                            &eb->u.ip_prefix.address,
+                                            ea->u.ip_prefix.prefixlen));
        case dns_aclelementtype_keyname:
                return (dns_name_equal(&ea->u.keyname, &eb->u.keyname));
        case dns_aclelementtype_nestedacl:
index e758bdf2758fa84dec71b2dceaf6158c3640881e..7ca4cefe749c2fd927ce5d2de82ec49495457c9f 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: acl.h,v 1.20 2001/08/28 03:58:11 marka Exp $ */
+/* $Id: acl.h,v 1.21 2002/10/29 04:40:24 marka Exp $ */
 
 #ifndef DNS_ACL_H
 #define DNS_ACL_H 1
@@ -199,6 +199,23 @@ dns_aclelement_match(isc_netaddr_t *reqaddr,
  * returned through 'matchelt' is not necessarily 'e' itself.
  */
 
+isc_result_t
+dns_acl_elementmatch(dns_acl_t *acl,
+                    dns_aclelement_t *elt,
+                    dns_aclelement_t **matchelt);
+/*
+ * Search for an ACL element in 'acl' which is exactly the same as 'elt'.
+ * If there is one, and 'matchelt' is non NULL, then '*matchelt' will point
+ * to the entry.
+ *
+ * This function is intended to be used for avoiding duplicated ACL entries
+ * before adding an entry.
+ *
+ * Returns:
+ *     ISC_R_SUCCESS           Match succeeds.
+ *     ISC_R_NOTFOUND          Match fails.
+ */
+
 ISC_LANG_ENDDECLS
 
 #endif /* DNS_ACL_H */
index f527a977dfaf86ddd177548b41612f89be767e13..2997588eae3edc451ceacde9dc3b9ac02f08ee4e 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: net.h,v 1.35 2002/10/24 03:52:35 marka Exp $ */
+/* $Id: net.h,v 1.36 2002/10/29 04:40:25 marka Exp $ */
 
 #ifndef ISC_NET_H
 #define ISC_NET_H 1
@@ -260,6 +260,18 @@ isc_net_probeipv6(void);
  *     ISC_R_UNEXPECTED
  */
 
+isc_result_t
+isc_net_probe_ipv6only(void);
+/*
+ * Check if the system's kernel supports the IPV6_V6ONLY socket option.
+ *
+ * Returns:
+ *
+ *     ISC_R_SUCCESS           the option is supported for both TCP and UDP.
+ *     ISC_R_NOTFOUND          IPv6 itself or the option is not supported.
+ *     ISC_R_UNEXPECTED
+ */
+
 #ifdef ISC_PLATFORM_NEEDNTOP
 const char *
 isc_net_ntop(int af, const void *src, char *dst, size_t size);
index bb86eae9ec473c77097fad7015474d8184eed1ee..b4899c17e59029b41e0faee7ea20365a47430cca 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: net.c,v 1.25 2001/11/30 01:59:45 gson Exp $ */
+/* $Id: net.c,v 1.26 2002/10/29 04:40:25 marka Exp $ */
 
 #include <config.h>
 
@@ -39,8 +39,10 @@ const struct in6_addr isc_net_in6addrloop = IN6ADDR_LOOPBACK_INIT;
 #endif
 
 static isc_once_t      once = ISC_ONCE_INIT;
+static isc_once_t      once_ipv6only = ISC_ONCE_INIT;
 static isc_result_t    ipv4_result = ISC_R_NOTFOUND;
 static isc_result_t    ipv6_result = ISC_R_NOTFOUND;
+static isc_result_t    ipv6only_result = ISC_R_NOTFOUND;
 
 static isc_result_t
 try_proto(int domain) {
@@ -146,8 +148,102 @@ isc_net_probeipv4(void) {
        return (ipv4_result);
 }
 
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifdef WANT_IPV6
 isc_result_t
 isc_net_probeipv6(void) {
        initialize();
        return (ipv6_result);
 }
+
+static void
+try_ipv6only(void) {
+#ifdef IPV6_V6ONLY
+       int s, on;
+       char strbuf[ISC_STRERRORSIZE];
+#endif
+       isc_result_t result;
+
+       result = isc_net_probeipv6();
+       if (result != ISC_R_SUCCESS) {
+               ipv6only_result = result;
+               return;
+       }
+
+#ifndef IPV6_V6ONLY
+       ipv6only_result = ISC_R_NOTFOUND;
+       return;
+#else
+       /* check for TCP sockets */
+       s = socket(PF_INET6, SOCK_STREAM, 0);
+       if (s == -1) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "socket() %s: %s",
+                                isc_msgcat_get(isc_msgcat,
+                                               ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED,
+                                               "failed"),
+                                strbuf);
+               ipv6only_result = ISC_R_UNEXPECTED;
+               return;
+       }
+
+       on = 1;
+       if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
+               ipv6only_result = ISC_R_NOTFOUND;
+               goto close;
+       }
+
+       close(s);
+
+       /* check for UDP sockets */
+       s = socket(PF_INET6, SOCK_DGRAM, 0);
+       if (s == -1) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "socket() %s: %s",
+                                isc_msgcat_get(isc_msgcat,
+                                               ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED,
+                                               "failed"),
+                                strbuf);
+               ipv6only_result = ISC_R_UNEXPECTED;
+               return;
+       }
+
+       on = 1;
+       if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
+               ipv6only_result = ISC_R_NOTFOUND;
+               goto close;
+       }
+
+       close(s);
+
+       ipv6only_result = ISC_R_SUCCESS;
+
+close:
+       close(s);
+       return;
+#endif
+}
+
+static void
+initialize_ipv6only(void) {
+       RUNTIME_CHECK(isc_once_do(&once_ipv6only,
+                                 try_ipv6only) == ISC_R_SUCCESS);
+}
+#endif
+#endif
+
+isc_result_t
+isc_net_probe_ipv6only(void) {
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifdef WANT_IPV6
+       initialize_ipv6only();
+#else
+       ipv6only_result = ISC_R_NOTFOUND;
+#endif
+#endif
+       return (ipv6only_result);
+}
index 43e54fbe366fa6deded2bf25455f429592c645f9..1f909362fde84bdd183c0e247bad1d15a0a0cd5a 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: net.h,v 1.17 2002/08/01 03:56:08 mayer Exp $ */
+/* $Id: net.h,v 1.18 2002/10/29 04:40:26 marka Exp $ */
 
 #ifndef ISC_NET_H
 #define ISC_NET_H 1
@@ -247,6 +247,18 @@ isc_net_probeipv6(void);
  *     ISC_R_UNEXPECTED
  */
 
+isc_result_t
+isc_net_probe_ipv6only(void);
+/*
+ * Check if the system's kernel supports the IPV6_V6ONLY socket option.
+ *
+ * Returns:
+ *
+ *     ISC_R_SUCCESS           the option is supported for both TCP and UDP.
+ *     ISC_R_NOTFOUND          IPv6 itself or the option is not supported.
+ *     ISC_R_UNEXPECTED
+ */
+
 #ifdef ISC_PLATFORM_NEEDNTOP
 const char *
 isc_net_ntop(int af, const void *src, char *dst, size_t size);
index 2491903236da52d85fea9b641948db0613e741ff..6f69f29fa5015543fb51ba3fb4449804ca4ade3e 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: net.c,v 1.4 2001/11/21 05:07:25 mayer Exp $ */
+/* $Id: net.c,v 1.5 2002/10/29 04:40:25 marka Exp $ */
 
 #include <config.h>
 
@@ -35,8 +35,10 @@ const struct in6_addr isc_net_in6addrany = IN6ADDR_ANY_INIT;
 #endif
 
 static isc_once_t      once = ISC_ONCE_INIT;
+static isc_once_t      once_ipv6only = ISC_ONCE_INIT;
 static isc_result_t    ipv4_result = ISC_R_NOTFOUND;
 static isc_result_t    ipv6_result = ISC_R_NOTFOUND;
+static isc_result_t    ipv6only_result = ISC_R_NOTFOUND;
 
 static isc_result_t
 try_proto(int domain) {
@@ -140,8 +142,102 @@ isc_net_probeipv4(void) {
        return (ipv4_result);
 }
 
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifdef WANT_IPV6
 isc_result_t
 isc_net_probeipv6(void) {
        initialize();
        return (ipv6_result);
 }
+
+static void
+try_ipv6only(void) {
+#ifdef IPV6_V6ONLY
+       int s, on;
+       char strbuf[ISC_STRERRORSIZE];
+#endif
+       isc_result_t result;
+
+       result = isc_net_probeipv6();
+       if (result != ISC_R_SUCCESS) {
+               ipv6only_result = result;
+               return;
+       }
+
+#ifndef IPV6_V6ONLY
+       ipv6only_result = ISC_R_NOTFOUND;
+       return;
+#else
+       /* check for TCP sockets */
+       s = socket(PF_INET6, SOCK_STREAM, 0);
+       if (s == -1) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "socket() %s: %s",
+                                isc_msgcat_get(isc_msgcat,
+                                               ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED,
+                                               "failed"),
+                                strbuf);
+               ipv6only_result = ISC_R_UNEXPECTED;
+               return;
+       }
+
+       on = 1;
+       if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
+               ipv6only_result = ISC_R_NOTFOUND;
+               goto close;
+       }
+
+       close(s);
+
+       /* check for UDP sockets */
+       s = socket(PF_INET6, SOCK_DGRAM, 0);
+       if (s == -1) {
+               isc__strerror(errno, strbuf, sizeof(strbuf));
+               UNEXPECTED_ERROR(__FILE__, __LINE__,
+                                "socket() %s: %s",
+                                isc_msgcat_get(isc_msgcat,
+                                               ISC_MSGSET_GENERAL,
+                                               ISC_MSG_FAILED,
+                                               "failed"),
+                                strbuf);
+               ipv6only_result = ISC_R_UNEXPECTED;
+               return;
+       }
+
+       on = 1;
+       if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
+               ipv6only_result = ISC_R_NOTFOUND;
+               goto close;
+       }
+
+       close(s);
+
+       ipv6only_result = ISC_R_SUCCESS;
+
+close:
+       close(s);
+       return;
+#endif
+}
+
+static void
+initialize_ipv6only(void) {
+       RUNTIME_CHECK(isc_once_do(&once_ipv6only,
+                                 try_ipv6only) == ISC_R_SUCCESS);
+}
+#endif
+#endif
+
+isc_result_t
+isc_net_probe_ipv6only(void) {
+#ifdef ISC_PLATFORM_HAVEIPV6
+#ifdef WANT_IPV6
+       initialize_ipv6only();
+#else
+       ipv6only_result = ISC_R_NOTFOUND;
+#endif
+#endif
+       return (ipv6only_result);
+}