]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
layer/rrsigcache: Check for DNSKEY RRSet presence in cache.
authorKarel Slany <karel.slany@nic.cz>
Tue, 30 Jun 2015 13:49:08 +0000 (15:49 +0200)
committerKarel Slany <karel.slany@nic.cz>
Tue, 30 Jun 2015 13:49:08 +0000 (15:49 +0200)
lib/layer/rrsigcache.c

index 6c5b8228cb10681ce658e3a00ffc0f181f7c9e11..4ede4402483fef3f7867bf538be6e592eae30eb5 100644 (file)
@@ -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, &timestamp);
+       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 */