Commit 6fac7ff1 authored by Mark Andrews's avatar Mark Andrews

1606. [bug] DVL insecurity proof was failing.

1605.   [func]          New dns_db_find() option DNS_DBFIND_COVERINGNSEC.
parent d968099d
......@@ -87,9 +87,10 @@
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
......
......@@ -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
......
......@@ -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
......@@ -142,8 +142,9 @@
#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.
......
......@@ -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;
};
......
......@@ -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;
}
......
......@@ -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>
......@@ -65,25 +65,28 @@
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
......
......@@ -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] = {
......
......@@ -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;