]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
.
authorVladimír Čunát <vladimir.cunat@nic.cz>
Thu, 10 May 2018 14:25:40 +0000 (16:25 +0200)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Thu, 10 May 2018 14:32:39 +0000 (16:32 +0200)
- kill unused struct nsec_p, and have a new one, due to the libknot
  structure needing deallocation
- implement NODATA wildcard answers (not tested yet)
- remove unused parameters (cover_*_kwz)

lib/cache/api.c
lib/cache/impl.h
lib/cache/nsec3.c

index 09c07ebdf66ff5ab8b74306a225dfd37b9b5d4d3..253cab3b0f5e8f7359b0cc19dbef17ccf95399f1 100644 (file)
@@ -182,17 +182,6 @@ int kr_cache_clear(struct kr_cache *cache)
        return ret;
 }
 
-
-
-struct nsec_p {
-       struct {
-               uint8_t salt_len;
-               uint8_t alg;
-               uint16_t iters;
-       } s;
-       uint8_t *salt;
-};
-
 /* When going stricter, BEWARE of breaking entry_h_consistent_NSEC() */
 struct entry_h * entry_h_consistent(knot_db_val_t data, uint16_t type)
 {
@@ -238,7 +227,7 @@ int32_t get_new_ttl(const struct entry_h *entry, const struct kr_query *qry,
        }
        int32_t res = entry->ttl - diff;
        if (res < 0 && owner && qry && qry->stale_cb) {
-               /* Stale-serving decision.  FIXME: modularize or make configurable, etc. */
+               /* Stale-serving decision, delegated to a callback. */
                int res_stale = qry->stale_cb(res, owner, type, qry);
                if (res_stale >= 0)
                        return res_stale;
@@ -368,6 +357,27 @@ int cache_peek(kr_layer_t *ctx, knot_pkt_t *pkt)
        return ret;
 }
 
+static int nsec_p_init(struct nsec_p *nsec_p, const uint8_t *nsec_p_raw)
+{
+       nsec_p->raw = nsec_p_raw;
+       if (!nsec_p_raw) return kr_ok();
+       nsec_p->hash = nsec_p_mkHash(nsec_p->raw);
+       /* Convert NSEC3 params to another format. */
+       const dnssec_binary_t rdata = {
+               .size = nsec_p_rdlen(nsec_p->raw),
+               .data = (uint8_t *)/*const-cast*/nsec_p->raw,
+       };
+       int ret = dnssec_nsec3_params_from_rdata(&nsec_p->libknot, &rdata);
+       return ret == DNSSEC_EOK ? kr_ok() : kr_error(ret);
+}
+
+static void nsec_p_cleanup(struct nsec_p *nsec_p)
+{
+       dnssec_binary_free(&nsec_p->libknot.salt);
+       /* We don't really need to clear it, but it's not large. (`salt` zeroed above) */
+       memset(nsec_p, 0, sizeof(*nsec_p));
+}
+
 /**
  * \note we don't transition to KR_STATE_FAIL even in case of "unexpected errors".
  */
@@ -481,11 +491,15 @@ static int peek_nosync(kr_layer_t *ctx, knot_pkt_t *pkt)
                memcpy(&stamp, el[i].data, sizeof(stamp));
                const int32_t remains = stamp - qry->timestamp.tv_sec; /* using SOA serial arith. */
                if (remains < 0) goto cont;
-               ans.nsec_p = el[i].len > sizeof(stamp) ?
-                       el[i].data + sizeof(stamp) : NULL;
+               {
+                       const uint8_t *nsec_p_raw = el[i].len > sizeof(stamp)
+                                       ? el[i].data + sizeof(stamp) : NULL;
+                       nsec_p_init(&ans.nsec_p, nsec_p_raw);
+               }
                /**** 2. and 3. inside */
                ret = peek_encloser(k, &ans, sname_labels,
                                        lowest_rank, qry, cache);
+               nsec_p_cleanup(&ans.nsec_p);
                if (!ret) break;
                if (ret < 0) return ctx->state;
        cont:
@@ -596,13 +610,13 @@ static int peek_encloser(
        /**** 2. Find a closest (provable) encloser (of sname). */
        int clencl_labels = -1;
        bool clencl_is_tentative = false;
-       if (!ans->nsec_p) { /* NSEC */
+       if (!ans->nsec_p.raw) { /* NSEC */
                int ret = nsec1_encloser(k, ans, sname_labels, &clencl_labels,
                                         &cover_low_kwz, &cover_hi_kwz, qry, cache);
                if (ret) return ret;
        } else {
                int ret = nsec3_encloser(k, ans, sname_labels, &clencl_labels,
-                                        &cover_low_kwz, &cover_hi_kwz, qry, cache);
+                                        qry, cache);
                clencl_is_tentative = ret == ABS(ENOENT) && clencl_labels >= 0;
                /* ^^ Last chance: *positive* wildcard record under this clencl. */
                if (ret && !clencl_is_tentative) return ret;
@@ -623,16 +637,15 @@ static int peek_encloser(
        /**** 3. source of synthesis checks, in case the next closer name was covered.
         **** 3a. We want to query for NSEC* of source of synthesis (SS) or its
         * predecessor, providing us with a proof of its existence or non-existence. */
-       if (ncloser_covered && !ans->nsec_p) {
+       if (ncloser_covered && !ans->nsec_p.raw) {
                int ret = nsec1_src_synth(k, ans, clencl_name,
                                          cover_low_kwz, cover_hi_kwz, qry, cache);
                if (ret == AR_SOA) return 0;
                assert(ret <= 0);
                if (ret) return ret;
 
-       } else if (ncloser_covered && ans->nsec_p && !clencl_is_tentative) {
-               int ret = nsec3_src_synth(k, ans, clencl_name,
-                                         cover_low_kwz, cover_hi_kwz, qry, cache);
+       } else if (ncloser_covered && ans->nsec_p.raw && !clencl_is_tentative) {
+               int ret = nsec3_src_synth(k, ans, clencl_name, qry, cache);
                if (ret == AR_SOA) return 0;
                assert(ret <= 0);
                if (ret) return ret;
@@ -1126,7 +1139,7 @@ static int found_exact_hit(kr_layer_t *ctx, knot_pkt_t *pkt, knot_db_val_t val,
 }
 
 
-/** Try to satisfy via wildcard.  See the single call site. */
+/** Try to satisfy via wildcard (positively).  See the single call site. */
 static int try_wild(struct key *k, struct answer *ans, const knot_dname_t *clencl_name,
                    const uint16_t type, const uint8_t lowest_rank,
                    const struct kr_query *qry, struct kr_cache *cache)
index abf522621f536c9451b1ed8e1295e466601bc50c..833a941df8c72e1be76fb63a8388b523e8cf5cb5 100644 (file)
@@ -23,6 +23,8 @@
 #include <stdbool.h>
 #include <stdint.h>
 
+#include <dnssec/error.h>
+#include <dnssec/nsec.h>
 #include <libknot/consts.h>
 #include <libknot/db/db.h>
 #include <libknot/dname.h>
@@ -238,11 +240,18 @@ static inline int rdataset_dematerialize_size(const knot_rdataset_t *rds)
 /** Dematerialize a rdataset. */
 int rdataset_dematerialize(const knot_rdataset_t *rds, void * restrict data);
 
+/** NSEC* parameters; almost nothing is meaningful for NSEC. */
+struct nsec_p {
+       const uint8_t *raw; /**< Pointer to raw NSEC3 parameters; NULL for NSEC. */
+       nsec_p_hash_t hash; /**< Hash of `raw`, used for cache keys. */
+       dnssec_nsec3_params_t libknot; /**< Format for libknot; owns malloced memory! */
+};
+
 /** Partially constructed answer when gathering RRsets from cache. */
 struct answer {
-       int rcode;      /**< PKT_NODATA, etc. */
-       const uint8_t *nsec_p;  /**< Let's avoid mixing different NSEC* parameters in one answer. */
-       knot_mm_t *mm;  /**< Allocator for rrsets */
+       int rcode;              /**< PKT_NODATA, etc. */
+       struct nsec_p nsec_p;   /**< Don't mix different NSEC* parameters in one answer. */
+       knot_mm_t *mm;          /**< Allocator for rrsets */
        struct answer_rrset {
                ranked_rr_array_entry_t set;    /**< set+rank for the main data */
                knot_rdataset_t sig_rds;        /**< RRSIG data, if any */
@@ -317,12 +326,10 @@ knot_db_val_t key_NSEC3(struct key *k, const knot_dname_t *nsec3_name,
 /** TODO.  See nsec1_encloser(...) */
 int nsec3_encloser(struct key *k, struct answer *ans,
                   const int sname_labels, int *clencl_labels,
-                  knot_db_val_t *cover_low_kwz, knot_db_val_t *cover_hi_kwz,
                   const struct kr_query *qry, struct kr_cache *cache);
 
 /** TODO.  See nsec1_src_synth(...) */
 int nsec3_src_synth(struct key *k, struct answer *ans, const knot_dname_t *clencl_name,
-                   knot_db_val_t cover_low_kwz, knot_db_val_t cover_hi_kwz,
                    const struct kr_query *qry, struct kr_cache *cache);
 
 
index a5691e7302b6488c9c6379fb4e7f0fd6cdae67ce..32e1d326abb427df9e8045f68df280956161d786 100644 (file)
@@ -24,8 +24,6 @@
 #include "lib/dnssec/nsec.h"
 #include "lib/layer/iterate.h"
 
-#include <dnssec/error.h>
-#include <dnssec/nsec.h>
 #include <libknot/rrtype/nsec3.h>
 
 static const knot_db_val_t VAL_EMPTY = { NULL, 0 };
@@ -77,12 +75,12 @@ knot_db_val_t key_NSEC3(struct key *k, const knot_dname_t *nsec3_name,
 /** Construct a string key for for NSEC3 predecessor-search, from an non-NSEC3 name.
  * \note k->zlf_len and k->zname are assumed to have been correctly set */
 static knot_db_val_t key_NSEC3_name(struct key *k, const knot_dname_t *name,
-               const bool add_wildcard,
-               const nsec_p_hash_t nsec_p_hash, const dnssec_nsec3_params_t *nsec3_p)
+               const bool add_wildcard, const struct nsec_p *nsec_p)
 {
-       knot_db_val_t val = key_NSEC3_common(k, k->zname, nsec_p_hash);
-       const bool ok = val.data && nsec3_p;
+       bool ok = k && name && nsec_p && nsec_p->raw;
        if (!ok) return VAL_EMPTY;
+       knot_db_val_t val = key_NSEC3_common(k, k->zname, nsec_p->hash);
+       if (!val.data) return val;
 
        /* Make `name` point to correctly wildcarded owner name. */
        uint8_t buf[KNOT_DNAME_MAXLEN];
@@ -106,7 +104,7 @@ static knot_db_val_t key_NSEC3_name(struct key *k, const knot_dname_t *name,
                .data = val.data + val.len,
        };
                /* FIXME: vv this requires a patched libdnssec - tries to realloc() */
-       int ret = dnssec_nsec3_hash(&dname, nsec3_p, &hash);
+       int ret = dnssec_nsec3_hash(&dname, &nsec_p->libknot, &hash);
        if (ret != DNSSEC_EOK) return VAL_EMPTY;
        assert(hash.size == NSEC3_HASH_LEN);
        val.len += hash.size;
@@ -259,32 +257,18 @@ static void nsec3_hash2text(const knot_dname_t *owner, char *text)
 
 int nsec3_encloser(struct key *k, struct answer *ans,
                   const int sname_labels, int *clencl_labels,
-                  knot_db_val_t *cover_low_kwz, knot_db_val_t *cover_hi_kwz,
                   const struct kr_query *qry, struct kr_cache *cache)
        /* TODO: cleanup params */
 {
        static const int ESKIP = ABS(ENOENT);
        /* Basic sanity check. */
        const bool ok = k && k->zname && ans && clencl_labels
-                       && cover_low_kwz && cover_hi_kwz
                        && qry && cache;
        if (!ok) {
                assert(!EINVAL);
                return kr_error(EINVAL);
        }
 
-       const nsec_p_hash_t nsec_p_hash = nsec_p_mkHash(ans->nsec_p);
-       /* Convert NSEC3 params to another format. */
-       dnssec_nsec3_params_t nsec3_p;
-       {
-               const dnssec_binary_t rdata = {
-                       .size = nsec_p_rdlen(ans->nsec_p),
-                       .data = (uint8_t *)/*const-cast*/ans->nsec_p,
-               };
-               int ret = dnssec_nsec3_params_from_rdata(&nsec3_p, &rdata);
-               if (ret != DNSSEC_EOK) return kr_error(ret);
-       }
-
        /*** Find the closest encloser - cycle: name starting at sname,
         * proceeding while longer than zname, shortening by one label on step.
         * We need a pair where a name doesn't exist *and* its parent does. */
@@ -299,8 +283,7 @@ int nsec3_encloser(struct key *k, struct answer *ans,
                                        --name_labels, name += 1 + name[0]) {
                /* Find a previous-or-equal NSEC3 in cache covering the name,
                 * checking TTL etc. */
-               const knot_db_val_t key =
-                       key_NSEC3_name(k, name, false, nsec_p_hash, &nsec3_p);
+               const knot_db_val_t key = key_NSEC3_name(k, name, false, &ans->nsec_p);
                if (!key.data) continue;
                WITH_VERBOSE(qry) {
                        char hash_txt[NSEC3_HASH_TXT_LEN + 1];
@@ -411,7 +394,9 @@ int nsec3_encloser(struct key *k, struct answer *ans,
                *clencl_labels = name_labels;
                ans->rcode = PKT_NXDOMAIN;
                /* Avoid repeated NSEC3 - remove either if the hashes match.
-                * This is very unlikely in larger zones: 1/size (per attempt). */
+                * This is very unlikely in larger zones: 1/size (per attempt).
+                * Well, deduplication would happen anyway when the answer
+                * from cache is read by kresd (internally). */
                if (unlikely(0 == memcmp(ans->rrsets[AR_NSEC].set.rr->owner + 1,
                                         ans->rrsets[AR_CPE ].set.rr->owner + 1,
                                         NSEC3_HASH_LEN))) {
@@ -433,27 +418,12 @@ int nsec3_encloser(struct key *k, struct answer *ans,
 }
 
 int nsec3_src_synth(struct key *k, struct answer *ans, const knot_dname_t *clencl_name,
-                   knot_db_val_t cover_low_kwz, knot_db_val_t cover_hi_kwz,
                    const struct kr_query *qry, struct kr_cache *cache)
        /* TODO: cleanup params */
 {
-       /* TODO: deduplicate this code block, *including* the recomputation. */
-       const nsec_p_hash_t nsec_p_hash = nsec_p_mkHash(ans->nsec_p);
-       /* Convert NSEC3 params to another format. */
-       dnssec_nsec3_params_t nsec3_p;
-       {
-               const dnssec_binary_t rdata = {
-                       .size = nsec_p_rdlen(ans->nsec_p),
-                       .data = (uint8_t *)/*const-cast*/ans->nsec_p,
-               };
-               int ret = dnssec_nsec3_params_from_rdata(&nsec3_p, &rdata);
-               if (ret != DNSSEC_EOK) return kr_error(ret);
-       }
-
        /* Find a previous-or-equal NSEC3 in cache covering or matching
         * the source of synthesis, checking TTL etc. */
-       const knot_db_val_t key =
-               key_NSEC3_name(k, clencl_name, true, nsec_p_hash, &nsec3_p);
+       const knot_db_val_t key = key_NSEC3_name(k, clencl_name, true, &ans->nsec_p);
        if (!key.data) return kr_error(1);
        WITH_VERBOSE(qry) {
                char hash_txt[NSEC3_HASH_TXT_LEN + 1];
@@ -471,7 +441,7 @@ int nsec3_src_synth(struct key *k, struct answer *ans, const knot_dname_t *clenc
                return kr_ok();
        }
 
-       /* FIXME: avoid duplicities in answer. */
+       /* LATER(optim.): avoid duplicities in answer. */
 
        /* Basic checks OK -> materialize the data (speculatively). */
        knot_dname_t owner[KNOT_DNAME_MAXLEN];
@@ -487,8 +457,7 @@ int nsec3_src_synth(struct key *k, struct answer *ans, const knot_dname_t *clenc
                                   owner, KNOT_RRTYPE_NSEC3, new_ttl);
                if (ret) return kr_error(ret);
        }
-
-       //const knot_rrset_t *nsec_rr = ans->rrsets[AR_WILD].set.rr;
+       const knot_rrset_t *nsec_rr = ans->rrsets[AR_WILD].set.rr;
 
        if (!exact_match) {
                /* The record proves wildcard non-existence. */
@@ -502,9 +471,24 @@ int nsec3_src_synth(struct key *k, struct answer *ans, const knot_dname_t *clenc
                return AR_SOA;
        }
 
+       /* The wildcard exists.  Find if it's NODATA - check type bitmap. */
+       uint8_t *bm = NULL;
+       uint16_t bm_size;
+       knot_nsec3_bitmap(&nsec_rr->rrs, 0, &bm, &bm_size);
+       assert(bm);
+       if (kr_nsec_bitmap_nodata_check(bm, bm_size, qry->stype, nsec_rr->owner) == 0) {
+               /* NODATA proven; just need to add SOA+RRSIG later */
+               VERBOSE_MSG(qry, "=> NSEC3 wildcard: match proved NODATA, new TTL %d\n",
+                                new_ttl);
+               ans->rcode = PKT_NODATA;
+               return AR_SOA;
 
-       /* FIXME XXX */
-       VERBOSE_MSG(qry, "=> NSEC3 wildcard: failed!\n");
+       } /* else */
+       /* The data probably exists -> don't add this NSEC3
+        * and (later) try to find the real wildcard data */
+       VERBOSE_MSG(qry, "=> NSEC3 wildcard: should exist (or error)\n");
+       ans->rcode = PKT_NOERROR;
+       memset(&ans->rrsets[AR_WILD], 0, sizeof(ans->rrsets[AR_WILD]));
        return kr_ok();
 }