]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
1448. [bug] Handle empty wildcards labels.
authorMark Andrews <marka@isc.org>
Thu, 27 Feb 2003 00:19:04 +0000 (00:19 +0000)
committerMark Andrews <marka@isc.org>
Thu, 27 Feb 2003 00:19:04 +0000 (00:19 +0000)
developer: marka
reviewer: explorer

CHANGES
bin/named/query.c
lib/dns/include/dns/result.h
lib/dns/rbtdb.c
lib/dns/result.c
lib/dns/validator.c

diff --git a/CHANGES b/CHANGES
index 91e5f61f20818cda0284d30e32b0b745b0b71fbd..762d3776d6ebdb6b6da6424aa3d0135d59fb9e0e 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,5 @@
+1448.  [bug]           Handle empty wildcards labels.
+
 1447.  [bug]           We were casting (unsigned int) to and from (void *).
                        rdataset->private4 is now rdataset->privateuint4
                        to reflect a type change.
index 6296d064676561f5ec55e6ac9287e77b2eec83ac..57651f3a2c9e4fd874f48d5a2588011995cbbda8 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: query.c,v 1.242 2003/01/31 12:07:56 marka Exp $ */
+/* $Id: query.c,v 1.243 2003/02/27 00:19:03 marka Exp $ */
 
 #include <config.h>
 
@@ -1899,7 +1899,7 @@ query_addwildcardproof(ns_client_t *client, dns_db_t *db,
                 */
                if (result == ISC_R_SUCCESS && ispositive)
                        break;
-               if (result == DNS_R_NXDOMAIN) {
+               if (result == DNS_R_NXDOMAIN || result == DNS_R_EMPTYNAME) {
                        if (!ispositive &&
                            dns_name_issubdomain(name, fname))
                                done = ISC_TRUE;
@@ -2269,6 +2269,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
        dns_rdata_cname_t cname;
        dns_rdata_dname_t dname;
        unsigned int options;
+       isc_boolean_t empty_wild;
 
        CTRACE("query_find");
 
@@ -2292,6 +2293,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
        version = NULL;
        zone = NULL;
        need_wildcardproof = ISC_FALSE;
+       empty_wild = ISC_FALSE;
        options = 0;
 
        if (event != NULL) {
@@ -2745,6 +2747,9 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                                                    &rdataset, &sigrdataset);
                }
                goto cleanup;
+       case DNS_R_EMPTYWILD:
+               empty_wild = ISC_TRUE;
+               /* FALLTHROUGH */
        case DNS_R_NXDOMAIN:
                INSIST(is_zone);
                if (dns_rdataset_isassociated(rdataset)) {
@@ -2792,7 +2797,10 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
                /*
                 * Set message rcode.
                 */
-               client->message->rcode = dns_rcode_nxdomain;
+               if (empty_wild)
+                       client->message->rcode = dns_rcode_noerror;
+               else
+                       client->message->rcode = dns_rcode_nxdomain;
                goto cleanup;
        case DNS_R_NCACHENXDOMAIN:
        case DNS_R_NCACHENXRRSET:
index 263e9e78af07c039055246b057f92c98a2130269..64c6304b9aab2806819646491b1a4de794894255 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: result.h,v 1.96 2003/01/18 03:18:31 marka Exp $ */
+/* $Id: result.h,v 1.97 2003/02/27 00:19:04 marka Exp $ */
 
 #ifndef DNS_RESULT_H
 #define DNS_RESULT_H 1
 #define DNS_R_UNEXPECTEDOPCODE         (ISC_RESULTCLASS_DNS + 90)
 #define DNS_R_CHASEDSSERVERS           (ISC_RESULTCLASS_DNS + 91)
 #define DNS_R_EMPTYNAME                        (ISC_RESULTCLASS_DNS + 92)
+#define DNS_R_EMPTYWILD                        (ISC_RESULTCLASS_DNS + 93)
 
-#define DNS_R_NRESULTS                 93      /* Number of results */
+#define DNS_R_NRESULTS                 94      /* Number of results */
 
 /*
  * DNS wire format rcodes.
index b10ccb501760fd2c0536682500f43b769b7217c6..4ec6a9e185b7afaf4b84260a1980e69647d362b8 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rbtdb.c,v 1.185 2003/02/26 23:52:29 marka Exp $ */
+/* $Id: rbtdb.c,v 1.186 2003/02/27 00:19:03 marka Exp $ */
 
 /*
  * Principal Author: Bob Halley
@@ -1086,6 +1086,34 @@ add_wildcard_magic(dns_rbtdb_t *rbtdb, dns_name_t *name) {
        return (ISC_R_SUCCESS);
 }
 
+static isc_result_t
+add_empty_wildcards(dns_rbtdb_t *rbtdb, dns_name_t *name) {
+       isc_result_t result;
+       dns_name_t foundname;
+       dns_offsets_t offsets;
+       unsigned int n, l, i;
+
+       dns_name_init(&foundname, offsets);
+       n = dns_name_countlabels(name);
+       l = dns_name_countlabels(&rbtdb->common.origin);
+       i = l + 1;
+       while (i < n) {
+               dns_rbtnode_t *node = NULL;     /* dummy */
+               dns_name_getlabelsequence(name, n - i, i, &foundname);
+               if (dns_name_iswildcard(&foundname)) {
+                       result = add_wildcard_magic(rbtdb, &foundname);
+                       if (result != ISC_R_SUCCESS)
+                               return (result);
+                       result = dns_rbt_addnode(rbtdb->tree, &foundname,
+                                                &node);
+                       if (result != ISC_R_SUCCESS && result != ISC_R_EXISTS)
+                               return (result);
+               }
+               i++;
+       }
+       return (ISC_R_SUCCESS);
+}
+
 static isc_result_t
 findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
         dns_dbnode_t **nodep)
@@ -1126,6 +1154,8 @@ findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
                        node->locknum = dns_name_hash(&nodename, ISC_TRUE) %
                                rbtdb->node_lock_count;
 #endif
+                       add_empty_wildcards(rbtdb, name);
+
                        if (dns_name_iswildcard(name)) {
                                result = add_wildcard_magic(rbtdb, name);
                                if (result != ISC_R_SUCCESS) {
@@ -1436,6 +1466,56 @@ valid_glue(rbtdb_search_t *search, dns_name_t *name, rbtdb_rdatatype_t type,
        return (valid);
 }
 
+static inline isc_boolean_t
+activeempty(rbtdb_search_t *search, dns_rbtnodechain_t *chain,
+           dns_name_t *name)
+{
+       dns_fixedname_t fnext;
+       dns_fixedname_t forigin;
+       dns_name_t *next;
+       dns_name_t *origin;
+       dns_name_t prefix;
+       dns_rbtdb_t *rbtdb;
+       dns_rbtnode_t *node;
+       isc_result_t result;
+       isc_boolean_t answer = ISC_FALSE;
+       rdatasetheader_t *header;
+
+       rbtdb = search->rbtdb;
+
+       dns_name_init(&prefix, NULL);
+       dns_fixedname_init(&fnext);
+       next = dns_fixedname_name(&fnext);
+       dns_fixedname_init(&forigin);
+       origin = dns_fixedname_name(&forigin);
+
+       result = dns_rbtnodechain_next(chain, NULL, NULL);
+       while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
+               node = NULL;
+               result = dns_rbtnodechain_current(chain, &prefix,
+                                                 origin, &node);
+               if (result != ISC_R_SUCCESS)
+                       break;
+               LOCK(&(rbtdb->node_locks[node->locknum].lock));
+               for (header = node->data;
+                    header != NULL;
+                    header = header->next) {
+                       if (header->serial <= search->serial &&
+                           !IGNORE(header) && EXISTS(header))
+                               break;
+               }
+               UNLOCK(&(rbtdb->node_locks[node->locknum].lock));
+               if (header != NULL)
+                       break;
+               result = dns_rbtnodechain_next(chain, NULL, NULL);
+       }
+       if (result == ISC_R_SUCCESS)
+               result = dns_name_concatenate(&prefix, origin, next, NULL);
+       if (result == ISC_R_SUCCESS && dns_name_issubdomain(next, name))
+               answer = ISC_TRUE;
+       return (answer);
+}
+
 static inline isc_boolean_t
 activeemtpynode(rbtdb_search_t *search, dns_name_t *qname, dns_name_t *wname) {
        dns_fixedname_t fnext;
@@ -1452,6 +1532,7 @@ activeemtpynode(rbtdb_search_t *search, dns_name_t *qname, dns_name_t *wname) {
        dns_rbtnodechain_t chain;
        isc_boolean_t check_next = ISC_TRUE;
        isc_boolean_t check_prev = ISC_TRUE;
+       isc_boolean_t answer = ISC_FALSE;
        isc_result_t result;
        rdatasetheader_t *header;
        unsigned int n;
@@ -1533,15 +1614,17 @@ activeemtpynode(rbtdb_search_t *search, dns_name_t *qname, dns_name_t *wname) {
 
        do {
                if ((check_prev && dns_name_issubdomain(prev, &rname)) ||
-                   (check_next && dns_name_issubdomain(next, &rname)))
-                       return (ISC_TRUE);
+                   (check_next && dns_name_issubdomain(next, &rname))) {
+                       answer = ISC_TRUE;
+                       break;
+               }
                /*
                 * Remove the left hand label.
                 */
                n = dns_name_countlabels(&rname);
                dns_name_getlabelsequence(&rname, 1, n - 1, &rname);
        } while (!dns_name_equal(&rname, &tname));
-       return (ISC_FALSE);
+       return (answer);
 }
 
 static inline isc_result_t
@@ -1557,6 +1640,7 @@ find_wildcard(rbtdb_search_t *search, dns_rbtnode_t **nodep,
        dns_fixedname_t fwname;
        dns_rbtdb_t *rbtdb;
        isc_boolean_t done, wild, active;
+       dns_rbtnodechain_t wchain;
 
        /*
         * Caller must be holding the tree lock and MUST NOT be holding
@@ -1630,8 +1714,9 @@ find_wildcard(rbtdb_search_t *search, dns_rbtnode_t **nodep,
                                break;
 
                        wnode = NULL;
+                       dns_rbtnodechain_init(&wchain, NULL);
                        result = dns_rbt_findnode(rbtdb->tree, wname,
-                                                 NULL, &wnode, NULL,
+                                                 NULL, &wnode, &wchain,
                                                  DNS_RBTFIND_EMPTYDATA,
                                                  NULL, NULL);
                        if (result == ISC_R_SUCCESS) {
@@ -1649,7 +1734,8 @@ find_wildcard(rbtdb_search_t *search, dns_rbtnode_t **nodep,
                                            break;
                            }
                            UNLOCK(&(rbtdb->node_locks[wnode->locknum].lock));
-                           if (header != NULL) {
+                           if (header != NULL ||
+                               activeempty(search, &wchain, wname)) {
                                    if (activeemtpynode(search, qname, wname))
                                                return (ISC_R_NOTFOUND);
                                    /*
@@ -1846,9 +1932,6 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
        rdatasetheader_t *header, *header_next, *found, *nxtheader;
        rdatasetheader_t *foundsig, *cnamesig, *nxtsig;
        rbtdb_rdatatype_t sigtype;
-       dns_fixedname_t fnext;
-       dns_fixedname_t forigin;
-       dns_name_t nname, *next, *origin;
        isc_boolean_t active;
        dns_rbtnodechain_t chain;
 
@@ -1925,45 +2008,9 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
                                goto tree_exit;
                }
 
-               /*
-                * Find if this is a active empty node (next active node is
-                * subdomain if 'name').  This is a simpler test than is
-                * required for activeemptynode() where name is not as
-                * constained.
-                */
-               active = ISC_FALSE;
-               dns_fixedname_init(&fnext);
-               next = dns_fixedname_name(&fnext);
-               dns_fixedname_init(&forigin);
-               origin = dns_fixedname_name(&forigin);
-               dns_name_init(&nname, NULL);
                chain = search.chain;
-               result = dns_rbtnodechain_next(&chain, NULL, NULL);
-               while (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
-                       node = NULL;
-                       result = dns_rbtnodechain_current(&chain, &nname,
-                                                         origin, &node);
-                       if (result != ISC_R_SUCCESS)
-                               break;
-                       LOCK(&(search.rbtdb->node_locks[node->locknum].lock));
-                       for (header = node->data;
-                            header != NULL;
-                            header = header->next) {
-                               if (header->serial <= search.serial &&
-                                   !IGNORE(header) && EXISTS(header))
-                                       break;
-                       }
-                       UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock));
-                       if (header != NULL) {
-                               result = dns_name_concatenate(&nname, origin,
-                                                             next, NULL);
-                               if (result == ISC_R_SUCCESS &&
-                                   dns_name_issubdomain(next, name))
-                                       active = ISC_TRUE;
-                               break;
-                       }
-                       result = dns_rbtnodechain_next(&chain, NULL, NULL);
-               }
+               active = activeempty(&search, &chain, name);
+
                /*
                 * If we're here, then the name does not exist, is not
                 * beneath a zonecut, and there's no matching wildcard.
@@ -2162,14 +2209,11 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
                 * active rdatasets in the desired version.  That means that
                 * this node doesn't exist in the desired version, and that
                 * we really have a partial match.
-                *
-                * If the node is the result of a wildcard match, then
-                * it must be active in the desired version, and hence
-                * empty_node should never be true.  We INSIST upon it.
                 */
-               INSIST(!wild);
-               UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock));
-               goto partial_match;
+               if (!wild) {
+                       UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock));
+                       goto partial_match;
+               }
        }
 
        /*
@@ -2198,8 +2242,18 @@ zone_find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
                         * The zone is secure but there's no NXT,
                         * or the NXT has no signature!
                         */
-                       result = DNS_R_BADDB;
-                       goto node_exit;
+                       if (!wild) {
+                               result = DNS_R_BADDB;
+                               goto node_exit;
+                       }
+                       
+                       UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock));
+                       result = find_closest_nxt(&search, nodep, foundname,
+                                                 rdataset, sigrdataset,
+                                                 search.rbtdb->secure);
+                       if (result == ISC_R_SUCCESS)
+                               result = DNS_R_EMPTYWILD;
+                       goto tree_exit;
                }
                if ((search.options & DNS_DBFIND_FORCENXT) != 0 &&
                    nxtheader == NULL)
@@ -4138,6 +4192,8 @@ loading_addrdataset(void *arg, dns_name_t *name, dns_rdataset_t *rdataset) {
            !IS_CACHE(rbtdb) && !dns_name_equal(name, &rbtdb->common.origin))
                return (DNS_R_NOTZONETOP);
 
+       add_empty_wildcards(rbtdb, name);
+
        if (dns_name_iswildcard(name)) {
                /*
                 * NS record owners cannot legally be wild cards.
index 823e78ab2f56dc594dcd447c86411ffc6df777de..02055bd0bf619ebc98fd296d46291ecfaef9c7eb 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: result.c,v 1.106 2003/01/18 03:18:30 marka Exp $ */
+/* $Id: result.c,v 1.107 2003/02/27 00:19:03 marka Exp $ */
 
 #include <config.h>
 
@@ -140,7 +140,8 @@ static const char *text[DNS_R_NRESULTS] = {
 
        "unexpected OPCODE",                   /* 90 DNS_R_UNEXPECTEDOPCODE  */
        "chase DS servers",                    /* 91 DNS_R_CHASEDSSERVERS    */
-       "empty name"                           /* 92 DNS_R_EMPTYNAME         */
+       "empty name",                          /* 92 DNS_R_EMPTYNAME         */
+       "empty wild"                           /* 93 DNS_R_EMPTYWILD         */
 };
 
 static const char *rcode_text[DNS_R_NRCODERESULTS] = {
index 6eebef377db1e2ba82c7f3b6829f88241c0b9af7..9649ae5fdd00772b0dd74a59c4f6531776c909f9 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: validator.c,v 1.111 2003/01/18 03:18:30 marka Exp $ */
+/* $Id: validator.c,v 1.112 2003/02/27 00:19:04 marka Exp $ */
 
 #include <config.h>
 
@@ -441,7 +441,7 @@ nxtprovesnonexistence(dns_validator_t *val, dns_name_t *nxtname,
        isc_boolean_t isnxdomain;
        isc_result_t result;
        dns_namereln_t relation;
-       unsigned int labels, bits;
+       unsigned int olabels, nlabels, labels, bits;
 
        INSIST(DNS_MESSAGE_VALID(val->event->message));
 
@@ -459,7 +459,8 @@ nxtprovesnonexistence(dns_validator_t *val, dns_name_t *nxtname,
        dns_rdataset_current(nxtset, &rdata);
 
        validator_log(val, ISC_LOG_DEBUG(3), "looking for relevant nxt");
-       order = dns_name_compare(val->event->name, nxtname);
+       relation = dns_name_fullcompare(val->event->name, nxtname,
+                                       &order, &olabels, &bits);
        if (order == 0) {
                /*
                 * The names are the same.  Look for the type present bit.
@@ -495,16 +496,39 @@ nxtprovesnonexistence(dns_validator_t *val, dns_name_t *nxtname,
                        RUNTIME_CHECK(result == ISC_R_SUCCESS);
                        relation = dns_name_fullcompare(&nxt.next,
                                                        val->event->name,
-                                                       &order, &labels, &bits);
-                       dns_rdata_freestruct(&nxt);
-                       if (order <= 0 || relation != dns_namereln_subdomain) {
+                                                       &order, &nlabels,
+                                                       &bits);
+                       if (order > 0 && relation == dns_namereln_subdomain) {
+                               dns_rdata_freestruct(&nxt);
                                validator_log(val, ISC_LOG_DEBUG(3),
-                                             "missing NXT record at name");
-                               return (ISC_FALSE);
+                                     "nxt proves empty node, ok");
+                               return (ISC_TRUE);
                        }
+                       /*
+                        * Look for empty wildcard matches.
+                        */
+                       labels = dns_name_countlabels(&nxt.next);
+                       if (nlabels >= olabels && nlabels + 1 < labels) {
+                               dns_name_t wild;
+                               dns_name_init(&wild, NULL);
+                               dns_name_getlabelsequence(&nxt.next,
+                                                         labels - 1 - nlabels,
+                                                         nlabels + 1,
+                                                         &wild);
+                               if (dns_name_iswildcard(&wild)) {
+                                       dns_rdata_freestruct(&nxt);
+                                       validator_log(val, ISC_LOG_DEBUG(3),
+                                             "nxt proves empty wildcard, ok");
+                                       return (ISC_TRUE);
+                               }
+                       }
+                       /*
+                        * We are not a empty name.
+                        */
+                       dns_rdata_freestruct(&nxt);
                        validator_log(val, ISC_LOG_DEBUG(3),
-                                     "nxt proves empty node, ok");
-                       return (ISC_TRUE);
+                                             "missing NXT record at name");
+                       return (ISC_FALSE);
                }
                if (dns_name_issubdomain(val->event->name, nxtname) &&
                    dns_nxt_typepresent(&rdata, dns_rdatatype_ns) &&
@@ -524,7 +548,7 @@ nxtprovesnonexistence(dns_validator_t *val, dns_name_t *nxtname,
                        return (ISC_FALSE);
                dns_rdata_reset(&rdata);
                relation = dns_name_fullcompare(&nxt.next, val->event->name,
-                                               &order, &labels, &bits);
+                                               &order, &nlabels, &bits);
                if (order <= 0) {
                        /*
                         * The NXT next name is less than the nonexistent