]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/zonecut: do not fetch DS/DNSKEY for cached insecure delegations
authorMarek Vavruša <marek.vavrusa@nic.cz>
Thu, 3 Dec 2015 12:55:04 +0000 (13:55 +0100)
committerMarek Vavruša <marek.vavrusa@nic.cz>
Thu, 3 Dec 2015 12:55:04 +0000 (13:55 +0100)
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

lib/resolve.c
lib/zonecut.c
lib/zonecut.h

index a730a214083634cf417dfb9881e3415defbef625..97bd81cedfa651cc2bdd47c81727014795dfbd9f 100644 (file)
@@ -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)) {
index 032a2e4bcf41e09ec8d1f04fedb63bf64a9ce4e2..ca120b7e52ac741b1b5e16481de115e7aab40a2f 100644 (file)
@@ -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) {
index 91b95154430fc8009939f49eee8f38a51e5bf889..a3eca008225a287cc1a4e46fae13ba8852e979f0 100644 (file)
@@ -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);