Commit b2838cc1 authored by Marek Vavruša's avatar Marek Vavruša

lib/zonecut: do not fetch DS/DNSKEY for cached insecure delegations

when a delegation is provably insecure, it is flagged as INSECURE in
cache (this is different from "unchecked"), when the next query finds
the same zone cut, this information is retrieved and if it was proved to
be insecure before, this status is reused

this prevents refetching of NS/DNSKEY in some situations
parent 266410c2
......@@ -154,7 +154,7 @@ static void check_empty_nonterms(struct kr_query *qry, knot_pkt_t *pkt, struct k
}
}
static int ns_fetch_cut(struct kr_query *qry, struct kr_request *req, knot_pkt_t *pkt, bool secured)
static int ns_fetch_cut(struct kr_query *qry, struct kr_request *req, knot_pkt_t *pkt)
{
int ret = 0;
......@@ -164,15 +164,22 @@ static int ns_fetch_cut(struct kr_query *qry, struct kr_request *req, knot_pkt_t
/* If at/subdomain of parent zone cut, start from its encloser.
* This is for case when we get to a dead end (and need glue from parent), or DS refetch. */
struct kr_query *parent = qry->parent;
bool secured = (qry->flags & QUERY_DNSSEC_WANT);
if (parent && parent->zone_cut.name[0] != '\0' && knot_dname_in(parent->zone_cut.name, qry->sname)) {
const knot_dname_t *encloser = knot_wire_next_label(parent->zone_cut.name, NULL);
ret = kr_zonecut_find_cached(req->ctx, &qry->zone_cut, encloser, &txn, qry->timestamp.tv_sec, secured);
ret = kr_zonecut_find_cached(req->ctx, &qry->zone_cut, encloser, &txn, qry->timestamp.tv_sec, &secured);
} else {
ret = kr_zonecut_find_cached(req->ctx, &qry->zone_cut, qry->sname, &txn, qry->timestamp.tv_sec, secured);
ret = kr_zonecut_find_cached(req->ctx, &qry->zone_cut, qry->sname, &txn, qry->timestamp.tv_sec, &secured);
}
/* Check if there's a non-terminal between target and current cut. */
if (ret == 0) {
check_empty_nonterms(qry, pkt, &txn, qry->timestamp.tv_sec);
/* Go insecure if the zone cut is provably insecure */
if ((qry->flags & QUERY_DNSSEC_WANT) && !secured) {
DEBUG_MSG(qry, "=> NS is provably without DS, going insecure\n");
qry->flags &= ~QUERY_DNSSEC_WANT;
qry->flags |= QUERY_DNSSEC_INSECURE;
}
}
kr_cache_txn_abort(&txn);
} else {
......@@ -561,7 +568,7 @@ static int zone_cut_check(struct kr_request *request, struct kr_query *qry, knot
} else {
qry->flags &= ~QUERY_DNSSEC_WANT;
}
int ret = ns_fetch_cut(qry, request, packet, (qry->flags & QUERY_DNSSEC_WANT));
int ret = ns_fetch_cut(qry, request, packet);
if (ret != 0) {
/* No cached cut found, start from SBELT and issue priming query. */
if (ret == kr_error(ENOENT)) {
......
......@@ -315,13 +315,12 @@ static void fetch_addr(struct kr_zonecut *cut, const knot_dname_t *ns, uint16_t
}
/** Fetch best NS for zone cut. */
static int fetch_ns(struct kr_context *ctx, struct kr_zonecut *cut, const knot_dname_t *name, struct kr_cache_txn *txn, uint32_t timestamp)
static int fetch_ns(struct kr_context *ctx, struct kr_zonecut *cut, const knot_dname_t *name, struct kr_cache_txn *txn, uint32_t timestamp, uint16_t * restrict rank)
{
uint16_t rank = 0;
uint32_t drift = timestamp;
knot_rrset_t cached_rr;
knot_rrset_init(&cached_rr, (knot_dname_t *)name, KNOT_RRTYPE_NS, KNOT_CLASS_IN);
int ret = kr_cache_peek_rr(txn, &cached_rr, &rank, &drift);
int ret = kr_cache_peek_rr(txn, &cached_rr, rank, &drift);
if (ret != 0) {
return ret;
}
......@@ -395,7 +394,7 @@ static int fetch_dnskey(struct kr_zonecut *cut, const knot_dname_t *name, struct
}
int kr_zonecut_find_cached(struct kr_context *ctx, struct kr_zonecut *cut, const knot_dname_t *name,
struct kr_cache_txn *txn, uint32_t timestamp, bool secured)
struct kr_cache_txn *txn, uint32_t timestamp, bool * restrict secured)
{
if (!ctx || !cut || !name) {
return kr_error(EINVAL);
......@@ -408,17 +407,21 @@ int kr_zonecut_find_cached(struct kr_context *ctx, struct kr_zonecut *cut, const
}
/* Start at QNAME parent. */
while (txn) {
/* Fetch NS first and see if it's insecure. */
uint16_t rank = 0;
const bool is_root = (label[0] == '\0');
bool has_ta = !secured || is_root || fetch_ta(cut, label, txn, timestamp) == 0;
if (has_ta && fetch_ns(ctx, cut, label, txn, timestamp) == 0) {
if (secured) {
if (fetch_ns(ctx, cut, label, txn, timestamp, &rank) == 0) {
/* Flag as insecure if cached as this */
if (rank & KR_RANK_INSECURE)
*secured = false;
/* Fetch DS if caller wants secure zone cut */
if (*secured || is_root) {
fetch_ta(cut, label, txn, timestamp);
fetch_dnskey(cut, label, txn, timestamp);
}
update_cut_name(cut, label);
mm_free(cut->pool, qname);
return kr_ok();
} else { /* Clear TA, as it is below any known NS. */
knot_rrset_free(&cut->trust_anchor, cut->pool);
}
/* Subtract label from QNAME. */
if (!is_root) {
......
......@@ -125,8 +125,8 @@ int kr_zonecut_set_sbelt(struct kr_context *ctx, struct kr_zonecut *cut);
* @param name QNAME to start finding zone cut for
* @param txn cache transaction (read)
* @param timestamp transaction timestamp
* @param secured search nearest containing a DNSKEY
* @param secured set to true if want secured zone cut, will return false if it is provably insecure
* @return 0 or error code (ENOENT if it doesn't find anything)
*/
int kr_zonecut_find_cached(struct kr_context *ctx, struct kr_zonecut *cut, const knot_dname_t *name,
struct kr_cache_txn *txn, uint32_t timestamp, bool secured);
struct kr_cache_txn *txn, uint32_t timestamp, bool * restrict secured);
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