]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
The validator didn't handle missing DS records correctly.
authorMark Andrews <marka@isc.org>
Fri, 19 Jul 2002 03:29:15 +0000 (03:29 +0000)
committerMark Andrews <marka@isc.org>
Fri, 19 Jul 2002 03:29:15 +0000 (03:29 +0000)
lib/dns/include/dns/ncache.h
lib/dns/ncache.c
lib/dns/validator.c

index 3436ce4fc96a9528c60f186e5585fb172f3ba4a6..67dc4019907dc5a7c6c7858027f05e327276f009 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: ncache.h,v 1.15 2002/02/20 03:34:35 marka Exp $ */
+/* $Id: ncache.h,v 1.16 2002/07/19 03:29:15 marka Exp $ */
 
 #ifndef DNS_NCACHE_H
 #define DNS_NCACHE_H 1
@@ -125,6 +125,34 @@ dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx,
  *     dns_name_towire().
  */
 
+isc_result_t
+dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
+                      dns_rdatatype_t type, dns_rdataset_t *rdataset);
+/*
+ * Search the negative caching rdataset for an rdataset with the
+ * specified name and type.
+ *
+ * Requires:
+ *     'ncacherdataset' is a valid negative caching rdataset.
+ *
+ *     'ncacherdataset' is not empty.
+ *
+ *     'name' is a valid name.
+ *
+ *     'type' is not SIG, or a meta-RR type.
+ *
+ *     'rdataset' is a valid disassociated rdataset.
+ *
+ * Ensures:
+ *     On a return of ISC_R_SUCCESS, 'rdataset' is bound to the found
+ *     rdataset.
+ *
+ * Returns:
+ *     ISC_R_SUCCESS           - the rdataset was found.
+ *     ISC_R_NOTFOUND          - the rdataset was not found.
+ *
+ */
+
 ISC_LANG_ENDDECLS
 
 #endif /* DNS_NCACHE_H */
index 7446dd0002ab8fbd5e9a21ecf80baf10f9c28ba2..d15a65bf3e8eb0d7bf5054c9c7794abc88abba6d 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: ncache.c,v 1.29 2002/02/20 03:34:15 marka Exp $ */
+/* $Id: ncache.c,v 1.30 2002/07/19 03:29:15 marka Exp $ */
 
 #include <config.h>
 
@@ -378,3 +378,170 @@ dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx,
 
        return (result);
 }
+
+static void
+rdataset_disassociate(dns_rdataset_t *rdataset) {
+       UNUSED(rdataset);
+}
+
+static isc_result_t
+rdataset_first(dns_rdataset_t *rdataset) {
+       unsigned char *raw = rdataset->private3;
+       unsigned int count;
+
+       count = raw[0] * 256 + raw[1];
+       if (count == 0) {
+               rdataset->private5 = NULL;
+               return (ISC_R_NOMORE);
+       }
+       raw += 2;
+       /*
+        * The private4 field is the number of rdata beyond the cursor
+        * position, so we decrement the total count by one before storing
+        * it.
+        */
+       count--;
+       rdataset->private4 = (void *)count;
+       rdataset->private5 = raw;
+
+       return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+rdataset_next(dns_rdataset_t *rdataset) {
+       unsigned int count;
+       unsigned int length;
+       unsigned char *raw;
+
+       count = (unsigned int)rdataset->private4;
+       if (count == 0)
+               return (ISC_R_NOMORE);
+       count--;
+       rdataset->private4 = (void *)count;
+       raw = rdataset->private5;
+       length = raw[0] * 256 + raw[1];
+       raw += length + 2;
+       rdataset->private5 = raw;
+
+       return (ISC_R_SUCCESS);
+}
+
+static void
+rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
+       unsigned char *raw = rdataset->private5;
+       isc_region_t r;
+
+       REQUIRE(raw != NULL);
+
+       r.length = raw[0] * 256 + raw[1];
+       raw += 2;
+       r.base = raw;
+       dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
+}
+
+static void
+rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
+       *target = *source;
+
+       /*
+        * Reset iterator state.
+        */
+       target->private4 = NULL;
+       target->private5 = NULL;
+}
+
+static unsigned int
+rdataset_count(dns_rdataset_t *rdataset) {
+       unsigned char *raw = rdataset->private3;
+       unsigned int count;
+
+       count = raw[0] * 256 + raw[1];
+
+       return (count);
+}
+
+static dns_rdatasetmethods_t rdataset_methods = {
+       rdataset_disassociate,
+       rdataset_first,
+       rdataset_next,
+       rdataset_current,
+       rdataset_clone,
+       rdataset_count
+};
+
+isc_result_t
+dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
+                      dns_rdatatype_t type, dns_rdataset_t *rdataset)
+{
+       isc_result_t result;
+       dns_rdata_t rdata = DNS_RDATA_INIT;
+       isc_region_t remaining;
+       isc_buffer_t source;
+       dns_name_t tname;
+       dns_rdatatype_t ttype;
+       unsigned int i, rcount;
+       isc_uint16_t length;
+
+       REQUIRE(ncacherdataset != NULL);
+       REQUIRE(ncacherdataset->type == 0);
+       REQUIRE(name != NULL);
+       REQUIRE(!dns_rdataset_isassociated(rdataset));
+       REQUIRE(type != dns_rdatatype_sig);
+
+       result = dns_rdataset_first(ncacherdataset);
+       if (result != ISC_R_SUCCESS)
+               return (result);
+       dns_rdataset_current(ncacherdataset, &rdata);
+       INSIST(dns_rdataset_next(ncacherdataset) == ISC_R_NOMORE);
+       isc_buffer_init(&source, rdata.data, rdata.length);
+       isc_buffer_add(&source, rdata.length);
+
+       do {
+               dns_name_init(&tname, NULL);
+               isc_buffer_remainingregion(&source, &remaining);
+               dns_name_fromregion(&tname, &remaining);
+               INSIST(remaining.length >= tname.length);
+               isc_buffer_forward(&source, tname.length);
+               remaining.length -= tname.length;
+
+               INSIST(remaining.length >= 4);
+               ttype = isc_buffer_getuint16(&source);
+
+               if (ttype == type && dns_name_equal(&tname, name)) {
+                       isc_buffer_remainingregion(&source, &remaining);
+                       break;
+               }
+
+               rcount = isc_buffer_getuint16(&source);
+               for (i = 0; i < rcount; i++) {
+                       isc_buffer_remainingregion(&source, &remaining);
+                       INSIST(remaining.length >= 2);
+                       length = isc_buffer_getuint16(&source);
+                       isc_buffer_remainingregion(&source, &remaining);
+                       INSIST(remaining.length >= length);
+                       isc_buffer_forward(&source, length);
+               }
+               isc_buffer_remainingregion(&source, &remaining);
+       } while (remaining.length > 0);
+
+       if (remaining.length == 0)
+               return (ISC_R_NOTFOUND);
+
+       rdataset->methods = &rdataset_methods;
+       rdataset->rdclass = ncacherdataset->rdclass;
+       rdataset->type = type;
+       rdataset->covers = 0;
+       rdataset->ttl = ncacherdataset->ttl;
+       rdataset->trust = ncacherdataset->trust;
+       rdataset->private1 = NULL;
+       rdataset->private2 = NULL;
+
+       rdataset->private3 = remaining.base;
+
+       /*
+        * Reset iterator state.
+        */
+       rdataset->private4 = NULL;
+       rdataset->private5 = NULL;
+       return (ISC_R_SUCCESS);
+}
index e25ab8877b883f924582713aa8fe2c03421672ff..acb084e6569999ac9d08bded7bc30b856ebb1dab 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: validator.c,v 1.108 2002/07/15 03:25:28 marka Exp $ */
+/* $Id: validator.c,v 1.109 2002/07/19 03:29:15 marka Exp $ */
 
 #include <config.h>
 
@@ -31,6 +31,7 @@
 #include <dns/keytable.h>
 #include <dns/log.h>
 #include <dns/message.h>
+#include <dns/ncache.h>
 #include <dns/nxt.h>
 #include <dns/rdata.h>
 #include <dns/rdatastruct.h>
@@ -42,7 +43,7 @@
 #include <dns/view.h>
 
 #define VALIDATOR_MAGIC                        ISC_MAGIC('V', 'a', 'l', '?')
-#define VALID_VALIDATOR(v)             ISC_MAGIC_VALID(v, VALIDATOR_MAGIC)
+#define VALID_VALIDATOR(v)             ISC_MAGIC_VALID(v, VALIDATOR_MAGIC)
 
 #define VALATTR_SHUTDOWN               0x01
 #define VALATTR_FOUNDNONEXISTENCE      0x02
@@ -142,6 +143,39 @@ auth_nonpending(dns_message_t *message) {
        }
 }
 
+static isc_boolean_t
+isdelegation(dns_name_t *name, dns_rdataset_t *rdataset,
+            isc_result_t dbresult)
+{
+       dns_rdataset_t set;
+       dns_rdata_t rdata = DNS_RDATA_INIT;
+       isc_boolean_t found;
+       isc_result_t result;
+
+       REQUIRE(dbresult == DNS_R_NXRRSET || dbresult == DNS_R_NCACHENXRRSET);
+
+       dns_rdataset_init(&set);
+       if (dbresult == DNS_R_NXRRSET)
+               dns_rdataset_clone(rdataset, &set);
+       else {
+               result = dns_ncache_getrdataset(rdataset, name,
+                                               dns_rdatatype_nxt, &set);
+               if (result != ISC_R_SUCCESS)
+                       return (ISC_FALSE);
+       }
+
+       INSIST(set.type == dns_rdatatype_nxt);
+
+       found = ISC_FALSE;
+       result = dns_rdataset_first(&set);
+       if (result == ISC_R_SUCCESS) {
+               dns_rdataset_current(&set, &rdata);
+               found = dns_nxt_typepresent(&rdata, dns_rdatatype_ns);
+       }
+       dns_rdataset_disassociate(&set);
+       return (found);
+}
+
 static void
 fetch_callback_validator(isc_task_t *task, isc_event_t *event) {
        dns_fetchevent_t *devent;
@@ -256,6 +290,7 @@ dsfetched2(isc_task_t *task, isc_event_t *event) {
        dns_fetchevent_t *devent;
        dns_validator_t *val;
        dns_rdataset_t *rdataset;
+       dns_name_t *tname;
        isc_boolean_t want_destroy;
        isc_result_t result;
        isc_result_t eresult;
@@ -267,7 +302,6 @@ dsfetched2(isc_task_t *task, isc_event_t *event) {
        rdataset = &val->frdataset;
        eresult = devent->result;
 
-       isc_event_free(&event);
        dns_resolver_destroyfetch(&val->fetch);
 
        INSIST(val->event != NULL);
@@ -276,10 +310,17 @@ dsfetched2(isc_task_t *task, isc_event_t *event) {
        LOCK(&val->lock);
        if (eresult == DNS_R_NXRRSET || eresult == DNS_R_NCACHENXRRSET) {
                /*
-                * There is no DS.  We're done.
+                * There is no DS.  If this is a delegation, we're done.
                 */
-               val->event->rdataset->trust = dns_trust_answer;
-               validator_done(val, ISC_R_SUCCESS);
+               tname = dns_fixedname_name(&devent->foundname);
+               if (isdelegation(tname, &val->frdataset, eresult)) {
+                       val->event->rdataset->trust = dns_trust_answer;
+                       validator_done(val, ISC_R_SUCCESS);
+               } else {
+                       result = proveunsecure(val, ISC_TRUE);
+                       if (result != DNS_R_WAIT)
+                               validator_done(val, result);
+               }
        } else if (eresult == ISC_R_SUCCESS ||
                   eresult == DNS_R_NXDOMAIN ||
                   eresult == DNS_R_NCACHENXDOMAIN)
@@ -296,6 +337,7 @@ dsfetched2(isc_task_t *task, isc_event_t *event) {
                else
                        validator_done(val, DNS_R_NOVALIDDS);
        }
+       isc_event_free(&event);
        want_destroy = exit_check(val);
        UNLOCK(&val->lock);
        if (want_destroy)
@@ -1480,7 +1522,8 @@ proveunsecure(dns_validator_t *val, isc_boolean_t resume) {
                result = view_find(val, tname, dns_rdatatype_ds);
                if (result == DNS_R_NXRRSET || result == DNS_R_NCACHENXRRSET) {
                        /*
-                        * There is no DS.  We're hopefully done.
+                        * There is no DS.  If this is a delegation,
+                        * we're done.
                         */
                        if (val->frdataset.trust < dns_trust_secure) {
                                /*
@@ -1492,11 +1535,14 @@ proveunsecure(dns_validator_t *val, isc_boolean_t resume) {
                                result = DNS_R_NOVALIDSIG;
                                goto out;
                        }
-                       val->event->rdataset->trust = dns_trust_answer;
-                       return (ISC_R_SUCCESS);
+                       if (isdelegation(tname, &val->frdataset, result)) {
+                               val->event->rdataset->trust = dns_trust_answer;
+                               return (ISC_R_SUCCESS);
+                       }
+                       continue;
                } else if (result == ISC_R_SUCCESS) {
                        /*
-                        * There is a DS here.  Verify that it's secure and
+                        * There is a DS here.  Verify that it's secure and
                         * continue.
                         */
                        if (val->frdataset.trust >= dns_trust_secure)
@@ -1518,7 +1564,7 @@ proveunsecure(dns_validator_t *val, isc_boolean_t resume) {
                           result == DNS_R_NCACHENXDOMAIN)
                {
                        /*
-                        * This is not a zone cut.  Assuming things are
+                        * This is not a zone cut.  Assuming things are
                         * as expected, continue.
                         */
                        if (!dns_rdataset_isassociated(&val->frdataset)) {