2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-03 16:15:27 +00:00

1448. [bug] Handle empty wildcards labels.

developer: marka
reviewer: explorer
This commit is contained in:
Mark Andrews
2003-02-27 00:19:04 +00:00
parent 80b782f356
commit 8b5de97014
6 changed files with 167 additions and 75 deletions

View File

@@ -1,3 +1,5 @@
1448. [bug] Handle empty wildcards labels.
1447. [bug] We were casting (unsigned int) to and from (void *). 1447. [bug] We were casting (unsigned int) to and from (void *).
rdataset->private4 is now rdataset->privateuint4 rdataset->private4 is now rdataset->privateuint4
to reflect a type change. to reflect a type change.

View File

@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * 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> #include <config.h>
@@ -1899,7 +1899,7 @@ query_addwildcardproof(ns_client_t *client, dns_db_t *db,
*/ */
if (result == ISC_R_SUCCESS && ispositive) if (result == ISC_R_SUCCESS && ispositive)
break; break;
if (result == DNS_R_NXDOMAIN) { if (result == DNS_R_NXDOMAIN || result == DNS_R_EMPTYNAME) {
if (!ispositive && if (!ispositive &&
dns_name_issubdomain(name, fname)) dns_name_issubdomain(name, fname))
done = ISC_TRUE; 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_cname_t cname;
dns_rdata_dname_t dname; dns_rdata_dname_t dname;
unsigned int options; unsigned int options;
isc_boolean_t empty_wild;
CTRACE("query_find"); CTRACE("query_find");
@@ -2292,6 +2293,7 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
version = NULL; version = NULL;
zone = NULL; zone = NULL;
need_wildcardproof = ISC_FALSE; need_wildcardproof = ISC_FALSE;
empty_wild = ISC_FALSE;
options = 0; options = 0;
if (event != NULL) { if (event != NULL) {
@@ -2745,6 +2747,9 @@ query_find(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype)
&rdataset, &sigrdataset); &rdataset, &sigrdataset);
} }
goto cleanup; goto cleanup;
case DNS_R_EMPTYWILD:
empty_wild = ISC_TRUE;
/* FALLTHROUGH */
case DNS_R_NXDOMAIN: case DNS_R_NXDOMAIN:
INSIST(is_zone); INSIST(is_zone);
if (dns_rdataset_isassociated(rdataset)) { 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. * 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; goto cleanup;
case DNS_R_NCACHENXDOMAIN: case DNS_R_NCACHENXDOMAIN:
case DNS_R_NCACHENXRRSET: case DNS_R_NCACHENXRRSET:

View File

@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * 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 #ifndef DNS_RESULT_H
#define DNS_RESULT_H 1 #define DNS_RESULT_H 1
@@ -134,8 +134,9 @@
#define DNS_R_UNEXPECTEDOPCODE (ISC_RESULTCLASS_DNS + 90) #define DNS_R_UNEXPECTEDOPCODE (ISC_RESULTCLASS_DNS + 90)
#define DNS_R_CHASEDSSERVERS (ISC_RESULTCLASS_DNS + 91) #define DNS_R_CHASEDSSERVERS (ISC_RESULTCLASS_DNS + 91)
#define DNS_R_EMPTYNAME (ISC_RESULTCLASS_DNS + 92) #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. * DNS wire format rcodes.

View File

@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * 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 * Principal Author: Bob Halley
@@ -1086,6 +1086,34 @@ add_wildcard_magic(dns_rbtdb_t *rbtdb, dns_name_t *name) {
return (ISC_R_SUCCESS); 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 static isc_result_t
findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create, findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
dns_dbnode_t **nodep) 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) % node->locknum = dns_name_hash(&nodename, ISC_TRUE) %
rbtdb->node_lock_count; rbtdb->node_lock_count;
#endif #endif
add_empty_wildcards(rbtdb, name);
if (dns_name_iswildcard(name)) { if (dns_name_iswildcard(name)) {
result = add_wildcard_magic(rbtdb, name); result = add_wildcard_magic(rbtdb, name);
if (result != ISC_R_SUCCESS) { 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); 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 static inline isc_boolean_t
activeemtpynode(rbtdb_search_t *search, dns_name_t *qname, dns_name_t *wname) { activeemtpynode(rbtdb_search_t *search, dns_name_t *qname, dns_name_t *wname) {
dns_fixedname_t fnext; 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; dns_rbtnodechain_t chain;
isc_boolean_t check_next = ISC_TRUE; isc_boolean_t check_next = ISC_TRUE;
isc_boolean_t check_prev = ISC_TRUE; isc_boolean_t check_prev = ISC_TRUE;
isc_boolean_t answer = ISC_FALSE;
isc_result_t result; isc_result_t result;
rdatasetheader_t *header; rdatasetheader_t *header;
unsigned int n; unsigned int n;
@@ -1533,15 +1614,17 @@ activeemtpynode(rbtdb_search_t *search, dns_name_t *qname, dns_name_t *wname) {
do { do {
if ((check_prev && dns_name_issubdomain(prev, &rname)) || if ((check_prev && dns_name_issubdomain(prev, &rname)) ||
(check_next && dns_name_issubdomain(next, &rname))) (check_next && dns_name_issubdomain(next, &rname))) {
return (ISC_TRUE); answer = ISC_TRUE;
break;
}
/* /*
* Remove the left hand label. * Remove the left hand label.
*/ */
n = dns_name_countlabels(&rname); n = dns_name_countlabels(&rname);
dns_name_getlabelsequence(&rname, 1, n - 1, &rname); dns_name_getlabelsequence(&rname, 1, n - 1, &rname);
} while (!dns_name_equal(&rname, &tname)); } while (!dns_name_equal(&rname, &tname));
return (ISC_FALSE); return (answer);
} }
static inline isc_result_t static inline isc_result_t
@@ -1557,6 +1640,7 @@ find_wildcard(rbtdb_search_t *search, dns_rbtnode_t **nodep,
dns_fixedname_t fwname; dns_fixedname_t fwname;
dns_rbtdb_t *rbtdb; dns_rbtdb_t *rbtdb;
isc_boolean_t done, wild, active; isc_boolean_t done, wild, active;
dns_rbtnodechain_t wchain;
/* /*
* Caller must be holding the tree lock and MUST NOT be holding * 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; break;
wnode = NULL; wnode = NULL;
dns_rbtnodechain_init(&wchain, NULL);
result = dns_rbt_findnode(rbtdb->tree, wname, result = dns_rbt_findnode(rbtdb->tree, wname,
NULL, &wnode, NULL, NULL, &wnode, &wchain,
DNS_RBTFIND_EMPTYDATA, DNS_RBTFIND_EMPTYDATA,
NULL, NULL); NULL, NULL);
if (result == ISC_R_SUCCESS) { if (result == ISC_R_SUCCESS) {
@@ -1649,7 +1734,8 @@ find_wildcard(rbtdb_search_t *search, dns_rbtnode_t **nodep,
break; break;
} }
UNLOCK(&(rbtdb->node_locks[wnode->locknum].lock)); UNLOCK(&(rbtdb->node_locks[wnode->locknum].lock));
if (header != NULL) { if (header != NULL ||
activeempty(search, &wchain, wname)) {
if (activeemtpynode(search, qname, wname)) if (activeemtpynode(search, qname, wname))
return (ISC_R_NOTFOUND); 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 *header, *header_next, *found, *nxtheader;
rdatasetheader_t *foundsig, *cnamesig, *nxtsig; rdatasetheader_t *foundsig, *cnamesig, *nxtsig;
rbtdb_rdatatype_t sigtype; rbtdb_rdatatype_t sigtype;
dns_fixedname_t fnext;
dns_fixedname_t forigin;
dns_name_t nname, *next, *origin;
isc_boolean_t active; isc_boolean_t active;
dns_rbtnodechain_t chain; 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; 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; chain = search.chain;
result = dns_rbtnodechain_next(&chain, NULL, NULL); active = activeempty(&search, &chain, name);
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);
}
/* /*
* If we're here, then the name does not exist, is not * If we're here, then the name does not exist, is not
* beneath a zonecut, and there's no matching wildcard. * 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 * active rdatasets in the desired version. That means that
* this node doesn't exist in the desired version, and that * this node doesn't exist in the desired version, and that
* we really have a partial match. * 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); if (!wild) {
UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock)); UNLOCK(&(search.rbtdb->node_locks[node->locknum].lock));
goto partial_match; 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, * The zone is secure but there's no NXT,
* or the NXT has no signature! * or the NXT has no signature!
*/ */
result = DNS_R_BADDB; if (!wild) {
goto node_exit; 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 && if ((search.options & DNS_DBFIND_FORCENXT) != 0 &&
nxtheader == NULL) 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)) !IS_CACHE(rbtdb) && !dns_name_equal(name, &rbtdb->common.origin))
return (DNS_R_NOTZONETOP); return (DNS_R_NOTZONETOP);
add_empty_wildcards(rbtdb, name);
if (dns_name_iswildcard(name)) { if (dns_name_iswildcard(name)) {
/* /*
* NS record owners cannot legally be wild cards. * NS record owners cannot legally be wild cards.

View File

@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * 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> #include <config.h>
@@ -140,7 +140,8 @@ static const char *text[DNS_R_NRESULTS] = {
"unexpected OPCODE", /* 90 DNS_R_UNEXPECTEDOPCODE */ "unexpected OPCODE", /* 90 DNS_R_UNEXPECTEDOPCODE */
"chase DS servers", /* 91 DNS_R_CHASEDSSERVERS */ "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] = { static const char *rcode_text[DNS_R_NRCODERESULTS] = {

View File

@@ -15,7 +15,7 @@
* WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * 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> #include <config.h>
@@ -441,7 +441,7 @@ nxtprovesnonexistence(dns_validator_t *val, dns_name_t *nxtname,
isc_boolean_t isnxdomain; isc_boolean_t isnxdomain;
isc_result_t result; isc_result_t result;
dns_namereln_t relation; dns_namereln_t relation;
unsigned int labels, bits; unsigned int olabels, nlabels, labels, bits;
INSIST(DNS_MESSAGE_VALID(val->event->message)); 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); dns_rdataset_current(nxtset, &rdata);
validator_log(val, ISC_LOG_DEBUG(3), "looking for relevant nxt"); 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) { if (order == 0) {
/* /*
* The names are the same. Look for the type present bit. * 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); RUNTIME_CHECK(result == ISC_R_SUCCESS);
relation = dns_name_fullcompare(&nxt.next, relation = dns_name_fullcompare(&nxt.next,
val->event->name, val->event->name,
&order, &labels, &bits); &order, &nlabels,
dns_rdata_freestruct(&nxt); &bits);
if (order <= 0 || relation != dns_namereln_subdomain) { if (order > 0 && relation == dns_namereln_subdomain) {
dns_rdata_freestruct(&nxt);
validator_log(val, ISC_LOG_DEBUG(3), validator_log(val, ISC_LOG_DEBUG(3),
"missing NXT record at name");
return (ISC_FALSE);
}
validator_log(val, ISC_LOG_DEBUG(3),
"nxt proves empty node, ok"); "nxt proves empty node, ok");
return (ISC_TRUE); 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),
"missing NXT record at name");
return (ISC_FALSE);
} }
if (dns_name_issubdomain(val->event->name, nxtname) && if (dns_name_issubdomain(val->event->name, nxtname) &&
dns_nxt_typepresent(&rdata, dns_rdatatype_ns) && dns_nxt_typepresent(&rdata, dns_rdatatype_ns) &&
@@ -524,7 +548,7 @@ nxtprovesnonexistence(dns_validator_t *val, dns_name_t *nxtname,
return (ISC_FALSE); return (ISC_FALSE);
dns_rdata_reset(&rdata); dns_rdata_reset(&rdata);
relation = dns_name_fullcompare(&nxt.next, val->event->name, relation = dns_name_fullcompare(&nxt.next, val->event->name,
&order, &labels, &bits); &order, &nlabels, &bits);
if (order <= 0) { if (order <= 0) {
/* /*
* The NXT next name is less than the nonexistent * The NXT next name is less than the nonexistent