]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
write NSEC3 key creation
authorVladimír Čunát <vladimir.cunat@nic.cz>
Mon, 30 Apr 2018 15:05:31 +0000 (17:05 +0200)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Mon, 30 Apr 2018 15:58:03 +0000 (17:58 +0200)
NSEC3 are probably stashed OK now

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

index 535236ec929163287703207083889c4f5f2af8c0..fbb0f32c04cbf6c15087a55f43315be084807c18 100644 (file)
@@ -805,7 +805,7 @@ static ssize_t stash_rrset(struct kr_cache *cache, const struct kr_query *qry, c
                assert(rr->type == KNOT_RRTYPE_NSEC3);
                const knot_rdata_t *np_data = knot_rdata_data(rr->rrs.data);
                const int np_dlen = nsec_p_rdlen(np_data);
-               key = key_NSEC3(k, encloser, /*wild_labels,*/ np_data);
+               key = key_NSEC3(k, encloser, nsec_p_hash(np_data));
                if (npp && !*npp) {
                        *npp = mm_alloc(&qry->request->pool, np_dlen);
                        if (!*npp) {
index 42ae30a89d49985ee170bc87fc7368d0c488caf1..9d438f1f3de008a7e04bca7406bef4ce2c46893c 100644 (file)
@@ -28,6 +28,7 @@
 #include <libknot/dname.h>
 
 #include "contrib/cleanup.h"
+#include "contrib/murmurhash3/murmurhash3.h" /* hash() for nsec_p_hash() */
 #include "lib/cache/cdb_api.h"
 #include "lib/resolve.h"
 
@@ -87,11 +88,12 @@ static inline uint16_t EL2RRTYPE(enum EL i)
 
 static inline int nsec_p_rdlen(const uint8_t *rdata)
 {
-       //TODO: the zero case?
+       //TODO: the zero case? // FIXME security: overflow potential
        return rdata ? 5 + rdata[4] : 0; /* rfc5155 4.2 and 3.2. */
 }
 static const int NSEC_P_MAXLEN = sizeof(uint32_t) + 5 + 255;
 
+
 /** Check basic consistency of entry_h for 'E' entries, not looking into ->data.
  * (for is_packet the length of data is checked)
  */
@@ -287,10 +289,19 @@ int nsec1_src_synth(struct key *k, struct answer *ans, const knot_dname_t *clenc
 
 /* NSEC3 stuff.  Implementation in ./nsec3.c */
 
-/** Construct a string key for for NSEC3 predecessor-search.
+typedef uint32_t nsec_p_hash_t;
+/** \note We assume it's not opt-out. */
+static inline nsec_p_hash_t nsec_p_hash(const uint8_t *nsec_p)
+{
+       assert(nsec_p);
+       return hash((const char *)nsec_p, nsec_p_rdlen(nsec_p));
+}
+
+
+/** Construct a string key for for NSEC3 predecessor-search, from an NSEC3 name.
  * \note k->zlf_len is assumed to have been correctly set */
-knot_db_val_t key_NSEC3(struct key *k, const knot_dname_t *name,
-                       const knot_rdata_t *nsec3param);
+knot_db_val_t key_NSEC3(struct key *k, const knot_dname_t *nsec3_name,
+                       const nsec_p_hash_t nsec_p_hash);
 
 /** TODO.  See nsec1_encloser(...) */
 int nsec3_encloser(struct key *k, struct answer *ans,
index bd1c3218092d26142cffeb721ca52607190da60d..ead68828b4b326858d334e18f7ac1d3b1219ec35 100644 (file)
  */
 
 #include "lib/cache/impl.h"
-#include "lib/dnssec/nsec.h"
 
-knot_db_val_t key_NSEC3(struct key *k, const knot_dname_t *name, const knot_rdata_t *nsec3param)
-{
-       // XXX are wildcard labels added before hashing??? + FIXME everything
+#include "contrib/base32hex.h"
+#include <dnssec/error.h>
+#include <dnssec/nsec.h>
+
+static const knot_db_val_t VAL_EMPTY = { NULL, 0 };
 
-       /* we basically need dname_lf with two bytes added
-        * on a correct place within the name (the cut) */
+/** Common part: write all but the NSEC3 hash. */
+static knot_db_val_t key_NSEC3_common(struct key *k, const knot_dname_t *zname,
+                                       const nsec_p_hash_t nsec_p_hash)
+{
        int ret;
-       const bool ok = k && name
-               && !(ret = kr_dname_lf(k->buf, k->zname, false));
+       const bool ok = k && zname
+               && !(ret = kr_dname_lf(k->buf, zname, false));
        if (!ok) {
                assert(false);
-               return (knot_db_val_t){ NULL, 0 };
+               return VAL_EMPTY;
        }
 
-       uint8_t *begin = k->buf + 1 + k->zlf_len; /* one byte after zone's zero */
-       uint8_t *end = k->buf + 1 + k->buf[0]; /* we don't use the final zero in key,
-                                               * but move it anyway */
-       if (end < begin) {
-               assert(false);
-               return (knot_db_val_t){ NULL, 0 };
-       }
-       int key_len;
-       if (end > begin) {
-               memmove(begin + 2, begin, end - begin);
-               key_len = k->buf[0] + 1;
-       } else {
-               key_len = k->buf[0] + 2;
-       }
-       /* CACHE_KEY_DEF: key == zone's dname_lf + '\0' + '3' + NSEC3 hash (binary!)
-        * Iff the latter is empty, there's no zero to cut and thus the key_len difference.
+       /* CACHE_KEY_DEF: key == zone's dname_lf + '\0' + '3' + nsec_p hash (4B)
+        *                      + NSEC3 hash (20B binary!)
+        * LATER(optim.) nsec_p hash: perhaps 2B would give a sufficient probability
+        * of avoiding collisions.
         */
+       uint8_t *begin = k->buf + 1 + k->zlf_len; /* one byte after zone's zero */
        begin[0] = 0;
        begin[1] = '3'; /* tag for NSEC3 */
        k->type = KNOT_RRTYPE_NSEC3;
+       memcpy(begin + 2, &nsec_p_hash, sizeof(nsec_p_hash));
+       return (knot_db_val_t){
+               .data = k->buf + 1,
+               .len = begin + 2 + sizeof(nsec_p_hash) - (k->buf + 1),
+       };
+}
 
-       /*
-       VERBOSE_MSG(NULL, "<> key_NSEC1; name: ");
-       kr_dname_print(name, add_wildcard ? "*." : "" , " ");
-       kr_log_verbose("(zone name LF length: %d; total key length: %d)\n",
-                       k->zlf_len, key_len);
-       */
+knot_db_val_t key_NSEC3(struct key *k, const knot_dname_t *nsec3_name,
+                       const nsec_p_hash_t nsec_p_hash)
+{
+       knot_db_val_t val = key_NSEC3_common(k, nsec3_name /*only zname required*/,
+                                               nsec_p_hash);
+       if (!val.data) return val;
+       int len = base32hex_decode(nsec3_name + 1, nsec3_name[0], val.data + val.len,
+                                  KR_CACHE_KEY_MAXLEN - val.len);
+       if (len != 20) {
+               assert(false); // FIXME: just debug, possible bogus input in real life
+               return VAL_EMPTY;
+       }
+       val.len += len;
+       return val;
+}
 
-       return (knot_db_val_t){ k->buf + 1, key_len };
+/** 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 uint8_t *nsec_p)
+{
+       knot_db_val_t val = key_NSEC3_common(k, k->zname, nsec_p_hash);
+       const bool ok = val.data && nsec_p;
+       if (!ok) return VAL_EMPTY;
+
+       /* Make `name` point to correctly wildcarded owner name. */
+       uint8_t buf[KNOT_DNAME_MAXLEN];
+       int name_len;
+       if (add_wildcard) {
+               buf[0] = '\1';
+               buf[1] = '*';
+               name_len = knot_dname_to_wire(buf + 2, name, sizeof(buf) - 2);
+               if (name_len < 0) return VAL_EMPTY; /* wants wildcard but doesn't fit */
+               name = buf;
+       } else {
+               name_len = knot_dname_size(name);
+       }
+       /* Append the NSEC3 hash. */
+       dnssec_nsec3_params_t params;
+       {
+               const dnssec_binary_t rdata = {
+                       .size = nsec_p_rdlen(nsec_p),
+                       .data = (uint8_t *)/*const-cast*/nsec_p,
+               };
+               int ret = dnssec_nsec3_params_from_rdata(&params, &rdata);
+               if (ret != DNSSEC_EOK) return VAL_EMPTY;
+       }
+       const dnssec_binary_t dname = {
+               .size = knot_dname_size(name),
+               .data = (uint8_t *)/*const-cast*/name,
+       };
+       dnssec_binary_t hash = {
+               .size = KR_CACHE_KEY_MAXLEN - val.len,
+               .data = val.data + val.len,
+       };
+               /* FIXME: vv this requires a patched libdnssec - tries to realloc() */
+       int ret = dnssec_nsec3_hash(&dname, &params, &hash);
+       if (ret != DNSSEC_EOK) return VAL_EMPTY;
+       val.len += hash.size;
+       return val;
 }
 
 int nsec3_encloser(struct key *k, struct answer *ans,
@@ -92,7 +143,7 @@ int nsec3_encloser(struct key *k, struct answer *ans,
        /*** One more step but searching for match this time
         * - that's the closest (provable) encloser. */
 
-       assert(false);
+       //assert(false);
        return -ENOSYS;
 }
 
@@ -113,7 +164,7 @@ int nsec3_src_synth(struct key *k, struct answer *ans, const knot_dname_t *clenc
 
        /* Handle the two cases: covered and matched. */
 
-       assert(false);
+       //assert(false);
        return -ENOSYS;
 }