diff --git a/CHANGES b/CHANGES index efad093e87..f90d4b9056 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,10 @@ +2117. [bug] DNSSEC fixes: named could fail to cache NSEC records + which could lead to validation failures. named didn't + handle negative DS responses that were in the process + of being validated. Check CNAME bit before accepting + NODATA proof. To be able to ignore a child NSEC there + must be SOA (and NS) set in the bitmap. [RT #16399] + 2116. [bug] 'rndc reload' could cause the cache to continually be cleaned. [RT #16401] diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index 18fbeaeb9e..04127a911d 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: resolver.c,v 1.336 2006/10/18 04:18:54 marka Exp $ */ +/* $Id: resolver.c,v 1.337 2006/12/07 06:47:36 marka Exp $ */ /*! \file */ @@ -4366,7 +4366,7 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, dns_message_t *message; dns_name_t *name, *qname, *ns_name, *soa_name, *ds_name; dns_rdataset_t *rdataset, *ns_rdataset; - isc_boolean_t done, aa, negative_response; + isc_boolean_t aa, negative_response; dns_rdatatype_t type; dns_section_t section = bind8_ns_resp ? DNS_SECTION_ANSWER : DNS_SECTION_AUTHORITY; @@ -4425,13 +4425,12 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, /* * Process the authority section. */ - done = ISC_FALSE; ns_name = NULL; ns_rdataset = NULL; soa_name = NULL; ds_name = NULL; result = dns_message_firstname(message, section); - while (!done && result == ISC_R_SUCCESS) { + while (result == ISC_R_SUCCESS) { name = NULL; dns_message_currentname(message, section, &name); if (dns_name_issubdomain(name, &fctx->domain)) { @@ -4493,15 +4492,29 @@ noanswer_response(fetchctx_t *fctx, dns_name_t *oqname, dns_trust_additional; } } - /* - * A negative response has a SOA record (Type 2) - * and a optional NS RRset (Type 1) or it has neither - * a SOA or a NS RRset (Type 3, handled above) or - * rcode is NXDOMAIN (handled above) in which case - * the NS RRset is allowed (Type 4). - */ - if (soa_name != NULL) - negative_response = ISC_TRUE; + } + result = dns_message_nextname(message, section); + if (result == ISC_R_NOMORE) + break; + else if (result != ISC_R_SUCCESS) + return (result); + } + + /* + * A negative response has a SOA record (Type 2) + * and a optional NS RRset (Type 1) or it has neither + * a SOA or a NS RRset (Type 3, handled above) or + * rcode is NXDOMAIN (handled above) in which case + * the NS RRset is allowed (Type 4). + */ + if (soa_name != NULL) + negative_response = ISC_TRUE; + + result = dns_message_firstname(message, section); + while (result == ISC_R_SUCCESS) { + name = NULL; + dns_message_currentname(message, section, &name); + if (dns_name_issubdomain(name, &fctx->domain)) { for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL; rdataset = ISC_LIST_NEXT(rdataset, link)) { diff --git a/lib/dns/validator.c b/lib/dns/validator.c index 3f940f17be..0371de2b72 100644 --- a/lib/dns/validator.c +++ b/lib/dns/validator.c @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: validator.c,v 1.145 2006/07/24 22:41:59 marka Exp $ */ +/* $Id: validator.c,v 1.146 2006/12/07 06:47:36 marka Exp $ */ /*! \file */ @@ -579,6 +579,8 @@ nsecnoexistnodata(dns_validator_t *val, dns_name_t* name, dns_name_t *nsecname, unsigned int olabels, nlabels, labels; dns_rdata_nsec_t nsec; isc_boolean_t atparent; + isc_boolean_t ns; + isc_boolean_t soa; REQUIRE(exists != NULL); REQUIRE(data != NULL); @@ -610,9 +612,9 @@ nsecnoexistnodata(dns_validator_t *val, dns_name_t* name, dns_name_t *nsecname, * The names are the same. */ atparent = dns_rdatatype_atparent(val->event->type); - if (dns_nsec_typepresent(&rdata, dns_rdatatype_ns) && - !dns_nsec_typepresent(&rdata, dns_rdatatype_soa)) - { + ns = dns_nsec_typepresent(&rdata, dns_rdatatype_ns); + soa = dns_nsec_typepresent(&rdata, dns_rdatatype_soa); + if (ns && !soa) { if (!atparent) { /* * This NSEC record is from somewhere higher in @@ -623,7 +625,7 @@ nsecnoexistnodata(dns_validator_t *val, dns_name_t* name, dns_name_t *nsecname, "ignoring parent nsec"); return (ISC_R_IGNORE); } - } else if (atparent) { + } else if (atparent && ns && soa) { /* * This NSEC record is from the child. * It can not be legitimately used here. @@ -632,12 +634,20 @@ nsecnoexistnodata(dns_validator_t *val, dns_name_t* name, dns_name_t *nsecname, "ignoring child nsec"); return (ISC_R_IGNORE); } - *exists = ISC_TRUE; - *data = dns_nsec_typepresent(&rdata, val->event->type); - validator_log(val, ISC_LOG_DEBUG(3), - "nsec proves name exists (owner) data=%d", - *data); - return (ISC_R_SUCCESS); + if (val->event->type == dns_rdatatype_cname || + val->event->type == dns_rdatatype_nxt || + val->event->type == dns_rdatatype_nsec || + val->event->type == dns_rdatatype_key || + !dns_nsec_typepresent(&rdata, dns_rdatatype_cname)) { + *exists = ISC_TRUE; + *data = dns_nsec_typepresent(&rdata, val->event->type); + validator_log(val, ISC_LOG_DEBUG(3), + "nsec proves name exists (owner) data=%d", + *data); + return (ISC_R_SUCCESS); + } + validator_log(val, ISC_LOG_DEBUG(3), "NSEC proves CNAME exists"); + return (ISC_R_IGNORE); } if (relation == dns_namereln_subdomain && @@ -697,6 +707,7 @@ nsecnoexistnodata(dns_validator_t *val, dns_name_t* name, dns_name_t *nsecname, result = dns_name_concatenate(dns_wildcardname, &common, wild, NULL); if (result != ISC_R_SUCCESS) { + dns_rdata_freestruct(&nsec); validator_log(val, ISC_LOG_DEBUG(3), "failure generating wildcard name"); return (result); @@ -750,6 +761,7 @@ authvalidated(isc_task_t *task, isc_event_t *event) { } } else { dns_name_t **proofs = val->event->proofs; + dns_name_t *wild = dns_fixedname_name(&val->wild); if (rdataset->trust == dns_trust_secure) val->seensig = ISC_TRUE; @@ -761,10 +773,9 @@ authvalidated(isc_task_t *task, isc_event_t *event) { (val->attributes & VALATTR_FOUNDNODATA) == 0 && (val->attributes & VALATTR_FOUNDNOQNAME) == 0 && nsecnoexistnodata(val, val->event->name, devent->name, - rdataset, &exists, &data, - dns_fixedname_name(&val->wild)) + rdataset, &exists, &data, wild) == ISC_R_SUCCESS) - { + { if (exists && !data) { val->attributes |= VALATTR_FOUNDNODATA; if (NEEDNODATA(val)) @@ -2085,12 +2096,6 @@ nsecvalidate(dns_validator_t *val, isc_boolean_t resume) { if (rdataset->type == dns_rdatatype_rrsig) continue; - if (rdataset->type == dns_rdatatype_soa) { - val->soaset = rdataset; - val->soaname = name; - } else if (rdataset->type == dns_rdatatype_nsec) - val->nsecset = rdataset; - for (sigrdataset = ISC_LIST_HEAD(name->list); sigrdataset != NULL; sigrdataset = ISC_LIST_NEXT(sigrdataset, @@ -2545,11 +2550,21 @@ proveunsecure(dns_validator_t *val, 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 (val->frdataset.trust == dns_trust_pending) { + result = create_fetch(val, tname, + dns_rdatatype_ds, + dsfetched2, + "proveunsecure"); + if (result != ISC_R_SUCCESS) + goto out; + return (DNS_R_WAIT); + } if (val->frdataset.trust < dns_trust_secure) { /* * This shouldn't happen, since the negative @@ -2852,9 +2867,6 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, val->keyset = NULL; val->dsset = NULL; dns_rdataset_init(&val->dlv); - val->soaset = NULL; - val->nsecset = NULL; - val->soaname = NULL; val->seensig = ISC_FALSE; val->havedlvsep = ISC_FALSE; val->depth = 0;