From: Vladimír Čunát Date: Wed, 15 Aug 2018 14:13:10 +0000 (+0200) Subject: cache+lua: add kr_cache_closest_apex() API X-Git-Tag: v3.0.0~1^2~19 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b24763e495622d2d8198f52a8718c79816d4d3a5;p=thirdparty%2Fknot-resolver.git cache+lua: add kr_cache_closest_apex() API --- diff --git a/daemon/lua/kres-gen.sh b/daemon/lua/kres-gen.sh index e02d72297..82ab19b6b 100755 --- a/daemon/lua/kres-gen.sh +++ b/daemon/lua/kres-gen.sh @@ -181,10 +181,11 @@ EOF kr_dnssec_key_tag kr_dnssec_key_match # Cache + kr_cache_closest_apex kr_cache_insert_rr - kr_cache_sync kr_cache_remove kr_cache_remove_subtree + kr_cache_sync EOF diff --git a/lib/cache/api.h b/lib/cache/api.h index d347af3ae..6808d4f20 100644 --- a/lib/cache/api.h +++ b/lib/cache/api.h @@ -131,7 +131,7 @@ int kr_cache_peek_exact(struct kr_cache *cache, const knot_dname_t *name, uint16 KR_EXPORT int32_t kr_cache_ttl(const struct kr_cache_p *peek, const struct kr_query *qry, const knot_dname_t *name, uint16_t type); -/*TODO: reorder*/ + KR_EXPORT int kr_cache_materialize(knot_rdataset_t *dst, const struct kr_cache_p *ref, knot_mm_t *pool); @@ -143,8 +143,8 @@ int kr_cache_materialize(knot_rdataset_t *dst, const struct kr_cache_p *ref, * @param name dname * @param type rr type * @return 0 or an errcode - * @note only "exact hits" are considered ATM, moreover xNAME records - * are "hidden" as NS. (see comments in struct entry_h) + * @note only "exact hits" are considered ATM, and + * some other information may be removed alongside. */ KR_EXPORT int kr_cache_remove(struct kr_cache *cache, const knot_dname_t *name, uint16_t type); @@ -171,6 +171,15 @@ KR_EXPORT int kr_cache_remove_subtree(struct kr_cache *cache, const knot_dname_t *name, bool exact_name, int maxcount); +/** + * Find the closest cached zone apex for a name (in cache). + * @param is_DS start searching one name higher + * @return the number of labels to remove from the name, or negative error code + * @note timestamp is found by a syscall, and stale-serving is not considered + */ +KR_EXPORT +int kr_cache_closest_apex(struct kr_cache *cache, const knot_dname_t *name, bool is_DS); + /** * Unpack dname and type from db key * @param key db key representation diff --git a/lib/cache/peek.c b/lib/cache/peek.c index 062bf64d4..cdb5c81c0 100644 --- a/lib/cache/peek.c +++ b/lib/cache/peek.c @@ -24,7 +24,8 @@ static int found_exact_hit(kr_layer_t *ctx, knot_pkt_t *pkt, knot_db_val_t val, uint8_t lowest_rank); -static int closest_NS(kr_layer_t *ctx, struct key *k, entry_list_t el); +static int closest_NS(struct kr_cache *cache, struct key *k, entry_list_t el, + struct kr_query *qry, bool only_NS, bool is_DS); static int answer_simple_hit(kr_layer_t *ctx, knot_pkt_t *pkt, uint16_t type, const struct entry_h *eh, const void *eh_bound, uint32_t new_ttl); static int try_wild(struct key *k, struct answer *ans, const knot_dname_t *clencl_name, @@ -66,9 +67,9 @@ static void nsec_p_cleanup(struct nsec_p *nsec_p) /** Compute new TTL for nsec_p entry, using SOA serial arith. * \param new_ttl (optionally) write the new TTL (even if negative) * \return error code, e.g. kr_error(ESTALE) */ -static int nsec_p_ttl(knot_db_val_t entry, const struct kr_query *qry, int32_t *new_ttl) +static int nsec_p_ttl(knot_db_val_t entry, const uint32_t timestamp, int32_t *new_ttl) { - if (!entry.data || !qry) { + if (!entry.data) { assert(!EINVAL); return kr_error(EINVAL); } @@ -81,7 +82,7 @@ static int nsec_p_ttl(knot_db_val_t entry, const struct kr_query *qry, int32_t * return kr_error(EILSEQ); } memcpy(&stamp, entry.data, sizeof(stamp)); - int32_t newttl = stamp - qry->timestamp.tv_sec; + int32_t newttl = stamp - timestamp; if (new_ttl) *new_ttl = newttl; return newttl < 0 ? kr_error(ESTALE) : kr_ok(); } @@ -155,7 +156,7 @@ int peek_nosync(kr_layer_t *ctx, knot_pkt_t *pkt) return ctx->state; } entry_list_t el; - ret = closest_NS(ctx, k, el); + ret = closest_NS(cache, k, el, qry, false, qry->stype == KNOT_RRTYPE_DS); if (ret) { assert(ret == kr_error(ENOENT)); if (ret != kr_error(ENOENT) || !el[0].len) { @@ -217,7 +218,7 @@ int peek_nosync(kr_layer_t *ctx, knot_pkt_t *pkt) * Let's not mix different parameters for NSEC* RRs in a single proof. */ for (int i = 0; ;) { int32_t log_new_ttl = -123456789; /* visually recognizable value */ - ret = nsec_p_ttl(el[i], qry, &log_new_ttl); + ret = nsec_p_ttl(el[i], qry->timestamp.tv_sec, &log_new_ttl); if (!ret || VERBOSE_STATUS) { nsec_p_init(&ans.nsec_p, el[i], !ret); } @@ -552,22 +553,50 @@ static int try_wild(struct key *k, struct answer *ans, const knot_dname_t *clenc return kr_ok(); } +int kr_cache_closest_apex(struct kr_cache *cache, const knot_dname_t *name, bool is_DS) +{ + if (!cache || !name) { + assert(!EINVAL); + return kr_error(EINVAL); + } + struct key k_storage, *k = &k_storage; + int ret = kr_dname_lf(k->buf, name, false); + if (ret) return kr_error(ret); + entry_list_t el_; + k->zname = name; + ret = closest_NS(cache, k, el_, NULL, true, is_DS); + if (ret && ret != -abs(ENOENT)) return ret; + return knot_dname_labels(name, NULL) - knot_dname_labels(k->zname, NULL); +} + /** \internal for closest_NS. Check suitability of a single entry, setting k->type if OK. - * \return error code, negative iff whole list should be skipped. */ -static int check_NS_entry(knot_db_val_t entry, int i, bool exact_match, - const struct kr_query *qry, struct key *k); + * \return error code, negative iff whole list should be skipped. + */ +static int check_NS_entry(struct key *k, knot_db_val_t entry, int i, + bool exact_match, bool is_DS, + const struct kr_query *qry, uint32_t timestamp); -/** Find the longest prefix zone/xNAME (with OK time+rank), starting at k->*. +/** + * Find the longest prefix zone/xNAME (with OK time+rank), starting at k->*. * - * Found type is returned via k->type; the values are returned in el. + * The found type is returned via k->type; the values are returned in el. * \note we use k->type = KNOT_RRTYPE_NS also for the nsec_p result. + * \param qry can be NULL (-> gettimeofday(), but you lose the stale-serve hook) + * \param only_NS don't consider xNAMEs * \return error code */ -static int closest_NS(kr_layer_t *ctx, struct key *k, entry_list_t el) +static int closest_NS(struct kr_cache *cache, struct key *k, entry_list_t el, + struct kr_query *qry, const bool only_NS, const bool is_DS) { - struct kr_request *req = ctx->req; - struct kr_query *qry = req->current_query; - struct kr_cache *cache = &req->ctx->cache; + /* get the current timestamp */ + uint32_t timestamp; + if (qry) { + timestamp = qry->timestamp.tv_sec; + } else { + struct timeval tv; + if (gettimeofday(&tv, NULL)) return kr_error(errno); + timestamp = tv.tv_sec; + } int zlf_len = k->buf[0]; @@ -597,8 +626,10 @@ static int closest_NS(kr_layer_t *ctx, struct key *k, entry_list_t el) need_zero = false; /* More types are possible; try in order. * For non-fatal failures just "continue;" to try the next type. */ - for (int i = 0; i < EL_LENGTH; ++i) { - ret = check_NS_entry(el[i], i, exact_match, qry, k); + const int el_count = only_NS ? EL_NS + 1 : EL_LENGTH; + for (int i = 0; i < el_count; ++i) { + ret = check_NS_entry(k, el[i], i, exact_match, is_DS, + qry, timestamp); if (ret < 0) goto next_label; else if (!ret) { /* We found our match. */ @@ -624,13 +655,14 @@ static int closest_NS(kr_layer_t *ctx, struct key *k, entry_list_t el) } while (true); } -static int check_NS_entry(const knot_db_val_t entry, const int i, const bool exact_match, - const struct kr_query *qry, struct key *k) +static int check_NS_entry(struct key *k, const knot_db_val_t entry, const int i, + const bool exact_match, const bool is_DS, + const struct kr_query *qry, uint32_t timestamp) { const int ESKIP = ABS(ENOENT); if (!entry.len /* On a zone cut we want DS from the parent zone. */ - || (i <= EL_NS && exact_match && qry->stype == KNOT_RRTYPE_DS) + || (i <= EL_NS && exact_match && is_DS) /* CNAME is interesting only if we * directly hit the name that was asked. * Note that we want it even in the DS case. */ @@ -646,7 +678,7 @@ static int check_NS_entry(const knot_db_val_t entry, const int i, const bool exa if (i < ENTRY_APEX_NSECS_CNT) { type = KNOT_RRTYPE_NS; int32_t log_new_ttl = -123456789; /* visually recognizable value */ - const int err = nsec_p_ttl(entry, qry, &log_new_ttl); + const int err = nsec_p_ttl(entry, timestamp, &log_new_ttl); if (err) { VERBOSE_MSG(qry, "=> skipping unfit nsec_p: new TTL %d, error %d\n", @@ -662,8 +694,7 @@ static int check_NS_entry(const knot_db_val_t entry, const int i, const bool exa assert(false); return kr_error(EILSEQ); } - const int32_t log_new_ttl = get_new_ttl(eh, qry, k->zname, type, - qry->timestamp.tv_sec); + const int32_t log_new_ttl = get_new_ttl(eh, qry, k->zname, type, timestamp); const uint8_t rank_min = KR_RANK_INSECURE | KR_RANK_AUTH; const bool ok = /* For NS any kr_rank is accepted, * as insecure or even nonauth is OK */