From 1ea2595e1b33cc63ea73ee1d54b580b717d7d155 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Thu, 7 Dec 2006 06:47:36 +0000 Subject: [PATCH] 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] --- CHANGES | 7 ++++++ lib/dns/resolver.c | 39 ++++++++++++++++++++---------- lib/dns/validator.c | 58 +++++++++++++++++++++++++++------------------ 3 files changed, 68 insertions(+), 36 deletions(-) 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;