]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
1606. [bug] DVL insecurity proof was failing.
authorMark Andrews <marka@isc.org>
Fri, 14 May 2004 04:45:58 +0000 (04:45 +0000)
committerMark Andrews <marka@isc.org>
Fri, 14 May 2004 04:45:58 +0000 (04:45 +0000)
1605.   [func]          New dns_db_find() option DNS_DBFIND_COVERINGNSEC.

CHANGES
lib/dns/include/dns/db.h
lib/dns/include/dns/result.h
lib/dns/include/dns/validator.h
lib/dns/rbtdb.c
lib/dns/resolver.c
lib/dns/result.c
lib/dns/validator.c
util/copyrights

diff --git a/CHANGES b/CHANGES
index 148fcace27443962b01f4e270f43570b942ffeef..34b2b9ead9c6c5a1083e186f992ad9e20fa8b600 100644 (file)
--- a/CHANGES
+++ b/CHANGES
 1607.  [bug]           dig, host and nslookup were still using random()
                        to generate query ids. [RT# 11013]
 
-1606.  [placeholder]   rt10440a
+1606.  [bug]           DVL insecurity proof was failing.
+
+1605.  [func]          New dns_db_find() option DNS_DBFIND_COVERINGNSEC.
 
-1605.  [placeholder]   rt10440a
 
 1604.  [bug]           A xfrout_ctx_create() failure would result in
                        xfrout_ctx_destroy() being called with a
index b62541f60fe74beb93dbf364ecfb1ce7d6af8b95..b4c7261da58fbfe6b0c46e0a78a948112dac112d 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: db.h,v 1.76 2004/03/05 05:09:41 marka Exp $ */
+/* $Id: db.h,v 1.77 2004/05/14 04:45:57 marka Exp $ */
 
 #ifndef DNS_DB_H
 #define DNS_DB_H 1
@@ -188,6 +188,7 @@ struct dns_db {
 #define DNS_DBFIND_PENDINGOK           0x08
 #define DNS_DBFIND_NOEXACT             0x10
 #define DNS_DBFIND_FORCENSEC           0x20
+#define DNS_DBFIND_COVERINGNSEC                0x40
 
 /*
  * Options that can be specified for dns_db_addrdataset().
@@ -647,6 +648,12 @@ dns_db_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
  *     is only necessary when querying a database that was not secure
  *     when created.
  *
+ *     If the DNS_DBFIND_COVERINGNSEC option is set, then look for a
+ *     NSEC record that potentially covers 'name' if a answer cannot
+ *     be found.  Note the returned NSEC needs to be checked to ensure
+ *     that it is correct.  This only affects answers returned from the
+ *     cache.
+ *
  *     To respond to a query for SIG records, the caller should create a
  *     rdataset iterator and extract the signatures from each rdataset.
  *
@@ -770,6 +777,9 @@ dns_db_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
  *             DNS_R_EMPTYNAME                 The name exists but there is
  *                                             no data at the name. 
  *
+ *             DNS_R_COVERINGNSEC              The returned data is a NSEC
+ *                                             that potentially covers 'name'.
+ *
  *     Error results:
  *
  *             ISC_R_NOMEMORY
index a41fbfa80f1ee0d7ffcb4748361082adaed7d29d..c134a9f398dfe3918e239fe389b145d166e5b764 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: result.h,v 1.105 2004/04/15 23:40:26 marka Exp $ */
+/* $Id: result.h,v 1.106 2004/05/14 04:45:58 marka Exp $ */
 
 #ifndef DNS_RESULT_H
 #define DNS_RESULT_H 1
 #define DNS_R_DYNAMIC                  (ISC_RESULTCLASS_DNS + 98)
 #define DNS_R_UNKNOWNCOMMAND           (ISC_RESULTCLASS_DNS + 99)
 #define DNS_R_MUSTBESECURE             (ISC_RESULTCLASS_DNS + 100)
+#define DNS_R_COVERINGNSEC             (ISC_RESULTCLASS_DNS + 101)
 
-#define DNS_R_NRESULTS                 101     /* Number of results */
+#define DNS_R_NRESULTS                 102     /* Number of results */
 
 /*
  * DNS wire format rcodes.
index 59d2aefe336e5ab8bd3012f1e49b5e7bb2a5f2f5..21be023d71a62fc92d35c346ae6b63c3a3dad8a0 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: validator.h,v 1.28 2004/04/15 23:40:26 marka Exp $ */
+/* $Id: validator.h,v 1.29 2004/05/14 04:45:58 marka Exp $ */
 
 #ifndef DNS_VALIDATOR_H
 #define DNS_VALIDATOR_H 1
@@ -121,6 +121,8 @@ struct dns_validator {
        dns_fixedname_t                 wild;
        ISC_LINK(dns_validator_t)       link;
        dns_rdataset_t *                dlv;
+       dns_fixedname_t                 dlvsep;
+       isc_boolean_t                   havedlvsep;
        isc_boolean_t                   mustbesecure;
 };
 
index 0c85c8238c251b17983b925cb48a8dde817c8e2e..48440fdf06a4db4c663561452896c042084d4c78 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rbtdb.c,v 1.198 2004/05/14 01:05:53 marka Exp $ */
+/* $Id: rbtdb.c,v 1.199 2004/05/14 04:45:56 marka Exp $ */
 
 /*
  * Principal Author: Bob Halley
@@ -842,8 +842,7 @@ clean_zone_node(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
                        /*
                         * If this is a NONEXISTENT rdataset, we can delete it.
                         */
-                       if ((current->attributes & RDATASET_ATTR_NONEXISTENT)
-                           != 0) {
+                       if (NONEXISTENT(current)) {
                                if (top_prev != NULL)
                                        top_prev->next = current->next;
                                else
@@ -1931,8 +1930,7 @@ find_closest_nsec(rbtdb_search_t *search, dns_dbnode_t **nodep,
                                         * Is this a "this rdataset doesn't
                                         * exist" record?
                                         */
-                                       if ((header->attributes &
-                                            RDATASET_ATTR_NONEXISTENT) != 0)
+                                       if (NONEXISTENT(header))
                                                header = NULL;
                                        break;
                                } else
@@ -2204,8 +2202,7 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
                                 * Is this a "this rdataset doesn't
                                 * exist" record?
                                 */
-                               if ((header->attributes &
-                                    RDATASET_ATTR_NONEXISTENT) != 0)
+                               if (NONEXISTENT(header))
                                        header = NULL;
                                break;
                        } else
@@ -2658,8 +2655,7 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node,
                                        node->dirty = 1;
                                        header_prev = header;
                                }
-                       } else if ((header->attributes &
-                                   RDATASET_ATTR_NONEXISTENT) == 0) {
+                       } else if (EXISTS(header)) {
                                /*
                                 * We've found an extant rdataset.  See if
                                 * we're interested in it.
@@ -2735,6 +2731,104 @@ find_deepest_zonecut(rbtdb_search_t *search, dns_rbtnode_t *node,
        return (result);
 }
 
+static isc_result_t
+find_coveringnsec(rbtdb_search_t *search, dns_dbnode_t **nodep,
+                 isc_stdtime_t now, dns_name_t *foundname,
+                 dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
+{
+       dns_rbtnode_t *node;
+       rdatasetheader_t *header, *header_next, *header_prev;
+       rdatasetheader_t *found, *foundsig;
+       isc_boolean_t empty_node;
+       isc_result_t result;
+       dns_fixedname_t fname, forigin;
+       dns_name_t *name, *origin;
+       rbtdb_rdatatype_t matchtype, sigmatchtype, nsectype;
+
+       matchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_nsec, 0);
+       nsectype = RBTDB_RDATATYPE_VALUE(0, dns_rdatatype_nsec);
+       sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig,
+                                            dns_rdatatype_nsec);
+       
+       do {
+               node = NULL;
+               dns_fixedname_init(&fname);
+               name = dns_fixedname_name(&fname);
+               dns_fixedname_init(&forigin);
+               origin = dns_fixedname_name(&forigin);
+               result = dns_rbtnodechain_current(&search->chain, name,
+                                                 origin, &node);
+               if (result != ISC_R_SUCCESS)
+                       return (result);
+               LOCK(&(search->rbtdb->node_locks[node->locknum].lock));
+               found = NULL;
+               foundsig = NULL;
+               empty_node = ISC_TRUE;
+               header_prev = NULL;
+               for (header = node->data;
+                    header != NULL;
+                    header = header_next) {
+                       header_next = header->next;
+                       if (header->ttl <= now) {
+                               /*
+                                * This rdataset is stale.  If no one else is
+                                * using the node, we can clean it up right
+                                * now, otherwise we mark it as stale, and the
+                                * node as dirty, so it will get cleaned up 
+                                * later.
+                                */
+                               if (node->references == 0) {
+                                       INSIST(header->down == NULL);
+                                       if (header_prev != NULL)
+                                               header_prev->next =
+                                                       header->next;
+                                       else
+                                               node->data = header->next;
+                                       free_rdataset(search->rbtdb->common.mctx,
+                                                     header);
+                               } else {
+                                       header->attributes |=
+                                                RDATASET_ATTR_STALE;
+                                       node->dirty = 1;
+                                       header_prev = header;
+                               }
+                               continue;
+                       }
+                       if (NONEXISTENT(header) || NXDOMAIN(header)) {
+                               header_prev = header;
+                               continue;
+                       }
+                       empty_node = ISC_FALSE;
+                       if (header->type == matchtype)
+                               found = header;
+                       else if (header->type == sigmatchtype)
+                               foundsig = header;
+                       header_prev = header;
+               }
+               if (found != NULL) {
+                       result = dns_name_concatenate(name, origin,
+                                                     foundname, NULL);
+                       if (result != ISC_R_SUCCESS)
+                               goto unlock_node;
+                       bind_rdataset(search->rbtdb, node, found,
+                                     now, rdataset);
+                       if (foundsig != NULL)
+                               bind_rdataset(search->rbtdb, node, foundsig,
+                                             now, sigrdataset);
+                       new_reference(search->rbtdb, node);
+                       *nodep = node;
+                       result = DNS_R_COVERINGNSEC;
+               } else if (!empty_node) {
+                       result = ISC_R_NOTFOUND;
+               }else
+                       result = dns_rbtnodechain_prev(&search->chain, NULL,
+                                                      NULL);
+ unlock_node:
+               UNLOCK(&(search->rbtdb->node_locks[node->locknum].lock));
+       } while (empty_node && result == ISC_R_SUCCESS);
+       return (result);
+}
+
 static isc_result_t
 cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
           dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
@@ -2750,7 +2844,7 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
        rdatasetheader_t *header, *header_prev, *header_next;
        rdatasetheader_t *found, *nsheader;
        rdatasetheader_t *foundsig, *nssig, *cnamesig;
-       rbtdb_rdatatype_t sigtype, nsecype;
+       rbtdb_rdatatype_t sigtype, nsectype;
 
        UNUSED(version);
 
@@ -2785,6 +2879,13 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
                                  cache_zonecut_callback, &search);
 
        if (result == DNS_R_PARTIALMATCH) {
+               if ((search.options & DNS_DBFIND_COVERINGNSEC) != 0) {
+                       result = find_coveringnsec(&search, nodep, now,
+                                                  foundname, rdataset,
+                                                  sigrdataset);
+                       if (result == DNS_R_COVERINGNSEC)
+                               goto tree_exit;
+               }
                if (search.zonecut != NULL) {
                    result = setup_delegation(&search, nodep, foundname,
                                              rdataset, sigrdataset);
@@ -2818,7 +2919,7 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
        found = NULL;
        foundsig = NULL;
        sigtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
-       nsecype = RBTDB_RDATATYPE_VALUE(0, type);
+       nsectype = RBTDB_RDATATYPE_VALUE(0, type);
        nsheader = NULL;
        nssig = NULL;
        cnamesig = NULL;
@@ -2846,8 +2947,7 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
                                node->dirty = 1;
                                header_prev = header;
                        }
-               } else if ((header->attributes & RDATASET_ATTR_NONEXISTENT)
-                          == 0) {
+               } else if (EXISTS(header)) {
                        /*
                         * We now know that there is at least one active
                         * non-stale rdataset at this node.
@@ -2889,7 +2989,7 @@ cache_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
                                 */
                                foundsig = header;
                        } else if (header->type == RBTDB_RDATATYPE_NCACHEANY ||
-                                  header->type == nsecype) {
+                                  header->type == nsectype) {
                                /*
                                 * We've found a negative cache entry.
                                 */
@@ -3114,8 +3214,7 @@ cache_findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
                                node->dirty = 1;
                                header_prev = header;
                        }
-               } else if ((header->attributes & RDATASET_ATTR_NONEXISTENT)
-                          == 0) {
+               } else if (EXISTS(header)) {
                        /*
                         * If we found a type we were looking for, remember
                         * it.
@@ -3449,8 +3548,7 @@ zone_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
                                 * Is this a "this rdataset doesn't
                                 * exist" record?
                                 */
-                               if ((header->attributes &
-                                    RDATASET_ATTR_NONEXISTENT) != 0)
+                               if (NONEXISTENT(header))
                                        header = NULL;
                                break;
                        } else
@@ -3500,7 +3598,7 @@ cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
        dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
        dns_rbtnode_t *rbtnode = (dns_rbtnode_t *)node;
        rdatasetheader_t *header, *header_next, *found, *foundsig;
-       rbtdb_rdatatype_t matchtype, sigmatchtype, nsecype;
+       rbtdb_rdatatype_t matchtype, sigmatchtype, nsectype;
        isc_result_t result;
 
        REQUIRE(VALID_RBTDB(rbtdb));
@@ -3518,7 +3616,7 @@ cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
        found = NULL;
        foundsig = NULL;
        matchtype = RBTDB_RDATATYPE_VALUE(type, covers);
-       nsecype = RBTDB_RDATATYPE_VALUE(0, type);
+       nsectype = RBTDB_RDATATYPE_VALUE(0, type);
        if (covers == 0)
                sigmatchtype = RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, type);
        else
@@ -3535,12 +3633,11 @@ cache_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
                         */
                        header->attributes |= RDATASET_ATTR_STALE;
                        rbtnode->dirty = 1;
-               } else if ((header->attributes & RDATASET_ATTR_NONEXISTENT) ==
-                          0) {
+               } else if (EXISTS(header)) {
                        if (header->type == matchtype)
                                found = header;
                        else if (header->type == RBTDB_RDATATYPE_NCACHEANY ||
-                                header->type == nsecype)
+                                header->type == nsectype)
                                found = header;
                        else if (header->type == sigmatchtype)
                                foundsig = header;
@@ -3720,7 +3817,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
        isc_boolean_t header_nx;
        isc_boolean_t newheader_nx;
        isc_boolean_t merge;
-       dns_rdatatype_t nsecype, rdtype, covers;
+       dns_rdatatype_t nsectype, rdtype, covers;
        dns_trust_t trust;
 
        /*
@@ -3758,7 +3855,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
        newheader_nx = NONEXISTENT(newheader) ? ISC_TRUE : ISC_FALSE;
        topheader_prev = NULL;
 
-       nsecype = 0;
+       nsectype = 0;
        if (rbtversion == NULL && !newheader_nx) {
                rdtype = RBTDB_RDATATYPE_BASE(newheader->type);
                if (rdtype == 0) {
@@ -3785,7 +3882,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
                                rbtnode->dirty = 1;
                                goto find_header;
                        }
-                       nsecype = RBTDB_RDATATYPE_VALUE(covers, 0);
+                       nsectype = RBTDB_RDATATYPE_VALUE(covers, 0);
                } else {
                        /*
                         * We're adding something that isn't a
@@ -3825,7 +3922,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
                                topheader = NULL;
                                goto find_header;
                        }
-                       nsecype = RBTDB_RDATATYPE_VALUE(0, rdtype);
+                       nsectype = RBTDB_RDATATYPE_VALUE(0, rdtype);
                }
        }
 
@@ -3833,7 +3930,7 @@ add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
             topheader != NULL;
             topheader = topheader->next) {
                if (topheader->type == newheader->type ||
-                   topheader->type == nsecype)
+                   topheader->type == nsectype)
                        break;
                topheader_prev = topheader;
        }
index b7eb0297a6111e9668875d7b1278fdf37411f73a..7f89953253a1ce1f92b8f9d0a6acdeb52d616bdb 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: resolver.c,v 1.287 2004/04/19 23:16:20 marka Exp $ */
+/* $Id: resolver.c,v 1.288 2004/05/14 04:45:56 marka Exp $ */
 
 #include <config.h>
 
                                      DNS_LOGCATEGORY_RESOLVER, \
                                      DNS_LOGMODULE_RESOLVER, \
                                      ISC_LOG_DEBUG(3), \
-                                     "fctx %p: %s", fctx, (m))
+                                     "fctx %p(%s'): %s", fctx, fctx->info, (m))
 #define FCTXTRACE2(m1, m2) \
                        isc_log_write(dns_lctx, \
                                      DNS_LOGCATEGORY_RESOLVER, \
                                      DNS_LOGMODULE_RESOLVER, \
                                      ISC_LOG_DEBUG(3), \
-                                     "fctx %p: %s %s", fctx, (m1), (m2))
+                                     "fctx %p(%s): %s %s", \
+                                     fctx, fctx->info, (m1), (m2))
 #define FTRACE(m)      isc_log_write(dns_lctx, \
                                      DNS_LOGCATEGORY_RESOLVER, \
                                      DNS_LOGMODULE_RESOLVER, \
                                      ISC_LOG_DEBUG(3), \
-                                     "fetch %p (fctx %p): %s", \
-                                     fetch, fetch->private, (m))
+                                     "fetch %p (fctx %p(%s)): %s", \
+                                     fetch, fetch->private, \
+                                     fetch->private->info, (m))
 #define QTRACE(m)      isc_log_write(dns_lctx, \
                                      DNS_LOGCATEGORY_RESOLVER, \
                                      DNS_LOGMODULE_RESOLVER, \
                                      ISC_LOG_DEBUG(3), \
-                                     "resquery %p (fctx %p): %s", \
-                                     query, query->fctx, (m))
+                                     "resquery %p (fctx %p(%s)): %s", \
+                                     query, query->fctx, \
+                                     query->fctx->info, (m))
 #else
 #define RTRACE(m)
 #define RRTRACE(r, m)
@@ -152,6 +155,7 @@ struct fetchctx {
        dns_rdatatype_t                 type;
        unsigned int                    options;
        unsigned int                    bucketnum;
+       char *                          info;
        /* Locked by appropriate bucket lock. */
        fetchstate                      state;
        isc_boolean_t                   want_shutdown;
@@ -1121,6 +1125,8 @@ resquery_send(resquery_t *query) {
                                                     &secure_domain);
                if (result != ISC_R_SUCCESS)
                        secure_domain = ISC_FALSE;
+               if (res->view->dlv != NULL)
+                       secure_domain = ISC_TRUE;
                if (secure_domain)
                        fctx->qmessage->flags |= DNS_MESSAGEFLAG_CD;
        } else
@@ -2287,6 +2293,7 @@ fctx_destroy(fetchctx_t *fctx) {
        dns_name_free(&fctx->name, res->mctx);
        dns_db_detach(&fctx->cache);
        dns_adb_detach(&fctx->adb);
+       isc_mem_free(res->mctx, fctx->info);
        isc_mem_put(res->mctx, fctx, sizeof(*fctx));
 
        LOCK(&res->nlock);
@@ -2575,6 +2582,8 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
        isc_interval_t interval;
        dns_fixedname_t qdomain;
        unsigned int findoptions = 0;
+       char buf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE];
+       char typebuf[DNS_RDATATYPE_FORMATSIZE];
 
        /*
         * Caller must be holding the lock for bucket number 'bucketnum'.
@@ -2584,11 +2593,18 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
        fctx = isc_mem_get(res->mctx, sizeof(*fctx));
        if (fctx == NULL)
                return (ISC_R_NOMEMORY);
+       dns_name_format(name, buf, sizeof(buf));
+       dns_rdatatype_format(type, typebuf, sizeof(typebuf));
+       strcat(buf, "/");       /* checked */
+       strcat(buf, typebuf);   /* checked */
+       fctx->info = isc_mem_strdup(res->mctx, buf);
+       if (fctx->info == NULL)
+               goto cleanup_fetch;
        FCTXTRACE("create");
        dns_name_init(&fctx->name, NULL);
        result = dns_name_dup(name, res->mctx, &fctx->name);
        if (result != ISC_R_SUCCESS)
-               goto cleanup_fetch;
+               goto cleanup_info;
        dns_name_init(&fctx->domain, NULL);
        dns_rdataset_init(&fctx->nameservers);
 
@@ -2761,6 +2777,9 @@ fctx_create(dns_resolver_t *res, dns_name_t *name, dns_rdatatype_t type,
  cleanup_name:
        dns_name_free(&fctx->name, res->mctx);
 
+ cleanup_info:
+       isc_mem_free(res->mctx, fctx->info);
+
  cleanup_fetch:
        isc_mem_put(res->mctx, fctx, sizeof(*fctx));
 
@@ -3091,7 +3110,6 @@ validated(isc_task_t *task, isc_event_t *event) {
                                           ardataset, &eresult);
                if (result != ISC_R_SUCCESS)
                        goto noanswer_response;
-
                goto answer_response;
        }
 
@@ -3152,8 +3170,9 @@ validated(isc_task_t *task, isc_event_t *event) {
                goto cleanup_event;
        }
 
+ answer_response:
        /*
-        * Cache any NS records that happened to be validate.
+        * Cache any NS/NSEC records that happened to be validated.
         */
        result = dns_message_firstname(fctx->rmessage, DNS_SECTION_AUTHORITY);
        while (result == ISC_R_SUCCESS) {
@@ -3163,14 +3182,15 @@ validated(isc_task_t *task, isc_event_t *event) {
                for (rdataset = ISC_LIST_HEAD(name->list);
                     rdataset != NULL;
                     rdataset = ISC_LIST_NEXT(rdataset, link)) {
-                       if (rdataset->type != dns_rdatatype_ns ||
+                       if ((rdataset->type != dns_rdatatype_ns &&
+                            rdataset->type != dns_rdatatype_nsec) ||
                            rdataset->trust != dns_trust_secure)
                                continue;
                        for (sigrdataset = ISC_LIST_HEAD(name->list);
                             sigrdataset != NULL;
                             sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) {
                                if (sigrdataset->type != dns_rdatatype_rrsig ||
-                                   sigrdataset->covers != dns_rdatatype_ns)
+                                   sigrdataset->covers != rdataset->type)
                                        continue;
                                break;
                        }
@@ -3197,7 +3217,6 @@ validated(isc_task_t *task, isc_event_t *event) {
 
        result = ISC_R_SUCCESS;
 
- answer_response:
        /*
         * Respond with an answer, positive or negative,
         * as opposed to an error.  'node' must be non-NULL.
@@ -3262,6 +3281,9 @@ cache_name(fetchctx_t *fctx, dns_name_t *name, isc_stdtime_t now) {
        if (result != ISC_R_SUCCESS)
                return (result);
 
+       if (res->view->dlv != NULL)
+               secure_domain = ISC_TRUE;
+
        if ((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0)
                need_validation = ISC_FALSE;
        else
@@ -3686,6 +3708,9 @@ ncache_message(fetchctx_t *fctx, dns_rdatatype_t covers, isc_stdtime_t now) {
        if (result != ISC_R_SUCCESS)
                return (result);
 
+       if (res->view->dlv != NULL)
+               secure_domain = ISC_TRUE;
+
        if ((fctx->options & DNS_FETCHOPT_NOVALIDATE) != 0)
                need_validation = ISC_FALSE;
        else
index 982cc4b1f5214789d7be6c23f6b0b0647fb950dc..d5ba87ce121c19ad3b14f947a4777b0450e6278b 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: result.c,v 1.116 2004/04/15 23:40:25 marka Exp $ */
+/* $Id: result.c,v 1.117 2004/05/14 04:45:57 marka Exp $ */
 
 #include <config.h>
 
@@ -150,7 +150,8 @@ static const char *text[DNS_R_NRESULTS] = {
        "dynamic zone",                        /* 98 DNS_R_DYNAMIC           */
        "unknown command",                     /* 99 DNS_R_UNKNOWNCOMMAND    */
 
-       "must-be-secure"                       /* 100 DNS_R_MUSTBESECURE     */
+       "must-be-secure",                      /* 100 DNS_R_MUSTBESECURE     */
+       "covering NSEC record returned"        /* 101 DNS_R_COVERINGNSEC     */
 };
 
 static const char *rcode_text[DNS_R_NRCODERESULTS] = {
index ddaf8c00c98510bc60820060d98f764d5b07f36b..078f9dbd3563cb9b2f867a2989b5cb9ad596abe4 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: validator.c,v 1.121 2004/04/15 23:40:25 marka Exp $ */
+/* $Id: validator.c,v 1.122 2004/05/14 04:45:57 marka Exp $ */
 
 #include <config.h>
 
@@ -53,6 +53,7 @@
 #define VALATTR_INSECURITY             0x0010
 #define VALATTR_DLV                    0x0020
 #define VALATTR_DLVTRIED               0x0040
+#define VALATTR_DLVSEPTRIED            0x0080
 
 #define VALATTR_NEEDNOQNAME            0x0100
 #define VALATTR_NEEDNOWILDCARD         0x0200
@@ -68,6 +69,7 @@
 #define NEEDNOWILDCARD(val) ((val->attributes & VALATTR_NEEDNOWILDCARD) != 0)
 #define DLV(val) ((val->attributes & VALATTR_DLV) != 0)
 #define DLVTRIED(val) ((val->attributes & VALATTR_DLVTRIED) != 0)
+#define DLVSEPTRIED(val) ((val->attributes & VALATTR_DLVSEPTRIED) != 0)
 
 #define SHUTDOWN(v)            (((v)->attributes & VALATTR_SHUTDOWN) != 0)
 
@@ -107,6 +109,9 @@ validator_logcreate(dns_validator_t *val,
 static isc_result_t
 dlv_validatezonekey(dns_validator_t *val);
 
+static isc_result_t
+finddlvsep(dns_validator_t *val, isc_boolean_t resume);
+
 static void
 validator_done(dns_validator_t *val, isc_result_t result) {
        isc_task_t *task;
@@ -735,6 +740,16 @@ negauthvalidated(isc_task_t *task, isc_event_t *event) {
 
 static inline isc_result_t
 view_find(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) {
+       dns_fixedname_t fixedname;
+       dns_name_t *foundname;
+       dns_rdata_nsec_t nsec;
+       dns_rdata_t rdata = DNS_RDATA_INIT;
+       isc_result_t result;
+       unsigned int options;
+       char buf1[DNS_NAME_FORMATSIZE];
+       char buf2[DNS_NAME_FORMATSIZE];
+       char buf3[DNS_NAME_FORMATSIZE];
+
        if (dns_rdataset_isassociated(&val->frdataset))
                dns_rdataset_disassociate(&val->frdataset);
        if (dns_rdataset_isassociated(&val->fsigrdataset))
@@ -742,9 +757,106 @@ view_find(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) {
 
        if (val->view->zonetable == NULL)
                return (ISC_R_CANCELED);
-       return (dns_view_simplefind(val->view, name, type, 0,
-                                   DNS_DBFIND_PENDINGOK, ISC_FALSE,
-                                   &val->frdataset, &val->fsigrdataset));
+
+       options = DNS_DBFIND_PENDINGOK;
+       if (type == dns_rdatatype_dlv)
+               options |= DNS_DBFIND_COVERINGNSEC;
+       dns_fixedname_init(&fixedname);
+       foundname = dns_fixedname_name(&fixedname);
+       result = dns_view_find(val->view, name, type, 0, options,
+                              ISC_FALSE, NULL, NULL, foundname,
+                              &val->frdataset, &val->fsigrdataset);
+       if (result == DNS_R_NXDOMAIN) {
+               if (dns_rdataset_isassociated(&val->frdataset))
+                       dns_rdataset_disassociate(&val->frdataset);
+               if (dns_rdataset_isassociated(&val->fsigrdataset))
+                       dns_rdataset_disassociate(&val->fsigrdataset);
+       } else if (result == DNS_R_COVERINGNSEC) {
+               validator_log(val, ISC_LOG_DEBUG(3), "DNS_R_COVERINGNSEC");
+               /*
+                * Check if the returned NSEC covers the name.
+                */
+               INSIST(type == dns_rdatatype_dlv);
+               if (val->frdataset.trust != dns_trust_secure) {
+                       validator_log(val, ISC_LOG_DEBUG(3),
+                                     "covering nsec: trust %u",
+                                     val->frdataset.trust);
+                       goto notfound;
+               }
+               result = dns_rdataset_first(&val->frdataset);
+               if (result != ISC_R_SUCCESS)
+                       goto notfound;
+               dns_rdataset_current(&val->frdataset, &rdata);
+               if (dns_nsec_typepresent(&rdata, dns_rdatatype_ns) &&
+                   !dns_nsec_typepresent(&rdata, dns_rdatatype_soa)) {
+                       /* Parent NSEC record. */
+                       if (dns_name_issubdomain(name, foundname)) {
+                               validator_log(val, ISC_LOG_DEBUG(3),
+                                             "covering nsec: for parent");
+                               goto notfound;
+                       }
+               }
+               result = dns_rdata_tostruct(&rdata, &nsec, NULL);
+               if (result != ISC_R_SUCCESS)
+                       goto notfound;
+               if (dns_name_compare(foundname, &nsec.next) >= 0) {
+                       /* End of zone chain. */
+                       if (!dns_name_issubdomain(name, &nsec.next)) {
+                               /*
+                                * XXXMPA We could look for a parent NSEC
+                                * at nsec.next and if found retest with
+                                * this NSEC.
+                                */
+                               dns_rdata_freestruct(&nsec);
+                               validator_log(val, ISC_LOG_DEBUG(3),
+                                             "covering nsec: not in zone");
+                               goto notfound;
+                       }
+               } else if (dns_name_compare(name, &nsec.next) >= 0) {
+                       /*
+                        * XXXMPA We could check if this NSEC is at a zone
+                        * apex and if the qname is not below it and look for
+                        * a parent NSEC with the same name.  This requires
+                        * that we can cache both NSEC records which we
+                        * currently don't support.
+                        */
+                       dns_rdata_freestruct(&nsec);
+                       validator_log(val, ISC_LOG_DEBUG(3),
+                                     "covering nsec: not in range");
+                       goto notfound;
+               }
+               if (isc_log_wouldlog(dns_lctx,ISC_LOG_DEBUG(3))) {
+                       dns_name_format(name, buf1, sizeof buf1);
+                       dns_name_format(foundname, buf2, sizeof buf2);
+                       dns_name_format(&nsec.next, buf3, sizeof buf3);
+                       validator_log(val, ISC_LOG_DEBUG(3),
+                                     "covering nsec found: '%s' '%s' '%s'",
+                                     buf1, buf2, buf3);
+               }
+               if (dns_rdataset_isassociated(&val->frdataset))
+                       dns_rdataset_disassociate(&val->frdataset);
+               if (dns_rdataset_isassociated(&val->fsigrdataset))
+                       dns_rdataset_disassociate(&val->fsigrdataset);
+               dns_rdata_freestruct(&nsec);
+               result = DNS_R_NCACHENXDOMAIN;
+       } else if (result != ISC_R_SUCCESS &&
+                   result != DNS_R_GLUE &&
+                   result != DNS_R_HINT &&
+                   result != DNS_R_NCACHENXDOMAIN &&
+                   result != DNS_R_NCACHENXRRSET &&
+                   result != DNS_R_NXRRSET &&
+                   result != DNS_R_HINTNXRRSET &&
+                   result != ISC_R_NOTFOUND) {
+               goto  notfound;
+       }
+       return (result);
+
+ notfound:
+       if (dns_rdataset_isassociated(&val->frdataset))
+               dns_rdataset_disassociate(&val->frdataset);
+       if (dns_rdataset_isassociated(&val->fsigrdataset))
+               dns_rdataset_disassociate(&val->fsigrdataset);
+       return (ISC_R_NOTFOUND);
 }
 
 static inline isc_boolean_t
@@ -2097,9 +2209,127 @@ check_ds_algorithm(dns_validator_t *val, dns_name_t *name,
        return (ISC_FALSE);
 }
 
+static void
+dlv_fetched2(isc_task_t *task, isc_event_t *event) {
+       dns_fetchevent_t *devent;
+       dns_validator_t *val;
+       isc_boolean_t want_destroy;
+       isc_result_t eresult;
+       isc_result_t result;
+
+       UNUSED(task);
+       INSIST(event->ev_type == DNS_EVENT_FETCHDONE);
+       devent = (dns_fetchevent_t *)event;
+       val = devent->ev_arg;
+       eresult = devent->result;
+       
+       isc_event_free(&event);
+       dns_resolver_destroyfetch(&val->fetch);
+       
+       INSIST(val->event != NULL);
+       validator_log(val, ISC_LOG_DEBUG(3), "in dlv_fetched2: %s",
+                     dns_result_totext(eresult));
+
+       LOCK(&val->lock);
+       if (eresult == ISC_R_SUCCESS) {
+               val->havedlvsep = ISC_TRUE;
+               result = proveunsecure(val, ISC_FALSE);
+               if (result != DNS_R_WAIT)
+                       validator_done(val, result);
+       } else if (eresult == DNS_R_NXRRSET ||
+                  eresult == DNS_R_NXDOMAIN ||
+                  eresult == DNS_R_NCACHENXRRSET ||
+                  eresult == DNS_R_NCACHENXDOMAIN) {
+                  result = finddlvsep(val, ISC_TRUE);
+               if (result == ISC_R_SUCCESS) {
+                       result = proveunsecure(val, ISC_FALSE);
+                       if (result != DNS_R_WAIT)
+                               validator_done(val, result);
+               } else if (result == ISC_R_NOTFOUND) {
+                       validator_done(val, ISC_R_SUCCESS);
+               } else if (result != DNS_R_WAIT)
+                       validator_done(val, result);
+       }
+       want_destroy = exit_check(val);
+       UNLOCK(&val->lock);
+       if (want_destroy)
+               destroy(val);
+}
+
+static isc_result_t
+finddlvsep(dns_validator_t *val, isc_boolean_t resume) {
+       dns_fixedname_t dlvfixed;
+       dns_name_t *dlvname;
+       dns_name_t *dlvsep;
+       dns_name_t noroot;
+       isc_result_t result;
+       unsigned int labels;
+
+       if (!resume) {
+               dns_fixedname_init(&val->dlvsep);
+               dlvsep = dns_fixedname_name(&val->dlvsep);
+               dns_name_copy(val->event->name, dlvsep, NULL);
+               val->attributes |= VALATTR_DLVSEPTRIED;
+       } else {
+               dlvsep = dns_fixedname_name(&val->dlvsep);
+               labels = dns_name_countlabels(dlvsep);
+               dns_name_getlabelsequence(dlvsep, 1, labels - 1, dlvsep);
+       }
+       dns_name_init(&noroot, NULL);
+       dns_fixedname_init(&dlvfixed);
+       dlvname = dns_fixedname_name(&dlvfixed);
+       labels = dns_name_countlabels(dlvsep);
+       dns_name_getlabelsequence(dlvsep, 0, labels - 1, &noroot);
+       result = dns_name_concatenate(&noroot, val->view->dlv, dlvname, NULL);
+       while (result == ISC_R_NOSPACE) {
+               labels = dns_name_countlabels(dlvsep);
+               dns_name_getlabelsequence(dlvsep, 1, labels - 1, dlvsep);
+               dns_name_getlabelsequence(dlvsep, 0, labels - 2, &noroot);
+               result = dns_name_concatenate(&noroot, val->view->dlv,
+                                             dlvname, NULL);
+       }
+       if (result != ISC_R_SUCCESS) {
+               validator_log(val, ISC_LOG_DEBUG(2), "DLV concatenate failed");
+               return (DNS_R_NOVALIDSIG);
+       }
+
+       while (dns_name_countlabels(dlvname) >
+              dns_name_countlabels(val->view->dlv)) 
+       {
+               result = view_find(val, dlvname, dns_rdatatype_dlv);
+               if (result == ISC_R_SUCCESS) {
+                       if (val->frdataset.trust < dns_trust_secure)
+                               return (DNS_R_NOVALIDSIG);
+                       val->havedlvsep = ISC_TRUE;
+                       return (ISC_R_SUCCESS);
+               }
+               if (result == ISC_R_NOTFOUND) {
+                        result = create_fetch(val, dlvname, dns_rdatatype_dlv,
+                                              dlv_fetched2, "finddlvsep");
+                        if (result != ISC_R_SUCCESS)
+                                return (result);
+                        return (DNS_R_WAIT);
+               }
+               if (result != DNS_R_NXRRSET &&
+                   result != DNS_R_NXDOMAIN &&
+                   result != DNS_R_NCACHENXRRSET &&
+                   result != DNS_R_NCACHENXDOMAIN) 
+                       return (result);
+               /*
+                * Strip first labels from both dlvsep and dlvname.
+                */
+               labels = dns_name_countlabels(dlvsep);
+               dns_name_getlabelsequence(dlvsep, 1, labels - 1, dlvsep);
+               labels = dns_name_countlabels(dlvname);
+               dns_name_getlabelsequence(dlvname, 1, labels - 1, dlvname);
+       }
+       return (ISC_R_NOTFOUND);
+}
+
 static isc_result_t
 proveunsecure(dns_validator_t *val, isc_boolean_t resume) {
        isc_result_t result;
+       isc_result_t tresult;
        dns_fixedname_t secroot;
        dns_name_t *tname;
 
@@ -2110,11 +2340,30 @@ proveunsecure(dns_validator_t *val, isc_boolean_t resume) {
        /*
         * If the name is not under a security root, it must be insecure.
         */
-       if (result == ISC_R_NOTFOUND)
-               return (ISC_R_SUCCESS);
+       if (val->view->dlv != NULL && !DLVSEPTRIED(val) && 
+           !dns_name_issubdomain(val->event->name, val->view->dlv)) {
+               tresult = finddlvsep(val, ISC_FALSE);
+               if (tresult != ISC_R_NOTFOUND && tresult != ISC_R_SUCCESS) {
+                       validator_log(val, ISC_LOG_DEBUG(3),
+                                     "finddlvsep returned: %s",
+                                     dns_result_totext(tresult));
+                       return (tresult);
+               }
+       }
 
-       else if (result != ISC_R_SUCCESS)
+       if (result == ISC_R_NOTFOUND) {
+               if (!val->havedlvsep)
+                       return (ISC_R_SUCCESS);
+               dns_name_copy(dns_fixedname_name(&val->dlvsep),
+                             dns_fixedname_name(&secroot), NULL);
+       } else if (result != ISC_R_SUCCESS)
                return (result);
+       else if (val->havedlvsep &&
+                dns_name_issubdomain(dns_fixedname_name(&val->dlvsep),
+                                     dns_fixedname_name(&secroot))) {
+               dns_name_copy(dns_fixedname_name(&val->dlvsep),
+                             dns_fixedname_name(&secroot), NULL);
+       }
 
        if (!resume) {
                val->labels =
@@ -2427,6 +2676,7 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type,
        val->nsecset = NULL;
        val->soaname = NULL;
        val->seensig = ISC_FALSE;
+       val->havedlvsep = ISC_FALSE;
        val->mustbesecure = dns_resolver_getmustbesecure(view->resolver, name);
        dns_rdataset_init(&val->frdataset);
        dns_rdataset_init(&val->fsigrdataset);
index 85b1cbda74bfced344acbd0aedf4929520625e4b..a14884949634a747fab26e94978c6406cc668a38 100644 (file)
 ./bin/tests/system/dialup/setup.sh             SH      2000,2001,2004
 ./bin/tests/system/dialup/tests.sh             SH      2000,2001,2004
 ./bin/tests/system/digcomp.pl                  PERL    2000,2001,2004
+./bin/tests/system/dlv/clean.sh                        SH      2004
+./bin/tests/system/dlv/setup.sh                        SH      2004
+./bin/tests/system/dlv/tests.sh                        SH      2004
+./bin/tests/system/dlv/ns1/named.conf          CONF-C  2004
+./bin/tests/system/dlv/ns1/root.db             ZONE    2004
+./bin/tests/system/dlv/ns1/rootservers.utld.db ZONE    2004
+./bin/tests/system/dlv/ns2/hints               ZONE    2004
+./bin/tests/system/dlv/ns2/named.conf          CONF-C  2004
+./bin/tests/system/dlv/ns2/utld.db             ZONE    2004
+./bin/tests/system/dlv/ns3/child.db.in         ZONE    2004
+./bin/tests/system/dlv/ns3/dlv.db.in           ZONE    2004
+./bin/tests/system/dlv/ns3/hints               ZONE    2004
+./bin/tests/system/dlv/ns3/named.conf          CONF-C  2004
+./bin/tests/system/dlv/ns3/sign.sh             SH      2004
+./bin/tests/system/dlv/ns4/child.db            ZONE    2004
+./bin/tests/system/dlv/ns4/hints               ZONE    2004
+./bin/tests/system/dlv/ns4/named.conf          CONF-C  2004
+./bin/tests/system/dlv/ns5/hints               ZONE    2004
+./bin/tests/system/dlv/ns5/named.conf          CONF-C  2004
 ./bin/tests/system/dnssec/README               TXT.BRIEF       2000,2001,2002,2004
 ./bin/tests/system/dnssec/clean.sh             SH      2000,2001,2002,2004
 ./bin/tests/system/dnssec/dnssec_update_test.pl        PERL    2002,2004