]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
[v9_10] fix ECS family 0 handling
authorEvan Hunt <each@isc.org>
Thu, 24 Mar 2016 02:04:04 +0000 (19:04 -0700)
committerEvan Hunt <each@isc.org>
Thu, 24 Mar 2016 02:04:04 +0000 (19:04 -0700)
4341. [bug] Correct the handling of ECS options with
address family 0. [RT #41377]

CHANGES
bin/dig/dig.1
bin/dig/dig.docbook
bin/dig/dig.html
bin/dig/dighost.c
bin/named/client.c
lib/dns/message.c
lib/dns/rdata/generic/opt_41.c

diff --git a/CHANGES b/CHANGES
index 2e0e7c09e2309f77962956fb8772c577e55dde5f..e349d1c24bcb327b6a11a9965b650cdf7c906adf 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,9 @@
 4342.  [bug]           'rndc flushtree' could fail to clean the tree if there
                        wasn't a node at the specified name. [RT #41846]
 
+4341.  [bug]           Correct the handling of ECS options with
+                       address family 0. [RT #41377]
+
 4338.  [bug]           Reimplement change 4324 as it wasn't properly doing
                        all the required book keeping. [RT #41941]
 
index a61350b4d05767d51941a4f765d9a1a60d3b15ef..f6d4131f8788ecf67c769f80bdf28ab5e701f7de 100644 (file)
@@ -587,13 +587,15 @@ causes fields not to be split at all\&. The default is 56 characters, or 44 char
 This query option toggles the printing of statistics: when the query was made, the size of the reply and so on\&. The default behavior is to print the query statistics\&.
 .RE
 .PP
-\fB+[no]subnet=addr[/netmask]\fR
+\fB+[no]subnet=addr[/prefix\-length]\fR
 .RS 4
 Send (don\*(Aqt send) an EDNS Client Subnet option with the specified IP address or network prefix\&.
 .sp
 \fBdig +subnet=0\&.0\&.0\&.0/0\fR, or simply
 \fBdig +subnet=0\fR
-for short, sends a Client Subnet option with an empty address and a source prefix length of zero, which signals a resolver that the EDNS Client Subnet option should not be used when resolving this query\&.
+for short, sends an EDNS client\-subnet option with an empty address and a source prefix\-length of zero, which signals a resolver that the client\*(Aqs address information must
+\fInot\fR
+be used when resolving this query\&.
 .RE
 .PP
 \fB+[no]tcp\fR
index edfd894028f64e1f25c22a0905a034c0b4770d6b..c54d677793fdd1f7b05557f12a61a87b1d307d4f 100644 (file)
        </varlistentry>
 
        <varlistentry>
-         <term><option>+[no]subnet=addr[/netmask]</option></term>
+         <term><option>+[no]subnet=addr[/prefix-length]</option></term>
          <listitem>
            <para>
              Send (don't send) an EDNS Client Subnet option with the
-              specified IP address or network prefix.
+             specified IP address or network prefix.
            </para>
            <para>
               <command>dig +subnet=0.0.0.0/0</command>, or simply
-              <command>dig +subnet=0</command> for short, sends a
-              Client Subnet option with an empty address and a
-              source prefix length of zero, which signals a resolver
-              that the EDNS Client Subnet option should not be used
-              when resolving this query.
+              <command>dig +subnet=0</command> for short, sends an EDNS
+              client-subnet option with an empty address and a source
+              prefix-length of zero, which signals a resolver that
+              the client's address information must
+              <emphasis>not</emphasis> be used when resolving
+              this query.
            </para>
          </listitem>
        </varlistentry>
index c66e385f650f415fd66119e9decafbf547c3ff55..8a91671518011cbdf676e840529f74838ce98b74 100644 (file)
              so on.  The default behavior is to print the query
              statistics.
            </p></dd>
-<dt><span class="term"><code class="option">+[no]subnet=addr[/netmask]</code></span></dt>
+<dt><span class="term"><code class="option">+[no]subnet=addr[/prefix-length]</code></span></dt>
 <dd>
 <p>
              Send (don't send) an EDNS Client Subnet option with the
-              specified IP address or network prefix.
+             specified IP address or network prefix.
            </p>
 <p>
               <span class="command"><strong>dig +subnet=0.0.0.0/0</strong></span>, or simply
-              <span class="command"><strong>dig +subnet=0</strong></span> for short, sends a
-              Client Subnet option with an empty address and a
-              source prefix length of zero, which signals a resolver
-              that the EDNS Client Subnet option should not be used
-              when resolving this query.
+              <span class="command"><strong>dig +subnet=0</strong></span> for short, sends an EDNS
+              client-subnet option with an empty address and a source
+              prefix-length of zero, which signals a resolver that
+              the client's address information must
+              <span class="emphasis"><em>not</em></span> be used when resolving
+              this query.
            </p>
 </dd>
 <dt><span class="term"><code class="option">+[no]tcp</code></span></dt>
index c3f92c87fdd3106e65245eb57719216f2b27a4f5..3ca7cb9448d531fc17dcd2279d39db0bdd72b88d 100644 (file)
@@ -1065,7 +1065,7 @@ parse_netprefix(isc_sockaddr_t **sap, const char *value) {
        isc_sockaddr_t *sa = NULL;
        struct in_addr in4;
        struct in6_addr in6;
-       isc_uint32_t netmask = 0xffffffff;
+       isc_uint32_t prefix_length = 0xffffffff;
        char *slash = NULL;
        isc_boolean_t parsed = ISC_FALSE;
        char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:XXX.XXX.XXX.XXX/128")];
@@ -1076,13 +1076,16 @@ parse_netprefix(isc_sockaddr_t **sap, const char *value) {
        slash = strchr(buf, '/');
        if (slash != NULL) {
                *slash = '\0';
-               result = isc_parse_uint32(&netmask, slash + 1, 10);
+               result = isc_parse_uint32(&prefix_length, slash + 1, 10);
                if (result != ISC_R_SUCCESS) {
                        fatal("invalid prefix length in '%s': %s\n",
                              value, isc_result_totext(result));
                }
-       } else if (strcmp(value, "0") == 0) {
-               netmask = 0;
+       }
+
+       if (strcmp(buf, "0") == 0) {
+               parsed = ISC_TRUE;
+               prefix_length = 0;
        }
 
        sa = isc_mem_allocate(mctx, sizeof(*sa));
@@ -1091,14 +1094,14 @@ parse_netprefix(isc_sockaddr_t **sap, const char *value) {
        if (inet_pton(AF_INET6, buf, &in6) == 1) {
                parsed = ISC_TRUE;
                isc_sockaddr_fromin6(sa, &in6, 0);
-               if (netmask > 128)
-                       netmask = 128;
+               if (prefix_length > 128)
+                       prefix_length = 128;
        } else if (inet_pton(AF_INET, buf, &in4) == 1) {
                parsed = ISC_TRUE;
                isc_sockaddr_fromin(sa, &in4, 0);
-               if (netmask > 32)
-                       netmask = 32;
-       } else if (netmask != 0xffffffff) {
+               if (prefix_length > 32)
+                       prefix_length = 32;
+       } else if (prefix_length != 0xffffffff && prefix_length != 0) {
                int i;
 
                for (i = 0; i < 3 && strlen(buf) < sizeof(buf) - 2; i++) {
@@ -1110,14 +1113,17 @@ parse_netprefix(isc_sockaddr_t **sap, const char *value) {
                        }
                }
 
-               if (netmask > 32)
-                       netmask = 32;
+               if (prefix_length > 32)
+                       prefix_length = 32;
        }
 
        if (!parsed)
                fatal("invalid address '%s'", value);
 
-       sa->length = netmask;
+       sa->length = prefix_length;
+       if (prefix_length == 0)
+               sa->type.sa.sa_family = AF_UNSPEC;
+
        *sap = sa;
 
        return (ISC_R_SUCCESS);
@@ -2467,7 +2473,7 @@ setup_lookup(dig_lookup_t *lookup) {
                }
 
                if (lookup->ecs_addr != NULL) {
-                       isc_uint8_t addr[16], family;
+                       isc_uint8_t addr[16], family, proto;
                        isc_uint32_t plen;
                        struct sockaddr *sa;
                        struct sockaddr_in *sin;
@@ -2485,17 +2491,29 @@ setup_lookup(dig_lookup_t *lookup) {
                        opts[i].length = (isc_uint16_t) addrl + 4;
                        check_result(result, "isc_buffer_allocate");
                        isc_buffer_init(&b, ecsbuf, sizeof(ecsbuf));
-                       if (sa->sa_family == AF_INET) {
+
+                       /* If prefix length is zero, don't set family */
+                       proto = sa->sa_family;
+                       if (plen == 0)
+                               proto = AF_UNSPEC;
+
+                       switch (proto) {
+                       case AF_UNSPEC:
+                               INSIST(plen == 0);
+                               family = 0;
+                               break;
+                       case AF_INET:
                                family = 1;
                                sin = (struct sockaddr_in *) sa;
-                               memcpy(addr, &sin->sin_addr, 4);
-                               if ((plen % 8) != 0)
-                                       addr[addrl-1] &=
-                                               ~0 << (8 - (plen % 8));
-                       } else {
+                               memmove(addr, &sin->sin_addr, 4);
+                               break;
+                       case AF_INET6:
                                family = 2;
                                sin6 = (struct sockaddr_in6 *) sa;
-                               memcpy(addr, &sin6->sin6_addr, 16);
+                               memmove(addr, &sin6->sin6_addr, 16);
+                               break;
+                       default:
+                               INSIST(0);
                        }
 
                        /* Mask off last address byte */
index e0262b3aa87571d64cdc7e4065151b215024278c..a824eae8c9aa22aeffe19c0200ac617f0c526121 100644 (file)
@@ -1678,7 +1678,7 @@ process_cookie(ns_client_t *client, isc_buffer_t *buf, size_t optlen) {
        isc_buffer_t db;
 
        /*
-        * If we have already seen a ECS option skip this ECS option.
+        * If we have already seen a SIT option skip this SIT option.
         */
        if ((client->attributes & NS_CLIENTATTR_WANTSIT) != 0) {
                isc_buffer_forward(buf, (isc_uint32_t)optlen);
index d591984a3956ac871e14482e5a2b60f6aab4f8c3..c49bfa2878225704d1c3de7dbe2a5cc0caa4b78f 100644 (file)
@@ -3234,6 +3234,9 @@ render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) {
        addrlen = isc_buffer_getuint8(ecsbuf);
        scopelen = isc_buffer_getuint8(ecsbuf);
 
+       if (addrlen == 0 && family != 0)
+               return (DNS_R_OPTERR);
+
        addrbytes = (addrlen + 7) / 8;
        if (isc_buffer_remaininglength(ecsbuf) < addrbytes)
                return (DNS_R_OPTERR);
@@ -3246,15 +3249,23 @@ render_ecs(isc_buffer_t *ecsbuf, isc_buffer_t *target) {
        for (i = 0; i < addrbytes; i ++)
                addr[i] = isc_buffer_getuint8(ecsbuf);
 
-       if (family == 1) {
+       switch (family) {
+       case 0:
+               if (addrlen != 0U || scopelen != 0U)
+                       return (DNS_R_OPTERR);
+               strlcpy(addr_text, "0", sizeof(addr_text));
+               break;
+       case 1:
                if (addrlen > 32 || scopelen > 32)
                        return (DNS_R_OPTERR);
                inet_ntop(AF_INET, addr, addr_text, sizeof(addr_text));
-       } else if (family == 2) {
+               break;
+       case 2:
                if (addrlen > 128 || scopelen > 128)
                        return (DNS_R_OPTERR);
                inet_ntop(AF_INET6, addr, addr_text, sizeof(addr_text));
-       } else {
+               break;
+       default:
                snprintf(addr_text, sizeof(addr_text),
                         "Unsupported family %u", family);
                ADD_STRING(target, addr_text);
index 8a00fdb658528c3cd0b2d0b94b4e7efa836a6a09..ea0e8cd44c267ddba0367da481e852419d7495c1 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004, 2005, 2007, 2009, 2011-2015  Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2007, 2009, 2011-2016  Internet Systems Consortium, Inc. ("ISC")
  * Copyright (C) 1998-2002  Internet Software Consortium.
  *
  * Permission to use, copy, modify, and/or distribute this software for any
@@ -15,8 +15,6 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id$ */
-
 /* Reviewed: Thu Mar 16 14:06:44 PST 2000 by gson */
 
 /* RFC2671 */
@@ -135,7 +133,24 @@ fromwire_opt(ARGS_FROMWIRE) {
                        isc_region_consume(&sregion, 1);
                        scope = uint8_fromregion(&sregion);
                        isc_region_consume(&sregion, 1);
+
+                       if (addrlen == 0U && family != 0U)
+                               return (DNS_R_OPTERR);
+
                        switch (family) {
+                       case 0:
+                               /*
+                                * XXXMUKS: In queries and replies, if
+                                * FAMILY is set to 0, SOURCE
+                                * PREFIX-LENGTH and SCOPE PREFIX-LENGTH
+                                * must be 0 and ADDRESS should not be
+                                * present as the address and prefix
+                                * lengths don't make sense because the
+                                * family is unknown.
+                                */
+                               if (addrlen != 0U || scope != 0U)
+                                       return (DNS_R_OPTERR);
+                               break;
                        case 1:
                                if (addrlen > 32U || scope > 32U)
                                        return (DNS_R_OPTERR);
@@ -144,6 +159,8 @@ fromwire_opt(ARGS_FROMWIRE) {
                                if (addrlen > 128U || scope > 128U)
                                        return (DNS_R_OPTERR);
                                break;
+                       default:
+                               return (DNS_R_OPTERR);
                        }
                        addrbytes = (addrlen + 7) / 8;
                        if (addrbytes + 4 != length)
@@ -166,6 +183,11 @@ fromwire_opt(ARGS_FROMWIRE) {
                                return (DNS_R_OPTERR);
                        isc_region_consume(&sregion, length);
                        break;
+               case DNS_OPT_COOKIE:
+                       if (length != 8 && (length < 16 || length > 40))
+                               return (DNS_R_OPTERR);
+                       isc_region_consume(&sregion, length);
+                       break;
                default:
                        isc_region_consume(&sregion, length);
                        break;