-Knot Resolver 1.5.0 (2017-11-xx)
+Knot Resolver 1.5.0 (2017-11-02)
================================
Bugfixes
------------
- new module ta_signal_query supporting Signaling Trust Anchor Knowledge
using Keytag Query (RFC 8145 section 5)
+- attempt validation for more records but require it for fewer of them
+ (e.g. avoids SERVFAIL when server adds extra records but omits RRSIGs)
Knot Resolver 1.4.0 (2017-09-22)
#include "lib/utils.h"
/* Cache version */
-#define KEY_VERSION "V\x04"
+#define KEY_VERSION "V\x05"
/* Key size */
#define KEY_HSIZE (sizeof(uint8_t) + sizeof(uint16_t))
#define KEY_SIZE (KEY_HSIZE + KNOT_DNAME_MAXLEN)
}
if (answer || type == KNOT_RRTYPE_DS
|| type == KNOT_RRTYPE_NSEC || type == KNOT_RRTYPE_NSEC3) {
+ /* We almost always want these validated, and it should be possible. */
return KR_RANK_INITIAL | KR_RANK_AUTH;
}
- if (type == KNOT_RRTYPE_NS) {
- /* Some servers add extra NS RRset, which allows us to refresh
- * cache "for free", potentially speeding up zone cut lookups
- * in future. Still, it might theoretically cause some problems:
- * https://mailarchive.ietf.org/arch/msg/dnsop/CYjPDlwtpxzdQV_qycB-WfnW6CI
- */
- if (!is_nonauth && knot_dname_is_equal(qry->zone_cut.name, rr->owner)) {
- return KR_RANK_INITIAL | KR_RANK_AUTH;
- } else {
- return KR_RANK_OMIT;
- }
- }
-
- return KR_RANK_INITIAL;
+ /* Be aggressive: try to validate anything else (almost never extra latency). */
+ return KR_RANK_TRY;
/* TODO: this classifier of authoritativity may not be perfect yet. */
}
for (unsigned i = 0; i < an->count; ++i) {
const knot_rrset_t *rr = knot_pkt_rr(an, i);
int err = kr_ranked_rrarray_add(&req->answ_selected, rr,
- KR_RANK_INITIAL | KR_RANK_AUTH, true, query->uid, &req->pool);
+ KR_RANK_OMIT | KR_RANK_AUTH, true, query->uid, &req->pool);
/* KR_RANK_AUTH: we don't have the records directly from
* an authoritative source, but we do trust the server and it's
* supposed to only send us authoritative records. */
return section_has_type(knot_pkt_section(pkt, KNOT_ADDITIONAL), type);
}
-static int validate_section(kr_rrset_validation_ctx_t *vctx, knot_mm_t *pool)
+static int validate_section(kr_rrset_validation_ctx_t *vctx, const struct kr_query *qry,
+ knot_mm_t *pool)
{
if (!vctx) {
return kr_error(EINVAL);
/* Can't use qry->zone_cut.name directly, as this name can
* change when updating cut information before validation.
*/
- vctx->zone_name = vctx->keys ? vctx->keys->owner : NULL;
+ vctx->zone_name = vctx->keys ? vctx->keys->owner : NULL;
int validation_result = 0;
for (ssize_t i = 0; i < vctx->rrs->len; ++i) {
continue;
}
+ uint8_t rank_orig = entry->rank;
validation_result = kr_rrset_validate(vctx, rr);
if (validation_result == kr_ok()) {
kr_rank_set(&entry->rank, KR_RANK_SECURE);
+
+ } else if (kr_rank_test(rank_orig, KR_RANK_TRY)) {
+ WITH_VERBOSE {
+ VERBOSE_MSG(qry, ">< failed to validate but skipping: ");
+ kr_rrtype_print(rr->type, "", " ");
+ kr_dname_print(rr->owner, "", "\n");
+ }
+ vctx->result = kr_ok();
+ kr_rank_set(&entry->rank, KR_RANK_TRY);
+ /* ^^ BOGUS would be more accurate, but it might change
+ * to MISMATCH on revalidation, e.g. in test val_referral_nods :-/
+ */
+
} else if (validation_result == kr_error(ENOENT)) {
/* no RRSIGs found */
kr_rank_set(&entry->rank, KR_RANK_MISSING);
vctx->err_cnt += 1;
+
} else {
kr_rank_set(&entry->rank, KR_RANK_BOGUS);
vctx->err_cnt += 1;
.result = 0
};
- int ret = validate_section(&vctx, pool);
+ int ret = validate_section(&vctx, qry, pool);
req->answ_validated = (vctx.err_cnt == 0);
if (ret != kr_ok()) {
return ret;
vctx.err_cnt = 0;
vctx.result = 0;
- ret = validate_section(&vctx, pool);
+ ret = validate_section(&vctx, qry, pool);
req->auth_validated = (vctx.err_cnt == 0);
if (ret != kr_ok()) {
return ret;
const knot_rrset_t *rr = entry->rr;
if (entry->yielded ||
(!kr_rank_test(entry->rank, KR_RANK_INITIAL) &&
- !kr_rank_test(entry->rank, KR_RANK_MISMATCH))) {
+ !kr_rank_test(entry->rank, KR_RANK_TRY) &&
+ !kr_rank_test(entry->rank, KR_RANK_MISMATCH))) {
continue;
}
if (rr->type == KNOT_RRTYPE_RRSIG) {
continue;
}
if (kr_rank_test(entry->rank, KR_RANK_INITIAL)
+ || kr_rank_test(entry->rank, KR_RANK_TRY)
|| kr_rank_test(entry->rank, KR_RANK_MISSING)) {
kr_rank_set(&entry->rank, rank_to_set);
}
switch (rank & ~KR_RANK_AUTH) {
case KR_RANK_INITIAL:
case KR_RANK_OMIT:
+ case KR_RANK_TRY:
case KR_RANK_INDET:
case KR_RANK_BOGUS:
case KR_RANK_MISMATCH:
* https://tools.ietf.org/html/rfc4035#section-4.3
*/
enum kr_rank {
- KR_RANK_INITIAL = 0, /**< Did not attempt to validate. */
- KR_RANK_OMIT = 1, /**< Do not attempt to validate. (And don't consider it a validation failure.) */
- KR_RANK_INDET, /**< Unable to determine whether it should be secure. */
+ KR_RANK_INITIAL = 0, /**< Did not attempt to validate. It's assumed
+ compulsory to validate (or prove insecure). */
+ KR_RANK_OMIT, /**< Do not attempt to validate.
+ (And don't consider it a validation failure.) */
+ KR_RANK_TRY, /**< Attempt to validate, but failures are non-fatal. */
+
+ KR_RANK_INDET = 4, /**< Unable to determine whether it should be secure. */
KR_RANK_BOGUS, /**< Ought to be secure but isn't. */
KR_RANK_MISMATCH,
KR_RANK_MISSING, /**< Unable to obtain a good signature. */