diff options
Diffstat (limited to 'lib/dns/validator.c')
-rw-r--r-- | lib/dns/validator.c | 504 |
1 files changed, 377 insertions, 127 deletions
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. |