]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib: turn on DO=1 per query, fixed caching of DNSSEC data
authorMarek Vavruša <marek.vavrusa@nic.cz>
Sat, 19 Sep 2015 19:26:37 +0000 (21:26 +0200)
committerMarek Vavruša <marek.vavrusa@nic.cz>
Sat, 19 Sep 2015 19:26:37 +0000 (21:26 +0200)
subrequests may be insecure (e.g. out of bailiwick insecure NS),
but the final answer may be secured
the commit also fixes caching in this case

lib/layer/pktcache.c
lib/layer/rrcache.c
lib/resolve.c
lib/resolve.h
modules/stats/stats.c

index 1b1057c1d519a9c6196d0924bef65b88428c475d..c4a50d0797a4a80c1ca2dbd052f6deb0f9484c9f 100644 (file)
@@ -26,9 +26,9 @@
 #define DEFAULT_MAXTTL (15 * 60)
 #define DEFAULT_NOTTL (5) /* Short-time "no data" retention to avoid bursts */
 
-static inline uint8_t get_tag(struct kr_request *req)
+static inline uint8_t get_tag(struct kr_query *qry)
 {
-       return (req->options & QUERY_DNSSEC_WANT) ? KR_CACHE_SEC : KR_CACHE_PKT;
+       return (qry->flags & QUERY_DNSSEC_WANT) ? KR_CACHE_SEC : KR_CACHE_PKT;
 }
 
 static uint32_t limit_ttl(uint32_t ttl)
@@ -115,7 +115,7 @@ static int peek(knot_layer_t *ctx, knot_pkt_t *pkt)
        }
 
        /* Fetch either answer to original or minimized query */
-       uint8_t tag = get_tag(req);
+       uint8_t tag = get_tag(qry);
        int ret = loot_cache(&txn, pkt, tag, qry);
        kr_cache_txn_abort(&txn);
        if (ret == 0) {
@@ -197,7 +197,7 @@ static int stash(knot_layer_t *ctx, knot_pkt_t *pkt)
        };
 
        /* Stash answer in the cache */
-       int ret = kr_cache_insert(&txn, get_tag(req), qname, qtype, &header, data);     
+       int ret = kr_cache_insert(&txn, get_tag(qry), qname, qtype, &header, data);     
        if (ret != 0) {
                kr_cache_txn_abort(&txn);
        } else {
index 2a3e6a150f139cbd8ff2ea1b316741f7147a64ae..f72dbf3f34852b0497db89c0cc5da8fcfc649a4c 100644 (file)
@@ -125,7 +125,7 @@ static int peek(knot_layer_t *ctx, knot_pkt_t *pkt)
         * Only one step of the chain is resolved at a time.
         */
        struct kr_cache *cache = &req->ctx->cache;
-       int ret = loot_cache(cache, pkt, qry, req->options & QUERY_DNSSEC_WANT);
+       int ret = loot_cache(cache, pkt, qry, (qry->flags & QUERY_DNSSEC_WANT));
        if (ret == 0) {
                DEBUG_MSG("=> satisfied from cache\n");
                qry->flags |= QUERY_CACHED|QUERY_NO_MINIMIZE;
@@ -141,6 +141,7 @@ static int peek(knot_layer_t *ctx, knot_pkt_t *pkt)
 struct stash_baton
 {
        struct kr_request *req;
+       struct kr_query *qry;
        struct kr_cache_txn *txn;
        unsigned timestamp;
        uint32_t min_ttl;
@@ -149,7 +150,7 @@ struct stash_baton
 static int commit_rrsig(struct stash_baton *baton, knot_rrset_t *rr)
 {
        /* If not doing secure resolution, ignore (unvalidated) RRSIGs. */
-       if (!(baton->req->options & QUERY_DNSSEC_WANT)) {
+       if (!(baton->qry->flags & QUERY_DNSSEC_WANT)) {
                return kr_ok();
        }
        /* Commit covering RRSIG to a separate cache namespace. */
@@ -197,12 +198,13 @@ static int commit_rr(const char *key, void *val, void *data)
        return kr_cache_insert_rr(baton->txn, rr, baton->timestamp);
 }
 
-static int stash_commit(map_t *stash, unsigned timestamp, struct kr_cache_txn *txn, struct kr_request *req)
+static int stash_commit(map_t *stash, struct kr_query *qry, struct kr_cache_txn *txn, struct kr_request *req)
 {
        struct stash_baton baton = {
                .req = req,
+               .qry = qry,
                .txn = txn,
-               .timestamp = timestamp,
+               .timestamp = qry->timestamp.tv_sec,
                .min_ttl = DEFAULT_MINTTL
        };
        return map_walk(stash, &commit_rr, &baton);
@@ -339,7 +341,7 @@ static int stash(knot_layer_t *ctx, knot_pkt_t *pkt)
                struct kr_cache *cache = &req->ctx->cache;
                struct kr_cache_txn txn;
                if (kr_cache_txn_begin(cache, &txn, 0) == 0) {
-                       ret = stash_commit(&stash, qry->timestamp.tv_sec, &txn, req);
+                       ret = stash_commit(&stash, qry, &txn, req);
                        if (ret == 0) {
                                kr_cache_txn_commit(&txn);
                        } else {
index 94084ce1730d26940d214cbb0806ae6ba871d6b6..c77b40cec9f3d6363d3ffbb441aa2ad2c0169bdf 100644 (file)
@@ -154,10 +154,6 @@ static int edns_put(knot_pkt_t *pkt)
 static int edns_create(knot_pkt_t *pkt, knot_pkt_t *template, struct kr_request *req)
 {
        pkt->opt_rr = knot_rrset_copy(req->ctx->opt_rr, &pkt->mm);
-       /* Set DO bit if set (DNSSEC requested). */
-       if (knot_pkt_has_dnssec(template) || (req->options & QUERY_DNSSEC_WANT)) {
-               knot_edns_set_do(pkt->opt_rr);
-       }
        return knot_pkt_reserve(pkt, knot_edns_wire_size(pkt->opt_rr));
 }
 
@@ -175,6 +171,10 @@ static int answer_prepare(knot_pkt_t *answer, knot_pkt_t *query, struct kr_reque
                if (ret != 0){
                        return ret;
                }
+               /* Set DO bit if set (DNSSEC requested). */
+               if (knot_pkt_has_dnssec(query)) {
+                       knot_edns_set_do(answer->opt_rr);
+               }
        }
        return kr_ok();
 }
@@ -197,10 +197,9 @@ static int answer_finalize(struct kr_request *request, int state)
        return kr_ok();
 }
 
-static int query_finalize(struct kr_request *request, knot_pkt_t *pkt)
+static int query_finalize(struct kr_request *request, struct kr_query *qry, knot_pkt_t *pkt)
 {
        /* Randomize query case (if not in safemode) */
-       struct kr_query *qry = kr_rplan_current(&request->rplan);
        qry->secret = (qry->flags & QUERY_SAFEMODE) ? 0 : kr_rand_uint(UINT32_MAX);
        knot_dname_t *qname_raw = (knot_dname_t *)knot_pkt_qname(pkt);
        randomized_qname_case(qname_raw, qry->secret);
@@ -209,7 +208,10 @@ static int query_finalize(struct kr_request *request, knot_pkt_t *pkt)
        knot_pkt_begin(pkt, KNOT_ADDITIONAL);
        if (!(qry->flags & QUERY_SAFEMODE)) {
                ret = edns_create(pkt, request->answer, request);
-               if (ret == 0) {
+               if (ret == 0) { /* Enable DNSSEC for query. */
+                       if (qry->flags & QUERY_DNSSEC_WANT) {
+                               knot_edns_set_do(pkt->opt_rr);
+                       }
                        ret = edns_put(pkt);
                }
        }
@@ -229,9 +231,12 @@ int kr_resolve_begin(struct kr_request *request, struct kr_context *ctx, knot_pk
        return KNOT_STATE_CONSUME;
 }
 
-int kr_resolve_query(struct kr_request *request, const knot_dname_t *qname, uint16_t qclass, uint16_t qtype)
+static int resolve_query(struct kr_request *request, const knot_pkt_t *packet)
 {
        struct kr_rplan *rplan = &request->rplan;
+       const knot_dname_t *qname = knot_pkt_qname(packet);
+       uint16_t qclass = knot_pkt_qclass(packet);
+       uint16_t qtype = knot_pkt_qtype(packet);
        struct kr_query *qry = kr_rplan_push(rplan, NULL, qname, qclass, qtype);
        if (!qry) {
                return KNOT_STATE_FAIL;
@@ -239,6 +244,9 @@ int kr_resolve_query(struct kr_request *request, const knot_dname_t *qname, uint
 
        /* Deferred zone cut lookup for this query. */
        qry->flags |= QUERY_AWAIT_CUT;
+       if (knot_pkt_has_dnssec(packet)) {
+               qry->flags |= QUERY_DNSSEC_WANT;
+       }
 
        /* Initialize answer packet */
        knot_pkt_t *answer = request->answer;
@@ -266,11 +274,7 @@ int kr_resolve_consume(struct kr_request *request, knot_pkt_t *packet)
                if (answer_prepare(request->answer, packet, request) != 0) {
                        return KNOT_STATE_FAIL;
                }
-               /* Start query resolution */
-               const knot_dname_t *qname = knot_pkt_qname(packet);
-               uint16_t qclass = knot_pkt_qclass(packet);
-               uint16_t qtype = knot_pkt_qtype(packet);
-               return kr_resolve_query(request, qname, qclass, qtype);
+               return resolve_query(request, packet);
        }
 
        /* Different processing for network error */
@@ -336,6 +340,9 @@ static int zone_cut_subreq(struct kr_rplan *rplan, struct kr_query *parent,
                return kr_error(ENOMEM);
        }
        next->flags |= QUERY_NO_MINIMIZE;
+       if (parent->flags & QUERY_DNSSEC_WANT) {
+               next->flags |= QUERY_DNSSEC_WANT;
+       }
        return kr_ok();
 }
 
@@ -472,7 +479,7 @@ ns_election:
        }
 
        /* Prepare additional query */
-       int ret = query_finalize(request, packet);
+       int ret = query_finalize(request, qry, packet);
        if (ret != 0) {
                return KNOT_STATE_FAIL;
        }
index a6afb2ba65b65415c71573c858c3dcd99675bb1a..c373819b7d9fa25c2e8ab7c2227bf3405487a3f9 100644 (file)
  *             .alloc = (mm_alloc_t) mp_alloc
  *     }
  * };
- * kr_resolve_begin(&req, ctx, answer);
- * int state = kr_resolve_query(&req, qname, qclass, qtype);
+ *
+ * // Setup and provide input query
+ * int state = kr_resolve_begin(&req, ctx, final_answer);
+ * state = kr_resolve_consume(&req, query);
  *
  * // Generate answer
  * while (state == KNOT_STATE_PRODUCE) {
@@ -126,16 +128,6 @@ struct kr_request {
  */
 int kr_resolve_begin(struct kr_request *request, struct kr_context *ctx, knot_pkt_t *answer);
 
-/**
- * Push new query for resolution to the state.
- * @param  request request state (if already has a question, this will be resolved first)
- * @param  qname
- * @param  qclass
- * @param  qtype
- * @return         PRODUCE|FAIL
- */
-int kr_resolve_query(struct kr_request *request, const knot_dname_t *qname, uint16_t qclass, uint16_t qtype);
-
 /**
  * Consume input packet (may be either first query or answer to query originated from kr_resolve_produce())
  *
index 3b449a9edad30bec43e86fa1fd7c62a54c9d66e6..7941bb5f0a6107602c2d078a82dc3f316e295bf4 100644 (file)
@@ -162,7 +162,7 @@ static int collect(knot_layer_t *ctx)
        /* Query parameters and transport mode */
        if (knot_pkt_has_edns(param->answer)) {
                stat_const_add(data, metric_query_edns, 1);
-               if (param->options & QUERY_DNSSEC_WANT) {
+               if (knot_pkt_has_dnssec(param->answer)) {
                        stat_const_add(data, metric_query_dnssec, 1);
                }
        }