diff --git a/lib/dns/validator.c b/lib/dns/validator.c index 4ab4ee407e..884209fc12 100644 --- a/lib/dns/validator.c +++ b/lib/dns/validator.c @@ -257,12 +257,25 @@ validator_done(dns_validator_t *val, isc_result_t result) { } /*% - * Look in the NSEC record returned from a DS query to see if there is - * a NS RRset at this name. If it is found we are at a delegation point. + * The isdelegation() function is called as part of seeking the DS record. + * Look in the NSEC or NSEC3 record returned from a DS query to see if the + * record has the NS bitmap set. If so, we are at a delegation point. + * + * If the response contains NSEC3 records with too high iterations, we cannot + * (or rather we are not going to) validate the insecurity proof. Instead we + * are going to treat the message as insecure and just assume the DS was at + * the delegation. + * + * Returns: + *\li #ISC_R_SUCCESS the NS bitmap was set in the NSEC or NSEC3 record, or + * the NSEC3 covers the name (in case of opt-out), or + * we cannot validate the insecurity proof and are going + * to treat the message as isnecure. + *\li #ISC_R_NOTFOUND the NS bitmap was not set, */ -static bool -isdelegation(dns_name_t *name, dns_rdataset_t *rdataset, - isc_result_t dbresult) { +static isc_result_t +isdelegation(dns_validator_t *val, dns_name_t *name, dns_rdataset_t *rdataset, + isc_result_t dbresult, const char *caller) { dns_fixedname_t fixed; dns_label_t hashlabel; dns_name_t nsec3name; @@ -290,7 +303,7 @@ isdelegation(dns_name_t *name, dns_rdataset_t *rdataset, goto trynsec3; } if (result != ISC_R_SUCCESS) { - return false; + return ISC_R_NOTFOUND; } } @@ -304,7 +317,7 @@ isdelegation(dns_name_t *name, dns_rdataset_t *rdataset, dns_rdata_reset(&rdata); } dns_rdataset_disassociate(&set); - return found; + return found ? ISC_R_SUCCESS : ISC_R_NOTFOUND; trynsec3: /* @@ -343,6 +356,18 @@ trynsec3: if (nsec3.next_length > NSEC3_MAX_HASH_LENGTH) { continue; } + /* + * If there are too many iterations assume bad things + * are happening and bail out early. Treat as if the + * DS was at the delegation. + */ + if (nsec3.iterations > DNS_NSEC3_MAXITERATIONS) { + validator_log(val, ISC_LOG_DEBUG(3), + "%s: too many iterations", + caller); + dns_rdataset_disassociate(&set); + return ISC_R_SUCCESS; + } length = isc_iterated_hash( hash, nsec3.hash, nsec3.iterations, nsec3.salt, nsec3.salt_length, name->ndata, name->length); @@ -354,7 +379,7 @@ trynsec3: found = dns_nsec3_typepresent(&rdata, dns_rdatatype_ns); dns_rdataset_disassociate(&set); - return found; + return found ? ISC_R_SUCCESS : ISC_R_NOTFOUND; } if ((nsec3.flags & DNS_NSEC3FLAG_OPTOUT) == 0) { continue; @@ -370,12 +395,12 @@ trynsec3: memcmp(hash, nsec3.next, length) < 0))) { dns_rdataset_disassociate(&set); - return true; + return ISC_R_SUCCESS; } } dns_rdataset_disassociate(&set); } - return found; + return found ? ISC_R_SUCCESS : ISC_R_NOTFOUND; } static void @@ -589,9 +614,10 @@ fetch_callback_ds(void *arg) { break; case DNS_R_NXRRSET: case DNS_R_NCACHENXRRSET: - if (isdelegation(resp->foundname, &val->frdataset, - eresult)) - { + result = isdelegation(val, resp->foundname, + &val->frdataset, eresult, + "fetch_callback_ds"); + if (result == ISC_R_SUCCESS) { /* * Failed to find a DS while trying to prove * insecurity. If this is a zone cut, that @@ -707,10 +733,13 @@ validator_callback_ds(void *arg) { dns_trust_totext(val->frdataset.trust)); have_dsset = (val->frdataset.type == dns_rdatatype_ds); name = dns_fixedname_name(&val->fname); + if ((val->attributes & VALATTR_INSECURITY) != 0 && val->frdataset.covers == dns_rdatatype_ds && NEGATIVE(&val->frdataset) && - isdelegation(name, &val->frdataset, DNS_R_NCACHENXRRSET)) + isdelegation(val, name, &val->frdataset, + DNS_R_NCACHENXRRSET, + "validator_callback_ds") == ISC_R_SUCCESS) { result = markanswer(val, "validator_callback_ds", "no DS and this is a delegation"); @@ -2932,7 +2961,8 @@ validate_nx(dns_validator_t *val, bool resume) { result = findnsec3proofs(val); if (result == DNS_R_NSEC3ITERRANGE) { validator_log(val, ISC_LOG_DEBUG(3), - "too many iterations"); + "%s: too many iterations", + __func__); markanswer(val, "validate_nx (3)", NULL); return ISC_R_SUCCESS; } @@ -2968,7 +2998,7 @@ validate_nx(dns_validator_t *val, bool resume) { result = findnsec3proofs(val); if (result == DNS_R_NSEC3ITERRANGE) { validator_log(val, ISC_LOG_DEBUG(3), - "too many iterations"); + "%s: too many iterations", __func__); markanswer(val, "validate_nx (4)", NULL); return ISC_R_SUCCESS; } @@ -3181,7 +3211,9 @@ seek_ds(dns_validator_t *val, isc_result_t *resp) { return ISC_R_COMPLETE; } - if (isdelegation(tname, &val->frdataset, result)) { + result = isdelegation(val, tname, &val->frdataset, result, + "seek_ds"); + if (result == ISC_R_SUCCESS) { *resp = markanswer(val, "seek_ds (3)", "this is a delegation"); return ISC_R_COMPLETE;