summaryrefslogtreecommitdiffstats
path: root/contrib/bind9/lib/dns/validator.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bind9/lib/dns/validator.c')
-rw-r--r--contrib/bind9/lib/dns/validator.c435
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);
OpenPOWER on IntegriCloud