]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
3644. [protocol] Check that EDNS subnet client options are well forme
authorMark Andrews <marka@isc.org>
Wed, 18 Sep 2013 01:26:26 +0000 (11:26 +1000)
committerMark Andrews <marka@isc.org>
Wed, 18 Sep 2013 01:50:28 +0000 (11:50 +1000)
                            [RT #34718]

    (cherry picked from commit 3ad8f24ddd043148525b68a676ebdc71f6900ca9)

Conflicts:
lib/dns/tests/rdata_test.c

CHANGES
lib/dns/include/dns/message.h
lib/dns/rdata.c
lib/dns/rdata/generic/opt_41.c
lib/dns/tests/Makefile.in
lib/dns/tests/rdata_test.c [new file with mode: 0644]

diff --git a/CHANGES b/CHANGES
index b347ba63e5741e23ede9a497fff03ad9e7b89eda..2c8056bd801dc3451bb9d5ac59d699b6eca04042 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -4,6 +4,9 @@
 3646.  [bug]           Journal filename string could be set incorrectly,
                        causing garbage in log messages. [RT #34738]
 
+3644.  [protocol]      Check that EDNS subnet client options are well formed.
+                       [RT #34718]
+
 3641.  [bug]           Handle changes to sig-validity-interval settings
                        better. [RT #34625]
                        
index 54d5a41b66f618a279c57790bf6fa27e2623b32e..f054f9bc6edba5e6f16e21ae58708e3a1c5733a0 100644 (file)
 
 /*%< EDNS0 extended OPT codes */
 #define DNS_OPT_NSID           0x0003          /*%< NSID opt code */
+#define DNS_OPT_CLIENT_SUBNET  0x0008          /*%< client subnet opt code */
 
 #define DNS_MESSAGE_REPLYPRESERVE      (DNS_MESSAGEFLAG_RD|DNS_MESSAGEFLAG_CD)
 #define DNS_MESSAGEEXTFLAG_REPLYPRESERVE (DNS_MESSAGEEXTFLAG_DO)
index 55a5f7f8df843888479a9b7a6f95acdb00a91cf4..7e17e3c505fe0d7411119125eff7876334c4f6b4 100644 (file)
@@ -36,6 +36,7 @@
 #include <dns/enumtype.h>
 #include <dns/keyflags.h>
 #include <dns/keyvalues.h>
+#include <dns/message.h>
 #include <dns/rcode.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
index aa2e43922a99c81e2c5b8f491664df0bb0cfc3be..ce7e60780b2a90581229252bea4c584052ea819d 100644 (file)
@@ -93,6 +93,7 @@ static inline isc_result_t
 fromwire_opt(ARGS_FROMWIRE) {
        isc_region_t sregion;
        isc_region_t tregion;
+       isc_uint16_t opt;
        isc_uint16_t length;
        unsigned int total;
 
@@ -108,17 +109,48 @@ fromwire_opt(ARGS_FROMWIRE) {
        while (sregion.length != 0) {
                if (sregion.length < 4)
                        return (ISC_R_UNEXPECTEDEND);
-               /*
-                * Eat the 16bit option code.  There is nothing to
-                * be done with it currently.
-                */
+               opt = uint16_fromregion(&sregion);
                isc_region_consume(&sregion, 2);
                length = uint16_fromregion(&sregion);
                isc_region_consume(&sregion, 2);
                total += 4;
                if (sregion.length < length)
                        return (ISC_R_UNEXPECTEDEND);
-               isc_region_consume(&sregion, length);
+               switch (opt) {
+               case DNS_OPT_CLIENT_SUBNET: {
+                       isc_uint16_t family;
+                       isc_uint8_t addrlen;
+                       isc_uint8_t scope;
+                       isc_uint8_t addrbytes;
+
+                       if (length < 4)
+                               return (DNS_R_FORMERR);
+                       family = uint16_fromregion(&sregion);
+                       isc_region_consume(&sregion, 2);
+                       addrlen = uint8_fromregion(&sregion);
+                       isc_region_consume(&sregion, 1);
+                       scope = uint8_fromregion(&sregion);
+                       isc_region_consume(&sregion, 1);
+                       switch (family) {
+                       case 1:
+                               if (addrlen > 32U || scope > 32U)
+                                       return (DNS_R_FORMERR);
+                               break;
+                       case 2:
+                               if (addrlen > 128U || scope > 128U)
+                                       return (DNS_R_FORMERR);
+                               break;
+                       }
+                       addrbytes = (addrlen + 7) / 8;
+                       if (addrbytes + 4 != length)
+                               return (DNS_R_FORMERR);
+                       isc_region_consume(&sregion, addrbytes);
+                       break;
+               }
+               default:
+                       isc_region_consume(&sregion, length);
+                       break;
+               }
                total += length;
        }
 
index 6dc9b9f4dadaa951b3dcaa629ca2b09afef185c7..c2e999ccaa73ee6ebb9e2745a07d2483c185c622 100644 (file)
@@ -38,11 +38,12 @@ LIBS =              @LIBS@ @ATFLIBS@
 
 OBJS =         dnstest.@O@
 SRCS =         dnstest.c master_test.c time_test.c dbiterator_test.c \
-               dbversion_test.c zonemgr_test.c nsec3_test.c
+               dbversion_test.c zonemgr_test.c nsec3_test.c rdata_test.c
 
 SUBDIRS =
 TARGETS =      master_test@EXEEXT@ time_test@EXEEXT@ dbiterator_test@EXEEXT@ \
-               dbversion_test@EXEEXT@ zonemgr_test@EXEEXT@ nsec3_test@EXEEXT@
+               dbversion_test@EXEEXT@ zonemgr_test@EXEEXT@ nsec3_test@EXEEXT@ \
+               rdata_test@EXEEXT@
 
 @BIND9_MAKE_RULES@
 
diff --git a/lib/dns/tests/rdata_test.c b/lib/dns/tests/rdata_test.c
new file mode 100644 (file)
index 0000000..7f226a0
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2012  Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id$ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <unistd.h>
+
+#include <isc/types.h>
+
+#include <dns/compress.h>
+#include <dns/rdata.h>
+
+#include "dnstest.h"
+
+
+/*
+ * Individual unit tests
+ */
+
+/* Successful load test */
+ATF_TC(hip);
+ATF_TC_HEAD(hip, tc) {
+       atf_tc_set_md_var(tc, "descr", "that a oversized HIP record will "
+                                      "be rejected");
+}
+ATF_TC_BODY(hip, tc) {
+       unsigned char hipwire[DNS_RDATA_MAXLENGTH] = {
+                                   0x01, 0x00, 0x00, 0x01, 0x00, 0x00,
+                                   0x04, 0x41, 0x42, 0x43, 0x44, 0x00 };
+       unsigned char buf[1024*1024];
+       isc_buffer_t source, target;
+       dns_rdata_t rdata;
+       dns_decompress_t dctx;
+       isc_result_t result;
+       size_t i;
+
+       UNUSED(tc);
+
+       /*
+        * Fill the rest of input buffer with compression pointers.
+        */
+       for (i = 12; i < sizeof(hipwire) - 2; i += 2) {
+               hipwire[i] = 0xc0;
+               hipwire[i+1] = 0x06;
+       }
+
+       isc_buffer_init(&source, hipwire, sizeof(hipwire));
+       isc_buffer_add(&source, sizeof(hipwire));
+       isc_buffer_setactive(&source, i);
+       isc_buffer_init(&target, buf, sizeof(buf));
+       dns_rdata_init(&rdata);
+       dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
+       result = dns_rdata_fromwire(&rdata, dns_rdataclass_in,
+                                   dns_rdatatype_hip, &source, &dctx,
+                                   0, &target);
+       dns_decompress_invalidate(&dctx);
+       ATF_REQUIRE_EQ(result, DNS_R_FORMERR);
+}
+
+ATF_TC(edns_client_subnet);
+ATF_TC_HEAD(edns_client_subnet, tc) {
+       atf_tc_set_md_var(tc, "descr",
+                         "check EDNS client subnet option parsing");
+}
+ATF_TC_BODY(edns_client_subnet, tc) {
+       struct {
+               unsigned char data[64];
+               size_t len;
+               isc_boolean_t ok;
+       } test_data[] = {
+               {
+                       /* option code with no content */
+                       { 0x00, 0x08, 0x0, 0x00 }, 4, ISC_FALSE
+               },
+               {
+                       /* Option code family 0, source 0, scope 0 */
+                       {
+                         0x00, 0x08, 0x00, 0x04,
+                         0x00, 0x00, 0x00, 0x00
+                       },
+                       8, ISC_TRUE
+               },
+               {
+                       /* Option code family 1 (ipv4), source 0, scope 0 */
+                       {
+                         0x00, 0x08, 0x00, 0x04,
+                         0x00, 0x01, 0x00, 0x00
+                       },
+                       8, ISC_TRUE
+               },
+               {
+                       /* Option code family 2 (ipv6) , source 0, scope 0 */
+                       {
+                         0x00, 0x08, 0x00, 0x04,
+                         0x00, 0x02, 0x00, 0x00
+                       },
+                       8, ISC_TRUE
+               },
+               {
+                       /* extra octet */
+                       {
+                         0x00, 0x08, 0x00, 0x05,
+                         0x00, 0x00, 0x00, 0x00,
+                         0x00
+                       },
+                       9, ISC_FALSE
+               },
+               {
+                       /* source too long for IPv4 */
+                       {
+                         0x00, 0x08, 0x00,    8, 
+                         0x00, 0x01,   33, 0x00,
+                         0x00, 0x00, 0x00, 0x00
+                       },
+                       12, ISC_FALSE
+               },
+               {
+                       /* source too long for IPv6 */
+                       {
+                         0x00, 0x08, 0x00,   20,
+                         0x00, 0x02,  129, 0x00,
+                         0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00,
+                       },
+                       24, ISC_FALSE
+               },
+               {
+                       /* scope too long for IPv4 */
+                       {
+                         0x00, 0x08, 0x00,    8, 
+                         0x00, 0x01, 0x00,   33,
+                         0x00, 0x00, 0x00, 0x00
+                       },
+                       12, ISC_FALSE
+               },
+               {
+                       /* scope too long for IPv6 */
+                       {
+                         0x00, 0x08, 0x00,   20,
+                         0x00, 0x02, 0x00,  129,
+                         0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00,
+                       },
+                       24, ISC_FALSE
+               },
+               {
+                       /* length too short for source generic */
+                       {
+                         0x00, 0x08, 0x00,    5, 
+                         0x00, 0x00,   17, 0x00,
+                         0x00, 0x00, 
+                       },
+                       19, ISC_FALSE
+               },
+               {
+                       /* length too short for source ipv4 */
+                       {
+                         0x00, 0x08, 0x00,    7, 
+                         0x00, 0x01,   32, 0x00,
+                         0x00, 0x00, 0x00, 0x00
+                       },
+                       11, ISC_FALSE
+               },
+               {
+                       /* length too short for source ipv6 */
+                       {
+                         0x00, 0x08, 0x00,   19,
+                         0x00, 0x02,  128, 0x00,
+                         0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00,
+                         0x00, 0x00, 0x00, 0x00,
+                       },
+                       23, ISC_FALSE
+               },
+               {
+                       /* sentinal */
+                       { 0x00 }, 0, ISC_FALSE
+               }
+       };
+       unsigned char buf[1024*1024];
+       isc_buffer_t source, target;
+       dns_rdata_t rdata;
+       dns_decompress_t dctx;
+       isc_result_t result;
+       size_t i;
+
+       UNUSED(tc);
+
+       for (i = 0; test_data[i].len != 0; i++) {
+               isc_buffer_init(&source, test_data[i].data, test_data[i].len);
+               isc_buffer_add(&source, test_data[i].len);
+               isc_buffer_setactive(&source, test_data[i].len);
+               isc_buffer_init(&target, buf, sizeof(buf));
+               dns_rdata_init(&rdata);
+               dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_ANY);
+               result = dns_rdata_fromwire(&rdata, dns_rdataclass_in,
+                                           dns_rdatatype_opt, &source,
+                                           &dctx, 0, &target);
+               dns_decompress_invalidate(&dctx);
+               if (test_data[i].ok) 
+                       ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+               else
+                       ATF_REQUIRE(result != ISC_R_SUCCESS);
+       }
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+       ATF_TP_ADD_TC(tp, hip);
+       ATF_TP_ADD_TC(tp, edns_client_subnet);
+
+       return (atf_no_error());
+}
+