]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Add dns_nsec_requiredtypespresent
authorMark Andrews <marka@isc.org>
Fri, 26 Nov 2021 22:12:08 +0000 (09:12 +1100)
committerPetr Špaček <pspacek@isc.org>
Thu, 2 Dec 2021 13:18:42 +0000 (14:18 +0100)
checks an NSEC rdataset to ensure that both NSEC and RRSIG are
present in the type map.  These types are required for the NSEC
to be valid

bin/tests/system/synthfromdnssec/ns1/minimal.db.in
bin/tests/system/synthfromdnssec/tests.sh
lib/dns/include/dns/nsec.h
lib/dns/nsec.c
lib/dns/resolver.c

index 6dd356a3cfb0abb2f9b2bbee7f9faa1a74e48a18..195062ed56900331aad9ad45fa0e81e685053c9d 100644 (file)
@@ -7,7 +7,11 @@ minimal.               3600    SOA     ns1.minimal. hostmaster.minimal. (
                                        3600       ; minimum (1 hour)
                                        )
                        3600    NS      ns1.minimal.
-                       3600    NSEC    black.minimal. NS SOA RRSIG NSEC DNSKEY
+                       3600    NSEC    badtypemap.minimal. NS SOA RRSIG NSEC DNSKEY
+; bad NSEC type map without RRSIG or NSEC
+badtypemap.minimal.    3600    NSEC    black.minimal. A
+badtypemap.minimal.    3600    A       1.2.3.4
+badtypemap.minimal.    3600    AAAA    2002::1
 ; cloudflare black lie
 black.minimal.         3600    NSEC    \000.black.minimal. RRSIG NSEC
 ;
index 125daf5f418d74c61e16b6894a4dfb55ef069e74..5a6140929495b3e3653507ed71a642feb9c96d66 100644 (file)
@@ -67,6 +67,19 @@ check_nosynth_a() (
     return 0
 )
 
+check_synth_aaaa() (
+    name=$(echo "$1" | sed 's/\./\\./g')
+    grep "^${name}.*[0-9]*.IN.AAAA" ${2} > /dev/null || return 1
+    grep "^${name}.*3600.IN.A" ${2} > /dev/null && return 1
+    return 0
+)
+
+check_nosynth_aaaa() (
+    name=$(echo "$1" | sed 's/\./\\./g')
+    grep "^${name}.*3600.IN.AAAA" ${2} > /dev/null || return 1
+    return 0
+)
+
 check_synth_cname() (
     name=$(echo "$1" | sed 's/\./\\./g')
     grep "^${name}.*[0-9]*.IN.CNAME" ${2} > /dev/null || return 1
@@ -200,6 +213,17 @@ do
     n=$((n+1))
     if [ $ret != 0 ]; then echo_i "failed"; fi
     status=$((status+ret))
+
+    echo_i "prime bad type map NODATA response (synth-from-dnssec ${description};) ($n)"
+    ret=0
+    dig_with_opts badtypemap.minimal. @10.53.0.${ns} TXT > dig.out.ns${ns}.test$n || ret=1
+    check_ad_flag $ad dig.out.ns${ns}.test$n || ret=1
+    check_status NOERROR dig.out.ns${ns}.test$n || ret=1
+    check_nosynth_soa minimal. dig.out.ns${ns}.test$n || ret=1
+    grep 'badtypemap.minimal.*3600.IN.NSEC.black.minimal. A$' dig.out.ns${ns}.test$n > /dev/null || ret=1
+    n=$((n+1))
+    if [ $ret != 0 ]; then echo_i "failed"; fi
+    status=$((status+ret))
 done
 
 echo_i "prime redirect response (+nodnssec) (synth-from-dnssec <default>;) ($n)"
@@ -388,6 +412,27 @@ do
     if [ $ret != 0 ]; then echo_i "failed"; fi
     status=$((status+ret))
 
+    echo_i "check bad type map NODATA response (synth-from-dnssec ${description};) ($n)"
+    ret=0
+    dig_with_opts badtypemap.minimal. @10.53.0.${ns} HINFO > dig.out.ns${ns}.test$n || ret=1
+    check_ad_flag $ad dig.out.ns${ns}.test$n || ret=1
+    check_status NOERROR dig.out.ns${ns}.test$n || ret=1
+    check_nosynth_soa minimal. dig.out.ns${ns}.test$n || ret=1
+    grep 'badtypemap.minimal.*3600.IN.NSEC.black.minimal. A$' dig.out.ns${ns}.test$n > /dev/null || ret=1
+    n=$((n+1))
+    if [ $ret != 0 ]; then echo_i "failed"; fi
+    status=$((status+ret))
+
+    echo_i "check bad type map NODATA response with existent data (synth-from-dnssec ${description};) ($n)"
+    ret=0
+    dig_with_opts badtypemap.minimal. @10.53.0.${ns} AAAA > dig.out.ns${ns}.test$n || ret=1
+    check_ad_flag $ad dig.out.ns${ns}.test$n || ret=1
+    check_status NOERROR dig.out.ns${ns}.test$n || ret=1
+    check_nosynth_aaaa badtypemap.minimal. dig.out.ns${ns}.test$n || ret=1
+    n=$((n+1))
+    if [ $ret != 0 ]; then echo_i "failed"; fi
+    status=$((status+ret))
+
     echo_i "check 'rndc stats' output for 'covering nsec returned' (synth-from-dnssec ${description};) ($n)"
     ret=0
     ${RNDCCMD} 10.53.0.${ns} stats 2>&1 | sed 's/^/ns6 /' | cat_i
index f6844cf82cb9e44b96302bab95d6d0708d78576a..7aae7e8ccb875546a79507cb106c5e5fd7ca74ee 100644 (file)
@@ -106,4 +106,14 @@ dns_nsec_noexistnodata(dns_rdatatype_t type, const dns_name_t *name,
  * Return ISC_R_IGNORE when the NSEC is not the appropriate one.
  */
 
+bool
+dns_nsec_requiredtypespresent(dns_rdataset_t *rdataset);
+/*
+ * Return true if all the NSEC records in rdataset have both
+ * NSEC and RRSIG present.
+ *
+ * Requires:
+ * \li rdataset to be a NSEC rdataset.
+ */
+
 ISC_LANG_ENDDECLS
index cbb27d60621d4faded0db50d0d721f155f1ee580..95af49c3a2d875b293b84a7003b8cdf2cae4ad82 100644 (file)
@@ -460,3 +460,32 @@ dns_nsec_noexistnodata(dns_rdatatype_t type, const dns_name_t *name,
        *exists = false;
        return (ISC_R_SUCCESS);
 }
+
+bool
+dns_nsec_requiredtypespresent(dns_rdataset_t *nsecset) {
+       dns_rdataset_t rdataset;
+       isc_result_t result;
+       bool found = false;
+
+       REQUIRE(DNS_RDATASET_VALID(nsecset));
+       REQUIRE(nsecset->type == dns_rdatatype_nsec);
+
+       dns_rdataset_init(&rdataset);
+       dns_rdataset_clone(nsecset, &rdataset);
+
+       for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS;
+            result = dns_rdataset_next(&rdataset))
+       {
+               dns_rdata_t rdata = DNS_RDATA_INIT;
+               dns_rdataset_current(&rdataset, &rdata);
+               if (!dns_nsec_typepresent(&rdata, dns_rdatatype_nsec) ||
+                   !dns_nsec_typepresent(&rdata, dns_rdatatype_rrsig))
+               {
+                       dns_rdataset_disassociate(&rdataset);
+                       return (false);
+               }
+               found = true;
+       }
+       dns_rdataset_disassociate(&rdataset);
+       return (found);
+}
index 6c6c67d5aaee1c983ed3e1f10c422cb169c7130a..f98295bf1235594f11735e01174ef176b3f1d72a 100644 (file)
@@ -5572,6 +5572,15 @@ answer_response:
                                continue;
                        }
 
+                       /*
+                        * Don't cache NSEC if missing NSEC or RRSIG types.
+                        */
+                       if (rdataset->type == dns_rdatatype_nsec &&
+                           !dns_nsec_requiredtypespresent(rdataset))
+                       {
+                               continue;
+                       }
+
                        /*
                         * Don't cache "white lies" but do cache
                         * "black lies".