Commit 4a037c10 authored by Vladimír Čunát's avatar Vladimír Čunát

Merge !237: layer/validate: clear AD with optout NSEC3

Fixes #169.
parents 3502c46c 6703a067
Pipeline #2483 passed with stages
in 1 minute and 14 seconds
......@@ -54,6 +54,11 @@ enum kr_cache_flag {
KR_CACHE_FLAG_WCARD_PROOF = 1, /* Entry contains either packet with wildcard
* answer either record for which wildcard
* expansion proof is needed */
KR_CACHE_FLAG_OPTOUT = 2, /* Entry contains secured packet containing a
* closest encloser proof in which the NSEC3 RR
* that covers the "next closer" name
* has the Opt-Out bit set
*/
};
......
......@@ -360,17 +360,20 @@ static int prepend_asterisk(uint8_t *tgt, size_t maxlen, const knot_dname_t *nam
/**
* Closest encloser proof (RFC5155 7.2.1).
* @note No RRSIGs are validated.
* @param pkt Packet structure to be processed.
* @param section_id Packet section to be processed.
* @param sname Name to be checked.
* @param encloser_name Returned matching encloser name, if found.
* @param matching_ecloser_nsec3 Pointer to matching encloser NSEC RRSet.
* @param covering_next_nsec3 Pointer to covering next closer NSEC3 RRSet.
* @return 0 or error code.
* @param pkt Packet structure to be processed.
* @param section_id Packet section to be processed.
* @param sname Name to be checked.
* @param encloser_name Returned matching encloser name, if found.
* @param matching_encloser_nsec3 Pointer to matching encloser NSEC RRSet.
* @param covering_next_nsec3 Pointer to covering next closer NSEC3 RRSet.
* @return 0 or error code.
*/
static int closest_encloser_proof(const knot_pkt_t *pkt, knot_section_t section_id,
const knot_dname_t *sname, const knot_dname_t **encloser_name,
const knot_rrset_t **matching_ecloser_nsec3, const knot_rrset_t **covering_next_nsec3)
static int closest_encloser_proof(const knot_pkt_t *pkt,
knot_section_t section_id,
const knot_dname_t *sname,
const knot_dname_t **encloser_name,
const knot_rrset_t **matching_encloser_nsec3,
const knot_rrset_t **covering_next_nsec3)
{
const knot_pktsection_t *sec = knot_pkt_section(pkt, section_id);
if (!sec || !sname) {
......@@ -427,8 +430,8 @@ static int closest_encloser_proof(const knot_pkt_t *pkt, knot_section_t section_
if (encloser_name && next_closer[0]) {
*encloser_name = knot_wire_next_label(next_closer, NULL);
}
if (matching_ecloser_nsec3) {
*matching_ecloser_nsec3 = matching;
if (matching_encloser_nsec3) {
*matching_encloser_nsec3 = matching;
}
if (covering_next_nsec3) {
*covering_next_nsec3 = covering;
......@@ -444,7 +447,10 @@ static int closest_encloser_proof(const knot_pkt_t *pkt, knot_section_t section_
* @param pkt Packet structure to be processed.
* @param section_id Packet section to be processed.
* @param encloser Closest (provable) encloser domain name.
* @return 0 or error code.
* @return 0 or error code:
* DNSSEC_OUT_OF_RANGE - NSEC3 RR (that covers a wildcard)
* has been found, but has opt-out flag set;
* otherwise - error.
*/
static int covers_closest_encloser_wildcard(const knot_pkt_t *pkt, knot_section_t section_id,
const knot_dname_t *encloser)
......@@ -474,7 +480,8 @@ static int covers_closest_encloser_wildcard(const knot_pkt_t *pkt, knot_section_
return ret;
}
if (flags & FLG_NAME_COVERED) {
return kr_ok();
return has_optout(rrset) ?
kr_error(DNSSEC_OUT_OF_RANGE) : kr_ok();
}
}
......@@ -485,11 +492,23 @@ int kr_nsec3_name_error_response_check(const knot_pkt_t *pkt, knot_section_t sec
const knot_dname_t *sname)
{
const knot_dname_t *encloser = NULL;
int ret = closest_encloser_proof(pkt, section_id, sname, &encloser, NULL, NULL);
const knot_rrset_t *covering_next_nsec3 = NULL;
int ret = closest_encloser_proof(pkt, section_id, sname,
&encloser, NULL, &covering_next_nsec3);
if (ret != 0) {
return ret;
}
ret = covers_closest_encloser_wildcard(pkt, section_id, encloser);
if (ret != 0) {
/* OK, but NSEC3 for wildcard at encloser has opt-out;
* or error */
return ret;
}
return covers_closest_encloser_wildcard(pkt, section_id, encloser);
/* Closest encloser proof is OK and
* NSEC3 for wildcard has been found and optout flag is not set.
* Now check if NSEC3 that covers next closer name has opt-out. */
return has_optout(covering_next_nsec3) ?
kr_error(DNSSEC_OUT_OF_RANGE) : kr_ok();
}
/**
......
......@@ -128,6 +128,9 @@ static int pktcache_peek(kr_layer_t *ctx, knot_pkt_t *pkt)
if (flags & KR_CACHE_FLAG_WCARD_PROOF) {
qry->flags |= QUERY_DNSSEC_WEXPAND;
}
if (flags & KR_CACHE_FLAG_OPTOUT) {
qry->flags |= QUERY_DNSSEC_OPTOUT;
}
pkt->parsed = pkt->size;
knot_wire_set_qr(pkt->wire);
knot_wire_set_aa(pkt->wire);
......@@ -229,6 +232,9 @@ static int pktcache_stash(kr_layer_t *ctx, knot_pkt_t *pkt)
if (qry->flags & QUERY_DNSSEC_WEXPAND) {
header.flags |= KR_CACHE_FLAG_WCARD_PROOF;
}
if (qry->flags & QUERY_DNSSEC_OPTOUT) {
header.flags |= KR_CACHE_FLAG_OPTOUT;
}
/* Check if we can replace (allow current or better rank, SECURE is always accepted). */
struct kr_cache *cache = &ctx->req->ctx->cache;
......
......@@ -641,7 +641,14 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
} else {
ret = kr_nsec3_name_error_response_check(pkt, KNOT_AUTHORITY, qry->sname);
}
if (ret != 0) {
if (has_nsec3 && (ret == kr_error(DNSSEC_OUT_OF_RANGE))) {
/* NXDOMAIN proof is OK,
* but NSEC3 that covers next closer name
* (or wildcard at next closer name) has opt-out flag.
* RFC5155 9.2; AD flag can not be set */
qry->flags |= QUERY_DNSSEC_OPTOUT;
VERBOSE_MSG(qry, "<= can't prove NXDOMAIN due to optout, going insecure\n");
} else if (ret != 0) {
VERBOSE_MSG(qry, "<= bad NXDOMAIN proof\n");
qry->flags |= QUERY_DNSSEC_BOGUS;
return KR_STATE_FAIL;
......@@ -665,7 +672,7 @@ static int validate(kr_layer_t *ctx, knot_pkt_t *pkt)
if (ret != 0) {
if (has_nsec3 && (ret == kr_error(DNSSEC_OUT_OF_RANGE))) {
VERBOSE_MSG(qry, "<= can't prove NODATA due to optout, going insecure\n");
qry->flags |= QUERY_DNSSEC_NODS;
qry->flags |= QUERY_DNSSEC_OPTOUT;
/* Could not return from here,
* we must continue, validate NSEC\NSEC3 and
* call update_parent_keys() to mark
......
......@@ -537,7 +537,8 @@ static int answer_finalize(struct kr_request *request, int state)
struct kr_query *last = array_tail(rplan->resolved);
/* Do not set AD for RRSIG query, as we can't validate it. */
const bool secure = (last->flags & QUERY_DNSSEC_WANT) &&
!(last->flags & QUERY_DNSSEC_INSECURE);
!(last->flags & QUERY_DNSSEC_INSECURE) &&
!(last->flags & QUERY_DNSSEC_OPTOUT);
if (!(last->flags & QUERY_STUB) /* Never set AD if forwarding. */
&& has_ad && secure
&& knot_pkt_qtype(answer) != KNOT_RRTYPE_RRSIG) {
......
......@@ -54,6 +54,7 @@
X(TRACE, 1 << 25) /**< Log answer with kr_verbose_log(), unless -DNDEBUG. */ \
X(NO_0X20, 1 << 26) /**< Disable query case randomization . */ \
X(DNSSEC_NODS, 1 << 27) /**< DS non-existance is proven */ \
X(DNSSEC_OPTOUT, 1 << 28) /**< Closest encloser proof has optout */ \
/* 1 << 31 Used by ../modules/dns64/dns64.lua */
/** Query flags */
......
Subproject commit b7453577c57cb837261ca6e21098b8a44a9e8b3d
Subproject commit b96ef5cd589ddb71eefb89e09fee1087a49edf35
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment