diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/dns/api | 6 | ||||
| -rw-r--r-- | lib/dns/include/dns/ncache.h | 33 | ||||
| -rw-r--r-- | lib/dns/include/dns/types.h | 5 | ||||
| -rw-r--r-- | lib/dns/ncache.c | 330 | ||||
| -rw-r--r-- | lib/dns/resolver.c | 73 | ||||
| -rw-r--r-- | lib/dns/validator.c | 504 |
6 files changed, 722 insertions, 229 deletions
diff --git a/lib/dns/api b/lib/dns/api index 121147fe7c2a..251eda6f4d41 100644 --- a/lib/dns/api +++ b/lib/dns/api @@ -1,3 +1,3 @@ -LIBINTERFACE = 38 -LIBREVISION = 1 -LIBAGE = 0 +LIBINTERFACE = 39 +LIBREVISION = 0 +LIBAGE = 1 diff --git a/lib/dns/include/dns/ncache.h b/lib/dns/include/dns/ncache.h index 459effb909d7..915d489c40ec 100644 --- a/lib/dns/include/dns/ncache.h +++ b/lib/dns/include/dns/ncache.h @@ -1,8 +1,8 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004, 2005, 2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * - * Permission to use, copy, modify, and distribute this software for any + * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ncache.h,v 1.17.18.2 2005/04/29 00:16:16 marka Exp $ */ +/* $Id: ncache.h,v 1.17.18.4 2010/06/04 23:46:02 tbox Exp $ */ #ifndef DNS_NCACHE_H #define DNS_NCACHE_H 1 @@ -63,6 +63,11 @@ isc_result_t dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, dns_rdatatype_t covers, isc_stdtime_t now, dns_ttl_t maxttl, dns_rdataset_t *addedrdataset); +isc_result_t +dns_ncache_addoptout(dns_message_t *message, dns_db_t *cache, + dns_dbnode_t *node, dns_rdatatype_t covers, + isc_stdtime_t now, dns_ttl_t maxttl, + isc_boolean_t optout, dns_rdataset_t *addedrdataset); /*%< * Convert the authority data from 'message' into a negative cache * rdataset, and store it in 'cache' at 'node' with a TTL limited to @@ -71,6 +76,8 @@ dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, * The 'covers' argument is the RR type whose nonexistence we are caching, * or dns_rdatatype_any when caching a NXDOMAIN response. * + * 'optout' indicates a DNS_RDATASETATTR_OPTOUT should be set. + * * Note: *\li If 'addedrdataset' is not NULL, then it will be attached to the added * rdataset. See dns_db_addrdataset() for more details. @@ -154,6 +161,26 @@ dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, * */ +isc_result_t +dns_ncache_getsigrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, + dns_rdatatype_t covers, dns_rdataset_t *rdataset); +/*%< + * Similar to dns_ncache_getrdataset() but get the rrsig that matches. + */ + +void +dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found, + dns_rdataset_t *rdataset); + +/*%< + * Extract the current rdataset and name from a ncache entry. + * + * Requires: + * \li 'ncacherdataset' to be valid and to be a negative cache entry + * \li 'found' to be valid. + * \li 'rdataset' to be unassociated. + */ + ISC_LANG_ENDDECLS #endif /* DNS_NCACHE_H */ diff --git a/lib/dns/include/dns/types.h b/lib/dns/include/dns/types.h index 94c2d86f8233..0e3a7cbcf394 100644 --- a/lib/dns/include/dns/types.h +++ b/lib/dns/include/dns/types.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2006, 2009 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2006, 2009, 2010 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1998-2003 Internet Software Consortium. * * Permission to use, copy, modify, and/or distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: types.h,v 1.109.18.15 2009/11/25 04:50:25 marka Exp $ */ +/* $Id: types.h,v 1.109.18.17 2010/06/04 23:46:02 tbox Exp $ */ #ifndef DNS_TYPES_H #define DNS_TYPES_H 1 @@ -285,6 +285,7 @@ enum { #define DNS_TRUST_PENDING(x) ((x) == dns_trust_pending_answer || \ (x) == dns_trust_pending_additional) #define DNS_TRUST_GLUE(x) ((x) == dns_trust_glue) +#define DNS_TRUST_ANSWER(x) ((x) == dns_trust_answer) /*% diff --git a/lib/dns/ncache.c b/lib/dns/ncache.c index 89106dad7c06..5ee79bfc9ffc 100644 --- a/lib/dns/ncache.c +++ b/lib/dns/ncache.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: ncache.c,v 1.36.18.5 2010/02/26 23:46:36 tbox Exp $ */ +/* $Id: ncache.c,v 1.36.18.8 2010/06/03 23:46:10 tbox Exp $ */ /*! \file */ @@ -30,6 +30,9 @@ #include <dns/rdata.h> #include <dns/rdatalist.h> #include <dns/rdataset.h> +#include <dns/rdatastruct.h> + +#define DNS_NCACHE_RDATA 20U /* * The format of an ncache rdata is a sequence of one or more records of @@ -37,6 +40,7 @@ * * owner name * type + * trust * rdata count * rdata length These two occur 'rdata count' * rdata times. @@ -100,10 +104,11 @@ dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, dns_name_t *name; dns_ttl_t ttl; dns_trust_t trust; - dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdata_t rdata[DNS_NCACHE_RDATA]; dns_rdataset_t ncrdataset; dns_rdatalist_t ncrdatalist; unsigned char data[4096]; + unsigned int next = 0; /* * Convert the authority data from 'message' into a negative cache @@ -118,7 +123,17 @@ dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, */ /* - * First, build an ncache rdata in buffer. + * Initialize the list. + */ + ncrdatalist.rdclass = dns_db_class(cache); + ncrdatalist.type = 0; + ncrdatalist.covers = covers; + ncrdatalist.ttl = maxttl; + ISC_LIST_INIT(ncrdatalist.rdata); + ISC_LINK_INIT(&ncrdatalist, link); + + /* + * Build an ncache rdatas into buffer. */ ttl = maxttl; trust = 0xffff; @@ -164,6 +179,8 @@ dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, return (ISC_R_NOSPACE); isc_buffer_putuint16(&buffer, rdataset->type); + isc_buffer_putuint8(&buffer, + rdataset->trust); /* * Copy the rdataset into the buffer. */ @@ -171,6 +188,21 @@ dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, &buffer); if (result != ISC_R_SUCCESS) return (result); + + if (next >= DNS_NCACHE_RDATA) + return (ISC_R_NOSPACE); + dns_rdata_init(&rdata[next]); + isc_buffer_remainingregion(&buffer, &r); + rdata[next].data = r.base; + rdata[next].length = r.length; + rdata[next].rdclass = + ncrdatalist.rdclass; + rdata[next].type = 0; + rdata[next].flags = 0; + ISC_LIST_APPEND(ncrdatalist.rdata, + &rdata[next], link); + isc_buffer_forward(&buffer, r.length); + next++; } } } @@ -205,10 +237,9 @@ dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, * Copy the type and a zero rdata count to the buffer. */ isc_buffer_availableregion(&buffer, &r); - if (r.length < 4) + if (r.length < 5) return (ISC_R_NOSPACE); - isc_buffer_putuint16(&buffer, 0); - isc_buffer_putuint16(&buffer, 0); + isc_buffer_putuint16(&buffer, 0); /* type */ /* * RFC2308, section 5, says that negative answers without * SOAs should not be cached. @@ -226,27 +257,27 @@ dns_ncache_add(dns_message_t *message, dns_db_t *cache, dns_dbnode_t *node, trust = dns_trust_authauthority; } else trust = dns_trust_additional; + isc_buffer_putuint8(&buffer, trust); /* trust */ + isc_buffer_putuint16(&buffer, 0); /* count */ + + /* + * Now add it to the cache. + */ + if (next >= DNS_NCACHE_RDATA) + return (ISC_R_NOSPACE); + dns_rdata_init(&rdata[next]); + isc_buffer_remainingregion(&buffer, &r); + rdata[next].data = r.base; + rdata[next].length = r.length; + rdata[next].rdclass = ncrdatalist.rdclass; + rdata[next].type = 0; + rdata[next].flags = 0; + ISC_LIST_APPEND(ncrdatalist.rdata, &rdata[next], link); } - /* - * Now add it to the cache. - */ INSIST(trust != 0xffff); - isc_buffer_usedregion(&buffer, &r); - rdata.data = r.base; - rdata.length = r.length; - rdata.rdclass = dns_db_class(cache); - rdata.type = 0; - rdata.flags = 0; - ncrdatalist.rdclass = rdata.rdclass; - ncrdatalist.type = 0; - ncrdatalist.covers = covers; ncrdatalist.ttl = ttl; - ISC_LIST_INIT(ncrdatalist.rdata); - ISC_LINK_INIT(&ncrdatalist, link); - - ISC_LIST_APPEND(ncrdatalist.rdata, &rdata, link); dns_rdataset_init(&ncrdataset); RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset) @@ -281,18 +312,14 @@ dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx, REQUIRE(rdataset != NULL); REQUIRE(rdataset->type == 0); - result = dns_rdataset_first(rdataset); - if (result != ISC_R_SUCCESS) - return (result); - dns_rdataset_current(rdataset, &rdata); - INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE); - isc_buffer_init(&source, rdata.data, rdata.length); - isc_buffer_add(&source, rdata.length); - savedbuffer = *target; - count = 0; - do { + + result = dns_rdataset_first(rdataset); + while (result == ISC_R_SUCCESS) { + dns_rdataset_current(rdataset, &rdata); + isc_buffer_init(&source, rdata.data, rdata.length); + isc_buffer_add(&source, rdata.length); dns_name_init(&name, NULL); isc_buffer_remainingregion(&source, &remaining); dns_name_fromregion(&name, &remaining); @@ -300,8 +327,9 @@ dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx, isc_buffer_forward(&source, name.length); remaining.length -= name.length; - INSIST(remaining.length >= 4); + INSIST(remaining.length >= 5); type = isc_buffer_getuint16(&source); + isc_buffer_forward(&source, 1); rcount = isc_buffer_getuint16(&source); for (i = 0; i < rcount; i++) { @@ -370,8 +398,12 @@ dns_ncache_towire(dns_rdataset_t *rdataset, dns_compress_t *cctx, count++; } - isc_buffer_remainingregion(&source, &remaining); - } while (remaining.length > 0); + INSIST(isc_buffer_remaininglength(&source) == 0); + result = dns_rdataset_next(rdataset); + dns_rdata_reset(&rdata); + } + if (result != ISC_R_NOMORE) + goto rollback; *countp = count; @@ -467,6 +499,13 @@ rdataset_count(dns_rdataset_t *rdataset) { return (count); } +static void +rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) { + unsigned char *raw = rdataset->private3; + + raw[-1] = trust; +} + static dns_rdatasetmethods_t rdataset_methods = { rdataset_disassociate, rdataset_first, @@ -479,8 +518,8 @@ static dns_rdatasetmethods_t rdataset_methods = { NULL, NULL, NULL, + rdataset_settrust, NULL, - NULL }; isc_result_t @@ -493,8 +532,8 @@ dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, isc_buffer_t source; dns_name_t tname; dns_rdatatype_t ttype; - unsigned int i, rcount; - isc_uint16_t length; + dns_trust_t trust = dns_trust_none; + dns_rdataset_t clone; REQUIRE(ncacherdataset != NULL); REQUIRE(ncacherdataset->type == 0); @@ -502,15 +541,13 @@ dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, REQUIRE(!dns_rdataset_isassociated(rdataset)); REQUIRE(type != dns_rdatatype_rrsig); - result = dns_rdataset_first(ncacherdataset); - if (result != ISC_R_SUCCESS) - return (result); - dns_rdataset_current(ncacherdataset, &rdata); - INSIST(dns_rdataset_next(ncacherdataset) == ISC_R_NOMORE); - isc_buffer_init(&source, rdata.data, rdata.length); - isc_buffer_add(&source, rdata.length); - - do { + dns_rdataset_init(&clone); + dns_rdataset_clone(ncacherdataset, &clone); + result = dns_rdataset_first(&clone); + while (result == ISC_R_SUCCESS) { + dns_rdataset_current(&clone, &rdata); + isc_buffer_init(&source, rdata.data, rdata.length); + isc_buffer_add(&source, rdata.length); dns_name_init(&tname, NULL); isc_buffer_remainingregion(&source, &remaining); dns_name_fromregion(&tname, &remaining); @@ -518,35 +555,133 @@ dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, isc_buffer_forward(&source, tname.length); remaining.length -= tname.length; - INSIST(remaining.length >= 4); + INSIST(remaining.length >= 3); ttype = isc_buffer_getuint16(&source); if (ttype == type && dns_name_equal(&tname, name)) { + trust = isc_buffer_getuint8(&source); + INSIST(trust <= dns_trust_ultimate); isc_buffer_remainingregion(&source, &remaining); break; } + result = dns_rdataset_next(&clone); + dns_rdata_reset(&rdata); + } + dns_rdataset_disassociate(&clone); + if (result == ISC_R_NOMORE) + return (ISC_R_NOTFOUND); + if (result != ISC_R_SUCCESS) + return (result); - rcount = isc_buffer_getuint16(&source); - for (i = 0; i < rcount; i++) { - isc_buffer_remainingregion(&source, &remaining); - INSIST(remaining.length >= 2); - length = isc_buffer_getuint16(&source); + INSIST(remaining.length != 0); + + rdataset->methods = &rdataset_methods; + rdataset->rdclass = ncacherdataset->rdclass; + rdataset->type = type; + rdataset->covers = 0; + rdataset->ttl = ncacherdataset->ttl; + rdataset->trust = trust; + rdataset->private1 = NULL; + rdataset->private2 = NULL; + + rdataset->private3 = remaining.base; + + /* + * Reset iterator state. + */ + rdataset->privateuint4 = 0; + rdataset->private5 = NULL; + rdataset->private6 = NULL; + return (ISC_R_SUCCESS); +} + +isc_result_t +dns_ncache_getsigrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, + dns_rdatatype_t covers, dns_rdataset_t *rdataset) +{ + dns_name_t tname; + dns_rdata_rrsig_t rrsig; + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_rdataset_t clone; + dns_rdatatype_t type; + dns_trust_t trust = dns_trust_none; + isc_buffer_t source; + isc_region_t remaining, sigregion; + isc_result_t result; + unsigned char *raw; + unsigned int count; + + REQUIRE(ncacherdataset != NULL); + REQUIRE(ncacherdataset->type == 0); + REQUIRE(name != NULL); + REQUIRE(!dns_rdataset_isassociated(rdataset)); + + dns_rdataset_init(&clone); + dns_rdataset_clone(ncacherdataset, &clone); + result = dns_rdataset_first(&clone); + while (result == ISC_R_SUCCESS) { + dns_rdataset_current(&clone, &rdata); + isc_buffer_init(&source, rdata.data, rdata.length); + isc_buffer_add(&source, rdata.length); + dns_name_init(&tname, NULL); + isc_buffer_remainingregion(&source, &remaining); + dns_name_fromregion(&tname, &remaining); + INSIST(remaining.length >= tname.length); + isc_buffer_forward(&source, tname.length); + remaining.length -= tname.length; + remaining.base += tname.length; + + INSIST(remaining.length >= 2); + type = isc_buffer_getuint16(&source); + remaining.length -= 2; + remaining.base += 2; + + if (type != dns_rdatatype_rrsig || + !dns_name_equal(&tname, name)) { + result = dns_rdataset_next(&clone); + dns_rdata_reset(&rdata); + continue; + } + + INSIST(remaining.length >= 1); + trust = isc_buffer_getuint8(&source); + INSIST(trust <= dns_trust_ultimate); + remaining.length -= 1; + remaining.base += 1; + + raw = remaining.base; + count = raw[0] * 256 + raw[1]; + INSIST(count > 0); + raw += 2; + sigregion.length = raw[0] * 256 + raw[1]; + raw += 2; + sigregion.base = raw; + dns_rdata_reset(&rdata); + dns_rdata_fromregion(&rdata, rdataset->rdclass, + dns_rdatatype_rrsig, &sigregion); + (void)dns_rdata_tostruct(&rdata, &rrsig, NULL); + if (rrsig.covered == covers) { isc_buffer_remainingregion(&source, &remaining); - INSIST(remaining.length >= length); - isc_buffer_forward(&source, length); + break; } - isc_buffer_remainingregion(&source, &remaining); - } while (remaining.length > 0); - if (remaining.length == 0) + result = dns_rdataset_next(&clone); + dns_rdata_reset(&rdata); + } + dns_rdataset_disassociate(&clone); + if (result == ISC_R_NOMORE) return (ISC_R_NOTFOUND); + if (result != ISC_R_SUCCESS) + return (result); + + INSIST(remaining.length != 0); rdataset->methods = &rdataset_methods; rdataset->rdclass = ncacherdataset->rdclass; - rdataset->type = type; - rdataset->covers = 0; + rdataset->type = dns_rdatatype_rrsig; + rdataset->covers = covers; rdataset->ttl = ncacherdataset->ttl; - rdataset->trust = ncacherdataset->trust; + rdataset->trust = trust; rdataset->private1 = NULL; rdataset->private2 = NULL; @@ -557,5 +692,78 @@ dns_ncache_getrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name, */ rdataset->privateuint4 = 0; rdataset->private5 = NULL; + rdataset->private6 = NULL; return (ISC_R_SUCCESS); } + +void +dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found, + dns_rdataset_t *rdataset) +{ + dns_rdata_t rdata = DNS_RDATA_INIT; + dns_trust_t trust; + isc_region_t remaining, sigregion; + isc_buffer_t source; + dns_name_t tname; + dns_rdatatype_t type; + unsigned int count; + dns_rdata_rrsig_t rrsig; + unsigned char *raw; + + REQUIRE(ncacherdataset != NULL); + REQUIRE(ncacherdataset->type == 0); + REQUIRE(found != NULL); + REQUIRE(!dns_rdataset_isassociated(rdataset)); + + dns_rdataset_current(ncacherdataset, &rdata); + isc_buffer_init(&source, rdata.data, rdata.length); + isc_buffer_add(&source, rdata.length); + + dns_name_init(&tname, NULL); + isc_buffer_remainingregion(&source, &remaining); + dns_name_fromregion(found, &remaining); + INSIST(remaining.length >= found->length); + isc_buffer_forward(&source, found->length); + remaining.length -= found->length; + + INSIST(remaining.length >= 5); + type = isc_buffer_getuint16(&source); + trust = isc_buffer_getuint8(&source); + INSIST(trust <= dns_trust_ultimate); + isc_buffer_remainingregion(&source, &remaining); + + rdataset->methods = &rdataset_methods; + rdataset->rdclass = ncacherdataset->rdclass; + rdataset->type = type; + if (type == dns_rdatatype_rrsig) { + /* + * Extract covers from RRSIG. + */ + raw = remaining.base; + count = raw[0] * 256 + raw[1]; + INSIST(count > 0); + raw += 2; + sigregion.length = raw[0] * 256 + raw[1]; + raw += 2; + sigregion.base = raw; + dns_rdata_reset(&rdata); + dns_rdata_fromregion(&rdata, rdataset->rdclass, + rdataset->type, &sigregion); + (void)dns_rdata_tostruct(&rdata, &rrsig, NULL); + rdataset->covers = rrsig.covered; + } else + rdataset->covers = 0; + rdataset->ttl = ncacherdataset->ttl; + rdataset->trust = trust; + rdataset->private1 = NULL; + rdataset->private2 = NULL; + + rdataset->private3 = remaining.base; + + /* + * Reset iterator state. + */ + rdataset->privateuint4 = 0; + rdataset->private5 = NULL; + rdataset->private6 = NULL; +} diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 95c7bd4a4f84..f14ac7fda535 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: resolver.c,v 1.284.18.101 2010/02/26 23:46:36 tbox Exp $ */ +/* $Id: resolver.c,v 1.284.18.103 2010/06/23 23:45:21 tbox Exp $ */ /*! \file */ @@ -5612,13 +5612,40 @@ answer_response(fetchctx_t *fctx) { return (result); } +static isc_boolean_t +fctx_decreference(fetchctx_t *fctx) { + isc_boolean_t bucket_empty = ISC_FALSE; + + INSIST(fctx->references > 0); + fctx->references--; + if (fctx->references == 0) { + /* + * No one cares about the result of this fetch anymore. + */ + if (fctx->pending == 0 && fctx->nqueries == 0 && + ISC_LIST_EMPTY(fctx->validators) && SHUTTINGDOWN(fctx)) { + /* + * This fctx is already shutdown; we were just + * waiting for the last reference to go away. + */ + bucket_empty = fctx_destroy(fctx); + } else { + /* + * Initiate shutdown. + */ + fctx_shutdown(fctx); + } + } + return (bucket_empty); +} + static void resume_dslookup(isc_task_t *task, isc_event_t *event) { dns_fetchevent_t *fevent; dns_resolver_t *res; fetchctx_t *fctx; isc_result_t result; - isc_boolean_t bucket_empty = ISC_FALSE; + isc_boolean_t bucket_empty; isc_boolean_t locked = ISC_FALSE; unsigned int bucketnum; dns_rdataset_t nameservers; @@ -5722,9 +5749,7 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { isc_event_free(&event); if (!locked) LOCK(&res->buckets[bucketnum].lock); - fctx->references--; - if (fctx->references == 0) - bucket_empty = fctx_destroy(fctx); + bucket_empty = fctx_decreference(fctx); UNLOCK(&res->buckets[bucketnum].lock); if (bucket_empty) empty_bucket(res); @@ -6449,12 +6474,14 @@ resquery_response(isc_task_t *task, isc_event_t *event) { &fctx->nsfetch); if (result != ISC_R_SUCCESS) fctx_done(fctx, result, __LINE__); - LOCK(&fctx->res->buckets[fctx->bucketnum].lock); - fctx->references++; - UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); - result = fctx_stopidletimer(fctx); - if (result != ISC_R_SUCCESS) - fctx_done(fctx, result, __LINE__); + else { + LOCK(&fctx->res->buckets[fctx->bucketnum].lock); + fctx->references++; + UNLOCK(&fctx->res->buckets[fctx->bucketnum].lock); + result = fctx_stopidletimer(fctx); + if (result != ISC_R_SUCCESS) + fctx_done(fctx, result, __LINE__); + } } else { /* * We're done. @@ -7288,7 +7315,7 @@ dns_resolver_destroyfetch(dns_fetch_t **fetchp) { dns_fetchevent_t *event, *next_event; fetchctx_t *fctx; unsigned int bucketnum; - isc_boolean_t bucket_empty = ISC_FALSE; + isc_boolean_t bucket_empty; REQUIRE(fetchp != NULL); fetch = *fetchp; @@ -7316,27 +7343,7 @@ dns_resolver_destroyfetch(dns_fetch_t **fetchp) { } } - INSIST(fctx->references > 0); - fctx->references--; - if (fctx->references == 0) { - /* - * No one cares about the result of this fetch anymore. - */ - if (fctx->pending == 0 && fctx->nqueries == 0 && - ISC_LIST_EMPTY(fctx->validators) && - SHUTTINGDOWN(fctx)) { - /* - * This fctx is already shutdown; we were just - * waiting for the last reference to go away. - */ - bucket_empty = fctx_destroy(fctx); - } else { - /* - * Initiate shutdown. - */ - fctx_shutdown(fctx); - } - } + bucket_empty = fctx_decreference(fctx); UNLOCK(&res->buckets[bucketnum].lock); diff --git a/lib/dns/validator.c b/lib/dns/validator.c index 20843464a223..6a1d0c9a04b4 100644 --- a/lib/dns/validator.c +++ b/lib/dns/validator.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: validator.c,v 1.119.18.54 2010/04/21 04:23:47 marka Exp $ */ +/* $Id: validator.c,v 1.119.18.59 2010/09/02 07:21:53 marka Exp $ */ /*! \file */ @@ -113,6 +113,10 @@ #define NEEDNOQNAME(val) ((val->attributes & VALATTR_NEEDNOQNAME) != 0) #define NEEDNOWILDCARD(val) ((val->attributes & VALATTR_NEEDNOWILDCARD) != 0) #define DLVTRIED(val) ((val->attributes & VALATTR_DLVTRIED) != 0) +#define FOUNDNODATA(val) ((val->attributes & VALATTR_FOUNDNODATA) != 0) +#define FOUNDNOQNAME(val) ((val->attributes & VALATTR_FOUNDNOQNAME) != 0) +#define FOUNDNOWILDCARD(val) ((val->attributes & VALATTR_FOUNDNOWILDCARD) != 0) +#define FOUNDOPTOUT(val) ((val->attributes & VALATTR_FOUNDOPTOUT) != 0) #define SHUTDOWN(v) (((v)->attributes & VALATTR_SHUTDOWN) != 0) #define CANCELED(v) (((v)->attributes & VALATTR_CANCELED) != 0) @@ -167,8 +171,8 @@ startfinddlvsep(dns_validator_t *val, dns_name_t *unsecure); * Mark the RRsets as a answer. */ static inline void -markanswer(dns_validator_t *val) { - validator_log(val, ISC_LOG_DEBUG(3), "marking as answer"); +markanswer(dns_validator_t *val, const char *where) { + validator_log(val, ISC_LOG_DEBUG(3), "marking as answer (%s)", where); if (val->event->rdataset != NULL) dns_rdataset_settrust(val->event->rdataset, dns_trust_answer); if (val->event->sigrdataset != NULL) @@ -179,7 +183,8 @@ markanswer(dns_validator_t *val) { static inline void marksecure(dns_validatorevent_t *event) { dns_rdataset_settrust(event->rdataset, dns_trust_secure); - dns_rdataset_settrust(event->sigrdataset, dns_trust_secure); + if (event->sigrdataset != NULL) + dns_rdataset_settrust(event->sigrdataset, dns_trust_secure); } static void @@ -475,7 +480,7 @@ dsfetched2(isc_task_t *task, isc_event_t *event) { "must be secure failure"); validator_done(val, DNS_R_MUSTBESECURE); } else if (val->view->dlv == NULL || DLVTRIED(val)) { - markanswer(val); + markanswer(val, "dsfetched2"); validator_done(val, ISC_R_SUCCESS); } else { result = startfinddlvsep(val, tname); @@ -601,11 +606,32 @@ dsvalidated(isc_task_t *task, isc_event_t *event) { if (CANCELED(val)) { validator_done(val, ISC_R_CANCELED); } else if (eresult == ISC_R_SUCCESS) { + isc_boolean_t have_dsset; + dns_name_t *name; validator_log(val, ISC_LOG_DEBUG(3), - "dsset with trust %d", val->frdataset.trust); - if ((val->attributes & VALATTR_INSECURITY) != 0) - result = proveunsecure(val, ISC_TRUE, ISC_TRUE); - else + "%s with trust %d", + val->frdataset.type == dns_rdatatype_ds ? + "dsset" : "ds non-existance", + val->frdataset.trust); + have_dsset = ISC_TF(val->frdataset.type == dns_rdatatype_ds); + name = dns_fixedname_name(&val->fname); + if ((val->attributes & VALATTR_INSECURITY) != 0 && + val->frdataset.covers == dns_rdatatype_ds && + val->frdataset.type == 0 && + isdelegation(name, &val->frdataset, DNS_R_NCACHENXRRSET)) { + if (val->mustbesecure) { + validator_log(val, ISC_LOG_WARNING, + "must be secure failure, no DS " + "and this is a delegation"); + result = DNS_R_MUSTBESECURE; + } else if (val->view->dlv == NULL || DLVTRIED(val)) { + markanswer(val, "dsvalidated"); + result = ISC_R_SUCCESS;; + } else + result = startfinddlvsep(val, name); + } else if ((val->attributes & VALATTR_INSECURITY) != 0) { + result = proveunsecure(val, have_dsset, ISC_TRUE); + } else result = validatezonekey(val); if (result != DNS_R_WAIT) validator_done(val, result); @@ -839,10 +865,8 @@ authvalidated(isc_task_t *task, isc_event_t *event) { if (rdataset->type == dns_rdatatype_nsec && rdataset->trust == dns_trust_secure && - ((val->attributes & VALATTR_NEEDNODATA) != 0 || - (val->attributes & VALATTR_NEEDNOQNAME) != 0) && - (val->attributes & VALATTR_FOUNDNODATA) == 0 && - (val->attributes & VALATTR_FOUNDNOQNAME) == 0 && + (NEEDNODATA(val) || NEEDNOQNAME(val)) && + !FOUNDNODATA(val) && !FOUNDNOQNAME(val) && nsecnoexistnodata(val, val->event->name, devent->name, rdataset, &exists, &data, wild) == ISC_R_SUCCESS) @@ -1227,11 +1251,14 @@ get_key(dns_validator_t *val, dns_rdata_rrsig_t *siginfo) { * We have an rrset for the given keyname. */ val->keyset = &val->frdataset; - if (DNS_TRUST_PENDING(val->frdataset.trust) && + if ((DNS_TRUST_PENDING(val->frdataset.trust) || + DNS_TRUST_ANSWER(val->frdataset.trust)) && dns_rdataset_isassociated(&val->fsigrdataset)) { /* - * We know the key but haven't validated it yet. + * We know the key but haven't validated it yet or + * we have a key of trust answer but a DS/DLV + * record for the zone may have been added. */ result = create_validator(val, &siginfo->signer, dns_rdatatype_dnskey, @@ -1474,7 +1501,7 @@ validate(dns_validator_t *val, isc_boolean_t resume) { "must be secure failure"); return (DNS_R_MUSTBESECURE); } - markanswer(val); + markanswer(val, "validate"); return (ISC_R_SUCCESS); } @@ -1531,7 +1558,7 @@ validate(dns_validator_t *val, isc_boolean_t resume) { } } val->key = NULL; - if ((val->attributes & VALATTR_NEEDNOQNAME) != 0) { + if (NEEDNOQNAME(val)) { if (val->event->message == NULL) { validator_log(val, ISC_LOG_DEBUG(3), "no message available for noqname proof"); @@ -1728,7 +1755,7 @@ dlv_validatezonekey(dns_validator_t *val) { } validator_log(val, ISC_LOG_DEBUG(3), "no supported algorithm/digest (dlv)"); - markanswer(val); + markanswer(val, "dlv_validatezonekey (2)"); return (ISC_R_SUCCESS); } else return (DNS_R_NOVALIDSIG); @@ -1774,6 +1801,17 @@ validatezonekey(dns_validator_t *val) { return (dlv_validatezonekey(val)); if (val->dsset == NULL) { + + /* + * We have a dlv sep. Skip looking up the SEP from + * {trusted,managed}-keys. If the dlv sep is for the + * root then it will have been handled above so we don't + * need to check whether val->event->name is "." prior to + * looking up the DS. + */ + if (val->havedlvsep) + goto find_ds; + /* * First, see if this key was signed by a trusted key. */ @@ -1781,8 +1819,12 @@ validatezonekey(dns_validator_t *val) { result == ISC_R_SUCCESS; result = dns_rdataset_next(val->event->sigrdataset)) { - dns_keynode_t *keynode = NULL, *nextnode = NULL; + dns_keynode_t *keynode = NULL; + dns_fixedname_t fixed; + dns_name_t *found; + dns_fixedname_init(&fixed); + found = dns_fixedname_name(&fixed); dns_rdata_reset(&sigrdata); dns_rdataset_current(val->event->sigrdataset, &sigrdata); @@ -1797,10 +1839,28 @@ validatezonekey(dns_validator_t *val) { sig.algorithm, sig.keyid, &keynode); + if (result == ISC_R_NOTFOUND && + dns_keytable_finddeepestmatch(val->keytable, + val->event->name, found) != ISC_R_SUCCESS) { + if (val->mustbesecure) { + validator_log(val, ISC_LOG_WARNING, + "must be secure failure, " + "not beneath secure root"); + return (DNS_R_MUSTBESECURE); + } else + validator_log(val, ISC_LOG_DEBUG(3), + "not beneath secure root"); + if (val->view->dlv == NULL) { + markanswer(val, "validatezonekey (1)"); + return (ISC_R_SUCCESS); + } + return (startfinddlvsep(val, dns_rootname)); + } if (result == DNS_R_PARTIALMATCH || result == ISC_R_SUCCESS) atsep = ISC_TRUE; while (result == ISC_R_SUCCESS) { + dns_keynode_t *nextnode = NULL; dstkey = dns_keynode_key(keynode); result = verify(val, dstkey, &sigrdata, sig.keyid); @@ -1826,17 +1886,6 @@ validatezonekey(dns_validator_t *val) { } } - /* - * If this is the root name and there was no trusted key, - * give up, since there's no DS at the root. - */ - if (dns_name_equal(event->name, dns_rootname)) { - if ((val->attributes & VALATTR_TRIEDVERIFY) != 0) - return (DNS_R_NOVALIDSIG); - else - return (DNS_R_NOVALIDDS); - } - if (atsep) { /* * We have not found a key to verify this DNSKEY @@ -1857,6 +1906,22 @@ validatezonekey(dns_validator_t *val) { } /* + * If this is the root name and there was no trusted key, + * give up, since there's no DS at the root. + */ + if (dns_name_equal(event->name, dns_rootname)) { + if ((val->attributes & VALATTR_TRIEDVERIFY) != 0) { + validator_log(val, ISC_LOG_DEBUG(3), + "root key failed to validate"); + return (DNS_R_NOVALIDSIG); + } else { + validator_log(val, ISC_LOG_DEBUG(3), + "no trusted root key"); + return (DNS_R_NOVALIDDS); + } + } + find_ds: + /* * Otherwise, try to find the DS record. */ result = view_find(val, val->event->name, dns_rdatatype_ds); @@ -1865,7 +1930,8 @@ validatezonekey(dns_validator_t *val) { * We have DS records. */ val->dsset = &val->frdataset; - if (DNS_TRUST_PENDING(val->frdataset.trust) && + if ((DNS_TRUST_PENDING(val->frdataset.trust) || + DNS_TRUST_ANSWER(val->frdataset.trust)) && dns_rdataset_isassociated(&val->fsigrdataset)) { result = create_validator(val, @@ -1928,7 +1994,7 @@ validatezonekey(dns_validator_t *val) { "must be secure failure"); return (DNS_R_MUSTBESECURE); } - markanswer(val); + markanswer(val, "validatezonekey (2)"); return (ISC_R_SUCCESS); } @@ -2074,7 +2140,7 @@ validatezonekey(dns_validator_t *val) { } validator_log(val, ISC_LOG_DEBUG(3), "no supported algorithm/digest (DS)"); - markanswer(val); + markanswer(val, "validatezonekey (3)"); return (ISC_R_SUCCESS); } else return (DNS_R_NOVALIDSIG); @@ -2101,6 +2167,80 @@ start_positive_validation(dns_validator_t *val) { } /*% + * val_rdataset_first and val_rdataset_next provide iteration methods + * that hide whether we are iterating across a message or a negative + * cache rdataset. + */ +static isc_result_t +val_rdataset_first(dns_validator_t *val, dns_name_t **namep, + dns_rdataset_t **rdatasetp) +{ + dns_message_t *message = val->event->message; + isc_result_t result; + + REQUIRE(rdatasetp != NULL); + REQUIRE(namep != NULL); + if (message == NULL) { + REQUIRE(*rdatasetp != NULL); + REQUIRE(*namep != NULL); + } else { + REQUIRE(*rdatasetp == NULL); + REQUIRE(*namep == NULL); + } + + if (message != NULL) { + result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); + if (result != ISC_R_SUCCESS) + return (result); + dns_message_currentname(message, DNS_SECTION_AUTHORITY, namep); + *rdatasetp = ISC_LIST_HEAD((*namep)->list); + INSIST(*rdatasetp != NULL); + } else { + result = dns_rdataset_first(val->event->rdataset); + if (result == ISC_R_SUCCESS) + dns_ncache_current(val->event->rdataset, *namep, + *rdatasetp); + } + return (result); +} + +static isc_result_t +val_rdataset_next(dns_validator_t *val, dns_name_t **namep, + dns_rdataset_t **rdatasetp) +{ + dns_message_t *message = val->event->message; + isc_result_t result = ISC_R_SUCCESS; + + REQUIRE(rdatasetp != NULL && *rdatasetp != NULL); + REQUIRE(namep != NULL && *namep != NULL); + + if (message != NULL) { + dns_rdataset_t *rdataset = *rdatasetp; + rdataset = ISC_LIST_NEXT(rdataset, link); + if (rdataset == NULL) { + *namep = NULL; + result = dns_message_nextname(message, + DNS_SECTION_AUTHORITY); + if (result == ISC_R_SUCCESS) { + dns_message_currentname(message, + DNS_SECTION_AUTHORITY, + namep); + rdataset = ISC_LIST_HEAD((*namep)->list); + INSIST(rdataset != NULL); + } + } + *rdatasetp = rdataset; + } else { + dns_rdataset_disassociate(*rdatasetp); + result = dns_rdataset_next(val->event->rdataset); + if (result == ISC_R_SUCCESS) + dns_ncache_current(val->event->rdataset, *namep, + *rdatasetp); + } + return (result); +} + +/*% * Look for NODATA at the wildcard and NOWILDCARD proofs in the * previously validated NSEC records. As these proofs are mutually * exclusive we stop when one is found. @@ -2110,100 +2250,81 @@ start_positive_validation(dns_validator_t *val) { */ static isc_result_t checkwildcard(dns_validator_t *val) { - dns_name_t *name, *wild; - dns_message_t *message = val->event->message; + dns_name_t *name, *wild, tname; isc_result_t result; isc_boolean_t exists, data; char namebuf[DNS_NAME_FORMATSIZE]; + dns_rdataset_t *rdataset, trdataset; + dns_name_init(&tname, NULL); + dns_rdataset_init(&trdataset); wild = dns_fixedname_name(&val->wild); dns_name_format(wild, namebuf, sizeof(namebuf)); validator_log(val, ISC_LOG_DEBUG(3), "in checkwildcard: %s", namebuf); - for (result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); + if (val->event->message == NULL) { + name = &tname; + rdataset = &trdataset; + } else { + name = NULL; + rdataset = NULL; + } + + for (result = val_rdataset_first(val, &name, &rdataset); result == ISC_R_SUCCESS; - result = dns_message_nextname(message, DNS_SECTION_AUTHORITY)) + result = val_rdataset_next(val, &name, &rdataset)) { - dns_rdataset_t *rdataset = NULL, *sigrdataset = NULL; + if (rdataset->type != dns_rdatatype_nsec || + rdataset->trust != dns_trust_secure) + continue; + val->nsecset = rdataset; - name = NULL; - dns_message_currentname(message, DNS_SECTION_AUTHORITY, &name); + if (rdataset->trust != dns_trust_secure) + continue; - for (rdataset = ISC_LIST_HEAD(name->list); - rdataset != NULL; - rdataset = ISC_LIST_NEXT(rdataset, link)) + if ((NEEDNODATA(val) || NEEDNOWILDCARD(val)) && + !FOUNDNODATA(val) && !FOUNDNOWILDCARD(val) && + nsecnoexistnodata(val, wild, name, rdataset, + &exists, &data, NULL) + == ISC_R_SUCCESS) { - if (rdataset->type != dns_rdatatype_nsec) - continue; - val->nsecset = rdataset; - - for (sigrdataset = ISC_LIST_HEAD(name->list); - sigrdataset != NULL; - sigrdataset = ISC_LIST_NEXT(sigrdataset, link)) - { - if (sigrdataset->type == dns_rdatatype_rrsig && - sigrdataset->covers == rdataset->type) - break; - } - if (sigrdataset == NULL) - continue; - - if (rdataset->trust != dns_trust_secure) - continue; - - if (((val->attributes & VALATTR_NEEDNODATA) != 0 || - (val->attributes & VALATTR_NEEDNOWILDCARD) != 0) && - (val->attributes & VALATTR_FOUNDNODATA) == 0 && - (val->attributes & VALATTR_FOUNDNOWILDCARD) == 0 && - nsecnoexistnodata(val, wild, name, rdataset, - &exists, &data, NULL) - == ISC_R_SUCCESS) - { - dns_name_t **proofs = val->event->proofs; - if (exists && !data) - val->attributes |= VALATTR_FOUNDNODATA; - if (exists && !data && NEEDNODATA(val)) - proofs[DNS_VALIDATOR_NODATAPROOF] = - name; - if (!exists) - val->attributes |= - VALATTR_FOUNDNOWILDCARD; - if (!exists && NEEDNOQNAME(val)) - proofs[DNS_VALIDATOR_NOWILDCARDPROOF] = - name; - return (ISC_R_SUCCESS); - } + dns_name_t **proofs = val->event->proofs; + if (exists && !data) + val->attributes |= VALATTR_FOUNDNODATA; + if (exists && !data && NEEDNODATA(val)) + proofs[DNS_VALIDATOR_NODATAPROOF] = + name; + if (!exists) + val->attributes |= + VALATTR_FOUNDNOWILDCARD; + if (!exists && NEEDNOQNAME(val)) + proofs[DNS_VALIDATOR_NOWILDCARDPROOF] = + name; + if (dns_rdataset_isassociated(&trdataset)) + dns_rdataset_disassociate(&trdataset); + return (ISC_R_SUCCESS); } } if (result == ISC_R_NOMORE) result = ISC_R_SUCCESS; + if (dns_rdataset_isassociated(&trdataset)) + dns_rdataset_disassociate(&trdataset); return (result); } /*% - * Prove a negative answer is good or that there is a NOQNAME when the - * answer is from a wildcard. - * - * Loop through the authority section looking for NODATA, NOWILDCARD - * and NOQNAME proofs in the NSEC records by calling authvalidated(). - * - * If the required proofs are found we are done. - * - * If the proofs are not found attempt to prove this is a unsecure - * response. + * Validate the authority section records. */ static isc_result_t -nsecvalidate(dns_validator_t *val, isc_boolean_t resume) { +validate_authority(dns_validator_t *val, isc_boolean_t resume) { dns_name_t *name; dns_message_t *message = val->event->message; isc_result_t result; if (!resume) result = dns_message_firstname(message, DNS_SECTION_AUTHORITY); - else { + else result = ISC_R_SUCCESS; - validator_log(val, ISC_LOG_DEBUG(3), "resuming nsecvalidate"); - } for (; result == ISC_R_SUCCESS; @@ -2266,16 +2387,121 @@ nsecvalidate(dns_validator_t *val, isc_boolean_t resume) { result = create_validator(val, name, rdataset->type, rdataset, sigrdataset, authvalidated, - "nsecvalidate"); + "validate_authority"); if (result != ISC_R_SUCCESS) return (result); val->authcount++; return (DNS_R_WAIT); + } + } + if (result == ISC_R_NOMORE) + result = ISC_R_SUCCESS; + return (result); +} + +/*% + * Validate the ncache elements. + */ +static isc_result_t +validate_ncache(dns_validator_t *val, isc_boolean_t resume) { + dns_name_t *name; + isc_result_t result; + + if (!resume) + result = dns_rdataset_first(val->event->rdataset); + else + result = dns_rdataset_next(val->event->rdataset); + + for (; + result == ISC_R_SUCCESS; + result = dns_rdataset_next(val->event->rdataset)) + { + dns_rdataset_t *rdataset, *sigrdataset = NULL; + + if (dns_rdataset_isassociated(&val->frdataset)) + dns_rdataset_disassociate(&val->frdataset); + if (dns_rdataset_isassociated(&val->fsigrdataset)) + dns_rdataset_disassociate(&val->fsigrdataset); + + dns_fixedname_init(&val->fname); + name = dns_fixedname_name(&val->fname); + rdataset = &val->frdataset; + dns_ncache_current(val->event->rdataset, name, rdataset); + + if (val->frdataset.type == dns_rdatatype_rrsig) + continue; + + result = dns_ncache_getsigrdataset(val->event->rdataset, name, + rdataset->type, + &val->fsigrdataset); + if (result == ISC_R_SUCCESS) + sigrdataset = &val->fsigrdataset; + + /* + * If a signed zone is missing the zone key, bad + * things could happen. A query for data in the zone + * would lead to a query for the zone key, which + * would return a negative answer, which would contain + * an SOA and an NSEC signed by the missing key, which + * would trigger another query for the DNSKEY (since + * the first one is still in progress), and go into an + * infinite loop. Avoid that. + */ + if (val->event->type == dns_rdatatype_dnskey && + dns_name_equal(name, val->event->name)) + { + dns_rdata_t nsec = DNS_RDATA_INIT; + + if (rdataset->type != dns_rdatatype_nsec) + continue; + result = dns_rdataset_first(rdataset); + if (result != ISC_R_SUCCESS) + return (result); + dns_rdataset_current(rdataset, &nsec); + if (dns_nsec_typepresent(&nsec, + dns_rdatatype_soa)) + continue; } + val->currentset = rdataset; + result = create_validator(val, name, rdataset->type, + rdataset, sigrdataset, + authvalidated, + "validate_ncache"); + if (result != ISC_R_SUCCESS) + return (result); + val->authcount++; + return (DNS_R_WAIT); } if (result == ISC_R_NOMORE) result = ISC_R_SUCCESS; + return (result); +} + +/*% + * Prove a negative answer is good or that there is a NOQNAME when the + * answer is from a wildcard. + * + * Loop through the authority section looking for NODATA, NOWILDCARD + * and NOQNAME proofs in the NSEC records by calling authvalidated(). + * + * If the required proofs are found we are done. + * + * If the proofs are not found attempt to prove this is a unsecure + * response. + */ +static isc_result_t +nsecvalidate(dns_validator_t *val, isc_boolean_t resume) { + isc_result_t result; + + if (resume) + validator_log(val, ISC_LOG_DEBUG(3), "resuming nsecvalidate"); + + if (val->event->message == NULL) + result = validate_ncache(val, resume); + else + result = validate_authority(val, resume); + if (result != ISC_R_SUCCESS) return (result); @@ -2302,23 +2528,20 @@ nsecvalidate(dns_validator_t *val, isc_boolean_t resume) { /* * Do we need to check for the wildcard? */ - if ((val->attributes & VALATTR_FOUNDNOQNAME) != 0 && - (((val->attributes & VALATTR_NEEDNODATA) != 0 && - (val->attributes & VALATTR_FOUNDNODATA) == 0) || - (val->attributes & VALATTR_NEEDNOWILDCARD) != 0)) { + if (FOUNDNOQNAME(val) && + ((NEEDNODATA(val) && !FOUNDNODATA(val)) || NEEDNOWILDCARD(val))) { result = checkwildcard(val); if (result != ISC_R_SUCCESS) return (result); } - if (((val->attributes & VALATTR_NEEDNODATA) != 0 && - (val->attributes & VALATTR_FOUNDNODATA) != 0) || - ((val->attributes & VALATTR_NEEDNOQNAME) != 0 && - (val->attributes & VALATTR_FOUNDNOQNAME) != 0 && - (val->attributes & VALATTR_NEEDNOWILDCARD) != 0 && - (val->attributes & VALATTR_FOUNDNOWILDCARD) != 0)) { + if ((NEEDNODATA(val) && FOUNDNODATA(val)) || + (NEEDNOQNAME(val) && FOUNDNOQNAME(val) && + NEEDNOWILDCARD(val) && FOUNDNOWILDCARD(val))) { validator_log(val, ISC_LOG_DEBUG(3), "nonexistence proof(s) found"); + if (val->event->message == NULL) + marksecure(val->event); return (ISC_R_SUCCESS); } @@ -2386,7 +2609,7 @@ dlvvalidated(isc_task_t *task, isc_event_t *event) { if (dlv_algorithm_supported(val)) dlv_validator_start(val); else { - markanswer(val); + markanswer(val, "dlvvalidated"); validator_done(val, ISC_R_SUCCESS); } } else { @@ -2455,7 +2678,7 @@ dlvfetched(isc_task_t *task, isc_event_t *event) { validator_log(val, ISC_LOG_DEBUG(3), "DLV %s found with no supported algorithms", namebuf); - markanswer(val); + markanswer(val, "dlvfetched (1)"); validator_done(val, ISC_R_SUCCESS); } } else if (eresult == DNS_R_NXRRSET || @@ -2474,12 +2697,12 @@ dlvfetched(isc_task_t *task, isc_event_t *event) { validator_log(val, ISC_LOG_DEBUG(3), "DLV %s found with no supported " "algorithms", namebuf); - markanswer(val); + markanswer(val, "dlvfetched (2)"); validator_done(val, ISC_R_SUCCESS); } } else if (result == ISC_R_NOTFOUND) { validator_log(val, ISC_LOG_DEBUG(3), "DLV not found"); - markanswer(val); + markanswer(val, "dlvfetched (3)"); validator_done(val, ISC_R_SUCCESS); } else { validator_log(val, ISC_LOG_DEBUG(3), "DLV lookup: %s", @@ -2529,7 +2752,7 @@ startfinddlvsep(dns_validator_t *val, dns_name_t *unsecure) { result = finddlvsep(val, ISC_FALSE); if (result == ISC_R_NOTFOUND) { validator_log(val, ISC_LOG_DEBUG(3), "DLV not found"); - markanswer(val); + markanswer(val, "startfinddlvsep (1)"); return (ISC_R_SUCCESS); } if (result != ISC_R_SUCCESS) { @@ -2546,7 +2769,7 @@ startfinddlvsep(dns_validator_t *val, dns_name_t *unsecure) { } validator_log(val, ISC_LOG_DEBUG(3), "DLV %s found with no supported " "algorithms", namebuf); - markanswer(val); + markanswer(val, "startfinddlvsep (2)"); validator_done(val, ISC_R_SUCCESS); return (ISC_R_SUCCESS); } @@ -2731,7 +2954,7 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) goto out; } if (val->view->dlv == NULL || DLVTRIED(val)) { - markanswer(val); + markanswer(val, "proveunsecure (1)"); return (ISC_R_SUCCESS); } return (startfinddlvsep(val, dns_rootname)); @@ -2769,7 +2992,7 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) "no supported algorithm/digest (%s/DS)", namebuf); if (val->view->dlv == NULL || DLVTRIED(val)) { - markanswer(val); + markanswer(val, "proveunsecure (2)"); result = ISC_R_SUCCESS; goto out; } @@ -2799,18 +3022,23 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) namebuf); result = view_find(val, tname, dns_rdatatype_ds); - if (result == DNS_R_NXRRSET || result == DNS_R_NCACHENXRRSET) { /* * There is no DS. If this is a delegation, * we maybe done. */ - if (DNS_TRUST_PENDING(val->frdataset.trust)) { - result = create_fetch(val, tname, - dns_rdatatype_ds, - dsfetched2, - "proveunsecure"); - if (result != ISC_R_SUCCESS) + /* + * If we have "trust == answer" then this namespace + * has switched from insecure to should be secure. + */ + if (DNS_TRUST_PENDING(val->frdataset.trust) || + DNS_TRUST_ANSWER(val->frdataset.trust)) { + result = create_validator(val, tname, + dns_rdatatype_ds, + &val->frdataset, + NULL, dsvalidated, + "proveunsecure"); + if (result != ISC_R_SUCCESS) goto out; return (DNS_R_WAIT); } @@ -2831,7 +3059,7 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) return (DNS_R_MUSTBESECURE); } if (val->view->dlv == NULL || DLVTRIED(val)) { - markanswer(val); + markanswer(val, "proveunsecure (3)"); return (ISC_R_SUCCESS); } return (startfinddlvsep(val, tname)); @@ -2856,7 +3084,8 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) } if (val->view->dlv == NULL || DLVTRIED(val)) { - markanswer(val); + markanswer(val, + "proveunsecure (5)"); result = ISC_R_SUCCESS; goto out; } @@ -2870,6 +3099,9 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) result = DNS_R_NOVALIDSIG; goto out; } + /* + * Validate / re-validate answer. + */ result = create_validator(val, tname, dns_rdatatype_ds, &val->frdataset, &val->fsigrdataset, @@ -2914,8 +3146,10 @@ proveunsecure(dns_validator_t *val, isc_boolean_t have_ds, isc_boolean_t resume) } else if (result == DNS_R_BROKENCHAIN) return (result); } + + /* Couldn't complete insecurity proof */ validator_log(val, ISC_LOG_DEBUG(3), "insecurity proof failed"); - return (DNS_R_NOTINSECURE); /* Couldn't complete insecurity proof */ + return (DNS_R_NOTINSECURE); out: if (dns_rdataset_isassociated(&val->frdataset)) @@ -3008,7 +3242,8 @@ validator_start(isc_task_t *task, isc_event_t *event) { if (result == DNS_R_NOTINSECURE) result = saved_result; } - } else if (val->event->rdataset != NULL) { + } else if (val->event->rdataset != NULL && + val->event->rdataset->type != 0) { /* * This is either an unsecure subdomain or a response from * a broken server. @@ -3034,6 +3269,21 @@ validator_start(isc_task_t *task, isc_event_t *event) { } else val->attributes |= VALATTR_NEEDNODATA; result = nsecvalidate(val, ISC_FALSE); + } else if (val->event->rdataset != NULL && + val->event->rdataset->type == 0) + { + /* + * This is a nonexistence validation. + */ + validator_log(val, ISC_LOG_DEBUG(3), + "attempting negative response validation"); + + if (val->event->rdataset->covers == dns_rdatatype_any) { + val->attributes |= VALATTR_NEEDNOQNAME; + val->attributes |= VALATTR_NEEDNOWILDCARD; + } else + val->attributes |= VALATTR_NEEDNODATA; + result = nsecvalidate(val, ISC_FALSE); } else { /* * This shouldn't happen. |
