* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: ncache.c,v 1.36.18.5 2010/02/26 23:46:36 tbox Exp $ */
+/* $Id: ncache.c,v 1.36.18.6 2010/06/03 00:07:58 marka Exp $ */
/*! \file */
#include <dns/rdata.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
+#include <dns/rdatastruct.h>
+
+#define DNS_NCACHE_RDATA 20U
/*
* The format of an ncache rdata is a sequence of one or more records of
*
* owner name
* type
+ * trust
* rdata count
* rdata length These two occur 'rdata count'
* rdata times.
dns_name_t *name;
dns_ttl_t ttl;
dns_trust_t trust;
- dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_t rdata[DNS_NCACHE_RDATA];
dns_rdataset_t ncrdataset;
dns_rdatalist_t ncrdatalist;
unsigned char data[4096];
+ unsigned int next = 0;
/*
* Convert the authority data from 'message' into a negative cache
*/
/*
- * First, build an ncache rdata in buffer.
+ * Initialize the list.
+ */
+ ncrdatalist.rdclass = dns_db_class(cache);
+ ncrdatalist.type = 0;
+ ncrdatalist.covers = covers;
+ ncrdatalist.ttl = maxttl;
+ ISC_LIST_INIT(ncrdatalist.rdata);
+ ISC_LINK_INIT(&ncrdatalist, link);
+
+ /*
+ * Build an ncache rdatas into buffer.
*/
ttl = maxttl;
trust = 0xffff;
return (ISC_R_NOSPACE);
isc_buffer_putuint16(&buffer,
rdataset->type);
+ isc_buffer_putuint8(&buffer,
+ rdataset->trust);
/*
* Copy the rdataset into the buffer.
*/
&buffer);
if (result != ISC_R_SUCCESS)
return (result);
+
+ if (next >= DNS_NCACHE_RDATA)
+ return (ISC_R_NOSPACE);
+ dns_rdata_init(&rdata[next]);
+ isc_buffer_remainingregion(&buffer, &r);
+ rdata[next].data = r.base;
+ rdata[next].length = r.length;
+ rdata[next].rdclass =
+ ncrdatalist.rdclass;
+ rdata[next].type = 0;
+ rdata[next].flags = 0;
+ ISC_LIST_APPEND(ncrdatalist.rdata,
+ &rdata[next], link);
+ isc_buffer_forward(&buffer, r.length);
+ next++;
}
}
}
trust = dns_trust_authauthority;
} else
trust = dns_trust_additional;
+ /*
+ * Now add it to the cache.
+ */
+ if (next >= DNS_NCACHE_RDATA)
+ return (ISC_R_NOSPACE);
+ dns_rdata_init(&rdata[next]);
+ isc_buffer_remainingregion(&buffer, &r);
+ rdata[next].data = r.base;
+ rdata[next].length = r.length;
+ rdata[next].rdclass = ncrdatalist.rdclass;
+ rdata[next].type = 0;
+ rdata[next].flags = 0;
+ ISC_LIST_APPEND(ncrdatalist.rdata, &rdata[next], link);
}
- /*
- * Now add it to the cache.
- */
INSIST(trust != 0xffff);
- isc_buffer_usedregion(&buffer, &r);
- rdata.data = r.base;
- rdata.length = r.length;
- rdata.rdclass = dns_db_class(cache);
- rdata.type = 0;
- rdata.flags = 0;
-
- ncrdatalist.rdclass = rdata.rdclass;
- ncrdatalist.type = 0;
- ncrdatalist.covers = covers;
- ncrdatalist.ttl = ttl;
- ISC_LIST_INIT(ncrdatalist.rdata);
- ISC_LINK_INIT(&ncrdatalist, link);
- ISC_LIST_APPEND(ncrdatalist.rdata, &rdata, link);
+ ncrdatalist.ttl = ttl;
dns_rdataset_init(&ncrdataset);
RUNTIME_CHECK(dns_rdatalist_tordataset(&ncrdatalist, &ncrdataset)
REQUIRE(rdataset != NULL);
REQUIRE(rdataset->type == 0);
- result = dns_rdataset_first(rdataset);
- if (result != ISC_R_SUCCESS)
- return (result);
- dns_rdataset_current(rdataset, &rdata);
- INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE);
- isc_buffer_init(&source, rdata.data, rdata.length);
- isc_buffer_add(&source, rdata.length);
-
savedbuffer = *target;
-
count = 0;
- do {
+
+ result = dns_rdataset_first(rdataset);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(rdataset, &rdata);
+ isc_buffer_init(&source, rdata.data, rdata.length);
+ isc_buffer_add(&source, rdata.length);
dns_name_init(&name, NULL);
isc_buffer_remainingregion(&source, &remaining);
dns_name_fromregion(&name, &remaining);
isc_buffer_forward(&source, name.length);
remaining.length -= name.length;
- INSIST(remaining.length >= 4);
+ INSIST(remaining.length >= 5);
type = isc_buffer_getuint16(&source);
+ isc_buffer_forward(&source, 1);
rcount = isc_buffer_getuint16(&source);
for (i = 0; i < rcount; i++) {
count++;
}
- isc_buffer_remainingregion(&source, &remaining);
- } while (remaining.length > 0);
+ INSIST(isc_buffer_remaininglength(&source) == 0);
+ result = dns_rdataset_next(rdataset);
+ dns_rdata_reset(&rdata);
+ }
+ if (result != ISC_R_NOMORE)
+ goto rollback;
*countp = count;
return (count);
}
+static void
+rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
+ unsigned char *raw = rdataset->private3;
+
+ raw[-1] = trust;
+}
+
static dns_rdatasetmethods_t rdataset_methods = {
rdataset_disassociate,
rdataset_first,
NULL,
NULL,
NULL,
+ rdataset_settrust,
NULL,
- NULL
};
isc_result_t
isc_buffer_t source;
dns_name_t tname;
dns_rdatatype_t ttype;
- unsigned int i, rcount;
- isc_uint16_t length;
+ dns_trust_t trust = dns_trust_none;
+ dns_rdataset_t clone;
REQUIRE(ncacherdataset != NULL);
REQUIRE(ncacherdataset->type == 0);
REQUIRE(!dns_rdataset_isassociated(rdataset));
REQUIRE(type != dns_rdatatype_rrsig);
- result = dns_rdataset_first(ncacherdataset);
- if (result != ISC_R_SUCCESS)
- return (result);
- dns_rdataset_current(ncacherdataset, &rdata);
- INSIST(dns_rdataset_next(ncacherdataset) == ISC_R_NOMORE);
- isc_buffer_init(&source, rdata.data, rdata.length);
- isc_buffer_add(&source, rdata.length);
-
- do {
+ dns_rdataset_init(&clone);
+ dns_rdataset_clone(ncacherdataset, &clone);
+ result = dns_rdataset_first(&clone);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(&clone, &rdata);
+ isc_buffer_init(&source, rdata.data, rdata.length);
+ isc_buffer_add(&source, rdata.length);
dns_name_init(&tname, NULL);
isc_buffer_remainingregion(&source, &remaining);
dns_name_fromregion(&tname, &remaining);
isc_buffer_forward(&source, tname.length);
remaining.length -= tname.length;
- INSIST(remaining.length >= 4);
+ INSIST(remaining.length >= 3);
ttype = isc_buffer_getuint16(&source);
if (ttype == type && dns_name_equal(&tname, name)) {
+ trust = isc_buffer_getuint8(&source);
+ INSIST(trust <= dns_trust_ultimate);
isc_buffer_remainingregion(&source, &remaining);
break;
}
+ result = dns_rdataset_next(&clone);
+ dns_rdata_reset(&rdata);
+ }
+ dns_rdataset_disassociate(&clone);
+ if (result == ISC_R_NOMORE)
+ return (ISC_R_NOTFOUND);
+ if (result != ISC_R_SUCCESS)
+ return (result);
- rcount = isc_buffer_getuint16(&source);
- for (i = 0; i < rcount; i++) {
- isc_buffer_remainingregion(&source, &remaining);
- INSIST(remaining.length >= 2);
- length = isc_buffer_getuint16(&source);
+ INSIST(remaining.length != 0);
+
+ rdataset->methods = &rdataset_methods;
+ rdataset->rdclass = ncacherdataset->rdclass;
+ rdataset->type = type;
+ rdataset->covers = 0;
+ rdataset->ttl = ncacherdataset->ttl;
+ rdataset->trust = trust;
+ rdataset->private1 = NULL;
+ rdataset->private2 = NULL;
+
+ rdataset->private3 = remaining.base;
+
+ /*
+ * Reset iterator state.
+ */
+ rdataset->privateuint4 = 0;
+ rdataset->private5 = NULL;
+ rdataset->private6 = NULL;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
+dns_ncache_getsigrdataset(dns_rdataset_t *ncacherdataset, dns_name_t *name,
+ dns_rdatatype_t covers, dns_rdataset_t *rdataset)
+{
+ dns_name_t tname;
+ dns_rdata_rrsig_t rrsig;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_t clone;
+ dns_rdatatype_t type;
+ dns_trust_t trust = dns_trust_none;
+ isc_buffer_t source;
+ isc_region_t remaining, sigregion;
+ isc_result_t result;
+ unsigned char *raw;
+ unsigned int count;
+
+ REQUIRE(ncacherdataset != NULL);
+ REQUIRE(ncacherdataset->type == 0);
+ REQUIRE(name != NULL);
+ REQUIRE(!dns_rdataset_isassociated(rdataset));
+
+ dns_rdataset_init(&clone);
+ dns_rdataset_clone(ncacherdataset, &clone);
+ result = dns_rdataset_first(&clone);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(&clone, &rdata);
+ isc_buffer_init(&source, rdata.data, rdata.length);
+ isc_buffer_add(&source, rdata.length);
+ dns_name_init(&tname, NULL);
+ isc_buffer_remainingregion(&source, &remaining);
+ dns_name_fromregion(&tname, &remaining);
+ INSIST(remaining.length >= tname.length);
+ isc_buffer_forward(&source, tname.length);
+ remaining.length -= tname.length;
+ remaining.base += tname.length;
+
+ INSIST(remaining.length >= 2);
+ type = isc_buffer_getuint16(&source);
+ remaining.length -= 2;
+ remaining.base += 2;
+
+ if (type != dns_rdatatype_rrsig ||
+ !dns_name_equal(&tname, name)) {
+ result = dns_rdataset_next(&clone);
+ dns_rdata_reset(&rdata);
+ continue;
+ }
+
+ INSIST(remaining.length >= 1);
+ trust = isc_buffer_getuint8(&source);
+ INSIST(trust <= dns_trust_ultimate);
+ remaining.length -= 1;
+ remaining.base += 1;
+
+ raw = remaining.base;
+ count = raw[0] * 256 + raw[1];
+ INSIST(count > 0);
+ raw += 2;
+ sigregion.length = raw[0] * 256 + raw[1];
+ raw += 2;
+ sigregion.base = raw;
+ dns_rdata_reset(&rdata);
+ dns_rdata_fromregion(&rdata, rdataset->rdclass,
+ dns_rdatatype_rrsig, &sigregion);
+ (void)dns_rdata_tostruct(&rdata, &rrsig, NULL);
+ if (rrsig.covered == covers) {
isc_buffer_remainingregion(&source, &remaining);
- INSIST(remaining.length >= length);
- isc_buffer_forward(&source, length);
+ break;
}
- isc_buffer_remainingregion(&source, &remaining);
- } while (remaining.length > 0);
- if (remaining.length == 0)
+ result = dns_rdataset_next(&clone);
+ dns_rdata_reset(&rdata);
+ }
+ dns_rdataset_disassociate(&clone);
+ if (result == ISC_R_NOMORE)
return (ISC_R_NOTFOUND);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ INSIST(remaining.length != 0);
rdataset->methods = &rdataset_methods;
rdataset->rdclass = ncacherdataset->rdclass;
- rdataset->type = type;
- rdataset->covers = 0;
+ rdataset->type = dns_rdatatype_rrsig;
+ rdataset->covers = covers;
rdataset->ttl = ncacherdataset->ttl;
- rdataset->trust = ncacherdataset->trust;
+ rdataset->trust = trust;
rdataset->private1 = NULL;
rdataset->private2 = NULL;
*/
rdataset->privateuint4 = 0;
rdataset->private5 = NULL;
+ rdataset->private6 = NULL;
return (ISC_R_SUCCESS);
}
+
+void
+dns_ncache_current(dns_rdataset_t *ncacherdataset, dns_name_t *found,
+ dns_rdataset_t *rdataset)
+{
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_trust_t trust;
+ isc_region_t remaining, sigregion;
+ isc_buffer_t source;
+ dns_name_t tname;
+ dns_rdatatype_t type;
+ unsigned int count;
+ dns_rdata_rrsig_t rrsig;
+ unsigned char *raw;
+
+ REQUIRE(ncacherdataset != NULL);
+ REQUIRE(ncacherdataset->type == 0);
+ REQUIRE(found != NULL);
+ REQUIRE(!dns_rdataset_isassociated(rdataset));
+
+ dns_rdataset_current(ncacherdataset, &rdata);
+ isc_buffer_init(&source, rdata.data, rdata.length);
+ isc_buffer_add(&source, rdata.length);
+
+ dns_name_init(&tname, NULL);
+ isc_buffer_remainingregion(&source, &remaining);
+ dns_name_fromregion(found, &remaining);
+ INSIST(remaining.length >= found->length);
+ isc_buffer_forward(&source, found->length);
+ remaining.length -= found->length;
+
+ INSIST(remaining.length >= 5);
+ type = isc_buffer_getuint16(&source);
+ trust = isc_buffer_getuint8(&source);
+ INSIST(trust <= dns_trust_ultimate);
+ isc_buffer_remainingregion(&source, &remaining);
+
+ rdataset->methods = &rdataset_methods;
+ rdataset->rdclass = ncacherdataset->rdclass;
+ rdataset->type = type;
+ if (type == dns_rdatatype_rrsig) {
+ /*
+ * Extract covers from RRSIG.
+ */
+ raw = remaining.base;
+ count = raw[0] * 256 + raw[1];
+ INSIST(count > 0);
+ raw += 2;
+ sigregion.length = raw[0] * 256 + raw[1];
+ raw += 2;
+ sigregion.base = raw;
+ dns_rdata_reset(&rdata);
+ dns_rdata_fromregion(&rdata, rdataset->rdclass,
+ rdataset->type, &sigregion);
+ (void)dns_rdata_tostruct(&rdata, &rrsig, NULL);
+ rdataset->covers = rrsig.covered;
+ } else
+ rdataset->covers = 0;
+ rdataset->ttl = ncacherdataset->ttl;
+ rdataset->trust = trust;
+ rdataset->private1 = NULL;
+ rdataset->private2 = NULL;
+
+ rdataset->private3 = remaining.base;
+
+ /*
+ * Reset iterator state.
+ */
+ rdataset->privateuint4 = 0;
+ rdataset->private5 = NULL;
+ rdataset->private6 = NULL;
+}
* 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.55 2010/06/03 00:07:58 marka Exp $ */
/*! \file */
#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)
* 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)
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
"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);
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);
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)
* 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,
"must be secure failure");
return (DNS_R_MUSTBESECURE);
}
- markanswer(val);
+ markanswer(val, "validate");
return (ISC_R_SUCCESS);
}
}
}
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");
}
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);
result = dns_rdataset_next(val->event->sigrdataset))
{
dns_keynode_t *keynode = NULL, *nextnode = 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);
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 || DLVTRIED(val)) {
+ 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;
* 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,
"must be secure failure");
return (DNS_R_MUSTBESECURE);
}
- markanswer(val);
+ markanswer(val, "validatezonekey (2)");
return (ISC_R_SUCCESS);
}
}
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);
return (validatezonekey(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
*/
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)
+ if (!resume) {
result = dns_message_firstname(message, DNS_SECTION_AUTHORITY);
- else {
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ } else
result = ISC_R_SUCCESS;
- validator_log(val, ISC_LOG_DEBUG(3), "resuming nsecvalidate");
- }
for (;
result == ISC_R_SUCCESS;
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);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ } 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);
/*
* 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);
}
if (dlv_algorithm_supported(val))
dlv_validator_start(val);
else {
- markanswer(val);
+ markanswer(val, "dlvvalidated");
validator_done(val, ISC_R_SUCCESS);
}
} else {
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 ||
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",
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) {
}
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);
}
goto out;
}
if (val->view->dlv == NULL || DLVTRIED(val)) {
- markanswer(val);
+ markanswer(val, "proveunsecure (1)");
return (ISC_R_SUCCESS);
}
return (startfinddlvsep(val, dns_rootname));
"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;
}
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);
}
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));
}
if (val->view->dlv == NULL ||
DLVTRIED(val)) {
- markanswer(val);
+ markanswer(val,
+ "proveunsecure (5)");
result = ISC_R_SUCCESS;
goto out;
}
result = DNS_R_NOVALIDSIG;
goto out;
}
+ /*
+ * Validate / re-validate answer.
+ */
result = create_validator(val, tname, dns_rdatatype_ds,
&val->frdataset,
&val->fsigrdataset,
} 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))
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.
} 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.