From: Karel Slany Date: Tue, 30 Jun 2015 13:49:08 +0000 (+0200) Subject: layer/rrsigcache: Check for DNSKEY RRSet presence in cache. X-Git-Tag: v1.0.0-beta1~53^2~173 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9c9eb09aab16b51915eda51fe80749a04463a970;p=thirdparty%2Fknot-resolver.git layer/rrsigcache: Check for DNSKEY RRSet presence in cache. --- diff --git a/lib/layer/rrsigcache.c b/lib/layer/rrsigcache.c index 6c5b8228c..4ede44024 100644 --- a/lib/layer/rrsigcache.c +++ b/lib/layer/rrsigcache.c @@ -74,15 +74,57 @@ static int stash_commit(map_t *stash, unsigned timestamp, struct kr_cache_txn *t return kr_ok(); } -static int merge_in_rrsigs(knot_rrset_t *cache_rr, const knot_rrset_t *rrsigset, uint16_t typec, mm_ctx_t *pool) +static int validate_rrsig(const knot_rrset_t *rrsig, size_t pos, const knot_rrset_t *rr, + struct kr_cache_txn *txn, struct kr_request *req) { + struct kr_rplan *rplan = &req->rplan; + struct kr_query *qry = kr_rplan_current(rplan); + uint32_t timestamp = qry->timestamp.tv_sec; + + const knot_dname_t *signer = knot_rrsig_signer_name(&rrsig->rrs, pos); + + knot_rrset_t dnskey_rr; + knot_rrset_init(&dnskey_rr, (knot_dname_t *)signer, KNOT_RRTYPE_DNSKEY, rr->rclass); + int ret = kr_cache_peek_rr(txn, &dnskey_rr, ×tamp); + if (ret != 0) { + DEBUG_MSG("<= missing DNSKEY\n"); + return KNOT_DNSSEC_ENOKEY; + } + + return kr_ok(); +} + +static int merge_in_rrsigs(knot_rrset_t *cache_rr, const knot_rrset_t *rrsigset, const knot_rrset_t *rr, + struct kr_cache_txn *txn, struct kr_request *req) +{ + struct kr_rplan *rplan = &req->rplan; int ret = KNOT_EOK; + /* Find rrset corresponding to RRSIG. */ for (unsigned i = 0; i < rrsigset->rrs.rr_count; ++i) { - if ((knot_rrsig_type_covered(&rrsigset->rrs, i) == typec) && + if ((knot_rrsig_type_covered(&rrsigset->rrs, i) == rr->type) && knot_dname_is_equal(cache_rr->owner, rrsigset->owner)) { + ret = validate_rrsig(rrsigset, i, rr, txn, req); + switch (ret) { + case KNOT_DNSSEC_ENOKEY: +#ifndef NDEBUG + { + char name_str[KNOT_DNAME_MAXLEN], type_str[16]; + knot_dname_to_str(name_str, knot_rrsig_signer_name(&rrsigset->rrs, i), sizeof(name_str)); + knot_rrtype_to_string(rr->type, type_str, sizeof(type_str)); + DEBUG_MSG_NOPLAN("%s() Missing DNSKEY for '%s %s'.\n", __func__, type_str, name_str); + } +#endif + break; + case 0: + break; + default: + return ret; + break; + } + const knot_rdata_t *rdata = knot_rdataset_at(&rrsigset->rrs, i); - ret = knot_rdataset_add(&cache_rr->rrs, rdata, pool); + ret = knot_rdataset_add(&cache_rr->rrs, rdata, rplan->pool); if (KNOT_EOK != ret) { return ret; } @@ -92,13 +134,46 @@ static int merge_in_rrsigs(knot_rrset_t *cache_rr, const knot_rrset_t *rrsigset, return ret; } +static int scan_for_rrsigs(knot_rrset_t *cache_rrsig, const knot_pktsection_t *section, + const knot_rrset_t *rr, struct kr_request *req) +{ + struct kr_rplan *rplan = &req->rplan; + struct kr_cache *cache = &req->ctx->cache; + + struct kr_cache_txn txn; + int ret = kr_cache_txn_begin(cache, &txn, 0); + if (0 != ret) { + return ret; + } + + knot_rrset_init(cache_rrsig, rr->owner, rr->type, rr->rclass); + for (uint16_t i = 0; i < section->count; ++i) { + const knot_rrset_t *rrset = knot_pkt_rr(section, i); + if (KNOT_RRTYPE_RRSIG != rrset->type) { + continue; + } + /* Currently only merge. Signature check is missing. */ + int ret = merge_in_rrsigs(cache_rrsig, rrset, rr, &txn, req); + if (KNOT_EOK != ret) { + knot_rrset_clear(cache_rrsig, rplan->pool); + kr_cache_txn_abort(&txn); + return ret; + } + } + + kr_cache_txn_abort(&txn); + return kr_ok(); +} + static int stash_add_rrsig(map_t *stash, const knot_pktsection_t *section, - const knot_rrset_t *rr, mm_ctx_t *pool) + const knot_rrset_t *rr, struct kr_request *req) { if (rr->type == KNOT_RRTYPE_RRSIG) { return kr_ok(); } + struct kr_rplan *rplan = &req->rplan; + /* Stash key = {[1-255] owner, [1-5] type covered, [1] \x00 } */ char key[8 + KNOT_DNAME_MAXLEN]; int ret = knot_dname_to_wire((uint8_t *)key, rr->owner, KNOT_DNAME_MAXLEN); @@ -119,27 +194,18 @@ static int stash_add_rrsig(map_t *stash, const knot_pktsection_t *section, /* Construct RRSIG RRSet containing related data. */ knot_rrset_t cache_rrsig; - knot_rrset_init(&cache_rrsig, rr->owner, rr->type, rr->rclass); - for (uint16_t i = 0; i < section->count; ++i) { - const knot_rrset_t *rrset = knot_pkt_rr(section, i); - if (KNOT_RRTYPE_RRSIG != rrset->type) { - continue; - } - /* Currently only merge. Signature check is missing. */ - ret = merge_in_rrsigs(&cache_rrsig, rrset, rr->type, pool); - if (KNOT_EOK != ret) { - knot_rrset_clear(&cache_rrsig, pool); - return ret; - } + ret = scan_for_rrsigs(&cache_rrsig, section, rr, req); + if (ret != 0) { + return ret; } if (cache_rrsig.rrs.rr_count) { - stashed = knot_rrset_copy(&cache_rrsig, pool); + stashed = knot_rrset_copy(&cache_rrsig, rplan->pool); if (!stashed) { return kr_error(ENOMEM); } } - knot_rrset_clear(&cache_rrsig, pool); + knot_rrset_clear(&cache_rrsig, rplan->pool); if (stashed) { return map_set(stash, key, stashed); } @@ -159,8 +225,10 @@ static void stash_glue(map_t *stash, knot_pkt_t *pkt, const knot_dname_t *ns_nam } } -static int stash_authority(struct kr_query *qry, knot_pkt_t *pkt, map_t *stash, mm_ctx_t *pool) +static int stash_authority(map_t *stash, knot_pkt_t *pkt, struct kr_request *req) { + struct kr_rplan *rplan = &req->rplan; + struct kr_query *qry = kr_rplan_current(rplan); const knot_pktsection_t *authority = knot_pkt_section(pkt, KNOT_AUTHORITY); for (unsigned i = 0; i < authority->count; ++i) { const knot_rrset_t *rr = knot_pkt_rr(authority, i); @@ -170,20 +238,22 @@ static int stash_authority(struct kr_query *qry, knot_pkt_t *pkt, map_t *stash, } /* Look up glue records for NS */ if (rr->type == KNOT_RRTYPE_NS) { - stash_glue(stash, pkt, knot_ns_name(&rr->rrs, 0), pool); + stash_glue(stash, pkt, knot_ns_name(&rr->rrs, 0), rplan->pool); } /* Ignore RRSIGs directly. */ if (rr->type == KNOT_RRTYPE_RRSIG) { continue; } /* Stash record */ - stash_add_rrsig(stash, authority, rr, pool); + stash_add_rrsig(stash, authority, rr, req); } return kr_ok(); } -static int stash_answer(struct kr_query *qry, knot_pkt_t *pkt, map_t *stash, mm_ctx_t *pool) +static int stash_answer(map_t *stash, knot_pkt_t *pkt, struct kr_request *req) { + struct kr_rplan *rplan = &req->rplan; + struct kr_query *qry = kr_rplan_current(rplan); const knot_dname_t *cname = qry->sname; const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER); for (unsigned i = 0; i < answer->count; ++i) { @@ -196,7 +266,7 @@ static int stash_answer(struct kr_query *qry, knot_pkt_t *pkt, map_t *stash, mm_ if (rr->type == KNOT_RRTYPE_RRSIG) { continue; } - stash_add_rrsig(stash, answer, rr, pool); + stash_add_rrsig(stash, answer, rr, req); /* Follow CNAME chain */ if (rr->type == KNOT_RRTYPE_CNAME) { cname = knot_cname_name(&rr->rrs); @@ -207,6 +277,15 @@ static int stash_answer(struct kr_query *qry, knot_pkt_t *pkt, map_t *stash, mm_ return kr_ok(); } +static int scan_rrsigs(map_t *stash, knot_pkt_t *pkt, struct kr_request *req) +{ + int ret = stash_authority(stash, pkt, req); + if (ret == 0 && knot_wire_get_aa(pkt->wire)) { + ret = stash_answer(stash, pkt, req); + } + return ret; +} + static int stash(knot_layer_t *ctx, knot_pkt_t *pkt) { /* Do nothing when no DNSSEC required. */ @@ -231,10 +310,7 @@ static int stash(knot_layer_t *ctx, knot_pkt_t *pkt) stash_rrsig.malloc = (map_alloc_f) mm_alloc; stash_rrsig.free = (map_free_f) mm_free; stash_rrsig.baton = rplan->pool; - int ret = stash_authority(qry, pkt, &stash_rrsig, rplan->pool); - if (ret == 0 && knot_wire_get_aa(pkt->wire)) { - ret = stash_answer(qry, pkt, &stash_rrsig, rplan->pool); - } + int ret = scan_rrsigs(&stash_rrsig, pkt, req); /* Cache stashed records */ if (ret == 0) { /* Open write transaction */