From: Vladimír Čunát Date: Thu, 10 May 2018 14:25:40 +0000 (+0200) Subject: . X-Git-Tag: v2.4.0~19^2~25 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=34fefc6cea454190ba2cd577f4a7c36c90864528;p=thirdparty%2Fknot-resolver.git . - 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) --- diff --git a/lib/cache/api.c b/lib/cache/api.c index 09c07ebdf..253cab3b0 100644 --- a/lib/cache/api.c +++ b/lib/cache/api.c @@ -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) diff --git a/lib/cache/impl.h b/lib/cache/impl.h index abf522621..833a941df 100644 --- a/lib/cache/impl.h +++ b/lib/cache/impl.h @@ -23,6 +23,8 @@ #include #include +#include +#include #include #include #include @@ -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); diff --git a/lib/cache/nsec3.c b/lib/cache/nsec3.c index a5691e730..32e1d326a 100644 --- a/lib/cache/nsec3.c +++ b/lib/cache/nsec3.c @@ -24,8 +24,6 @@ #include "lib/dnssec/nsec.h" #include "lib/layer/iterate.h" -#include -#include #include 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(); }