diff options
Diffstat (limited to 'contrib/bind9/lib/dns/validator.c')
-rw-r--r-- | contrib/bind9/lib/dns/validator.c | 435 |
1 files changed, 314 insertions, 121 deletions
diff --git a/contrib/bind9/lib/dns/validator.c b/contrib/bind9/lib/dns/validator.c index a62db34..ec727b7 100644 --- a/contrib/bind9/lib/dns/validator.c +++ b/contrib/bind9/lib/dns/validator.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004, 2005 Internet Systems Consortium, Inc. ("ISC") + * Copyright (C) 2004-2006 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 2000-2003 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any @@ -15,7 +15,7 @@ * PERFORMANCE OF THIS SOFTWARE. */ -/* $Id: validator.c,v 1.91.2.5.8.21 2005/11/02 02:07:47 marka Exp $ */ +/* $Id: validator.c,v 1.91.2.5.8.27 2006/02/26 23:03:52 marka Exp $ */ #include <config.h> @@ -43,20 +43,65 @@ #include <dns/validator.h> #include <dns/view.h> +/*! \file + * \brief + * Basic processing sequences. + * + * \li When called with rdataset and sigrdataset: + * validator_start -> validate -> proveunsecure -> startfinddlvsep -> + * dlv_validator_start -> validator_start -> validate -> proveunsecure + * + * validator_start -> validate -> nsecvalidate (secure wildcard answer) + * + * \li When called with rdataset, sigrdataset and with DNS_VALIDATOR_DLV: + * validator_start -> startfinddlvsep -> dlv_validator_start -> + * validator_start -> validate -> proveunsecure + * + * \li When called with rdataset: + * validator_start -> proveunsecure -> startfinddlvsep -> + * dlv_validator_start -> validator_start -> proveunsecure + * + * \li When called with rdataset and with DNS_VALIDATOR_DLV: + * validator_start -> startfinddlvsep -> dlv_validator_start -> + * validator_start -> proveunsecure + * + * \li When called without a rdataset: + * validator_start -> nsecvalidate -> proveunsecure -> startfinddlvsep -> + * dlv_validator_start -> validator_start -> nsecvalidate -> proveunsecure + * + * \li When called without a rdataset and with DNS_VALIDATOR_DLV: + * validator_start -> startfinddlvsep -> dlv_validator_start -> + * validator_start -> nsecvalidate -> proveunsecure + * + * validator_start: determines what type of validation to do. + * validate: attempts to perform a positive validation. + * proveunsecure: attempts to prove the answer comes from a unsecure zone. + * nsecvalidate: attempts to prove a negative response. + * startfinddlvsep: starts the DLV record lookup. + * dlv_validator_start: resets state and restarts the lookup using the + * DLV RRset found by startfinddlvsep. + */ + #define VALIDATOR_MAGIC ISC_MAGIC('V', 'a', 'l', '?') #define VALID_VALIDATOR(v) ISC_MAGIC_VALID(v, VALIDATOR_MAGIC) -#define VALATTR_SHUTDOWN 0x0001 -#define VALATTR_FOUNDNONEXISTENCE 0x0002 -#define VALATTR_TRIEDVERIFY 0x0004 -#define VALATTR_NEGATIVE 0x0008 -#define VALATTR_INSECURITY 0x0010 -#define VALATTR_DLVTRIED 0x0020 +#define VALATTR_SHUTDOWN 0x0001 /*%< Shutting down. */ +#define VALATTR_TRIEDVERIFY 0x0004 /*%< We have found a key and + * have attempted a verify. */ +#define VALATTR_INSECURITY 0x0010 /*%< Attempting proveunsecure. */ +#define VALATTR_DLVTRIED 0x0020 /*%< Looked for a DLV record. */ +#define VALATTR_AUTHNONPENDING 0x0040 /*%< Tidy up pending auth. */ +/*! + * NSEC proofs to be looked for. + */ #define VALATTR_NEEDNOQNAME 0x0100 #define VALATTR_NEEDNOWILDCARD 0x0200 #define VALATTR_NEEDNODATA 0x0400 +/*! + * NSEC proofs that have been found. + */ #define VALATTR_FOUNDNOQNAME 0x1000 #define VALATTR_FOUNDNOWILDCARD 0x2000 #define VALATTR_FOUNDNODATA 0x4000 @@ -104,19 +149,35 @@ validator_logcreate(dns_validator_t *val, static isc_result_t dlv_validatezonekey(dns_validator_t *val); -static isc_result_t +static void dlv_validator_start(dns_validator_t *val); static isc_result_t finddlvsep(dns_validator_t *val, isc_boolean_t resume); +static void +auth_nonpending(dns_message_t *message); + +static isc_result_t +startfinddlvsep(dns_validator_t *val, dns_name_t *unsecure); + +/*% + * Mark the RRsets as a answer. + * + * If VALATTR_AUTHNONPENDING is set then this is a negative answer + * in a insecure zone. We need to mark any pending RRsets as + * dns_trust_authauthority answers (this is deferred from resolver.c). + */ static inline void markanswer(dns_validator_t *val) { validator_log(val, ISC_LOG_DEBUG(3), "marking as answer"); - if (val->event->rdataset) + if (val->event->rdataset != NULL) val->event->rdataset->trust = dns_trust_answer; - if (val->event->sigrdataset) + if (val->event->sigrdataset != NULL) val->event->sigrdataset->trust = dns_trust_answer; + if (val->event->message != NULL && + (val->attributes & VALATTR_AUTHNONPENDING) != 0) + auth_nonpending(val->event->message); } static void @@ -155,6 +216,9 @@ exit_check(dns_validator_t *val) { return (ISC_TRUE); } +/*% + * Mark pending answers in the authority section as dns_trust_authauthority. + */ static void auth_nonpending(dns_message_t *message) { isc_result_t result; @@ -177,6 +241,10 @@ auth_nonpending(dns_message_t *message) { } } +/*% + * 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. + */ static isc_boolean_t isdelegation(dns_name_t *name, dns_rdataset_t *rdataset, isc_result_t dbresult) @@ -210,6 +278,11 @@ isdelegation(dns_name_t *name, dns_rdataset_t *rdataset, return (found); } +/*% + * We have been asked to to look for a key. + * If found resume the validation process. + * If not found fail the validation process. + */ static void fetch_callback_validator(isc_task_t *task, isc_event_t *event) { dns_fetchevent_t *devent; @@ -269,6 +342,11 @@ fetch_callback_validator(isc_task_t *task, isc_event_t *event) { destroy(val); } +/*% + * We were asked to look for a DS record as part of following a key chain + * upwards. If found resume the validation process. If not found fail the + * validation process. + */ static void dsfetched(isc_task_t *task, isc_event_t *event) { dns_fetchevent_t *devent; @@ -330,8 +408,16 @@ dsfetched(isc_task_t *task, isc_event_t *event) { destroy(val); } -/* - * XXX there's too much duplicated code here. +/*% + * We were asked to look for the DS record as part of proving that a + * name is unsecure. + * + * If the DS record doesn't exist and the query name corresponds to + * a delegation point we are transitioning from a secure zone to a + * unsecure zone. + * + * If the DS record exists it will be secure. We can continue looking + * for the break point in the chain of trust. */ static void dsfetched2(isc_task_t *task, isc_event_t *event) { @@ -359,7 +445,8 @@ dsfetched2(isc_task_t *task, isc_event_t *event) { INSIST(val->event != NULL); - validator_log(val, ISC_LOG_DEBUG(3), "in dsfetched2"); + validator_log(val, ISC_LOG_DEBUG(3), "in dsfetched2: %s", + dns_result_totext(eresult)); LOCK(&val->lock); if (eresult == DNS_R_NXRRSET || eresult == DNS_R_NCACHENXRRSET) { /* @@ -371,9 +458,13 @@ dsfetched2(isc_task_t *task, isc_event_t *event) { validator_log(val, ISC_LOG_WARNING, "must be secure failure"); validator_done(val, DNS_R_MUSTBESECURE); - } else { + } else if (val->view->dlv == NULL || DLVTRIED(val)) { markanswer(val); validator_done(val, ISC_R_SUCCESS); + } else { + result = startfinddlvsep(val, tname); + if (result != DNS_R_WAIT) + validator_done(val, result); } } else { result = proveunsecure(val, ISC_TRUE); @@ -385,7 +476,9 @@ dsfetched2(isc_task_t *task, isc_event_t *event) { eresult == DNS_R_NCACHENXDOMAIN) { /* - * Either there is a DS or this is not a zone cut. Continue. + * There is a DS which may or may not be a zone cut. + * In either case we are still in a secure zone resume + * validation. */ result = proveunsecure(val, ISC_TRUE); if (result != DNS_R_WAIT) @@ -403,6 +496,11 @@ dsfetched2(isc_task_t *task, isc_event_t *event) { destroy(val); } +/*% + * Callback from when a DNSKEY RRset has been validated. + * + * Resumes the stalled validation process. + */ static void keyvalidated(isc_task_t *task, isc_event_t *event) { dns_validatorevent_t *devent; @@ -448,6 +546,11 @@ keyvalidated(isc_task_t *task, isc_event_t *event) { destroy(val); } +/*% + * Callback when the DS record has been validated. + * + * Resumes validation of the zone key or the unsecure zone proof. + */ static void dsvalidated(isc_task_t *task, isc_event_t *event) { dns_validatorevent_t *devent; @@ -491,10 +594,12 @@ dsvalidated(isc_task_t *task, isc_event_t *event) { destroy(val); } -/* +/*% * Return ISC_R_SUCCESS if we can determine that the name doesn't exist * or we can determine whether there is data or not at the name. * If the name does not exist return the wildcard name. + * + * Return ISC_R_IGNORE when the NSEC is not the appropriate one. */ static isc_result_t nsecnoexistnodata(dns_validator_t *val, dns_name_t* name, dns_name_t *nsecname, @@ -627,7 +732,7 @@ nsecnoexistnodata(dns_validator_t *val, dns_name_t* name, dns_name_t *nsecname, wild, NULL); if (result != ISC_R_SUCCESS) { validator_log(val, ISC_LOG_DEBUG(3), - "failure generating wilcard name"); + "failure generating wildcard name"); return (result); } } @@ -637,6 +742,13 @@ nsecnoexistnodata(dns_validator_t *val, dns_name_t* name, dns_name_t *nsecname, return (ISC_R_SUCCESS); } +/*% + * Callback for when NSEC records have been validated. + * + * Looks for NOQNAME and NODATA proofs. + * + * Resumes nsecvalidate. + */ static void authvalidated(isc_task_t *task, isc_event_t *event) { dns_validatorevent_t *devent; @@ -715,44 +827,20 @@ authvalidated(isc_task_t *task, isc_event_t *event) { isc_event_free(&event); } -static void -negauthvalidated(isc_task_t *task, isc_event_t *event) { - dns_validatorevent_t *devent; - dns_validator_t *val; - isc_boolean_t want_destroy; - isc_result_t eresult; - - UNUSED(task); - INSIST(event->ev_type == DNS_EVENT_VALIDATORDONE); - - devent = (dns_validatorevent_t *)event; - val = devent->ev_arg; - eresult = devent->result; - isc_event_free(&event); - dns_validator_destroy(&val->subvalidator); - - INSIST(val->event != NULL); - - validator_log(val, ISC_LOG_DEBUG(3), "in negauthvalidated"); - LOCK(&val->lock); - if (eresult == ISC_R_SUCCESS) { - val->attributes |= VALATTR_FOUNDNONEXISTENCE; - validator_log(val, ISC_LOG_DEBUG(3), - "nonexistence proof found"); - auth_nonpending(val->event->message); - validator_done(val, ISC_R_SUCCESS); - } else { - validator_log(val, ISC_LOG_DEBUG(3), - "negauthvalidated: got %s", - isc_result_totext(eresult)); - validator_done(val, eresult); - } - want_destroy = exit_check(val); - UNLOCK(&val->lock); - if (want_destroy) - destroy(val); -} - +/*% + * Looks for the requested name and type in the view (zones and cache). + * + * When looking for a DLV record also checks to make sure the NSEC record + * returns covers the query name as part of aggressive negative caching. + * + * Returns: + * \li ISC_R_SUCCESS + * \li ISC_R_NOTFOUND + * \li DNS_R_NCACHENXDOMAIN + * \li DNS_R_NCACHENXRRSET + * \li DNS_R_NXRRSET + * \li DNS_R_NXDOMAIN + */ static inline isc_result_t view_find(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) { dns_fixedname_t fixedname; @@ -855,12 +943,9 @@ view_find(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) { dns_rdata_freestruct(&nsec); result = DNS_R_NCACHENXDOMAIN; } else if (result != ISC_R_SUCCESS && - result != DNS_R_GLUE && - result != DNS_R_HINT && result != DNS_R_NCACHENXDOMAIN && result != DNS_R_NCACHENXRRSET && result != DNS_R_NXRRSET && - result != DNS_R_HINTNXRRSET && result != ISC_R_NOTFOUND) { goto notfound; } @@ -874,11 +959,15 @@ view_find(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) { return (ISC_R_NOTFOUND); } +/*% + * Checks to make sure we are not going to loop. As we use a SHARED fetch + * the validation process will stall if looping was to occur. + */ static inline isc_boolean_t check_deadlock(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) { dns_validator_t *parent; - for (parent = val->parent; parent != NULL; parent = parent->parent) { + for (parent = val; parent != NULL; parent = parent->parent) { if (parent->event != NULL && parent->event->type == type && dns_name_equal(parent->event->name, name)) @@ -892,6 +981,9 @@ check_deadlock(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type) { return (ISC_FALSE); } +/*% + * Start a fetch for the requested name and type. + */ static inline isc_result_t create_fetch(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type, isc_taskaction_t callback, const char *caller) @@ -914,6 +1006,9 @@ create_fetch(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type, &val->fetch)); } +/*% + * Start a subvalidation process. + */ static inline isc_result_t create_validator(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type, dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset, @@ -936,7 +1031,7 @@ create_validator(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type, return (result); } -/* +/*% * Try to find a key that could have signed 'siginfo' among those * in 'rdataset'. If found, build a dst_key_t for it and point * val->key at it. @@ -1004,6 +1099,9 @@ get_dst_key(dns_validator_t *val, dns_rdata_rrsig_t *siginfo, return (result); } +/*% + * Get the key that genertated this signature. + */ static isc_result_t get_key(dns_validator_t *val, dns_rdata_rrsig_t *siginfo) { isc_result_t result; @@ -1130,7 +1228,7 @@ compute_keytag(dns_rdata_t *rdata, dns_rdata_dnskey_t *key) { return (dst_region_computeid(&r, key->algorithm)); } -/* +/*% * Is this keyset self-signed? */ static isc_boolean_t @@ -1172,8 +1270,19 @@ isselfsigned(dns_validator_t *val) { return (ISC_FALSE); } +/*% + * Attempt to verify the rdataset using the given key and rdata (RRSIG). + * The signature was good and from a wildcard record and the QNAME does + * not match the wildcard we need to look for a NOQNAME proof. + * + * Returns: + * \li ISC_R_SUCCESS if the verification succeeds. + * \li Others if the verification fails. + */ static isc_result_t -verify(dns_validator_t *val, dst_key_t *key, dns_rdata_t *rdata) { +verify(dns_validator_t *val, dst_key_t *key, dns_rdata_t *rdata, + isc_uint16_t keyid) +{ isc_result_t result; dns_fixedname_t fixed; @@ -1183,8 +1292,8 @@ verify(dns_validator_t *val, dst_key_t *key, dns_rdata_t *rdata) { key, ISC_FALSE, val->view->mctx, rdata, dns_fixedname_name(&fixed)); validator_log(val, ISC_LOG_DEBUG(3), - "verify rdataset: %s", - isc_result_totext(result)); + "verify rdataset (keyid=%u): %s", + keyid, isc_result_totext(result)); if (result == DNS_R_FROMWILDCARD) { if (!dns_name_equal(val->event->name, dns_fixedname_name(&fixed))) @@ -1194,14 +1303,14 @@ verify(dns_validator_t *val, dst_key_t *key, dns_rdata_t *rdata) { return (result); } -/* +/*% * Attempts positive response validation of a normal RRset. * * Returns: - * ISC_R_SUCCESS Validation completed successfully - * DNS_R_WAIT Validation has started but is waiting + * \li ISC_R_SUCCESS Validation completed successfully + * \li DNS_R_WAIT Validation has started but is waiting * for an event. - * Other return codes are possible and all indicate failure. + * \li Other return codes are possible and all indicate failure. */ static isc_result_t validate(dns_validator_t *val, isc_boolean_t resume) { @@ -1272,7 +1381,8 @@ validate(dns_validator_t *val, isc_boolean_t resume) { } do { - result = verify(val, val->key, &rdata); + result = verify(val, val->key, &rdata, + val->siginfo->keyid); if (result == ISC_R_SUCCESS) break; if (val->keynode != NULL) { @@ -1356,6 +1466,10 @@ validate(dns_validator_t *val, isc_boolean_t resume) { return (DNS_R_NOVALIDSIG); } +/*% + * Validate the DNSKEY RRset by looking for a DNSKEY that matches a + * DLV record and that also verifies the DNSKEY RRset. + */ static isc_result_t dlv_validatezonekey(dns_validator_t *val) { dns_keytag_t keytag; @@ -1373,12 +1487,12 @@ dlv_validatezonekey(dns_validator_t *val) { unsigned char dsbuf[DNS_DS_BUFFERSIZE]; validator_log(val, ISC_LOG_DEBUG(3), "dlv_validatezonekey"); + /* * Look through the DLV record and find the keys that can sign the * key set and the matching signature. For each such key, attempt * verification. */ - supported_algorithm = ISC_FALSE; for (result = dns_rdataset_first(&val->dlv); @@ -1456,7 +1570,7 @@ dlv_validatezonekey(dns_validator_t *val) { */ continue; - result = verify(val, dstkey, &sigrdata); + result = verify(val, dstkey, &sigrdata, sig.keyid); dst_key_free(&dstkey); if (result == ISC_R_SUCCESS) break; @@ -1486,14 +1600,14 @@ dlv_validatezonekey(dns_validator_t *val) { return (DNS_R_NOVALIDSIG); } -/* +/*% * Attempts positive response validation of an RRset containing zone keys. * * Returns: - * ISC_R_SUCCESS Validation completed successfully - * DNS_R_WAIT Validation has started but is waiting + * \li ISC_R_SUCCESS Validation completed successfully + * \li DNS_R_WAIT Validation has started but is waiting * for an event. - * Other return codes are possible and all indicate failure. + * \li Other return codes are possible and all indicate failure. */ static isc_result_t validatezonekey(dns_validator_t *val) { @@ -1505,12 +1619,14 @@ validatezonekey(dns_validator_t *val) { dns_rdata_t keyrdata = DNS_RDATA_INIT; dns_rdata_t sigrdata = DNS_RDATA_INIT; unsigned char dsbuf[DNS_DS_BUFFERSIZE]; + char namebuf[DNS_NAME_FORMATSIZE]; dns_keytag_t keytag; dns_rdata_ds_t ds; dns_rdata_dnskey_t key; dns_rdata_rrsig_t sig; dst_key_t *dstkey; isc_boolean_t supported_algorithm; + isc_boolean_t atsep = ISC_FALSE; /* * Caller must be holding the validator lock. @@ -1541,9 +1657,13 @@ validatezonekey(dns_validator_t *val) { sig.algorithm, sig.keyid, &keynode); + if (result == DNS_R_PARTIALMATCH || + result == ISC_R_SUCCESS) + atsep = ISC_TRUE; while (result == ISC_R_SUCCESS) { dstkey = dns_keynode_key(keynode); - result = verify(val, dstkey, &sigrdata); + result = verify(val, dstkey, &sigrdata, + sig.keyid); if (result == ISC_R_SUCCESS) { dns_keytable_detachkeynode(val->keytable, &keynode); @@ -1578,6 +1698,22 @@ validatezonekey(dns_validator_t *val) { return (DNS_R_NOVALIDDS); } + if (atsep) { + /* + * We have not found a key to verify this DNSKEY + * RRset. As this is a SEP we have to assume that + * the RRset is invalid. + */ + dns_name_format(val->event->name, namebuf, + sizeof(namebuf)); + validator_log(val, ISC_LOG_DEBUG(2), + "unable to find a DNSKEY which verifies " + "the DNSKEY RRset and also matches one " + "of specified trusted-keys for '%s'", + namebuf); + return (DNS_R_NOVALIDKEY); + } + /* * Otherwise, try to find the DS record. */ @@ -1680,6 +1816,9 @@ validatezonekey(dns_validator_t *val) { dns_rdataset_init(&trdataset); dns_rdataset_clone(val->event->rdataset, &trdataset); + /* + * Look for the KEY that matches the DS record. + */ for (result = dns_rdataset_first(&trdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(&trdataset)) @@ -1714,7 +1853,7 @@ validatezonekey(dns_validator_t *val) { dns_rdataset_current(val->event->sigrdataset, &sigrdata); (void)dns_rdata_tostruct(&sigrdata, &sig, NULL); - if (ds.key_tag != sig.keyid && + if (ds.key_tag != sig.keyid || ds.algorithm != sig.algorithm) continue; @@ -1728,8 +1867,7 @@ validatezonekey(dns_validator_t *val) { * This really shouldn't happen, but... */ continue; - - result = verify(val, dstkey, &sigrdata); + result = verify(val, dstkey, &sigrdata, sig.keyid); dst_key_free(&dstkey); if (result == ISC_R_SUCCESS) break; @@ -1759,14 +1897,14 @@ validatezonekey(dns_validator_t *val) { return (DNS_R_NOVALIDSIG); } -/* +/*% * Starts a positive response validation. * * Returns: - * ISC_R_SUCCESS Validation completed successfully - * DNS_R_WAIT Validation has started but is waiting + * \li ISC_R_SUCCESS Validation completed successfully + * \li DNS_R_WAIT Validation has started but is waiting * for an event. - * Other return codes are possible and all indicate failure. + * \li Other return codes are possible and all indicate failure. */ static isc_result_t start_positive_validation(dns_validator_t *val) { @@ -1779,6 +1917,14 @@ start_positive_validation(dns_validator_t *val) { return (validatezonekey(val)); } +/*% + * 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. + * + * Returns + * \li ISC_R_SUCCESS + */ static isc_result_t checkwildcard(dns_validator_t *val) { dns_name_t *name, *wild; @@ -1851,6 +1997,18 @@ checkwildcard(dns_validator_t *val) { 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) { dns_name_t *name; @@ -1946,7 +2104,8 @@ nsecvalidate(dns_validator_t *val, isc_boolean_t resume) { return (result); /* - * Do we only need to check for NOQNAME? + * Do we only need to check for NOQNAME? To get here we must have + * had a secure wildcard answer. */ if ((val->attributes & VALATTR_NEEDNODATA) == 0 && (val->attributes & VALATTR_NEEDNOWILDCARD) == 0 && @@ -1982,28 +2141,17 @@ nsecvalidate(dns_validator_t *val, isc_boolean_t resume) { ((val->attributes & VALATTR_NEEDNOQNAME) != 0 && (val->attributes & VALATTR_FOUNDNOQNAME) != 0 && (val->attributes & VALATTR_NEEDNOWILDCARD) != 0 && - (val->attributes & VALATTR_FOUNDNOWILDCARD) != 0)) - val->attributes |= VALATTR_FOUNDNONEXISTENCE; - - if ((val->attributes & VALATTR_FOUNDNONEXISTENCE) == 0) { - if (!val->seensig && val->soaset != NULL) { - result = create_validator(val, val->soaname, - dns_rdatatype_soa, - val->soaset, NULL, - negauthvalidated, - "nsecvalidate"); - if (result != ISC_R_SUCCESS) - return (result); - return (DNS_R_WAIT); - } + (val->attributes & VALATTR_FOUNDNOWILDCARD) != 0)) { validator_log(val, ISC_LOG_DEBUG(3), - "nonexistence proof not found"); - return (DNS_R_NOVALIDNSEC); - } else { - validator_log(val, ISC_LOG_DEBUG(3), - "nonexistence proof found"); + "nonexistence proof(s) found"); return (ISC_R_SUCCESS); } + + validator_log(val, ISC_LOG_DEBUG(3), + "nonexistence proof(s) not found"); + val->attributes |= VALATTR_AUTHNONPENDING; + val->attributes |= VALATTR_INSECURITY; + return (proveunsecure(val, ISC_FALSE)); } static isc_boolean_t @@ -2029,6 +2177,11 @@ check_ds(dns_validator_t *val, dns_name_t *name, dns_rdataset_t *rdataset) { return (ISC_FALSE); } +/*% + * Callback from fetching a DLV record. + * + * Resumes the DLV lookup process. + */ static void dlvfetched(isc_task_t *task, isc_event_t *event) { char namebuf[DNS_NAME_FORMATSIZE]; @@ -2065,9 +2218,7 @@ dlvfetched(isc_task_t *task, isc_event_t *event) { dns_rdataset_clone(&val->frdataset, &val->dlv); val->havedlvsep = ISC_TRUE; validator_log(val, ISC_LOG_DEBUG(3), "DLV %s found", namebuf); - result = dlv_validator_start(val); - if (result != DNS_R_WAIT) - validator_done(val, result); + dlv_validator_start(val); } else if (eresult == DNS_R_NXRRSET || eresult == DNS_R_NXDOMAIN || eresult == DNS_R_NCACHENXRRSET || @@ -2078,9 +2229,7 @@ dlvfetched(isc_task_t *task, isc_event_t *event) { namebuf, sizeof(namebuf)); validator_log(val, ISC_LOG_DEBUG(3), "DLV %s found", namebuf); - result = dlv_validator_start(val); - if (result != DNS_R_WAIT) - validator_done(val, result); + dlv_validator_start(val); } else if (result == ISC_R_NOTFOUND) { validator_log(val, ISC_LOG_DEBUG(3), "DLV not found"); markanswer(val); @@ -2094,6 +2243,7 @@ dlvfetched(isc_task_t *task, isc_event_t *event) { } else { validator_log(val, ISC_LOG_DEBUG(3), "DLV lookup: %s", dns_result_totext(eresult)); + validator_done(val, eresult); } want_destroy = exit_check(val); UNLOCK(&val->lock); @@ -2101,6 +2251,14 @@ dlvfetched(isc_task_t *task, isc_event_t *event) { destroy(val); } +/*% + * Start the DLV lookup proccess. + * + * Returns + * \li ISC_R_SUCCESS + * \li DNS_R_WAIT + * \li Others on validation failures. + */ static isc_result_t startfinddlvsep(dns_validator_t *val, dns_name_t *unsecure) { char namebuf[DNS_NAME_FORMATSIZE]; @@ -2135,9 +2293,19 @@ startfinddlvsep(dns_validator_t *val, dns_name_t *unsecure) { dns_name_format(dns_fixedname_name(&val->dlvsep), namebuf, sizeof(namebuf)); validator_log(val, ISC_LOG_DEBUG(3), "DLV %s found", namebuf); - return (dlv_validator_start(val)); + dlv_validator_start(val); + return (DNS_R_WAIT); } +/*% + * Continue the DLV lookup process. + * + * Returns + * \li ISC_R_SUCCESS + * \li ISC_R_NOTFOUND + * \li DNS_R_WAIT + * \li Others on validation failure. + */ static isc_result_t finddlvsep(dns_validator_t *val, isc_boolean_t resume) { char namebuf[DNS_NAME_FORMATSIZE]; @@ -2147,7 +2315,7 @@ finddlvsep(dns_validator_t *val, isc_boolean_t resume) { dns_name_t noroot; isc_result_t result; unsigned int labels; - + INSIST(val->view->dlv != NULL); if (!resume) { @@ -2231,11 +2399,24 @@ finddlvsep(dns_validator_t *val, isc_boolean_t resume) { return (ISC_R_NOTFOUND); } -/* +/*% * proveunsecure walks down from the SEP looking for a break in the - * chain of trust. That occurs when we can prove the DS record does + * chain of trust. That occurs when we can prove the DS record does * not exist at a delegation point or the DS exists at a delegation * but we don't support the algorithm/digest. + * + * If DLV is active and we look for a DLV record at or below the + * point we go insecure. If found we restart the validation process. + * If not found or DLV isn't active we mark the response as a answer. + * + * Returns: + * \li ISC_R_SUCCESS val->event->name is in a unsecure zone + * \li DNS_R_WAIT validation is in progress. + * \li DNS_R_MUSTBESECURE val->event->name is supposed to be secure + * (policy) but we proved that it is unsecure. + * \li DNS_R_NOVALIDSIG + * \li DNS_R_NOVALIDNSEC + * \li DNS_R_NOTINSECURE */ static isc_result_t proveunsecure(dns_validator_t *val, isc_boolean_t resume) { @@ -2253,7 +2434,7 @@ proveunsecure(dns_validator_t *val, isc_boolean_t resume) { result = dns_keytable_finddeepestmatch(val->keytable, val->event->name, secroot); - + if (result == ISC_R_NOTFOUND) { validator_log(val, ISC_LOG_DEBUG(3), "not beneath secure root"); @@ -2395,8 +2576,7 @@ proveunsecure(dns_validator_t *val, isc_boolean_t resume) { goto out; return (DNS_R_WAIT); } else if (result == DNS_R_NXDOMAIN || - result == DNS_R_NCACHENXDOMAIN) - { + result == DNS_R_NCACHENXDOMAIN) { /* * This is not a zone cut. Assuming things are * as expected, continue. @@ -2441,7 +2621,10 @@ proveunsecure(dns_validator_t *val, isc_boolean_t resume) { return (result); } -static isc_result_t +/*% + * Reset state and revalidate the answer using DLV. + */ +static void dlv_validator_start(dns_validator_t *val) { isc_event_t *event; @@ -2455,9 +2638,20 @@ dlv_validator_start(dns_validator_t *val) { event = (isc_event_t *)val->event; isc_task_send(val->task, &event); - return (DNS_R_WAIT); } +/*% + * Start the validation process. + * + * Attempt to valididate the answer based on the category it appears to + * fall in. + * \li 1. secure positive answer. + * \li 2. unsecure positive answer. + * \li 3. a negative answer (secure or unsecure). + * + * Note a answer that appears to be a secure positive answer may actually + * be a unsecure positive answer. + */ static void validator_start(isc_task_t *task, isc_event_t *event) { dns_validator_t *val; @@ -2529,7 +2723,6 @@ validator_start(isc_task_t *task, isc_event_t *event) { validator_log(val, ISC_LOG_DEBUG(3), "attempting negative response validation"); - val->attributes |= VALATTR_NEGATIVE; if (val->event->message->rcode == dns_rcode_nxdomain) { val->attributes |= VALATTR_NEEDNOQNAME; val->attributes |= VALATTR_NEEDNOWILDCARD; @@ -2640,7 +2833,7 @@ dns_validator_create(dns_view_t *view, dns_name_t *name, dns_rdatatype_t type, cleanup_event: isc_task_detach(&tclone); - isc_event_free((isc_event_t **)&val->event); + isc_event_free(ISC_EVENT_PTR(&event)); cleanup_val: dns_view_weakdetach(&val->view); |