summaryrefslogtreecommitdiffstats
path: root/lib/cache
diff options
context:
space:
mode:
Diffstat (limited to 'lib/cache')
-rw-r--r--lib/cache/README.rst69
-rw-r--r--lib/cache/api.c1029
-rw-r--r--lib/cache/api.h194
-rw-r--r--lib/cache/cdb_api.h97
-rw-r--r--lib/cache/cdb_lmdb.c868
-rw-r--r--lib/cache/cdb_lmdb.h16
-rw-r--r--lib/cache/entry_list.c301
-rw-r--r--lib/cache/entry_pkt.c206
-rw-r--r--lib/cache/entry_rr.c115
-rw-r--r--lib/cache/impl.h439
-rw-r--r--lib/cache/knot_pkt.c94
-rw-r--r--lib/cache/nsec1.c488
-rw-r--r--lib/cache/nsec3.c481
-rw-r--r--lib/cache/overflow.test.integr/deckard.yaml22
-rw-r--r--lib/cache/overflow.test.integr/kresd_config.j291
-rw-r--r--lib/cache/overflow.test.integr/world_cz_vutbr_www.rpl298
-rw-r--r--lib/cache/peek.c774
-rw-r--r--lib/cache/test.integr/cache_minimal_nsec3.rpl4120
-rw-r--r--lib/cache/test.integr/deckard.yaml13
-rw-r--r--lib/cache/test.integr/kresd_config.j269
-rw-r--r--lib/cache/util.h4
21 files changed, 9788 insertions, 0 deletions
diff --git a/lib/cache/README.rst b/lib/cache/README.rst
new file mode 100644
index 0000000..767c4c0
--- /dev/null
+++ b/lib/cache/README.rst
@@ -0,0 +1,69 @@
+.. SPDX-License-Identifier: GPL-3.0-or-later
+
+.. _cache_sizing:
+
+Cache sizing
+------------
+
+For personal use-cases and small deployments cache size around 100 MB is more than enough.
+
+For large deployments we recommend to run Knot Resolver on a dedicated machine, and to allocate 90% of machine's free memory for resolver's cache.
+
+For example, imagine you have a machine with 16 GB of memory.
+After machine restart you use command ``free -m`` to determine amount of free memory (without swap):
+
+.. code-block:: bash
+
+ $ free -m
+ total used free
+ Mem: 15907 979 14928
+
+Now you can configure cache size to be 90% of the free memory 14 928 MB, i.e. 13 453 MB:
+
+.. code-block:: lua
+
+ -- 90 % of free memory after machine restart
+ cache.size = 13453 * MB
+
+.. _cache_persistence:
+
+Cache persistence
+-----------------
+.. tip:: Using tmpfs for cache improves performance and reduces disk I/O.
+
+By default the cache is saved on a persistent storage device
+so the content of the cache is persisted during system reboot.
+This usually leads to smaller latency after restart etc.,
+however in certain situations a non-persistent cache storage might be preferred, e.g.:
+
+ - Resolver handles high volume of queries and I/O performance to disk is too low.
+ - Threat model includes attacker getting access to disk content in power-off state.
+ - Disk has limited number of writes (e.g. flash memory in routers).
+
+If non-persistent cache is desired configure cache directory to be on
+tmpfs_ filesystem, a temporary in-memory file storage.
+The cache content will be saved in memory, and thus have faster access
+and will be lost on power-off or reboot.
+
+
+.. note:: In most of the Unix-like systems ``/tmp`` and ``/var/run`` are commonly mounted to tmpfs.
+ While it is technically possible to move the cache to an existing
+ tmpfs filesystem, it is *not recommended*: The path to cache is specified in
+ multiple systemd units, and a shared tmpfs space could be used up by other
+ applications, leading to ``SIGBUS`` errors during runtime.
+
+Mounting the cache directory as tmpfs_ is recommended approach.
+Make sure to use appropriate ``size=`` option and don't forget to adjust the
+size in the config file as well.
+
+.. code-block::
+
+ # /etc/fstab
+ tmpfs /var/cache/knot-resolver tmpfs rw,size=2G,uid=knot-resolver,gid=knot-resolver,nosuid,nodev,noexec,mode=0700 0 0
+
+.. code-block:: lua
+
+ # /etc/knot-resolver/config
+ cache.size = 2 * GB
+
+.. _tmpfs: https://en.wikipedia.org/wiki/Tmpfs
diff --git a/lib/cache/api.c b/lib/cache/api.c
new file mode 100644
index 0000000..116d775
--- /dev/null
+++ b/lib/cache/api.c
@@ -0,0 +1,1029 @@
+/* Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <libknot/descriptor.h>
+#include <libknot/dname.h>
+#include <libknot/errcode.h>
+#include <libknot/rrtype/rrsig.h>
+
+#include <uv.h>
+
+#include "contrib/base32hex.h"
+#include "contrib/cleanup.h"
+#include "contrib/ucw/lib.h"
+#include "lib/cache/api.h"
+#include "lib/cache/cdb_lmdb.h"
+#include "lib/defines.h"
+#include "lib/dnssec/nsec3.h"
+#include "lib/generic/trie.h"
+#include "lib/resolve.h"
+#include "lib/rplan.h"
+#include "lib/utils.h"
+
+#include "lib/cache/impl.h"
+
+/* TODO:
+ * - Reconsider when RRSIGs are put in and retrieved from the cache.
+ * Currently it's always done, which _might_ be spurious, depending
+ * on how kresd will use the returned result.
+ * There's also the "problem" that kresd ATM does _not_ ask upstream
+ * with DO bit in some cases.
+ */
+
+
+/** Cache version */
+static const uint16_t CACHE_VERSION = 6;
+/** Key size */
+#define KEY_HSIZE (sizeof(uint8_t) + sizeof(uint16_t))
+#define KEY_SIZE (KEY_HSIZE + KNOT_DNAME_MAXLEN)
+
+
+/** @internal Forward declarations of the implementation details
+ * \param needs_pkt[out] optionally set *needs_pkt = true;
+ * We do that when some RRset wasn't stashed to aggressive cache,
+ * even though it might have taken part in a successful DNSSEC proof:
+ * 1. any opt-out NSEC3, as they typically aren't much use aggressively anyway
+ * 2. some kinds of minimal NSEC* ranges, as they'd seem more trouble than worth:
+ * - extremely short range of covered names limits the benefits severely
+ * - the type-set is often a lie, either a working lie, e.g. CloudFlare's
+ * black lies, or even a non-working lie, e.g. DVE-2018-0003
+ * 3. some kinds of "weird" RRsets, to get at least some caching on them
+ */
+static ssize_t stash_rrset(struct kr_cache *cache, const struct kr_query *qry,
+ const knot_rrset_t *rr, const knot_rrset_t *rr_sigs, uint32_t timestamp,
+ uint8_t rank, trie_t *nsec_pmap, knot_mm_t *pool, bool *needs_pkt);
+/** Preliminary checks before stash_rrset(). Don't call if returns <= 0. */
+static int stash_rrset_precond(const knot_rrset_t *rr, const struct kr_query *qry/*logs*/);
+
+/** @internal Ensure the cache version is right, possibly by clearing it. */
+static int assert_right_version(struct kr_cache *cache)
+{
+ /* Check cache ABI version. */
+ /* CACHE_KEY_DEF: to avoid collisions with kr_cache_match(). */
+ uint8_t key_str[4] = "VERS";
+ knot_db_val_t key = { .data = key_str, .len = sizeof(key_str) };
+ knot_db_val_t val = { NULL, 0 };
+ int ret = cache_op(cache, read, &key, &val, 1);
+ if (ret == 0 && val.len == sizeof(CACHE_VERSION)
+ && memcmp(val.data, &CACHE_VERSION, sizeof(CACHE_VERSION)) == 0) {
+ ret = kr_ok();
+ } else {
+ int oldret = ret;
+ /* Version doesn't match or we were unable to read it, possibly because DB is empty.
+ * Recreate cache and write version key. */
+ ret = cache_op(cache, count);
+ if (ret != 0) { /* Log for non-empty cache to limit noise on fresh start. */
+ kr_log_info(CACHE, "incompatible cache database detected, purging\n");
+ if (oldret) {
+ kr_log_debug(CACHE, "reading version returned: %d\n", oldret);
+ } else if (val.len != sizeof(CACHE_VERSION)) {
+ kr_log_debug(CACHE, "version has bad length: %d\n", (int)val.len);
+ } else {
+ uint16_t ver;
+ memcpy(&ver, val.data, sizeof(ver));
+ kr_log_debug(CACHE, "version has bad value: %d instead of %d\n",
+ (int)ver, (int)CACHE_VERSION);
+ }
+ }
+ ret = cache_op(cache, clear);
+ }
+ /* Rewrite the entry even if it isn't needed. Because of cache-size-changing
+ * possibility it's good to always perform some write during opening of cache. */
+ if (ret == 0) {
+ /* Key/Val is invalidated by cache purge, recreate it */
+ val.data = /*const-cast*/(void *)&CACHE_VERSION;
+ val.len = sizeof(CACHE_VERSION);
+ ret = cache_op(cache, write, &key, &val, 1);
+ }
+ kr_cache_commit(cache);
+ return ret;
+}
+
+int kr_cache_open(struct kr_cache *cache, const struct kr_cdb_api *api, struct kr_cdb_opts *opts, knot_mm_t *mm)
+{
+ if (kr_fails_assert(cache))
+ return kr_error(EINVAL);
+ memset(cache, 0, sizeof(*cache));
+ /* Open cache */
+ if (!api)
+ api = kr_cdb_lmdb();
+ cache->api = api;
+ int ret = cache->api->open(&cache->db, &cache->stats, opts, mm);
+ if (ret == 0) {
+ ret = assert_right_version(cache);
+ // The included write also committed maxsize increase to the file.
+ }
+ if (ret == 0 && opts->maxsize) {
+ /* If some maxsize is requested and it's smaller than in-file maxsize,
+ * LMDB only restricts our env without changing the in-file maxsize.
+ * That is worked around by reopening (found no other reliable way). */
+ cache->api->close(cache->db, &cache->stats);
+ struct kr_cdb_opts opts2;
+ memcpy(&opts2, opts, sizeof(opts2));
+ opts2.maxsize = 0;
+ ret = cache->api->open(&cache->db, &cache->stats, &opts2, mm);
+ }
+
+ char *fpath = kr_absolutize_path(opts->path, "data.mdb");
+ if (kr_fails_assert(fpath)) {
+ /* non-critical, but still */
+ fpath = "<ENOMEM>";
+ } else {
+ kr_cache_emergency_file_to_remove = fpath;
+ }
+
+ if (ret == 0 && opts->maxsize) {
+ size_t maxsize = cache->api->get_maxsize(cache->db);
+ if (maxsize > opts->maxsize) kr_log_warning(CACHE,
+ "Warning: real cache size is %zu instead of the requested %zu bytes."
+ " To reduce the size you need to remove the file '%s' by hand.\n",
+ maxsize, opts->maxsize, fpath);
+ }
+ if (ret != 0)
+ return ret;
+ cache->ttl_min = KR_CACHE_DEFAULT_TTL_MIN;
+ cache->ttl_max = KR_CACHE_DEFAULT_TTL_MAX;
+ kr_cache_make_checkpoint(cache);
+ return 0;
+}
+
+const char *kr_cache_emergency_file_to_remove = NULL;
+
+
+#define cache_isvalid(cache) ((cache) && (cache)->api && (cache)->db)
+
+void kr_cache_close(struct kr_cache *cache)
+{
+ kr_cache_check_health(cache, -1);
+ if (cache_isvalid(cache)) {
+ cache_op(cache, close);
+ cache->db = NULL;
+ }
+ free(/*const-cast*/(char*)kr_cache_emergency_file_to_remove);
+ kr_cache_emergency_file_to_remove = NULL;
+}
+
+int kr_cache_commit(struct kr_cache *cache)
+{
+ if (!cache_isvalid(cache)) {
+ return kr_error(EINVAL);
+ }
+ if (cache->api->commit) {
+ return cache_op(cache, commit);
+ }
+ return kr_ok();
+}
+
+int kr_cache_clear(struct kr_cache *cache)
+{
+ if (!cache_isvalid(cache)) {
+ return kr_error(EINVAL);
+ }
+ int ret = cache_op(cache, clear);
+ if (ret == 0) {
+ kr_cache_make_checkpoint(cache);
+ ret = assert_right_version(cache);
+ }
+ return ret;
+}
+
+/* When going stricter, BEWARE of breaking entry_h_consistent_NSEC() */
+struct entry_h * entry_h_consistent_E(knot_db_val_t data, uint16_t type)
+{
+ (void) type; /* unused, for now */
+ if (!data.data) return NULL;
+ /* Length checks. */
+ if (data.len < offsetof(struct entry_h, data))
+ return NULL;
+ const struct entry_h *eh = data.data;
+ if (eh->is_packet) {
+ uint16_t pkt_len;
+ if (data.len < offsetof(struct entry_h, data) + sizeof(pkt_len)) {
+ return NULL;
+ }
+ memcpy(&pkt_len, eh->data, sizeof(pkt_len));
+ if (data.len < offsetof(struct entry_h, data) + sizeof(pkt_len)
+ + pkt_len) {
+ return NULL;
+ }
+ }
+
+ bool ok = true;
+ ok = ok && kr_rank_check(eh->rank);
+ ok = ok && (!kr_rank_test(eh->rank, KR_RANK_BOGUS)
+ || eh->is_packet);
+ ok = ok && (eh->is_packet || !eh->has_optout);
+
+ return ok ? /*const-cast*/(struct entry_h *)eh : NULL;
+}
+
+int32_t get_new_ttl(const struct entry_h *entry, const struct kr_query *qry,
+ const knot_dname_t *owner, uint16_t type, uint32_t now)
+{
+ int32_t diff = now - entry->time;
+ if (diff < 0) {
+ /* We may have obtained the record *after* the request started. */
+ diff = 0;
+ }
+ int32_t res = entry->ttl - diff;
+ if (res < 0 && owner && qry && qry->stale_cb) {
+ /* Stale-serving decision, delegated to a callback. */
+ int res_stale = qry->stale_cb(res, owner, type, qry);
+ if (res_stale >= 0) {
+ VERBOSE_MSG(qry, "responding with stale answer\n");
+ /* LATER: Perhaps we could use a more specific Stale
+ * NXDOMAIN Answer code for applicable responses. */
+ kr_request_set_extended_error(qry->request, KNOT_EDNS_EDE_STALE, "6Q6X");
+ return res_stale;
+ }
+ }
+ return res;
+}
+
+int32_t kr_cache_ttl(const struct kr_cache_p *peek, const struct kr_query *qry,
+ const knot_dname_t *name, uint16_t type)
+{
+ const struct entry_h *eh = peek->raw_data;
+ return get_new_ttl(eh, qry, name, type, qry->timestamp.tv_sec);
+}
+
+/** Check that no label contains a zero character, incl. a log trace.
+ *
+ * We refuse to work with those, as LF and our cache keys might become ambiguous.
+ * Assuming uncompressed name, as usual.
+ * CACHE_KEY_DEF
+ */
+static bool check_dname_for_lf(const knot_dname_t *n, const struct kr_query *qry/*logging*/)
+{
+ const bool ret = knot_dname_size(n) == strlen((const char *)n) + 1;
+ if (!ret && kr_log_is_debug_qry(CACHE, qry)) {
+ auto_free char *n_str = kr_dname_text(n);
+ VERBOSE_MSG(qry, "=> skipping zero-containing name %s\n", n_str);
+ }
+ return ret;
+}
+
+/** Return false on types to be ignored. Meant both for sname and direct cache requests. */
+static bool check_rrtype(uint16_t type, const struct kr_query *qry/*logging*/)
+{
+ const bool ret = !knot_rrtype_is_metatype(type)
+ && type != KNOT_RRTYPE_RRSIG;
+ if (!ret && kr_log_is_debug_qry(CACHE, qry)) {
+ auto_free char *type_str = kr_rrtype_text(type);
+ VERBOSE_MSG(qry, "=> skipping RR type %s\n", type_str);
+ }
+ return ret;
+}
+
+/** Like key_exact_type() but omits a couple checks not holding for pkt cache. */
+knot_db_val_t key_exact_type_maypkt(struct key *k, uint16_t type)
+{
+ if (kr_fails_assert(check_rrtype(type, NULL)))
+ return (knot_db_val_t){ NULL, 0 };
+ switch (type) {
+ case KNOT_RRTYPE_RRSIG: /* no RRSIG query caching, at least for now */
+ kr_assert(false);
+ return (knot_db_val_t){ NULL, 0 };
+ /* xNAME lumped into NS. */
+ case KNOT_RRTYPE_CNAME:
+ case KNOT_RRTYPE_DNAME:
+ type = KNOT_RRTYPE_NS;
+ default:
+ break;
+ }
+
+ int name_len = k->buf[0];
+ k->buf[name_len + 1] = 0; /* make sure different names can never match */
+ k->buf[name_len + 2] = 'E'; /* tag for exact name+type matches */
+ memcpy(k->buf + name_len + 3, &type, 2);
+ k->type = type;
+ /* CACHE_KEY_DEF: key == dname_lf + '\0' + 'E' + RRTYPE */
+ return (knot_db_val_t){ k->buf + 1, name_len + 4 };
+}
+
+
+/** The inside for cache_peek(); implementation separated to ./peek.c */
+int peek_nosync(kr_layer_t *ctx, knot_pkt_t *pkt);
+/** function for .produce phase */
+int cache_peek(kr_layer_t *ctx, knot_pkt_t *pkt)
+{
+ struct kr_request *req = ctx->req;
+ struct kr_query *qry = req->current_query;
+ /* We first check various exit-conditions and then call the _real function. */
+
+ if (!kr_cache_is_open(&req->ctx->cache)
+ || ctx->state & (KR_STATE_FAIL|KR_STATE_DONE) || qry->flags.NO_CACHE
+ || (qry->flags.CACHE_TRIED && !qry->stale_cb)
+ || !check_rrtype(qry->stype, qry) /* LATER: some other behavior for some of these? */
+ || qry->sclass != KNOT_CLASS_IN) {
+ return ctx->state; /* Already resolved/failed or already tried, etc. */
+ }
+ /* ATM cache only peeks for qry->sname and that would be useless
+ * to repeat on every iteration, so disable it from now on.
+ * LATER(optim.): assist with more precise QNAME minimization. */
+ qry->flags.CACHE_TRIED = true;
+
+ if (qry->stype == KNOT_RRTYPE_NSEC) {
+ VERBOSE_MSG(qry, "=> skipping stype NSEC\n");
+ return ctx->state;
+ }
+ if (!check_dname_for_lf(qry->sname, qry)) {
+ return ctx->state;
+ }
+
+ int ret = peek_nosync(ctx, pkt);
+ kr_cache_commit(&req->ctx->cache);
+ return ret;
+}
+
+
+
+/** It's simply inside of cycle taken out to decrease indentation. \return error code. */
+static int stash_rrarray_entry(ranked_rr_array_t *arr, int arr_i,
+ const struct kr_query *qry, struct kr_cache *cache,
+ int *unauth_cnt, trie_t *nsec_pmap, bool *needs_pkt);
+/** Stash a single nsec_p. \return 0 (errors are ignored). */
+static int stash_nsec_p(const knot_dname_t *dname, const char *nsec_p_v,
+ struct kr_cache *cache, uint32_t timestamp, knot_mm_t *pool,
+ const struct kr_query *qry/*logging*/);
+
+/** The whole .consume phase for the cache module. */
+int cache_stash(kr_layer_t *ctx, knot_pkt_t *pkt)
+{
+ struct kr_request *req = ctx->req;
+ struct kr_query *qry = req->current_query;
+ struct kr_cache *cache = &req->ctx->cache;
+
+ /* Note: we cache even in KR_STATE_FAIL. For example,
+ * BOGUS answer can go to +cd cache even without +cd request. */
+ if (!kr_cache_is_open(cache) || !qry
+ || qry->flags.CACHED || !check_rrtype(knot_pkt_qtype(pkt), qry)
+ || qry->sclass != KNOT_CLASS_IN) {
+ return ctx->state;
+ }
+ /* Do not cache truncated answers, at least for now. LATER */
+ if (knot_wire_get_tc(pkt->wire)) {
+ return ctx->state;
+ }
+ int unauth_cnt = 0;
+ bool needs_pkt = false;
+ if (qry->flags.STUB) {
+ needs_pkt = true;
+ goto stash_packet;
+ }
+
+ /* Stash individual records. */
+ ranked_rr_array_t *selected[] = kr_request_selected(req);
+ trie_t *nsec_pmap = trie_create(&req->pool);
+ if (kr_fails_assert(nsec_pmap))
+ goto finally;
+ for (int psec = KNOT_ANSWER; psec <= KNOT_ADDITIONAL; ++psec) {
+ ranked_rr_array_t *arr = selected[psec];
+ /* uncached entries are located at the end */
+ for (ssize_t i = arr->len - 1; i >= 0; --i) {
+ ranked_rr_array_entry_t *entry = arr->at[i];
+ if (entry->qry_uid != qry->uid || entry->dont_cache) {
+ continue;
+ /* TODO: probably safe to break on uid mismatch but maybe not worth it */
+ }
+ int ret = stash_rrarray_entry(
+ arr, i, qry, cache, &unauth_cnt, nsec_pmap,
+ /* ADDITIONAL RRs are considered non-essential
+ * in our (resolver) answers */
+ (psec == KNOT_ADDITIONAL ? NULL : &needs_pkt));
+ if (ret) {
+ VERBOSE_MSG(qry, "=> stashing RRs errored out\n");
+ goto finally;
+ }
+ /* LATER(optim.): maybe filter out some type-rank combinations
+ * that won't be useful as separate RRsets. */
+ }
+ }
+
+ trie_it_t *it;
+ for (it = trie_it_begin(nsec_pmap); !trie_it_finished(it); trie_it_next(it)) {
+ stash_nsec_p((const knot_dname_t *)trie_it_key(it, NULL),
+ (const char *)*trie_it_val(it),
+ cache, qry->timestamp.tv_sec, &req->pool, req->current_query);
+ }
+ trie_it_free(it);
+ /* LATER(optim.): typically we also have corresponding NS record in the list,
+ * so we might save a cache operation. */
+stash_packet:
+ if (qry->flags.PKT_IS_SANE && check_dname_for_lf(knot_pkt_qname(pkt), qry)) {
+ stash_pkt(pkt, qry, req, needs_pkt);
+ }
+
+finally:
+ if (unauth_cnt) {
+ VERBOSE_MSG(qry, "=> stashed also %d nonauth RRsets\n", unauth_cnt);
+ };
+ kr_cache_commit(cache);
+ return ctx->state; /* we ignore cache-stashing errors */
+}
+
+/** Preliminary checks before stash_rrset(). Don't call if returns <= 0. */
+static int stash_rrset_precond(const knot_rrset_t *rr, const struct kr_query *qry/*logs*/)
+{
+ if (kr_fails_assert(rr && rr->rclass == KNOT_CLASS_IN))
+ return kr_error(EINVAL);
+ if (!check_rrtype(rr->type, qry))
+ return kr_ok();
+ if (!check_dname_for_lf(rr->owner, qry))
+ return kr_ok();
+ return 1/*proceed*/;
+}
+
+/** Return true on some cases of NSEC* RRsets covering minimal ranges.
+ * Also include some abnormal RR cases; qry is just for logging. */
+static bool rrset_has_min_range_or_weird(const knot_rrset_t *rr, const struct kr_query *qry)
+{
+ if (rr->rrs.count != 1) {
+ kr_assert(rr->rrs.count > 0);
+ if (rr->type == KNOT_RRTYPE_NSEC || rr->type == KNOT_RRTYPE_NSEC3
+ || rr->rrs.count == 0) {
+ return true; /*< weird */
+ }
+ }
+ bool ret; /**< NOT used for the weird cases */
+ if (rr->type == KNOT_RRTYPE_NSEC) {
+ if (!check_dname_for_lf(rr->owner, qry))
+ return true; /*< weird, probably filtered even before this point */
+ ret = !check_dname_for_lf(knot_nsec_next(rr->rrs.rdata), qry);
+ /* ^^ Zero inside the next-name label means it's probably a minimal range,
+ * and anyway it's problematic for our aggressive cache (comparisons).
+ * Real-life examples covered:
+ * NSEC: name -> \000.name (e.g. typical foobar.CloudFlare.net)
+ * NSEC: name -> name\000 (CloudFlare on delegations)
+ */
+ } else if (rr->type == KNOT_RRTYPE_NSEC3) {
+ if (knot_nsec3_next_len(rr->rrs.rdata) != NSEC3_HASH_LEN
+ || *rr->owner != NSEC3_HASH_TXT_LEN) {
+ return true; /*< weird */
+ }
+ /* Let's work on the binary hashes. Find if they "differ by one",
+ * by constructing the owner hash incremented by one and comparing. */
+ uint8_t owner_hash[NSEC3_HASH_LEN];
+ if (base32hex_decode(rr->owner + 1, NSEC3_HASH_TXT_LEN,
+ owner_hash, NSEC3_HASH_LEN) != NSEC3_HASH_LEN) {
+ return true; /*< weird */
+ }
+ for (int i = NSEC3_HASH_LEN - 1; i >= 0; --i) {
+ if (++owner_hash[i] != 0) break;
+ }
+ const uint8_t *next_hash = knot_nsec3_next(rr->rrs.rdata);
+ ret = memcmp(owner_hash, next_hash, NSEC3_HASH_LEN) == 0;
+ } else {
+ return false;
+ }
+ if (ret) VERBOSE_MSG(qry, "=> minimized NSEC* range detected\n");
+ return ret;
+}
+
+static ssize_t stash_rrset(struct kr_cache *cache, const struct kr_query *qry,
+ const knot_rrset_t *rr, const knot_rrset_t *rr_sigs, uint32_t timestamp,
+ uint8_t rank, trie_t *nsec_pmap, knot_mm_t *pool, bool *needs_pkt)
+{
+ if (kr_rank_test(rank, KR_RANK_BOGUS)) {
+ WITH_VERBOSE(qry) {
+ auto_free char *type_str = kr_rrtype_text(rr->type);
+ VERBOSE_MSG(qry, "=> skipping bogus RR set %s\n", type_str);
+ }
+ return kr_ok();
+ }
+ if (rr->type == KNOT_RRTYPE_NSEC3 && rr->rrs.count
+ && knot_nsec3_iters(rr->rrs.rdata) > KR_NSEC3_MAX_ITERATIONS) {
+ /* This shouldn't happen often, thanks to downgrades during validation. */
+ VERBOSE_MSG(qry, "=> skipping NSEC3 with too many iterations\n");
+ return kr_ok();
+ }
+ if (kr_fails_assert(cache && stash_rrset_precond(rr, qry) > 0))
+ return kr_error(EINVAL);
+
+ int ret = kr_ok();
+ if (rrset_has_min_range_or_weird(rr, qry))
+ goto return_needs_pkt;
+ const int wild_labels = rr_sigs == NULL ? 0 :
+ knot_dname_labels(rr->owner, NULL) - knot_rrsig_labels(rr_sigs->rrs.rdata);
+ if (wild_labels < 0)
+ goto return_needs_pkt;
+ const knot_dname_t *encloser = rr->owner; /**< the closest encloser name */
+ for (int i = 0; i < wild_labels; ++i) {
+ encloser = knot_wire_next_label(encloser, NULL);
+ }
+
+ /* Construct the key under which RRs will be stored,
+ * and add corresponding nsec_pmap item (if necessary). */
+ struct key k_storage, *k = &k_storage;
+ knot_db_val_t key;
+ switch (rr->type) {
+ case KNOT_RRTYPE_NSEC3:
+ /* Skip opt-out NSEC3 sets. */
+ if (KNOT_NSEC3_FLAG_OPT_OUT & knot_nsec3_flags(rr->rrs.rdata))
+ goto return_needs_pkt;
+ /* fall through */
+ case KNOT_RRTYPE_NSEC:
+ /* Skip any NSEC*s that aren't validated or are suspicious. */
+ if (!kr_rank_test(rank, KR_RANK_SECURE) || rr->rrs.count != 1)
+ goto return_needs_pkt;
+ if (kr_fails_assert(rr_sigs && rr_sigs->rrs.count && rr_sigs->rrs.rdata)) {
+ ret = kr_error(EINVAL);
+ goto return_needs_pkt;
+ }
+ const knot_dname_t *signer = knot_rrsig_signer_name(rr_sigs->rrs.rdata);
+ const int signer_size = knot_dname_size(signer);
+ k->zlf_len = signer_size - 1;
+
+ void **npp = NULL;
+ if (nsec_pmap) {
+ npp = trie_get_ins(nsec_pmap, (const char *)signer, signer_size);
+ if (kr_fails_assert(npp))
+ return kr_error(ENOMEM);
+ }
+ if (rr->type == KNOT_RRTYPE_NSEC) {
+ key = key_NSEC1(k, encloser, wild_labels);
+ break;
+ }
+
+ kr_require(rr->type == KNOT_RRTYPE_NSEC3);
+ const knot_rdata_t * const rdata = rr->rrs.rdata;
+ if (rdata->len <= 4) {
+ ret = kr_error(EILSEQ); /*< data from outside; less trust */
+ goto return_needs_pkt;
+ }
+ const int np_dlen = nsec_p_rdlen(rdata->data);
+ if (np_dlen > rdata->len) {
+ ret = kr_error(EILSEQ);
+ goto return_needs_pkt;
+ }
+ key = key_NSEC3(k, encloser, nsec_p_mkHash(rdata->data));
+ if (npp && !*npp) {
+ *npp = mm_alloc(pool, np_dlen);
+ if (kr_fails_assert(*npp))
+ break;
+ memcpy(*npp, rdata->data, np_dlen);
+ }
+ break;
+ default:
+ ret = kr_dname_lf(k->buf, encloser, wild_labels);
+ if (kr_fails_assert(ret == 0))
+ goto return_needs_pkt;
+ key = key_exact_type(k, rr->type);
+ }
+
+ /* Compute in-cache size for the new data. */
+ const knot_rdataset_t *rds_sigs = rr_sigs ? &rr_sigs->rrs : NULL;
+ const int rr_ssize = rdataset_dematerialize_size(&rr->rrs);
+ if (kr_fails_assert(rr_ssize == to_even(rr_ssize)))
+ return kr_error(EINVAL);
+ knot_db_val_t val_new_entry = {
+ .data = NULL,
+ .len = offsetof(struct entry_h, data) + rr_ssize
+ + rdataset_dematerialize_size(rds_sigs),
+ };
+
+ /* Prepare raw memory for the new entry. */
+ ret = entry_h_splice(&val_new_entry, rank, key, k->type, rr->type,
+ rr->owner, qry, cache, timestamp);
+ if (ret) return kr_ok(); /* some aren't really errors */
+ if (kr_fails_assert(val_new_entry.data))
+ return kr_error(EFAULT);
+
+ /* Write the entry itself. */
+ struct entry_h *eh = val_new_entry.data;
+ memset(eh, 0, offsetof(struct entry_h, data));
+ eh->time = timestamp;
+ eh->ttl = rr->ttl;
+ eh->rank = rank;
+ rdataset_dematerialize(&rr->rrs, eh->data);
+ rdataset_dematerialize(rds_sigs, eh->data + rr_ssize);
+ if (kr_fails_assert(entry_h_consistent_E(val_new_entry, rr->type)))
+ return kr_error(EINVAL);
+
+ #if 0 /* Occasionally useful when debugging some kinds of changes. */
+ {
+ kr_cache_commit(cache);
+ knot_db_val_t val = { NULL, 0 };
+ ret = cache_op(cache, read, &key, &val, 1);
+ if (ret != kr_error(ENOENT)) { // ENOENT might happen in some edge case, I guess
+ kr_assert(!ret);
+ entry_list_t el;
+ entry_list_parse(val, el);
+ }
+ }
+ #endif
+
+ /* Verbose-log some not-too-common cases. */
+ WITH_VERBOSE(qry) { if (kr_rank_test(rank, KR_RANK_AUTH)
+ || rr->type == KNOT_RRTYPE_NS) {
+ auto_free char *type_str = kr_rrtype_text(rr->type),
+ *encl_str = kr_dname_text(encloser);
+ VERBOSE_MSG(qry, "=> stashed %s%s %s, rank 0%.2o, "
+ "%d B total, incl. %d RRSIGs\n",
+ (wild_labels ? "*." : ""), encl_str, type_str, rank,
+ (int)val_new_entry.len, (rr_sigs ? rr_sigs->rrs.count : 0)
+ );
+ } }
+
+ return (ssize_t) val_new_entry.len;
+return_needs_pkt:
+ if (needs_pkt) *needs_pkt = true;
+ return ret;
+}
+
+static int stash_rrarray_entry(ranked_rr_array_t *arr, int arr_i,
+ const struct kr_query *qry, struct kr_cache *cache,
+ int *unauth_cnt, trie_t *nsec_pmap, bool *needs_pkt)
+{
+ ranked_rr_array_entry_t *entry = arr->at[arr_i];
+ if (entry->cached) {
+ return kr_ok();
+ }
+ const knot_rrset_t *rr = entry->rr;
+ if (rr->type == KNOT_RRTYPE_RRSIG) {
+ return kr_ok(); /* reduce verbose logging from the following call */
+ }
+ int ret = stash_rrset_precond(rr, qry);
+ if (ret <= 0) {
+ return ret;
+ }
+
+ /* Try to find corresponding signatures, always. LATER(optim.): speed. */
+ ranked_rr_array_entry_t *entry_rrsigs = NULL;
+ const knot_rrset_t *rr_sigs = NULL;
+ for (ssize_t j = arr->len - 1; j >= 0; --j) {
+ /* TODO: ATM we assume that some properties are the same
+ * for all RRSIGs in the set (esp. label count). */
+ ranked_rr_array_entry_t *e = arr->at[j];
+ if (kr_fails_assert(!e->in_progress))
+ return kr_error(EINVAL);
+ bool ok = e->qry_uid == qry->uid && !e->cached
+ && e->rr->type == KNOT_RRTYPE_RRSIG
+ && knot_rrsig_type_covered(e->rr->rrs.rdata) == rr->type
+ && knot_dname_is_equal(rr->owner, e->rr->owner);
+ if (!ok) continue;
+ entry_rrsigs = e;
+ rr_sigs = e->rr;
+ break;
+ }
+
+ ssize_t written = stash_rrset(cache, qry, rr, rr_sigs, qry->timestamp.tv_sec,
+ entry->rank, nsec_pmap, &qry->request->pool, needs_pkt);
+ if (written < 0) {
+ kr_log_error(CACHE, "[%05u.%02u] stash failed, ret = %d\n", qry->request->uid,
+ qry->uid, ret);
+ return (int) written;
+ }
+
+ if (written > 0) {
+ /* Mark entry as cached for the rest of the query processing */
+ entry->cached = true;
+ if (entry_rrsigs) {
+ entry_rrsigs->cached = true;
+ }
+ if (!kr_rank_test(entry->rank, KR_RANK_AUTH) && rr->type != KNOT_RRTYPE_NS) {
+ *unauth_cnt += 1;
+ }
+ }
+
+ return kr_ok();
+}
+
+static int stash_nsec_p(const knot_dname_t *dname, const char *nsec_p_v,
+ struct kr_cache *cache, uint32_t timestamp, knot_mm_t *pool,
+ const struct kr_query *qry/*logging*/)
+{
+ uint32_t valid_until = timestamp + cache->ttl_max;
+ /* LATER(optim.): be more precise here ^^ and reduce calls. */
+ static const int32_t ttl_margin = 3600;
+ const uint8_t *nsec_p = (const uint8_t *)nsec_p_v;
+ int data_stride = sizeof(valid_until) + nsec_p_rdlen(nsec_p);
+
+ unsigned int log_hash = 0xFeeeFeee; /* this type is simpler for printf args */
+ auto_free char *log_dname = NULL;
+ WITH_VERBOSE(qry) {
+ log_hash = nsec_p_v ? nsec_p_mkHash((const uint8_t *)nsec_p_v) : 0;
+ log_dname = kr_dname_text(dname);
+ }
+ /* Find what's in the cache. */
+ struct key k_storage, *k = &k_storage;
+ int ret = kr_dname_lf(k->buf, dname, false);
+ if (ret) return kr_error(ret);
+ knot_db_val_t key = key_exact_type(k, KNOT_RRTYPE_NS);
+ knot_db_val_t val_orig = { NULL, 0 };
+ ret = cache_op(cache, read, &key, &val_orig, 1);
+ if (ret && ret != -ABS(ENOENT)) {
+ VERBOSE_MSG(qry, "=> EL read failed (ret: %d)\n", ret);
+ return kr_ok();
+ }
+ /* Prepare new entry_list_t so we can just write at el[0]. */
+ entry_list_t el;
+ int log_refresh_by = 0;
+ if (ret == -ABS(ENOENT)) {
+ memset(el, 0, sizeof(el));
+ } else {
+ ret = entry_list_parse(val_orig, el);
+ if (ret) {
+ VERBOSE_MSG(qry, "=> EL parse failed (ret: %d)\n", ret);
+ return kr_error(0);
+ }
+ /* Find the index to replace. */
+ int i_replace = ENTRY_APEX_NSECS_CNT - 1;
+ for (int i = 0; i < ENTRY_APEX_NSECS_CNT; ++i) {
+ if (el[i].len != data_stride) continue;
+ if (nsec_p && memcmp(nsec_p, (uint8_t *)el[i].data + sizeof(uint32_t),
+ data_stride - sizeof(uint32_t)) != 0) {
+ continue;
+ }
+ /* Save a cache operation if TTL extended only a little. */
+ uint32_t valid_orig;
+ memcpy(&valid_orig, el[i].data, sizeof(valid_orig));
+ const int32_t ttl_extended_by = valid_until - valid_orig;
+ if (ttl_extended_by < ttl_margin) {
+ VERBOSE_MSG(qry,
+ "=> nsec_p stash for %s skipped (extra TTL: %d, hash: %x)\n",
+ log_dname, ttl_extended_by, log_hash);
+ return kr_ok();
+ }
+ i_replace = i;
+ log_refresh_by = ttl_extended_by;
+ break;
+ }
+ /* Shift the other indices: move the first `i_replace` blocks
+ * by one position. */
+ if (i_replace) {
+ memmove(&el[1], &el[0], sizeof(el[0]) * i_replace);
+ }
+ }
+ /* Prepare old data into a buffer. See entry_h_splice() for why. LATER(optim.) */
+ el[0].len = data_stride;
+ el[0].data = NULL;
+ knot_db_val_t val;
+ val.len = entry_list_serial_size(el),
+ val.data = mm_alloc(pool, val.len),
+ entry_list_memcpy(val.data, el);
+ /* Prepare the new data chunk */
+ memcpy(el[0].data, &valid_until, sizeof(valid_until));
+ if (nsec_p) {
+ memcpy((uint8_t *)el[0].data + sizeof(valid_until), nsec_p,
+ data_stride - sizeof(valid_until));
+ }
+ /* Write it all to the cache */
+ ret = cache_op(cache, write, &key, &val, 1);
+ mm_free(pool, val.data);
+ if (ret || !val.data) {
+ VERBOSE_MSG(qry, "=> EL write failed (ret: %d)\n", ret);
+ return kr_ok();
+ }
+ if (log_refresh_by) {
+ VERBOSE_MSG(qry, "=> nsec_p stashed for %s (refresh by %d, hash: %x)\n",
+ log_dname, log_refresh_by, log_hash);
+ } else {
+ VERBOSE_MSG(qry, "=> nsec_p stashed for %s (new, hash: %x)\n",
+ log_dname, log_hash);
+ }
+ return kr_ok();
+}
+
+int kr_cache_insert_rr(struct kr_cache *cache,
+ const knot_rrset_t *rr, const knot_rrset_t *rrsig,
+ uint8_t rank, uint32_t timestamp, bool ins_nsec_p)
+{
+ int err = stash_rrset_precond(rr, NULL);
+ if (err <= 0) {
+ return kr_ok();
+ }
+
+ trie_t *nsec_pmap = NULL;
+ knot_mm_t *pool = NULL;
+ if (ins_nsec_p && (rr->type == KNOT_RRTYPE_NSEC || rr->type == KNOT_RRTYPE_NSEC3)) {
+ pool = mm_ctx_mempool2(4096);
+ nsec_pmap = trie_create(pool);
+ kr_assert(pool && nsec_pmap);
+ }
+
+ ssize_t written = stash_rrset(cache, NULL, rr, rrsig, timestamp, rank,
+ nsec_pmap, pool, NULL);
+
+ if (nsec_pmap) {
+ trie_it_t *it;
+ for (it = trie_it_begin(nsec_pmap); !trie_it_finished(it); trie_it_next(it)) {
+ stash_nsec_p((const knot_dname_t *)trie_it_key(it, NULL),
+ (const char *)*trie_it_val(it),
+ cache, timestamp, pool, NULL);
+ }
+ trie_it_free(it);
+ mm_ctx_delete(pool);
+ }
+
+ if (written >= 0) {
+ return kr_ok();
+ }
+
+ return (int) written;
+}
+
+static int peek_exact_real(struct kr_cache *cache, const knot_dname_t *name, uint16_t type,
+ struct kr_cache_p *peek)
+{
+ if (!check_rrtype(type, NULL) || !check_dname_for_lf(name, NULL)) {
+ return kr_error(ENOTSUP);
+ }
+ struct key k_storage, *k = &k_storage;
+
+ int ret = kr_dname_lf(k->buf, name, false);
+ if (ret) return kr_error(ret);
+
+ knot_db_val_t key = key_exact_type(k, type);
+ knot_db_val_t val = { NULL, 0 };
+ ret = cache_op(cache, read, &key, &val, 1);
+ if (!ret) ret = entry_h_seek(&val, type);
+ if (ret) return kr_error(ret);
+
+ const struct entry_h *eh = entry_h_consistent_E(val, type);
+ if (!eh || eh->is_packet) {
+ // TODO: no packets, but better get rid of whole kr_cache_peek_exact().
+ return kr_error(ENOENT);
+ }
+ *peek = (struct kr_cache_p){
+ .time = eh->time,
+ .ttl = eh->ttl,
+ .rank = eh->rank,
+ .raw_data = val.data,
+ .raw_bound = knot_db_val_bound(val),
+ };
+ return kr_ok();
+}
+int kr_cache_peek_exact(struct kr_cache *cache, const knot_dname_t *name, uint16_t type,
+ struct kr_cache_p *peek)
+{ /* Just wrap with extra verbose logging. */
+ const int ret = peek_exact_real(cache, name, type, peek);
+ if (false && kr_log_is_debug(CACHE, NULL)) { /* too noisy for usual --verbose */
+ auto_free char *type_str = kr_rrtype_text(type),
+ *name_str = kr_dname_text(name);
+ const char *result_str = (ret == kr_ok() ? "hit" :
+ (ret == kr_error(ENOENT) ? "miss" : "error"));
+ VERBOSE_MSG(NULL, "_peek_exact: %s %s %s (ret: %d)",
+ type_str, name_str, result_str, ret);
+ }
+ return ret;
+}
+
+int kr_cache_remove(struct kr_cache *cache, const knot_dname_t *name, uint16_t type)
+{
+ if (!cache_isvalid(cache)) {
+ return kr_error(EINVAL);
+ }
+ if (!cache->api->remove) {
+ return kr_error(ENOSYS);
+ }
+ struct key k_storage, *k = &k_storage;
+ int ret = kr_dname_lf(k->buf, name, false);
+ if (ret) return kr_error(ret);
+
+ knot_db_val_t key = key_exact_type(k, type);
+ return cache_op(cache, remove, &key, 1);
+}
+
+int kr_cache_match(struct kr_cache *cache, const knot_dname_t *name,
+ bool exact_name, knot_db_val_t keyval[][2], int maxcount)
+{
+ if (!cache_isvalid(cache)) {
+ return kr_error(EINVAL);
+ }
+ if (!cache->api->match) {
+ return kr_error(ENOSYS);
+ }
+
+ struct key k_storage, *k = &k_storage;
+
+ int ret = kr_dname_lf(k->buf, name, false);
+ if (ret) return kr_error(ret);
+
+ // use a mock type
+ knot_db_val_t key = key_exact_type(k, KNOT_RRTYPE_A);
+ /* CACHE_KEY_DEF */
+ key.len -= sizeof(uint16_t); /* the type */
+ if (!exact_name) {
+ key.len -= 2; /* '\0' 'E' */
+ if (name[0] == '\0') ++key.len; /* the root name is special ATM */
+ }
+ return cache_op(cache, match, &key, keyval, maxcount);
+}
+
+int kr_unpack_cache_key(knot_db_val_t key, knot_dname_t *buf, uint16_t *type)
+{
+ if (key.data == NULL || buf == NULL || type == NULL) {
+ return kr_error(EINVAL);
+ }
+
+ int len = -1;
+ const char *tag, *key_data = key.data;
+ for (tag = key_data + 1; tag < key_data + key.len; ++tag) {
+ /* CACHE_KEY_DEF */
+ if (tag[-1] == '\0' && (tag == key_data + 1 || tag[-2] == '\0')) {
+ if (tag[0] != 'E') return kr_error(EINVAL);
+ len = tag - 1 - key_data;
+ break;
+ }
+ }
+
+ if (len == -1 || len > KNOT_DNAME_MAXLEN) {
+ return kr_error(EINVAL);
+ }
+
+ int ret = knot_dname_lf2wire(buf, len, key.data);
+ if (ret < 0) {
+ return kr_error(ret);
+ }
+
+ /* CACHE_KEY_DEF: jump over "\0 E/1" */
+ memcpy(type, tag + 1, sizeof(uint16_t));
+
+ return kr_ok();
+}
+
+
+int kr_cache_remove_subtree(struct kr_cache *cache, const knot_dname_t *name,
+ bool exact_name, int maxcount)
+{
+ if (!cache_isvalid(cache)) {
+ return kr_error(EINVAL);
+ }
+
+ knot_db_val_t keyval[maxcount][2], keys[maxcount];
+ int ret = kr_cache_match(cache, name, exact_name, keyval, maxcount);
+ if (ret <= 0) { /* ENOENT -> nothing to remove */
+ return (ret == KNOT_ENOENT) ? 0 : ret;
+ }
+ const int count = ret;
+ /* Duplicate the key strings, as deletion may invalidate the pointers. */
+ int i;
+ for (i = 0; i < count; ++i) {
+ keys[i].len = keyval[i][0].len;
+ keys[i].data = malloc(keys[i].len);
+ if (!keys[i].data) {
+ ret = kr_error(ENOMEM);
+ goto cleanup;
+ }
+ memcpy(keys[i].data, keyval[i][0].data, keys[i].len);
+ }
+ ret = cache_op(cache, remove, keys, count);
+cleanup:
+ kr_cache_commit(cache); /* Sync even after just kr_cache_match(). */
+ /* Free keys */
+ while (--i >= 0) {
+ free(keys[i].data);
+ }
+ return ret;
+}
+
+static void health_timer_cb(uv_timer_t *health_timer)
+{
+ struct kr_cache *cache = health_timer->data;
+ if (cache)
+ cache_op(cache, check_health);
+ /* We don't do anything with the return code. For example, in some situations
+ * the file may not exist (temporarily), and we just expect to be more lucky
+ * when the timer fires again. */
+}
+
+int kr_cache_check_health(struct kr_cache *cache, int interval)
+{
+ if (interval == 0)
+ return cache_op(cache, check_health);
+ if (interval < 0) {
+ if (!cache->health_timer)
+ return kr_ok(); // tolerate stopping a "stopped" timer
+ uv_close((uv_handle_t *)cache->health_timer, (uv_close_cb)free);
+ cache->health_timer->data = NULL;
+ cache->health_timer = NULL;
+ return kr_ok();
+ }
+
+ if (!cache->health_timer) {
+ /* We avoid depending on daemon's symbols by using uv_default_loop. */
+ cache->health_timer = malloc(sizeof(*cache->health_timer));
+ if (!cache->health_timer) return kr_error(ENOMEM);
+ uv_loop_t *loop = uv_default_loop();
+ kr_require(loop);
+ int ret = uv_timer_init(loop, cache->health_timer);
+ if (ret) {
+ free(cache->health_timer);
+ cache->health_timer = NULL;
+ return kr_error(ret);
+ }
+ cache->health_timer->data = cache;
+ }
+ kr_assert(cache->health_timer->data);
+ return kr_error(uv_timer_start(cache->health_timer, health_timer_cb, interval, interval));
+}
+
diff --git a/lib/cache/api.h b/lib/cache/api.h
new file mode 100644
index 0000000..0abe920
--- /dev/null
+++ b/lib/cache/api.h
@@ -0,0 +1,194 @@
+/* Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include <libknot/consts.h>
+#include <libknot/rrset.h>
+#include <sys/time.h>
+#include "lib/cache/cdb_api.h"
+#include "lib/defines.h"
+#include "contrib/ucw/config.h" /*uint*/
+
+#include "lib/module.h"
+/* Prototypes for the 'cache' module implementation. */
+int cache_peek(kr_layer_t *ctx, knot_pkt_t *pkt);
+int cache_stash(kr_layer_t *ctx, knot_pkt_t *pkt);
+
+
+/**
+ * Cache structure, keeps API, instance and metadata.
+ */
+struct kr_cache
+{
+ kr_cdb_pt db; /**< Storage instance */
+ const struct kr_cdb_api *api; /**< Storage engine */
+ struct kr_cdb_stats stats;
+ uint32_t ttl_min, ttl_max; /**< TTL limits; enforced primarily in iterator actually. */
+
+ /* A pair of stamps for detection of real-time shifts during runtime. */
+ struct timeval checkpoint_walltime; /**< Wall time on the last check-point. */
+ uint64_t checkpoint_monotime; /**< Monotonic milliseconds on the last check-point. */
+
+ uv_timer_t *health_timer; /**< Timer used for kr_cache_check_health() */
+};
+// https://datatracker.ietf.org/doc/html/rfc2181#section-8
+#define TTL_MAX_MAX ((1u << 31) - 1)
+
+/**
+ * Open/create cache with provided storage options.
+ * @param cache cache structure to be initialized
+ * @param api storage engine API
+ * @param opts storage-specific options (may be NULL for default)
+ * @param mm memory context.
+ * @return 0 or an error code
+ */
+KR_EXPORT
+int kr_cache_open(struct kr_cache *cache, const struct kr_cdb_api *api, struct kr_cdb_opts *opts, knot_mm_t *mm);
+
+/**
+ * Path to cache file to remove on critical out-of-space error. (do NOT modify it)
+ */
+KR_EXPORT extern
+const char *kr_cache_emergency_file_to_remove;
+
+/**
+ * Close persistent cache.
+ * @note This doesn't clear the data, just closes the connection to the database.
+ * @param cache structure
+ */
+KR_EXPORT
+void kr_cache_close(struct kr_cache *cache);
+
+/** Run after a row of operations to release transaction/lock if needed. */
+KR_EXPORT
+int kr_cache_commit(struct kr_cache *cache);
+
+/**
+ * Return true if cache is open and enabled.
+ */
+static inline bool kr_cache_is_open(struct kr_cache *cache)
+{
+ return cache->db != NULL;
+}
+
+/** (Re)set the time pair to the current values. */
+static inline void kr_cache_make_checkpoint(struct kr_cache *cache)
+{
+ cache->checkpoint_monotime = kr_now();
+ gettimeofday(&cache->checkpoint_walltime, NULL);
+}
+
+/**
+ * Insert RRSet into cache, replacing any existing data.
+ * @param cache cache structure
+ * @param rr inserted RRSet
+ * @param rrsig RRSIG for inserted RRSet (optional)
+ * @param rank rank of the data
+ * @param timestamp current time (as-if; if the RR are older, their timestamp is appropriate)
+ * @param ins_nsec_p update NSEC* parameters if applicable
+ * @return 0 or an errcode
+ */
+KR_EXPORT
+int kr_cache_insert_rr(struct kr_cache *cache,
+ const knot_rrset_t *rr, const knot_rrset_t *rrsig,
+ uint8_t rank, uint32_t timestamp, bool ins_nsec_p);
+
+/**
+ * Clear all items from the cache.
+ * @param cache cache structure
+ * @return if nonzero is returned, there's a big problem - you probably want to abort(),
+ * perhaps except for kr_error(EAGAIN) which probably indicates transient errors.
+ */
+KR_EXPORT
+int kr_cache_clear(struct kr_cache *cache);
+
+
+/* ** This interface is temporary. ** */
+
+struct kr_cache_p {
+ uint32_t time; /**< The time of inception. */
+ uint32_t ttl; /**< TTL at inception moment. Assuming it fits into int32_t ATM. */
+ uint8_t rank; /**< See enum kr_rank */
+ struct {
+ /* internal: pointer to eh struct */
+ void *raw_data, *raw_bound;
+ };
+};
+KR_EXPORT
+int kr_cache_peek_exact(struct kr_cache *cache, const knot_dname_t *name, uint16_t type,
+ struct kr_cache_p *peek);
+/* Parameters (qry, name, type) are used for timestamp and stale-serving decisions. */
+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);
+
+KR_EXPORT
+int kr_cache_materialize(knot_rdataset_t *dst, const struct kr_cache_p *ref,
+ knot_mm_t *pool);
+
+
+/**
+ * Remove an entry from cache.
+ * @param cache cache structure
+ * @param name dname
+ * @param type rr type
+ * @return number of deleted records, or negative error code
+ * @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);
+
+/**
+ * Get keys matching a dname lf prefix
+ * @param cache cache structure
+ * @param name dname
+ * @param exact_name whether to only consider exact name matches
+ * @param keyval matched key-value pairs
+ * @param maxcount limit on the number of returned key-value pairs
+ * @return result count or an errcode
+ * @note the cache keys are matched by prefix, i.e. it very much depends
+ * on their structure; CACHE_KEY_DEF.
+ */
+KR_EXPORT
+int kr_cache_match(struct kr_cache *cache, const knot_dname_t *name,
+ bool exact_name, knot_db_val_t keyval[][2], int maxcount);
+
+/**
+ * Remove a subtree in cache. It's like _match but removing them instead of returning.
+ * @return number of deleted entries or an errcode
+ */
+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,
+ knot_dname_t **apex);
+
+/**
+ * Unpack dname and type from db key
+ * @param key db key representation
+ * @param buf output buffer of domain name in dname format
+ * @param type output for type
+ * @return length of dname or an errcode
+ * @note only "exact hits" are considered ATM, moreover xNAME records
+ * are "hidden" as NS. (see comments in struct entry_h)
+ */
+KR_EXPORT
+int kr_unpack_cache_key(knot_db_val_t key, knot_dname_t *buf, uint16_t *type);
+
+/** Periodic kr_cdb_api::check_health().
+ * @param interval in milliseconds. 0 for one-time check, -1 to stop the checks.
+ * @return see check_health() for one-time check; otherwise normal kr_error() code. */
+KR_EXPORT
+int kr_cache_check_health(struct kr_cache *cache, int interval);
+
diff --git a/lib/cache/cdb_api.h b/lib/cache/cdb_api.h
new file mode 100644
index 0000000..fcca8a9
--- /dev/null
+++ b/lib/cache/cdb_api.h
@@ -0,0 +1,97 @@
+/* Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+*/
+
+#pragma once
+
+#include <stdint.h>
+
+#include <libknot/db/db.h>
+
+/* Cache options. */
+struct kr_cdb_opts {
+ const char *path; /*!< Cache URI path. */
+ size_t maxsize; /*!< Suggested cache size in bytes; pass 0 to keep unchanged/default. */
+};
+
+struct kr_cdb_stats {
+ uint64_t open;
+ uint64_t close;
+ uint64_t count;
+ uint64_t count_entries;
+ uint64_t clear;
+ uint64_t commit;
+ uint64_t read;
+ uint64_t read_miss;
+ uint64_t write;
+ uint64_t remove;
+ uint64_t remove_miss;
+ uint64_t match;
+ uint64_t match_miss;
+ uint64_t read_leq;
+ uint64_t read_leq_miss;
+ double usage_percent;
+};
+
+/*! Pointer to a cache structure.
+ *
+ * This struct is opaque and never defined; the purpose is to get better
+ * type safety than with void *.
+ */
+typedef struct kr_cdb *kr_cdb_pt;
+
+/*! Cache database API.
+ * This is a simplified version of generic DB API from libknot,
+ * that is tailored to caching purposes.
+ */
+struct kr_cdb_api {
+ const char *name;
+
+ /* Context operations */
+
+ int (*open)(kr_cdb_pt *db, struct kr_cdb_stats *stat, struct kr_cdb_opts *opts, knot_mm_t *mm);
+ void (*close)(kr_cdb_pt db, struct kr_cdb_stats *stat);
+ int (*count)(kr_cdb_pt db, struct kr_cdb_stats *stat);
+ int (*clear)(kr_cdb_pt db, struct kr_cdb_stats *stat);
+
+ /** Run after a row of operations to release transaction/lock if needed. */
+ int (*commit)(kr_cdb_pt db, struct kr_cdb_stats *stat);
+
+ /* Data access */
+
+ int (*read)(kr_cdb_pt db, struct kr_cdb_stats *stat,
+ const knot_db_val_t *key, knot_db_val_t *val, int maxcount);
+ int (*write)(kr_cdb_pt db, struct kr_cdb_stats *stat, const knot_db_val_t *key,
+ knot_db_val_t *val, int maxcount);
+
+ /** Remove maxcount keys.
+ * \returns the number of successfully removed keys or the first error code
+ * It returns on first error, but ENOENT is not considered an error. */
+ int (*remove)(kr_cdb_pt db, struct kr_cdb_stats *stat,
+ knot_db_val_t keys[], int maxcount);
+
+ /* Specialised operations */
+
+ /** Find key-value pairs that are prefixed by the given key, limited by maxcount.
+ * \return the number of pairs or negative error. */
+ int (*match)(kr_cdb_pt db, struct kr_cdb_stats *stat,
+ knot_db_val_t *key, knot_db_val_t keyval[][2], int maxcount);
+
+ /** Less-or-equal search (lexicographic ordering).
+ * On successful return, key->data and val->data point to DB-owned data.
+ * return: 0 for equality, > 0 for less, < 0 kr_error */
+ int (*read_leq)(kr_cdb_pt db, struct kr_cdb_stats *stat,
+ knot_db_val_t *key, knot_db_val_t *val);
+
+ /** Return estimated space usage (0--100). */
+ double (*usage_percent)(kr_cdb_pt db);
+
+ /** Return the current cache size limit in bytes; could be cached by check_health(). */
+ size_t (*get_maxsize)(kr_cdb_pt db);
+
+ /** Perform maintenance.
+ * In LMDB case it checks whether data.mdb is still the same
+ * and reopens it if it isn't; it errors out if the file doesn't exist anymore.
+ * \return 0 if OK, 1 if reopened OK, < 0 kr_error */
+ int (*check_health)(kr_cdb_pt db, struct kr_cdb_stats *stat);
+};
diff --git a/lib/cache/cdb_lmdb.c b/lib/cache/cdb_lmdb.c
new file mode 100644
index 0000000..80c7372
--- /dev/null
+++ b/lib/cache/cdb_lmdb.c
@@ -0,0 +1,868 @@
+/* Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+*/
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <lmdb.h>
+
+#include "contrib/cleanup.h"
+#include "contrib/ucw/lib.h"
+#include "lib/cache/cdb_lmdb.h"
+#include "lib/cache/cdb_api.h"
+#include "lib/utils.h"
+
+
+/* Defines */
+#define LMDB_DIR_MODE 0770
+#define LMDB_FILE_MODE 0660
+
+/* TODO: we rely on mirrors of these two structs not changing layout
+ * in libknot and knot resolver! */
+struct lmdb_env
+{
+ size_t mapsize;
+ MDB_dbi dbi;
+ MDB_env *env;
+
+ /** Cached transactions
+ *
+ * - only one of (ro,rw) may be active at once
+ * - non-NULL .ro may be active or reset
+ * - non-NULL .rw is always active
+ */
+ struct {
+ bool ro_active, ro_curs_active;
+ MDB_txn *ro, *rw;
+ MDB_cursor *ro_curs;
+ } txn;
+
+ /* Cached part of struct stat for data.mdb. */
+ dev_t st_dev;
+ ino_t st_ino;
+ off_t st_size;
+ const char *mdb_data_path; /**< path to data.mdb, for convenience */
+};
+
+struct libknot_lmdb_env {
+ bool shared;
+ unsigned dbi;
+ void *env;
+ knot_mm_t *pool;
+};
+
+/** Type-safe conversion helper.
+ *
+ * We keep lmdb_env as a separate type from kr_db_pt, as different implementation of API
+ * would need to define the contents differently.
+ */
+static inline struct lmdb_env * db2env(kr_cdb_pt db)
+{
+ return (struct lmdb_env *)db;
+}
+static inline kr_cdb_pt env2db(struct lmdb_env *env)
+{
+ return (kr_cdb_pt)env;
+}
+
+static int cdb_commit(kr_cdb_pt db, struct kr_cdb_stats *stats);
+
+/** @brief Convert LMDB error code. */
+static int lmdb_error(int error)
+{
+ switch (error) {
+ case MDB_SUCCESS:
+ return kr_ok();
+ case MDB_NOTFOUND:
+ return kr_error(ENOENT);
+ case ENOSPC:
+ case MDB_MAP_FULL:
+ case MDB_TXN_FULL:
+ return kr_error(ENOSPC);
+ default:
+ kr_log_error(CACHE, "LMDB error: %s\n", mdb_strerror(error));
+ return kr_error(error);
+ }
+}
+
+/** Conversion between knot and lmdb structs for values. */
+static inline knot_db_val_t val_mdb2knot(MDB_val v)
+{
+ return (knot_db_val_t){ .len = v.mv_size, .data = v.mv_data };
+}
+static inline MDB_val val_knot2mdb(knot_db_val_t v)
+{
+ return (MDB_val){ .mv_size = v.len, .mv_data = v.data };
+}
+
+/** Refresh mapsize value from file, including env->mapsize.
+ * It's much lighter than reopen_env(). */
+static int refresh_mapsize(struct lmdb_env *env)
+{
+ int ret = cdb_commit(env2db(env), NULL);
+ if (!ret) ret = lmdb_error(mdb_env_set_mapsize(env->env, 0));
+ if (ret) return ret;
+
+ MDB_envinfo info;
+ ret = lmdb_error(mdb_env_info(env->env, &info));
+ if (ret) return ret;
+
+ env->mapsize = info.me_mapsize;
+ if (env->mapsize != env->st_size) {
+ kr_log_info(CACHE, "suspicious size of cache file '%s'"
+ ": file size %zu != LMDB map size %zu\n",
+ env->mdb_data_path, (size_t)env->st_size, env->mapsize);
+ }
+ return kr_ok();
+}
+
+static void clear_stale_readers(struct lmdb_env *env)
+{
+ int cleared;
+ int ret = mdb_reader_check(env->env, &cleared);
+ if (ret != MDB_SUCCESS) {
+ kr_log_error(CACHE, "failed to clear stale reader locks: "
+ "LMDB error %d %s\n", ret, mdb_strerror(ret));
+ } else if (cleared != 0) {
+ kr_log_info(CACHE, "cleared %d stale reader locks\n", cleared);
+ }
+}
+
+#define FLAG_RENEW (2*MDB_RDONLY)
+/** mdb_txn_begin or _renew + handle retries in some situations
+ *
+ * The retrying logic is so ugly that it has its own function.
+ * \note this assumes no transactions are active
+ * \return MDB_ errcode, not usual kr_error(...)
+ */
+static int txn_get_noresize(struct lmdb_env *env, unsigned int flag, MDB_txn **txn)
+{
+ if (kr_fails_assert(!env->txn.rw && (!env->txn.ro || !env->txn.ro_active)))
+ return kr_error(1);
+ int attempts = 0;
+ int ret;
+retry:
+ /* Do a few attempts in case we encounter multiple issues at once. */
+ if (++attempts > 2)
+ return kr_error(1);
+
+ if (flag == FLAG_RENEW) {
+ ret = mdb_txn_renew(*txn);
+ } else {
+ ret = mdb_txn_begin(env->env, NULL, flag, txn);
+ }
+
+ if (unlikely(ret == MDB_MAP_RESIZED)) {
+ kr_log_info(CACHE, "detected size increased by another process\n");
+ ret = refresh_mapsize(env);
+ if (ret == 0)
+ goto retry;
+ } else if (unlikely(ret == MDB_READERS_FULL)) {
+ clear_stale_readers(env);
+ goto retry;
+ }
+ return ret;
+}
+
+/** Obtain a transaction. (they're cached in env->txn) */
+static int txn_get(struct lmdb_env *env, MDB_txn **txn, bool rdonly)
+{
+ if (kr_fails_assert(env && txn))
+ return kr_error(EINVAL);
+ if (env->txn.rw) {
+ /* Reuse the *open* RW txn even if only reading is requested.
+ * We leave the management of this to the cdb_commit command.
+ * The user may e.g. want to do some reads between the writes. */
+ *txn = env->txn.rw;
+ return kr_ok();
+ }
+
+ if (!rdonly) {
+ /* avoid two active transactions */
+ if (env->txn.ro && env->txn.ro_active) {
+ mdb_txn_reset(env->txn.ro);
+ env->txn.ro_active = false;
+ env->txn.ro_curs_active = false;
+ }
+ int ret = txn_get_noresize(env, 0/*RW*/, &env->txn.rw);
+ if (ret == MDB_SUCCESS) {
+ *txn = env->txn.rw;
+ kr_assert(*txn);
+ }
+ return lmdb_error(ret);
+ }
+
+ /* Get an active RO txn and return it. */
+ int ret = MDB_SUCCESS;
+ if (!env->txn.ro) { //:unlikely
+ ret = txn_get_noresize(env, MDB_RDONLY, &env->txn.ro);
+ } else if (!env->txn.ro_active) {
+ ret = txn_get_noresize(env, FLAG_RENEW, &env->txn.ro);
+ }
+ if (ret != MDB_SUCCESS) {
+ return lmdb_error(ret);
+ }
+ env->txn.ro_active = true;
+ *txn = env->txn.ro;
+ kr_assert(*txn);
+ return kr_ok();
+}
+
+static int cdb_commit(kr_cdb_pt db, struct kr_cdb_stats *stats)
+{
+ struct lmdb_env *env = db2env(db);
+ int ret = kr_ok();
+ if (env->txn.rw) {
+ if (stats) stats->commit++;
+ ret = lmdb_error(mdb_txn_commit(env->txn.rw));
+ env->txn.rw = NULL; /* the transaction got freed even in case of errors */
+ } else if (env->txn.ro && env->txn.ro_active) {
+ mdb_txn_reset(env->txn.ro);
+ env->txn.ro_active = false;
+ env->txn.ro_curs_active = false;
+ }
+ return ret;
+}
+
+/** Obtain a read-only cursor (and a read-only transaction). */
+static int txn_curs_get(struct lmdb_env *env, MDB_cursor **curs, struct kr_cdb_stats *stats)
+{
+ if (kr_fails_assert(env && curs))
+ return kr_error(EINVAL);
+ if (env->txn.ro_curs_active)
+ goto success;
+ /* Only in a read-only txn; TODO: it's a bit messy/coupled */
+ if (env->txn.rw) {
+ int ret = cdb_commit(env2db(env), stats);
+ if (ret) return ret;
+ }
+ MDB_txn *txn = NULL;
+ int ret = txn_get(env, &txn, true);
+ if (ret) return ret;
+
+ if (env->txn.ro_curs) {
+ ret = mdb_cursor_renew(txn, env->txn.ro_curs);
+ } else {
+ ret = mdb_cursor_open(txn, env->dbi, &env->txn.ro_curs);
+ }
+ if (ret) return lmdb_error(ret);
+ env->txn.ro_curs_active = true;
+success:
+ kr_assert(env->txn.ro_curs_active && env->txn.ro && env->txn.ro_active
+ && !env->txn.rw);
+ *curs = env->txn.ro_curs;
+ kr_assert(*curs);
+ return kr_ok();
+}
+
+static void txn_free_ro(struct lmdb_env *env)
+{
+ if (env->txn.ro_curs) {
+ mdb_cursor_close(env->txn.ro_curs);
+ env->txn.ro_curs = NULL;
+ }
+ if (env->txn.ro) {
+ mdb_txn_abort(env->txn.ro);
+ env->txn.ro = NULL;
+ }
+}
+
+/** Abort all transactions.
+ *
+ * This is useful after an error happens, as those (always?) require abortion.
+ * It's possible that _reset() would suffice and marking cursor inactive,
+ * but these errors should be rare so let's close them completely. */
+static void txn_abort(struct lmdb_env *env)
+{
+ txn_free_ro(env);
+ if (env->txn.rw) {
+ mdb_txn_abort(env->txn.rw);
+ env->txn.rw = NULL; /* the transaction got freed even in case of errors */
+ }
+}
+
+/*! \brief Close the database. */
+static void cdb_close_env(struct lmdb_env *env, struct kr_cdb_stats *stats)
+{
+ if (kr_fails_assert(env && env->env))
+ return;
+
+ /* Get rid of any transactions. */
+ txn_free_ro(env);
+ cdb_commit(env2db(env), stats);
+
+ mdb_env_sync(env->env, 1);
+ stats->close++;
+ mdb_dbi_close(env->env, env->dbi);
+ mdb_env_close(env->env);
+ free_const(env->mdb_data_path);
+ memset(env, 0, sizeof(*env));
+}
+
+/** We assume that *env is zeroed and we return it zeroed on errors. */
+static int cdb_open_env(struct lmdb_env *env, const char *path, const size_t mapsize,
+ struct kr_cdb_stats *stats)
+{
+ int ret = mkdir(path, LMDB_DIR_MODE);
+ if (ret && errno != EEXIST) return kr_error(errno);
+
+ stats->open++;
+ ret = mdb_env_create(&env->env);
+ if (ret != MDB_SUCCESS) return lmdb_error(ret);
+
+ env->mdb_data_path = kr_absolutize_path(path, "data.mdb");
+ if (!env->mdb_data_path) {
+ ret = ENOMEM;
+ goto error_sys;
+ }
+
+ /* Set map size, rounded to page size. */
+ errno = 0;
+ const long pagesize = sysconf(_SC_PAGESIZE);
+ if (errno) {
+ ret = errno;
+ goto error_sys;
+ }
+
+ const bool size_requested = mapsize;
+ if (size_requested) {
+ env->mapsize = (mapsize / pagesize) * pagesize;
+ ret = mdb_env_set_mapsize(env->env, env->mapsize);
+ if (ret != MDB_SUCCESS) goto error_mdb;
+ }
+
+ /* Cache doesn't require durability, we can be
+ * loose with the requirements as a tradeoff for speed. */
+ const unsigned flags = MDB_WRITEMAP | MDB_MAPASYNC | MDB_NOTLS;
+ ret = mdb_env_open(env->env, path, flags, LMDB_FILE_MODE);
+ if (ret != MDB_SUCCESS) goto error_mdb;
+
+ mdb_filehandle_t fd = -1;
+ ret = mdb_env_get_fd(env->env, &fd);
+ if (ret != MDB_SUCCESS) goto error_mdb;
+
+ struct stat st;
+ if (fstat(fd, &st)) {
+ ret = errno;
+ goto error_sys;
+ }
+ env->st_dev = st.st_dev;
+ env->st_ino = st.st_ino;
+ env->st_size = st.st_size;
+
+ /* Get the real mapsize. Shrinking can be restricted, etc.
+ * Unfortunately this is only reliable when not setting the size explicitly. */
+ if (!size_requested) {
+ ret = refresh_mapsize(env);
+ if (ret) goto error_sys;
+ }
+
+ /* Open the database. */
+ MDB_txn *txn = NULL;
+ ret = mdb_txn_begin(env->env, NULL, 0, &txn);
+ if (ret != MDB_SUCCESS) goto error_mdb;
+
+ ret = mdb_dbi_open(txn, NULL, 0, &env->dbi);
+ if (ret != MDB_SUCCESS) {
+ mdb_txn_abort(txn);
+ goto error_mdb;
+ }
+
+#if !defined(__MACOSX__) && !(defined(__APPLE__) && defined(__MACH__))
+ if (size_requested) {
+ ret = posix_fallocate(fd, 0, MAX(env->mapsize, env->st_size));
+ } else {
+ ret = 0;
+ }
+ if (ret == EINVAL || ret == EOPNOTSUPP) {
+ /* POSIX says this can happen when the feature isn't supported by the FS.
+ * We haven't seen this happen on Linux+glibc but it was reported on
+ * Linux+musl and FreeBSD. */
+ kr_log_info(CACHE, "space pre-allocation failed and ignored; "
+ "your (file)system probably doesn't support it.\n");
+ } else if (ret != 0) {
+ mdb_txn_abort(txn);
+ goto error_sys;
+ }
+#endif
+
+ stats->commit++;
+ ret = mdb_txn_commit(txn);
+ if (ret != MDB_SUCCESS) goto error_mdb;
+
+ /* Stale RO transactions could have been left behind by a cashing process
+ * (e.g. one whose termination lead to spawning the current one).
+ * According to docs they might hold onto some space until we clear them. */
+ clear_stale_readers(env);
+
+ return kr_ok();
+
+error_mdb:
+ ret = lmdb_error(ret);
+error_sys:
+ free_const(env->mdb_data_path);
+ stats->close++;
+ mdb_env_close(env->env);
+ memset(env, 0, sizeof(*env));
+ return kr_error(ret);
+}
+
+static int cdb_init(kr_cdb_pt *db, struct kr_cdb_stats *stats,
+ struct kr_cdb_opts *opts, knot_mm_t *pool)
+{
+ if (!db || !stats || !opts) {
+ return kr_error(EINVAL);
+ }
+
+ /* Open the database. */
+ struct lmdb_env *env = calloc(1, sizeof(*env));
+ if (!env) {
+ return kr_error(ENOMEM);
+ }
+ int ret = cdb_open_env(env, opts->path, opts->maxsize, stats);
+ if (ret != 0) {
+ free(env);
+ return ret;
+ }
+
+ *db = env2db(env);
+ return 0;
+}
+
+static void cdb_deinit(kr_cdb_pt db, struct kr_cdb_stats *stats)
+{
+ cdb_close_env(db2env(db), stats);
+ free(db);
+}
+
+static int cdb_count(kr_cdb_pt db, struct kr_cdb_stats *stats)
+{
+ struct lmdb_env *env = db2env(db);
+ MDB_txn *txn = NULL;
+ int ret = txn_get(env, &txn, true);
+ if (ret != 0) {
+ return ret;
+ }
+
+ MDB_stat stat;
+ stats->count++;
+ ret = mdb_stat(txn, env->dbi, &stat);
+
+ if (ret == MDB_SUCCESS) {
+ return stat.ms_entries;
+ } else {
+ txn_abort(env);
+ return lmdb_error(ret);
+ }
+}
+
+static int reopen_env(struct lmdb_env *env, struct kr_cdb_stats *stats, const size_t mapsize)
+{
+ /* Keep copy as it points to current handle internals. */
+ const char *path;
+ int ret = mdb_env_get_path(env->env, &path);
+ if (ret != MDB_SUCCESS) {
+ return lmdb_error(ret);
+ }
+ auto_free char *path_copy = strdup(path);
+ cdb_close_env(env, stats);
+ return cdb_open_env(env, path_copy, mapsize, stats);
+}
+
+static int cdb_check_health(kr_cdb_pt db, struct kr_cdb_stats *stats)
+{
+ struct lmdb_env *env = db2env(db);
+
+ struct stat st;
+ if (stat(env->mdb_data_path, &st)) {
+ int ret = errno;
+ return kr_error(ret);
+ }
+
+ if (st.st_dev != env->st_dev || st.st_ino != env->st_ino) {
+ kr_log_debug(CACHE, "cache file has been replaced, reopening\n");
+ int ret = reopen_env(env, stats, 0); // we accept mapsize from the new file
+ return ret == 0 ? 1 : ret;
+ }
+
+ /* Cache check through file size works OK without reopening,
+ * contrary to methods based on mdb_env_info(). */
+ if (st.st_size == env->st_size)
+ return kr_ok();
+ kr_log_info(CACHE, "detected size change (by another instance?) of file '%s'"
+ ": file size %zu -> file size %zu\n",
+ env->mdb_data_path, (size_t)env->st_size, (size_t)st.st_size);
+ env->st_size = st.st_size; // avoid retrying in cycle even if we fail
+ return refresh_mapsize(env);
+}
+
+/** Obtain exclusive (advisory) lock by creating a file, returning FD or negative kr_error().
+ * The lock is auto-released by OS in case the process finishes in any way (file remains). */
+static int lockfile_get(const char *path)
+{
+ if (kr_fails_assert(path))
+ return kr_error(EINVAL);
+ const int fd = open(path, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
+ if (fd < 0)
+ return kr_error(errno);
+
+ struct flock lock_info;
+ memset(&lock_info, 0, sizeof(lock_info));
+ lock_info.l_type = F_WRLCK;
+ lock_info.l_whence = SEEK_SET;
+ lock_info.l_start = 0;
+ lock_info.l_len = 1; // it's OK for locks to extend beyond the end of the file
+ int err;
+ do {
+ err = fcntl(fd, F_SETLK, &lock_info);
+ } while (err == -1 && errno == EINTR);
+ if (err) {
+ close(fd);
+ return kr_error(errno);
+ }
+ return fd;
+}
+
+/** Release and remove lockfile created by lockfile_get(). Return kr_error(). */
+static int lockfile_release(int fd)
+{
+ if (kr_fails_assert(fd > 0)) // fd == 0 is surely a mistake, in our case at least
+ return kr_error(EINVAL);
+ if (close(fd)) {
+ return kr_error(errno);
+ } else {
+ return kr_ok();
+ }
+}
+
+static int cdb_clear(kr_cdb_pt db, struct kr_cdb_stats *stats)
+{
+ struct lmdb_env *env = db2env(db);
+ stats->clear++;
+ /* First try mdb_drop() to clear the DB; this may fail with ENOSPC. */
+ {
+ MDB_txn *txn = NULL;
+ int ret = txn_get(env, &txn, false);
+ if (ret == kr_ok()) {
+ ret = lmdb_error(mdb_drop(txn, env->dbi, 0));
+ if (ret == kr_ok()) {
+ ret = cdb_commit(db, stats);
+ }
+ if (ret == kr_ok()) {
+ return ret;
+ }
+ }
+ kr_log_info(CACHE, "clearing error, falling back\n");
+ }
+ /* Fallback: we'll remove the database files and reopen.
+ * Other instances can continue to use the removed lmdb,
+ * though it's best for them to reopen soon. */
+
+ /* We are about to switch to a different file, so end all txns, to be sure. */
+ txn_free_ro(env);
+ (void) cdb_commit(db, stats);
+
+ const char *path = NULL;
+ int ret = mdb_env_get_path(env->env, &path);
+ if (ret != MDB_SUCCESS) {
+ return lmdb_error(ret);
+ }
+ auto_free char *mdb_lockfile = kr_strcatdup(2, path, "/lock.mdb");
+ auto_free char *lockfile = kr_strcatdup(2, path, "/krcachelock");
+ if (!mdb_lockfile || !lockfile) {
+ return kr_error(ENOMEM);
+ }
+
+ /* Find if we get a lock on lockfile. */
+ const int lockfile_fd = lockfile_get(lockfile);
+ if (lockfile_fd < 0) {
+ kr_log_error(CACHE, "clearing failed to get ./krcachelock (%s); retry later\n",
+ kr_strerror(lockfile_fd));
+ /* As we're out of space (almost certainly - mdb_drop didn't work),
+ * we will retry on the next failing write operation. */
+ return kr_error(EAGAIN);
+ }
+
+ /* We acquired lockfile. Now find whether *.mdb are what we have open now.
+ * If they are not we don't want to remove them; most likely they have been
+ * cleaned by another instance. */
+ ret = cdb_check_health(db, stats);
+ if (ret != 0) {
+ if (ret == 1) // file changed and reopened successfully
+ ret = kr_ok();
+ // else pass some other error
+ } else {
+ kr_log_debug(CACHE, "clear: identical files, unlinking\n");
+ // coverity[toctou]
+ unlink(env->mdb_data_path);
+ unlink(mdb_lockfile);
+ ret = reopen_env(env, stats, env->mapsize);
+ }
+
+ /* Environment updated, release lockfile. */
+ int lrerr = lockfile_release(lockfile_fd);
+ if (lrerr) {
+ kr_log_error(CACHE, "failed to release ./krcachelock: %s\n",
+ kr_strerror(lrerr));
+ }
+ return ret;
+}
+
+static int cdb_readv(kr_cdb_pt db, struct kr_cdb_stats *stats,
+ const knot_db_val_t *key, knot_db_val_t *val, int maxcount)
+{
+ struct lmdb_env *env = db2env(db);
+ MDB_txn *txn = NULL;
+ int ret = txn_get(env, &txn, true);
+ if (ret) {
+ return ret;
+ }
+
+ for (int i = 0; i < maxcount; ++i) {
+ /* Convert key structs */
+ MDB_val _key = val_knot2mdb(key[i]);
+ MDB_val _val = val_knot2mdb(val[i]);
+ stats->read++;
+ ret = mdb_get(txn, env->dbi, &_key, &_val);
+ if (ret != MDB_SUCCESS) {
+ if (ret == MDB_NOTFOUND) {
+ stats->read_miss++;
+ } else {
+ txn_abort(env);
+ }
+ ret = lmdb_error(ret);
+ if (ret == kr_error(ENOSPC)) {
+ /* we're likely to be forced to cache clear anyway */
+ ret = kr_error(ENOENT);
+ }
+ return ret;
+ }
+ /* Update the result. */
+ val[i] = val_mdb2knot(_val);
+ }
+ return kr_ok();
+}
+
+static int cdb_write(struct lmdb_env *env, MDB_txn **txn, const knot_db_val_t *key,
+ knot_db_val_t *val, unsigned flags,
+ struct kr_cdb_stats *stats)
+{
+ /* Convert key structs and write */
+ MDB_val _key = val_knot2mdb(*key);
+ MDB_val _val = val_knot2mdb(*val);
+ stats->write++;
+ int ret = mdb_put(*txn, env->dbi, &_key, &_val, flags);
+
+ /* We don't try to recover from MDB_TXN_FULL. */
+ if (ret != MDB_SUCCESS) {
+ txn_abort(env);
+ return lmdb_error(ret);
+ }
+
+ /* Update the result. */
+ val->data = _val.mv_data;
+ val->len = _val.mv_size;
+ return kr_ok();
+}
+
+static int cdb_writev(kr_cdb_pt db, struct kr_cdb_stats *stats,
+ const knot_db_val_t *key, knot_db_val_t *val, int maxcount)
+{
+ struct lmdb_env *env = db2env(db);
+ MDB_txn *txn = NULL;
+ int ret = txn_get(env, &txn, false);
+
+ for (int i = 0; ret == kr_ok() && i < maxcount; ++i) {
+ /* This is LMDB specific optimisation,
+ * if caller specifies value with NULL data and non-zero length,
+ * LMDB will preallocate the entry for caller and leave write
+ * transaction open, caller is responsible for syncing thus committing transaction.
+ */
+ unsigned mdb_flags = 0;
+ if (val[i].len > 0 && val[i].data == NULL) {
+ mdb_flags |= MDB_RESERVE;
+ }
+ ret = cdb_write(env, &txn, &key[i], &val[i], mdb_flags, stats);
+ }
+
+ return ret;
+}
+
+static int cdb_remove(kr_cdb_pt db, struct kr_cdb_stats *stats,
+ knot_db_val_t keys[], int maxcount)
+{
+ struct lmdb_env *env = db2env(db);
+ MDB_txn *txn = NULL;
+ int ret = txn_get(env, &txn, false);
+ int deleted = 0;
+
+ for (int i = 0; ret == kr_ok() && i < maxcount; ++i) {
+ MDB_val _key = val_knot2mdb(keys[i]);
+ MDB_val val = { 0, NULL };
+ stats->remove++;
+ ret = lmdb_error(mdb_del(txn, env->dbi, &_key, &val));
+ if (ret == kr_ok())
+ deleted++;
+ else if (ret == KNOT_ENOENT) {
+ stats->remove_miss++;
+ ret = kr_ok(); /* skip over non-existing entries */
+ } else {
+ txn_abort(env);
+ break;
+ }
+ }
+
+ return ret < 0 ? ret : deleted;
+}
+
+static int cdb_match(kr_cdb_pt db, struct kr_cdb_stats *stats,
+ knot_db_val_t *key, knot_db_val_t keyval[][2], int maxcount)
+{
+ struct lmdb_env *env = db2env(db);
+ MDB_txn *txn = NULL;
+ int ret = txn_get(env, &txn, true);
+ if (ret != 0) {
+ return ret;
+ }
+
+ /* LATER(optim.): use txn_curs_get() instead, to save resources. */
+ MDB_cursor *cur = NULL;
+ ret = mdb_cursor_open(txn, env->dbi, &cur);
+ if (ret != 0) {
+ txn_abort(env);
+ return lmdb_error(ret);
+ }
+
+ MDB_val cur_key = val_knot2mdb(*key);
+ MDB_val cur_val = { 0, NULL };
+ stats->match++;
+ ret = mdb_cursor_get(cur, &cur_key, &cur_val, MDB_SET_RANGE);
+ if (ret != MDB_SUCCESS) {
+ mdb_cursor_close(cur);
+ if (ret != MDB_NOTFOUND) {
+ txn_abort(env);
+ }
+ return lmdb_error(ret);
+ }
+
+ int results = 0;
+ while (ret == MDB_SUCCESS) {
+ /* Retrieve current key and compare with prefix */
+ if (cur_key.mv_size < key->len || memcmp(cur_key.mv_data, key->data, key->len) != 0) {
+ break;
+ }
+ /* Add to result set */
+ if (results < maxcount) {
+ keyval[results][0] = val_mdb2knot(cur_key);
+ keyval[results][1] = val_mdb2knot(cur_val);
+ ++results;
+ } else {
+ break;
+ }
+ stats->match++;
+ ret = mdb_cursor_get(cur, &cur_key, &cur_val, MDB_NEXT);
+ }
+
+ mdb_cursor_close(cur);
+ if (ret != MDB_SUCCESS && ret != MDB_NOTFOUND) {
+ txn_abort(env);
+ return lmdb_error(ret);
+ } else if (results == 0) {
+ stats->match_miss++;
+ }
+ return results;
+}
+
+
+static int cdb_read_leq(kr_cdb_pt db, struct kr_cdb_stats *stats,
+ knot_db_val_t *key, knot_db_val_t *val)
+{
+ if (kr_fails_assert(db && key && key->data && val))
+ return kr_error(EINVAL);
+ struct lmdb_env *env = db2env(db);
+ MDB_cursor *curs = NULL;
+ int ret = txn_curs_get(env, &curs, stats);
+ if (ret) return ret;
+
+ MDB_val key2_m = val_knot2mdb(*key);
+ MDB_val val2_m = { 0, NULL };
+ stats->read_leq++;
+ ret = mdb_cursor_get(curs, &key2_m, &val2_m, MDB_SET_RANGE);
+ if (ret) goto failure;
+ /* test for equality //:unlikely */
+ if (key2_m.mv_size == key->len
+ && memcmp(key2_m.mv_data, key->data, key->len) == 0) {
+ ret = 0; /* equality */
+ goto success;
+ }
+ stats->read_leq_miss++;
+
+ /* we must be greater than key; do one step to smaller */
+ stats->read_leq++;
+ ret = mdb_cursor_get(curs, &key2_m, &val2_m, MDB_PREV);
+ if (ret) goto failure;
+ ret = 1;
+success:
+ /* finalize the output */
+ *key = val_mdb2knot(key2_m);
+ *val = val_mdb2knot(val2_m);
+ return ret;
+failure:
+ if (ret == MDB_NOTFOUND) {
+ stats->read_leq_miss++;
+ } else {
+ txn_abort(env);
+ }
+ return lmdb_error(ret);
+}
+
+static double cdb_usage_percent(kr_cdb_pt db)
+{
+ knot_db_t *kdb = kr_cdb_pt2knot_db_t(db);
+ const size_t db_size = knot_db_lmdb_get_mapsize(kdb);
+ const size_t db_usage_abs = knot_db_lmdb_get_usage(kdb);
+ const double db_usage = (double)db_usage_abs / db_size * 100.0;
+ free(kdb);
+ return db_usage;
+}
+
+static size_t cdb_get_maxsize(kr_cdb_pt db)
+{
+ return db2env(db)->mapsize;
+}
+
+/** Conversion between knot and lmdb structs. */
+knot_db_t *kr_cdb_pt2knot_db_t(kr_cdb_pt db)
+{
+ /* this is struct lmdb_env as in resolver/cdb_lmdb.c */
+ const struct lmdb_env *kres_db = db2env(db);
+ struct libknot_lmdb_env *libknot_db = malloc(sizeof(*libknot_db));
+ if (libknot_db != NULL) {
+ libknot_db->shared = false;
+ libknot_db->pool = NULL;
+ libknot_db->env = kres_db->env;
+ libknot_db->dbi = kres_db->dbi;
+ }
+ return libknot_db;
+}
+
+const struct kr_cdb_api *kr_cdb_lmdb(void)
+{
+ static const struct kr_cdb_api api = {
+ "lmdb",
+ cdb_init, cdb_deinit, cdb_count, cdb_clear, cdb_commit,
+ cdb_readv, cdb_writev, cdb_remove,
+ cdb_match,
+ cdb_read_leq,
+ cdb_usage_percent,
+ cdb_get_maxsize,
+ cdb_check_health,
+ };
+
+ return &api;
+}
diff --git a/lib/cache/cdb_lmdb.h b/lib/cache/cdb_lmdb.h
new file mode 100644
index 0000000..988fccf
--- /dev/null
+++ b/lib/cache/cdb_lmdb.h
@@ -0,0 +1,16 @@
+/* Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+*/
+
+#pragma once
+
+#include "lib/cache/cdb_api.h"
+#include "lib/defines.h"
+
+KR_EXPORT KR_CONST
+const struct kr_cdb_api *kr_cdb_lmdb(void);
+
+/** Create a pointer for knot_db_lmdb_api. You free() it to release it. */
+KR_EXPORT
+knot_db_t *kr_cdb_pt2knot_db_t(kr_cdb_pt db);
+
diff --git a/lib/cache/entry_list.c b/lib/cache/entry_list.c
new file mode 100644
index 0000000..4dced2f
--- /dev/null
+++ b/lib/cache/entry_list.c
@@ -0,0 +1,301 @@
+/* Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+/** @file
+ * Implementation of chaining in struct entry_h. Prototypes in ./impl.h
+ */
+
+#include "lib/cache/impl.h"
+#include "lib/utils.h"
+
+
+static int entry_h_len(knot_db_val_t val);
+
+
+void entry_list_memcpy(struct entry_apex *ea, entry_list_t list)
+{
+ if (kr_fails_assert(ea))
+ return;
+ memset(ea, 0, offsetof(struct entry_apex, data));
+ ea->has_ns = list[EL_NS ].len;
+ ea->has_cname = list[EL_CNAME ].len;
+ ea->has_dname = list[EL_DNAME ].len;
+ for (int i = 0; i < ENTRY_APEX_NSECS_CNT; ++i) {
+ ea->nsecs[i] = list[i].len == 0 ? 0 :
+ (list[i].len == 4 ? 1 : 3);
+ }
+ uint8_t *it = ea->data;
+ for (int i = 0; i < EL_LENGTH; ++i) {
+ if (list[i].data) {
+ memcpy(it, list[i].data, list[i].len);
+ /* LATER(optim.): coalesce consecutive writes? */
+ } else {
+ list[i].data = it;
+ }
+ it += to_even(list[i].len);
+ }
+}
+
+int entry_list_parse(const knot_db_val_t val, entry_list_t list)
+{
+ if (kr_fails_assert(val.data && val.len && list))
+ return kr_error(EINVAL);
+ /* Parse the apex itself (nsec parameters). */
+ const struct entry_apex *ea = entry_apex_consistent(val);
+ if (!ea) {
+ return kr_error(EILSEQ);
+ }
+ const uint8_t *it = ea->data,
+ *it_bound = knot_db_val_bound(val);
+ for (int i = 0; i < ENTRY_APEX_NSECS_CNT; ++i) {
+ if (it > it_bound) {
+ return kr_error(EILSEQ);
+ }
+ list[i].data = (void *)it;
+ switch (ea->nsecs[i]) {
+ case 0:
+ list[i].len = 0;
+ break;
+ case 1:
+ list[i].len = sizeof(uint32_t); /* just timestamp */
+ break;
+ case 3: { /* timestamp + NSEC3PARAM wire */
+ if (it + sizeof(uint32_t) + 4 > it_bound) {
+ return kr_error(EILSEQ);
+ }
+ list[i].len = sizeof(uint32_t)
+ + nsec_p_rdlen(it + sizeof(uint32_t));
+ break;
+ }
+ default:
+ return kr_error(EILSEQ);
+ };
+ it += to_even(list[i].len);
+ }
+ /* Parse every entry_h. */
+ for (int i = ENTRY_APEX_NSECS_CNT; i < EL_LENGTH; ++i) {
+ list[i].data = (void *)it;
+ bool has_type;
+ switch (i) {
+ case EL_NS: has_type = ea->has_ns; break;
+ case EL_CNAME: has_type = ea->has_cname; break;
+ case EL_DNAME: has_type = ea->has_dname; break;
+ default:
+ kr_assert(!EINVAL);
+ return kr_error(EINVAL); /* something very bad */
+ }
+ if (!has_type) {
+ list[i].len = 0;
+ continue;
+ }
+ if (kr_fails_assert(it < it_bound))
+ return kr_error(EILSEQ);
+ const int len = entry_h_len(
+ (knot_db_val_t){ .data = (void *)it, .len = it_bound - it });
+ if (kr_fails_assert(len >= 0))
+ return kr_error(len);
+ list[i].len = len;
+ it += to_even(len);
+ }
+ if (kr_fails_assert(it == it_bound)) /* better not use it; might be "damaged" */
+ return kr_error(EILSEQ);
+ return kr_ok();
+}
+
+/** Given a valid entry header, find its length (i.e. offset of the next entry).
+ * \param val The beginning of the data and the bound (read only).
+ */
+static int entry_h_len(const knot_db_val_t val)
+{
+ const bool ok = val.data && ((ssize_t)val.len) > 0;
+ if (!ok) return kr_error(EINVAL);
+ const struct entry_h *eh = val.data;
+ const uint8_t *d = eh->data; /* iterates over the data in entry */
+ const uint8_t *data_bound = knot_db_val_bound(val);
+ if (d >= data_bound) return kr_error(EILSEQ);
+ if (!eh->is_packet) { /* Positive RRset + its RRsig set (may be empty). */
+ int sets = 2;
+ while (sets-- > 0) {
+ d += KR_CACHE_RR_COUNT_SIZE + rdataset_dematerialized_size(d, NULL);
+ if (kr_fails_assert(d <= data_bound))
+ return kr_error(EILSEQ);
+ }
+ } else { /* A "packet" (opaque ATM). */
+ uint16_t len;
+ if (d + sizeof(len) > data_bound) return kr_error(EILSEQ);
+ memcpy(&len, d, sizeof(len));
+ d += 2 + to_even(len);
+ }
+ if (kr_fails_assert(d <= data_bound))
+ return kr_error(EILSEQ);
+ return d - (uint8_t *)val.data;
+}
+
+struct entry_apex * entry_apex_consistent(knot_db_val_t val)
+{
+ //XXX: check lengths, etc.
+ return val.data;
+}
+
+/* See the header file. */
+int entry_h_seek(knot_db_val_t *val, uint16_t type)
+{
+ int i = -1;
+ switch (type) {
+ case KNOT_RRTYPE_NS: i = EL_NS; break;
+ case KNOT_RRTYPE_CNAME: i = EL_CNAME; break;
+ case KNOT_RRTYPE_DNAME: i = EL_DNAME; break;
+ default: return kr_ok();
+ }
+
+ entry_list_t el;
+ int ret = entry_list_parse(*val, el);
+ if (ret) return ret;
+ *val = el[i];
+ return val->len ? kr_ok() : kr_error(ENOENT);
+}
+
+static int cache_write_or_clear(struct kr_cache *cache, const knot_db_val_t *key,
+ knot_db_val_t *val, const struct kr_query *qry)
+{
+ static uint64_t ignoring_errors_until = 0; /// zero or a timestamp
+ int ret = cache_op(cache, write, key, val, 1);
+ if (!ret) {
+ ignoring_errors_until = 0;
+ return kr_ok();
+ }
+ VERBOSE_MSG(qry, "=> failed backend write, ret = %d\n", ret);
+
+ if (ret == kr_error(ENOSPC) && cache->api->usage_percent(cache->db) > 90) {
+ // Cache seems overfull. Maybe kres-cache-gc service doesn't work.
+ goto recovery;
+ }
+
+ /* If we get ENOSPC with usage < 90% (especially just above 80% when GC fires),
+ * it most likely isn't real overfull state but some LMDB bug related
+ * to transactions. Upstream seems unlikely to address it:
+ https://lists.openldap.org/hyperkitty/list/openldap-technical@openldap.org/thread/QHOTE2Y3WZ6E7J27OOKI44P344ETUOSF/
+ *
+ * In real life we see all processes getting a LMDB failure
+ * but it should recover after the transactions get reopened.
+ *
+ * Fortunately the kresd cache can afford to be slightly lossy,
+ * so we ignore this and other errors for a short while.
+ */
+ const uint64_t now = kr_now();
+ if (!ignoring_errors_until) { // First error after a success.
+ kr_log_info(CACHE, "LMDB refusing writes (ignored for 5-9s): %s\n",
+ kr_strerror(ret));
+ ignoring_errors_until = now + 5000 + kr_rand_bytes(2)/16;
+ return kr_error(ret);
+ }
+ if (now < ignoring_errors_until)
+ return kr_error(ret);
+ // We've lost patience with cache writes not working continuously.
+
+recovery: // Try to recover by clearing cache.
+ ret = kr_cache_clear(cache);
+ switch (ret) {
+ default:
+ kr_log_crit(CACHE, "CRITICAL: clearing cache failed: %s; fatal error, aborting\n",
+ kr_strerror(ret));
+ abort();
+ case 0:
+ kr_log_info(CACHE, "stuck cache cleared\n");
+ ignoring_errors_until = 0;
+ case -EAGAIN: // fall-through; krcachelock race -> retry later
+ return kr_error(ENOSPC);
+ }
+}
+
+
+/* See the header file. */
+int entry_h_splice(
+ knot_db_val_t *val_new_entry, uint8_t rank,
+ const knot_db_val_t key, const uint16_t ktype, const uint16_t type,
+ const knot_dname_t *owner/*log only*/,
+ const struct kr_query *qry, struct kr_cache *cache, uint32_t timestamp)
+{
+ //TODO: another review, perhaps including the API
+ if (kr_fails_assert(val_new_entry && val_new_entry->len > 0))
+ return kr_error(EINVAL);
+
+ int i_type;
+ switch (type) {
+ case KNOT_RRTYPE_NS: i_type = EL_NS; break;
+ case KNOT_RRTYPE_CNAME: i_type = EL_CNAME; break;
+ case KNOT_RRTYPE_DNAME: i_type = EL_DNAME; break;
+ default: i_type = 0;
+ }
+
+ /* Get eh_orig (original entry), and also el list if multi-entry case. */
+ const struct entry_h *eh_orig = NULL;
+ entry_list_t el;
+ int ret = -1;
+ if (!kr_rank_test(rank, KR_RANK_SECURE) || ktype == KNOT_RRTYPE_NS) {
+ knot_db_val_t val;
+ ret = cache_op(cache, read, &key, &val, 1);
+ if (i_type) {
+ if (!ret) ret = entry_list_parse(val, el);
+ if (ret) memset(el, 0, sizeof(el));
+ val = el[i_type];
+ }
+ /* val is on the entry, in either case (or error) */
+ if (!ret) {
+ eh_orig = entry_h_consistent_E(val, type);
+ }
+ } else {
+ /* We want to fully overwrite the entry, so don't even read it. */
+ memset(el, 0, sizeof(el));
+ }
+
+ if (!kr_rank_test(rank, KR_RANK_SECURE) && eh_orig) {
+ /* If equal rank was accepted, spoofing a *single* answer would be
+ * enough to e.g. override NS record in AUTHORITY section.
+ * This way they would have to hit the first answer
+ * (whenever TTL nears expiration).
+ * Stale-serving is NOT considered, but TTL 1 would be considered
+ * as expiring anyway, ... */
+ int32_t old_ttl = get_new_ttl(eh_orig, qry, NULL, 0, timestamp);
+ if (old_ttl > 0 && !is_expiring(eh_orig->ttl, old_ttl)
+ && rank <= eh_orig->rank) {
+ WITH_VERBOSE(qry) {
+ auto_free char *type_str = kr_rrtype_text(type),
+ *owner_str = kr_dname_text(owner);
+ VERBOSE_MSG(qry, "=> not overwriting %s %s\n",
+ type_str, owner_str);
+ }
+ return kr_error(EEXIST);
+ }
+ }
+
+ if (!i_type) {
+ /* The non-list types are trivial now. */
+ return cache_write_or_clear(cache, &key, val_new_entry, qry);
+ }
+ /* Now we're in trouble. In some cases, parts of data to be written
+ * is an lmdb entry that may be invalidated by our write request.
+ * (lmdb does even in-place updates!) Therefore we copy all into a buffer.
+ * LATER(optim.): do this only when necessary, or perhaps another approach.
+ * This is also complicated by the fact that the val_new_entry part
+ * is to be written *afterwards* by the caller.
+ */
+ el[i_type] = (knot_db_val_t){
+ .len = val_new_entry->len,
+ .data = NULL, /* perhaps unclear in the entry_h_splice() API */
+ };
+ knot_db_val_t val = {
+ .len = entry_list_serial_size(el),
+ .data = NULL,
+ };
+ uint8_t buf[val.len];
+ entry_list_memcpy((struct entry_apex *)buf, el);
+ ret = cache_write_or_clear(cache, &key, &val, qry);
+ if (ret) return kr_error(ret);
+ memcpy(val.data, buf, val.len); /* we also copy the "empty" space, but well... */
+ val_new_entry->data = (uint8_t *)val.data
+ + ((uint8_t *)el[i_type].data - buf);
+ return kr_ok();
+}
+
diff --git a/lib/cache/entry_pkt.c b/lib/cache/entry_pkt.c
new file mode 100644
index 0000000..884bfaa
--- /dev/null
+++ b/lib/cache/entry_pkt.c
@@ -0,0 +1,206 @@
+/* Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+/** @file
+ * Implementation of packet-caching. Prototypes in ./impl.h
+ *
+ * The packet is stashed in entry_h::data as uint16_t length + full packet wire format.
+ */
+
+#include "lib/utils.h"
+#include "lib/layer/iterate.h" /* kr_response_classify */
+#include "lib/cache/impl.h"
+
+
+/** Compute TTL for a packet. It's minimum TTL or zero. (You can apply limits.) */
+KR_EXPORT
+uint32_t packet_ttl(const knot_pkt_t *pkt)
+{
+ bool has_ttl = false;
+ uint32_t ttl = TTL_MAX_MAX;
+ for (knot_section_t i = KNOT_ANSWER; i <= KNOT_ADDITIONAL; ++i) {
+ const knot_pktsection_t *sec = knot_pkt_section(pkt, i);
+ for (unsigned k = 0; k < sec->count; ++k) {
+ const knot_rrset_t *rr = knot_pkt_rr(sec, k);
+ ttl = MIN(ttl, rr->ttl);
+ has_ttl = true;
+ }
+ }
+ return has_ttl ? ttl : 0;
+}
+
+
+void stash_pkt(const knot_pkt_t *pkt, const struct kr_query *qry,
+ const struct kr_request *req, const bool needs_pkt)
+{
+ /* In some cases, stash also the packet. */
+ const bool is_negative = kr_response_classify(pkt)
+ & (PKT_NODATA|PKT_NXDOMAIN);
+ const struct kr_qflags * const qf = &qry->flags;
+ const bool want_negative = qf->DNSSEC_INSECURE || !qf->DNSSEC_WANT;
+ const bool want_pkt = qf->DNSSEC_BOGUS /*< useful for +cd answers */
+ || (is_negative && want_negative) || needs_pkt;
+
+ if (!want_pkt || !knot_wire_get_aa(pkt->wire)
+ || pkt->parsed != pkt->size /*< malformed packet; still can't detect KNOT_EFEWDATA */
+ ) {
+ return;
+ }
+
+ /* Compute rank. If cd bit is set or we got answer via non-validated
+ * forwarding, make the rank bad; otherwise it depends on flags.
+ * TODO: probably make validator attempt validation even with +cd. */
+ uint8_t rank = KR_RANK_AUTH;
+ const bool risky_vldr = is_negative && qf->FORWARD && qf->CNAME;
+ /* ^^ CNAME'ed NXDOMAIN answer in forwarding mode can contain
+ * unvalidated records; original commit: d6e22f476. */
+ if (knot_wire_get_cd(req->qsource.packet->wire) || qf->STUB || risky_vldr) {
+ kr_rank_set(&rank, KR_RANK_OMIT);
+ } else {
+ if (qf->DNSSEC_BOGUS) {
+ kr_rank_set(&rank, KR_RANK_BOGUS);
+ } else if (qf->DNSSEC_INSECURE) {
+ kr_rank_set(&rank, KR_RANK_INSECURE);
+ } else if (!qf->DNSSEC_WANT) {
+ /* no TAs at all, leave _RANK_AUTH */
+ } else if (needs_pkt) {
+ /* All bad cases should be filtered above,
+ * at least the same way as pktcache in kresd 1.5.x. */
+ kr_rank_set(&rank, KR_RANK_SECURE);
+ } else kr_assert(false);
+ }
+
+ const uint16_t pkt_type = knot_pkt_qtype(pkt);
+ const knot_dname_t *owner = knot_pkt_qname(pkt); /* qname can't be compressed */
+
+ // LATER: nothing exists under NXDOMAIN. Implement that (optionally)?
+#if 0
+ if (knot_wire_get_rcode(pkt->wire) == KNOT_RCODE_NXDOMAIN
+ /* && !qf->DNSSEC_INSECURE */ ) {
+ pkt_type = KNOT_RRTYPE_NS;
+ }
+#endif
+
+ /* Construct the key under which the pkt will be stored. */
+ struct key k_storage, *k = &k_storage;
+ knot_db_val_t key;
+ int ret = kr_dname_lf(k->buf, owner, false);
+ if (ret) {
+ /* A server might (incorrectly) reply with QDCOUNT=0. */
+ kr_assert(owner == NULL);
+ return;
+ }
+ key = key_exact_type_maypkt(k, pkt_type);
+
+ /* For now we stash the full packet byte-exactly as it came from upstream. */
+ const uint16_t pkt_size = pkt->size;
+ knot_db_val_t val_new_entry = {
+ .data = NULL,
+ .len = offsetof(struct entry_h, data) + sizeof(pkt_size) + pkt->size,
+ };
+ /* Prepare raw memory for the new entry and fill it. */
+ struct kr_cache *cache = &req->ctx->cache;
+ ret = entry_h_splice(&val_new_entry, rank, key, k->type, pkt_type,
+ owner, qry, cache, qry->timestamp.tv_sec);
+ if (ret || kr_fails_assert(val_new_entry.data)) return; /* some aren't really errors */
+ struct entry_h *eh = val_new_entry.data;
+ memset(eh, 0, offsetof(struct entry_h, data));
+ eh->time = qry->timestamp.tv_sec;
+ eh->ttl = MAX(MIN(packet_ttl(pkt), cache->ttl_max), cache->ttl_min);
+ eh->rank = rank;
+ eh->is_packet = true;
+ eh->has_optout = qf->DNSSEC_OPTOUT;
+ memcpy(eh->data, &pkt_size, sizeof(pkt_size));
+ memcpy(eh->data + sizeof(pkt_size), pkt->wire, pkt_size);
+
+ WITH_VERBOSE(qry) {
+ auto_free char *type_str = kr_rrtype_text(pkt_type),
+ *owner_str = kr_dname_text(owner);
+ VERBOSE_MSG(qry, "=> stashed packet: rank 0%.2o, TTL %d, "
+ "%s %s (%d B)\n",
+ eh->rank, eh->ttl,
+ type_str, owner_str, (int)val_new_entry.len);
+ }
+}
+
+
+int answer_from_pkt(kr_layer_t *ctx, knot_pkt_t *pkt, uint16_t type,
+ const struct entry_h *eh, const void *eh_bound, uint32_t new_ttl)
+{
+ struct kr_request *req = ctx->req;
+ struct kr_query *qry = req->current_query;
+
+ const uint16_t msgid = knot_wire_get_id(pkt->wire);
+
+ /* Ensure the wire buffer is large enough. Strategy: fit and at least double. */
+ uint16_t pkt_len;
+ memcpy(&pkt_len, eh->data, sizeof(pkt_len));
+ if (pkt_len > pkt->max_size) {
+ pkt->max_size = MIN(KNOT_WIRE_MAX_PKTSIZE,
+ MAX(pkt->max_size * 2, pkt_len));
+ mm_free(&ctx->req->pool, pkt->wire); /* no-op, but... */
+ pkt->wire = mm_alloc(&ctx->req->pool, pkt->max_size);
+ pkt->compr.wire = pkt->wire;
+ /* TODO: ^^ nicer way how to replace knot_pkt_t::wire ? */
+ }
+ kr_require(pkt->max_size >= pkt_len);
+
+ /* Copy answer and reparse it, but keep the original message id. */
+ knot_pkt_clear(pkt);
+ memcpy(pkt->wire, eh->data + 2, pkt_len);
+ pkt->size = pkt_len;
+ int ret = knot_pkt_parse(pkt, 0);
+ if (ret == KNOT_EFEWDATA || ret == KNOT_EMALF) {
+ return kr_error(ENOENT);
+ /* LATER(opt): try harder to avoid stashing such packets */
+ }
+ if (kr_fails_assert(ret == KNOT_EOK))
+ return kr_error(ret);
+ knot_wire_set_id(pkt->wire, msgid);
+
+ /* Add rank into the additional field. */
+ for (size_t i = 0; i < pkt->rrset_count; ++i) {
+ kr_assert(!pkt->rr[i].additional);
+ uint8_t *rr_rank = mm_alloc(&pkt->mm, sizeof(*rr_rank));
+ if (!rr_rank) {
+ return kr_error(ENOMEM);
+ }
+ *rr_rank = eh->rank;
+ pkt->rr[i].additional = rr_rank;
+ }
+
+ /* Adjust TTL in each record. */
+ const uint32_t drift = eh->ttl - new_ttl;
+ for (knot_section_t i = KNOT_ANSWER; i <= KNOT_ADDITIONAL; ++i) {
+ const knot_pktsection_t *sec = knot_pkt_section(pkt, i);
+ for (unsigned k = 0; k < sec->count; ++k) {
+ knot_rrset_t *rrs = // vv FIXME??
+ /*const-cast*/(knot_rrset_t *)knot_pkt_rr(sec, k);
+ /* We need to be careful: due to enforcing minimum TTL
+ * on packet, some records may be below that value.
+ * We keep those records at TTL 0. */
+ if (rrs->ttl >= drift) {
+ rrs->ttl -= drift;
+ } else {
+ rrs->ttl = 0;
+ }
+ }
+ }
+
+ /* Finishing touches. TODO: perhaps factor out */
+ struct kr_qflags * const qf = &qry->flags;
+ qf->EXPIRING = is_expiring(eh->ttl, new_ttl);
+ qf->CACHED = true;
+ qf->NO_MINIMIZE = true;
+ qf->DNSSEC_INSECURE = kr_rank_test(eh->rank, KR_RANK_INSECURE);
+ qf->DNSSEC_BOGUS = kr_rank_test(eh->rank, KR_RANK_BOGUS);
+ if (qf->DNSSEC_INSECURE || qf->DNSSEC_BOGUS) {
+ qf->DNSSEC_WANT = false;
+ }
+ qf->DNSSEC_OPTOUT = eh->has_optout;
+ VERBOSE_MSG(qry, "=> satisfied by exact packet: rank 0%.2o, new TTL %d\n",
+ eh->rank, new_ttl);
+ return kr_ok();
+}
+
diff --git a/lib/cache/entry_rr.c b/lib/cache/entry_rr.c
new file mode 100644
index 0000000..3239e7e
--- /dev/null
+++ b/lib/cache/entry_rr.c
@@ -0,0 +1,115 @@
+/* Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+/** @file
+ * Implementation of RRset (de)materialization, i.e. (de)serialization to storage
+ * format used in cache (some repeated fields are omitted). Prototypes in ./impl.h
+ */
+
+#include "lib/cache/impl.h"
+
+void rdataset_dematerialize(const knot_rdataset_t *rds, uint8_t * restrict data)
+{
+ /* FIXME: either give up on even alignment and thus direct usability
+ * of rdatasets as they are in lmdb, or align inside cdb_* functions
+ * (request sizes one byte longer and shift iff on an odd address). */
+ //if ((size_t)data & 1) VERBOSE_MSG(NULL, "dematerialize: odd address\n");
+ //const uint8_t *data0 = data;
+ kr_require(data);
+ const uint16_t rr_count = rds ? rds->count : 0;
+ memcpy(data, &rr_count, sizeof(rr_count));
+ data += sizeof(rr_count);
+ if (rr_count) {
+ memcpy(data, rds->rdata, rds->size);
+ data += rds->size;
+ }
+ //VERBOSE_MSG(NULL, "dematerialized to %d B\n", (int)(data - data0));
+ (void)data; // silence analyzers
+}
+
+/** Materialize a knot_rdataset_t from cache with given TTL.
+ * Return the number of bytes consumed or an error code.
+ */
+static int rdataset_materialize(knot_rdataset_t * restrict rds, const uint8_t * const data,
+ const uint8_t *data_bound, knot_mm_t *pool)
+{
+ if (kr_fails_assert(rds && data && data_bound && data_bound > data && !rds->rdata
+ /*&& !((size_t)data & 1)*/))
+ return kr_error(EINVAL);
+ kr_assert(pool); /* not required, but that's our current usage; guard leaks */
+ const uint8_t *d = data; /* iterates over the cache data */
+ /* First sum up the sizes for wire format length. */
+ /* TODO: we might overrun here already, but we need to trust cache anyway...*/
+ rds->size = rdataset_dematerialized_size(d, &rds->count);
+ d += KR_CACHE_RR_COUNT_SIZE;
+ if (d + rds->size > data_bound) {
+ VERBOSE_MSG(NULL, "materialize: EILSEQ!\n");
+ return kr_error(EILSEQ);
+ }
+ if (!rds->count) { /* avoid mm_alloc(pool, 0); etc. */
+ rds->rdata = NULL;
+ return d - data;
+ }
+ rds->rdata = mm_alloc(pool, rds->size);
+ if (!rds->rdata) {
+ return kr_error(ENOMEM);
+ }
+ memcpy(rds->rdata, d, rds->size);
+ d += rds->size;
+ //VERBOSE_MSG(NULL, "materialized from %d B\n", (int)(d - data));
+ return d - data;
+}
+
+int kr_cache_materialize(knot_rdataset_t *dst, const struct kr_cache_p *ref,
+ knot_mm_t *pool)
+{
+ struct entry_h *eh = ref->raw_data;
+ return rdataset_materialize(dst, eh->data, ref->raw_bound, pool);
+}
+
+
+int entry2answer(struct answer *ans, int id,
+ const struct entry_h *eh, const uint8_t *eh_bound,
+ const knot_dname_t *owner, uint16_t type, uint32_t new_ttl)
+{
+ /* We assume it's zeroed. Do basic sanity check. */
+ const bool not_ok = ans->rrsets[id].set.rr || ans->rrsets[id].sig_rds.rdata
+ || (type == KNOT_RRTYPE_NSEC && ans->nsec_p.raw)
+ || (type == KNOT_RRTYPE_NSEC3 && !ans->nsec_p.raw);
+ if (kr_fails_assert(!not_ok))
+ return kr_error(EINVAL);
+ /* Materialize the base RRset. */
+ knot_rrset_t *rr = ans->rrsets[id].set.rr
+ = knot_rrset_new(owner, type, KNOT_CLASS_IN, new_ttl, ans->mm);
+ if (kr_fails_assert(rr))
+ return kr_error(ENOMEM);
+ int ret = rdataset_materialize(&rr->rrs, eh->data, eh_bound, ans->mm);
+ if (kr_fails_assert(ret >= 0)) goto fail;
+ size_t data_off = ret;
+ ans->rrsets[id].set.rank = eh->rank;
+ ans->rrsets[id].set.expiring = is_expiring(eh->ttl, new_ttl);
+ /* Materialize the RRSIG RRset for the answer in (pseudo-)packet. */
+ bool want_rrsigs = true; /* LATER(optim.): might be omitted in some cases. */
+ if (want_rrsigs) {
+ ret = rdataset_materialize(&ans->rrsets[id].sig_rds, eh->data + data_off,
+ eh_bound, ans->mm);
+ if (kr_fails_assert(ret >= 0)) goto fail;
+ /* Sanity check: we consumed exactly all data. */
+ int unused_bytes = eh_bound - (uint8_t *)eh->data - data_off - ret;
+ if (kr_fails_assert(unused_bytes == 0)) {
+ kr_log_error(CACHE, "entry2answer ERROR: unused bytes: %d\n",
+ unused_bytes);
+ ret = kr_error(EILSEQ);
+ goto fail; /* to be on the safe side */
+ }
+ }
+ return kr_ok();
+fail:
+ /* Cleanup the item that we might've (partially) written to. */
+ knot_rrset_free(ans->rrsets[id].set.rr, ans->mm);
+ knot_rdataset_clear(&ans->rrsets[id].sig_rds, ans->mm);
+ memset(&ans->rrsets[id], 0, sizeof(ans->rrsets[id]));
+ return kr_error(ret);
+}
+
diff --git a/lib/cache/impl.h b/lib/cache/impl.h
new file mode 100644
index 0000000..305f36e
--- /dev/null
+++ b/lib/cache/impl.h
@@ -0,0 +1,439 @@
+/* Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+/** @file
+ * Header internal for cache implementation(s).
+ * Only LMDB works for now.
+ */
+#pragma once
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include <libdnssec/error.h>
+#include <libdnssec/nsec.h>
+#include <libknot/consts.h>
+#include <libknot/db/db.h>
+#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"
+
+/* Cache entry values - binary layout.
+ *
+ * It depends on type which is recognizable by the key.
+ * Code depending on the contents of the key is marked by CACHE_KEY_DEF.
+ *
+ * 'E' entry (exact hit):
+ * - ktype == NS: struct entry_apex - multiple types inside (NS and xNAME);
+ * - ktype != NS: struct entry_h
+ * * is_packet: uint16_t length, the rest is opaque and handled by ./entry_pkt.c
+ * * otherwise RRset + its RRSIG set (possibly empty).
+ * '1' or '3' entry (NSEC or NSEC3)
+ * - struct entry_h, contents is the same as for exact hit
+ * - flags don't make sense there
+ */
+
+struct entry_h {
+ uint32_t time; /**< The time of inception. */
+ uint32_t ttl; /**< TTL at inception moment. Assuming it fits into int32_t ATM. */
+ uint8_t rank : 6; /**< See enum kr_rank */
+ bool is_packet : 1; /**< Negative-answer packet for insecure/bogus name. */
+ bool has_optout : 1; /**< Only for packets; persisted DNSSEC_OPTOUT. */
+ uint8_t _pad; /**< We need even alignment for data now. */
+ uint8_t data[];
+/* Well, we don't really need packing or alignment changes,
+ * but due to LMDB the whole structure may not be stored at an aligned address,
+ * and we need compilers (for non-x86) to know it to avoid SIGBUS (test: UBSAN). */
+} __attribute__ ((packed,aligned(1)));
+struct entry_apex;
+
+/** Check basic consistency of entry_h for 'E' entries, not looking into ->data.
+ * (for is_packet the length of data is checked)
+ */
+KR_EXPORT
+struct entry_h * entry_h_consistent_E(knot_db_val_t data, uint16_t type);
+
+struct entry_apex * entry_apex_consistent(knot_db_val_t val);
+
+/** Consistency check, ATM common for NSEC and NSEC3. */
+static inline struct entry_h * entry_h_consistent_NSEC(knot_db_val_t data)
+{
+ /* ATM it's enough to just extend the checks for exact entries. */
+ const struct entry_h *eh = entry_h_consistent_E(data, KNOT_RRTYPE_NSEC);
+ bool ok = eh != NULL;
+ ok = ok && !eh->is_packet && !eh->has_optout;
+ return ok ? /*const-cast*/(struct entry_h *)eh : NULL;
+}
+
+static inline struct entry_h * entry_h_consistent(knot_db_val_t data, uint16_t type)
+{
+ switch (type) {
+ case KNOT_RRTYPE_NSEC:
+ case KNOT_RRTYPE_NSEC3:
+ return entry_h_consistent_NSEC(data);
+ default:
+ return entry_h_consistent_E(data, type);
+ }
+}
+
+/* nsec_p* - NSEC* chain parameters */
+
+static inline int nsec_p_rdlen(const uint8_t *rdata)
+{
+ //TODO: do we really need the zero case?
+ return rdata ? 5 + rdata[4] : 0; /* rfc5155 4.2 and 3.2. */
+}
+static const int NSEC_P_MAXLEN = sizeof(uint32_t) + 5 + 255; // TODO: remove??
+
+/** Hash of NSEC3 parameters, used as a tag to separate different chains for same zone. */
+typedef uint32_t nsec_p_hash_t;
+static inline nsec_p_hash_t nsec_p_mkHash(const uint8_t *nsec_p)
+{
+ kr_require(nsec_p && !(KNOT_NSEC3_FLAG_OPT_OUT & nsec_p[1]));
+ return hash((const char *)nsec_p, nsec_p_rdlen(nsec_p));
+}
+
+/** NSEC* parameters for the chain. */
+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! */
+};
+
+
+
+/** LATER(optim.): this is overshot, but struct key usage should be cheap ATM. */
+#define KR_CACHE_KEY_MAXLEN (KNOT_DNAME_MAXLEN + 100) /* CACHE_KEY_DEF */
+
+struct key {
+ const knot_dname_t *zname; /**< current zone name (points within qry->sname) */
+ uint8_t zlf_len; /**< length of current zone's lookup format */
+
+ /** Corresponding key type; e.g. NS for CNAME.
+ * Note: NSEC type is ambiguous (exact and range key). */
+ uint16_t type;
+ /** The key data start at buf+1, and buf[0] contains some length.
+ * For details see key_exact* and key_NSEC* functions. */
+ uint8_t buf[KR_CACHE_KEY_MAXLEN];
+ /* LATER(opt.): ^^ probably change the anchoring, so that kr_dname_lf()
+ * doesn't need to move data after knot_dname_lf(). */
+};
+
+static inline size_t key_nwz_off(const struct key *k)
+{
+ /* CACHE_KEY_DEF: zone name lf + 0 ('1' or '3').
+ * NSEC '1' case continues just with the name within zone. */
+ return k->zlf_len + 2;
+}
+static inline size_t key_nsec3_hash_off(const struct key *k)
+{
+ /* CACHE_KEY_DEF NSEC3: tag (nsec_p_hash_t) + 20 bytes NSEC3 name hash) */
+ return key_nwz_off(k) + sizeof(nsec_p_hash_t);
+}
+/** Hash is always SHA1; I see no plans to standardize anything else.
+ * https://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml#dnssec-nsec3-parameters-3
+ */
+static const int NSEC3_HASH_LEN = 20,
+ NSEC3_HASH_TXT_LEN = 32;
+
+/** Finish constructing string key for for exact search.
+ * It's assumed that kr_dname_lf(k->buf, owner, *) had been ran.
+ */
+knot_db_val_t key_exact_type_maypkt(struct key *k, uint16_t type);
+
+/** Like key_exact_type_maypkt but with extra checks if used for RRs only. */
+static inline knot_db_val_t key_exact_type(struct key *k, uint16_t type)
+{
+ switch (type) {
+ /* Sanity check: forbidden types represented in other way(s). */
+ case KNOT_RRTYPE_NSEC:
+ case KNOT_RRTYPE_NSEC3:
+ kr_assert(false);
+ return (knot_db_val_t){ NULL, 0 };
+ }
+ return key_exact_type_maypkt(k, type);
+}
+
+
+/* entry_h chaining; implementation in ./entry_list.c */
+
+enum { ENTRY_APEX_NSECS_CNT = 2 };
+
+/** Header of 'E' entry with ktype == NS. Inside is private to ./entry_list.c
+ *
+ * We store xNAME at NS type to lower the number of searches in closest_NS().
+ * CNAME is only considered for equal name, of course.
+ * We also store NSEC* parameters at NS type.
+ */
+struct entry_apex {
+ /* ENTRY_H_FLAGS */
+ bool has_ns : 1;
+ bool has_cname : 1;
+ bool has_dname : 1;
+
+ uint8_t pad_; /**< 1 byte + 2 bytes + x bytes would be weird; let's do 2+2+x. */
+
+ /** We have two slots for NSEC* parameters.
+ *
+ * This array describes how they're filled;
+ * values: 0: none, 1: NSEC, 3: NSEC3.
+ *
+ * Two slots are a compromise to smoothly handle normal rollovers
+ * (either changing NSEC3 parameters or between NSEC and NSEC3). */
+ int8_t nsecs[ENTRY_APEX_NSECS_CNT];
+ uint8_t data[];
+ /* XXX: if not first, stamp of last being the first?
+ * Purpose: save cache operations if rolled the algo/params long ago. */
+};
+
+/** Indices for decompressed entry_list_t. */
+enum EL {
+ EL_NS = ENTRY_APEX_NSECS_CNT,
+ EL_CNAME,
+ EL_DNAME,
+ EL_LENGTH
+};
+/** Decompressed entry_apex. It's an array of unparsed entry_h references.
+ * Note: arrays are passed "by reference" to functions (in C99). */
+typedef knot_db_val_t entry_list_t[EL_LENGTH];
+
+static inline uint16_t EL2RRTYPE(enum EL i)
+{
+ switch (i) {
+ case EL_NS: return KNOT_RRTYPE_NS;
+ case EL_CNAME: return KNOT_RRTYPE_CNAME;
+ case EL_DNAME: return KNOT_RRTYPE_DNAME;
+ default: kr_assert(false); return 0;
+ }
+}
+
+/** There may be multiple entries within, so rewind `val` to the one we want.
+ *
+ * ATM there are multiple types only for the NS ktype - it also accommodates xNAMEs.
+ * \note `val->len` represents the bound of the whole list, not of a single entry.
+ * \note in case of ENOENT, `val` is still rewound to the beginning of the next entry.
+ * \return error code
+ * TODO: maybe get rid of this API?
+ */
+int entry_h_seek(knot_db_val_t *val, uint16_t type);
+
+/** Prepare space to insert an entry.
+ *
+ * Some checks are performed (rank, TTL), the current entry in cache is copied
+ * with a hole ready for the new entry (old one of the same type is cut out).
+ *
+ * \param val_new_entry The only changing parameter; ->len is read, ->data written.
+ * \return error code
+ */
+int entry_h_splice(
+ knot_db_val_t *val_new_entry, uint8_t rank,
+ const knot_db_val_t key, const uint16_t ktype, const uint16_t type,
+ const knot_dname_t *owner/*log only*/,
+ const struct kr_query *qry, struct kr_cache *cache, uint32_t timestamp);
+
+/** Parse an entry_apex into individual items. @return error code. */
+KR_EXPORT int entry_list_parse(const knot_db_val_t val, entry_list_t list);
+
+static inline size_t to_even(size_t n)
+{
+ return n + (n & 1);
+}
+
+static inline int entry_list_serial_size(const entry_list_t list)
+{
+ int size = offsetof(struct entry_apex, data);
+ for (int i = 0; i < EL_LENGTH; ++i) {
+ size += to_even(list[i].len);
+ }
+ return size;
+}
+
+/** Fill contents of an entry_apex.
+ *
+ * @note NULL pointers are overwritten - caller may like to fill the space later.
+ */
+void entry_list_memcpy(struct entry_apex *ea, entry_list_t list);
+
+
+
+/* Packet caching; implementation in ./entry_pkt.c */
+
+/** Stash the packet into cache (if suitable, etc.)
+ * \param needs_pkt we need the packet due to not stashing some RRs;
+ * see stash_rrset() for details
+ * It assumes check_dname_for_lf(). */
+void stash_pkt(const knot_pkt_t *pkt, const struct kr_query *qry,
+ const struct kr_request *req, bool needs_pkt);
+
+/** Try answering from packet cache, given an entry_h.
+ *
+ * This assumes the TTL is OK and entry_h_consistent, but it may still return error.
+ * On success it handles all the rest, incl. qry->flags.
+ */
+int answer_from_pkt(kr_layer_t *ctx, knot_pkt_t *pkt, uint16_t type,
+ const struct entry_h *eh, const void *eh_bound, uint32_t new_ttl);
+
+
+/** Record is expiring if it has less than 1% TTL (or less than 5s) */
+static inline bool is_expiring(uint32_t orig_ttl, uint32_t new_ttl)
+{
+ int64_t nttl = new_ttl; /* avoid potential over/under-flow */
+ return 100 * (nttl - 5) < orig_ttl;
+}
+
+/** Returns signed result so you can inspect how much stale the RR is.
+ *
+ * @param owner name for stale-serving decisions. You may pass NULL to disable stale.
+ * @note: NSEC* uses zone name ATM; for NSEC3 the owner may not even be knowable.
+ * @param type for stale-serving.
+ */
+int32_t get_new_ttl(const struct entry_h *entry, const struct kr_query *qry,
+ const knot_dname_t *owner, uint16_t type, uint32_t now);
+
+
+/* RRset (de)materialization; implementation in ./entry_rr.c */
+
+/** Size of the RR count field */
+#define KR_CACHE_RR_COUNT_SIZE sizeof(uint16_t)
+
+/** Compute size of serialized rdataset. NULL is accepted as empty set. */
+static inline int rdataset_dematerialize_size(const knot_rdataset_t *rds)
+{
+ return KR_CACHE_RR_COUNT_SIZE + (rds == NULL ? 0 : rds->size);
+}
+
+/** Analyze the length of a dematerialized rdataset.
+ * Note that in the data it's KR_CACHE_RR_COUNT_SIZE and then this returned size. */
+static inline int rdataset_dematerialized_size(const uint8_t *data, uint16_t *rdataset_count)
+{
+ uint16_t count;
+ static_assert(sizeof(count) == KR_CACHE_RR_COUNT_SIZE,
+ "Unexpected KR_CACHE_RR_COUNT_SIZE.");
+ memcpy(&count, data, sizeof(count));
+ const uint8_t *rdata = data + sizeof(count);
+ if (rdataset_count) // memcpy is safe for unaligned case (on non-x86)
+ memcpy(rdataset_count, &count, sizeof(count));
+ for (int i = 0; i < count; ++i) {
+ __typeof__(((knot_rdata_t *)NULL)->len) len; // memcpy as above
+ memcpy(&len, rdata + offsetof(knot_rdata_t, len), sizeof(len));
+ rdata += knot_rdata_size(len);
+ }
+ return rdata - (data + sizeof(count));
+}
+
+/** Serialize an rdataset. It may be NULL as short-hand for empty. */
+void rdataset_dematerialize(const knot_rdataset_t *rds, uint8_t * restrict data);
+
+
+/** Partially constructed answer when gathering RRsets from cache. */
+struct answer {
+ 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 */
+ } rrsets[1+1+3]; /**< see AR_ANSWER and friends; only required records are filled */
+};
+enum {
+ AR_ANSWER = 0, /**< Positive answer record. It might be wildcard-expanded. */
+ AR_SOA, /**< SOA record. */
+ AR_NSEC, /**< NSEC* covering or matching the SNAME (next closer name in NSEC3 case). */
+ AR_WILD, /**< NSEC* covering or matching the source of synthesis. */
+ AR_CPE, /**< NSEC3 matching the closest provable encloser. */
+};
+
+/** Materialize RRset + RRSIGs into ans->rrsets[id].
+ * LATER(optim.): it's slightly wasteful that we allocate knot_rrset_t for the packet
+ *
+ * \return error code. They are all bad conditions and "guarded" by kresd's assertions.
+ */
+int entry2answer(struct answer *ans, int id,
+ const struct entry_h *eh, const uint8_t *eh_bound,
+ const knot_dname_t *owner, uint16_t type, uint32_t new_ttl);
+
+
+/* Preparing knot_pkt_t for cache answer from RRs; implementation in ./knot_pkt.c */
+
+/** Prepare answer packet to be filled by RRs (without RR data in wire). */
+int pkt_renew(knot_pkt_t *pkt, const knot_dname_t *name, uint16_t type);
+
+/** Append RRset + its RRSIGs into the current section (*shallow* copy), with given rank.
+ *
+ * \note it works with empty set as well (skipped)
+ * \note pkt->wire is not updated in any way
+ * \note KNOT_CLASS_IN is assumed
+ * \note Whole RRsets are put into the pseudo-packet;
+ * normal parsed packets would only contain single-RR sets.
+ */
+int pkt_append(knot_pkt_t *pkt, const struct answer_rrset *rrset, uint8_t rank);
+
+
+
+/* NSEC (1) stuff. Implementation in ./nsec1.c */
+
+/** Construct a string key for for NSEC (1) predecessor-search.
+ * \param add_wildcard Act as if the name was extended by "*."
+ * \note k->zlf_len is assumed to have been correctly set */
+knot_db_val_t key_NSEC1(struct key *k, const knot_dname_t *name, bool add_wildcard);
+
+/** Closest encloser check for NSEC (1).
+ * To understand the interface, see the call point.
+ * \param k space to store key + input: zname and zlf_len
+ * \return 0: success; >0: try other (NSEC3); <0: exit cache immediately. */
+int nsec1_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);
+
+/** Source of synthesis (SS) check for NSEC (1).
+ * To understand the interface, see the call point.
+ * \return 0: continue; <0: exit cache immediately;
+ * AR_SOA: skip to adding SOA (SS was covered or matched for NODATA). */
+int nsec1_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);
+
+
+/* NSEC3 stuff. Implementation in ./nsec3.c */
+
+/** 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 *nsec3_name,
+ const nsec_p_hash_t nsec_p_hash);
+
+/** TODO. See nsec1_encloser(...) */
+int nsec3_encloser(struct key *k, struct answer *ans,
+ const int sname_labels, int *clencl_labels,
+ 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,
+ const struct kr_query *qry, struct kr_cache *cache);
+
+
+
+#define VERBOSE_MSG(qry, ...) kr_log_q((qry), CACHE, ## __VA_ARGS__)
+#define WITH_VERBOSE(qry) if (kr_log_is_debug_qry(CACHE, (qry)))
+
+/** Shorthand for operations on cache backend */
+#define cache_op(cache, op, ...) (cache)->api->op((cache)->db, &(cache)->stats, ## __VA_ARGS__)
+
+
+static inline uint16_t get_uint16(const void *address)
+{
+ uint16_t tmp;
+ memcpy(&tmp, address, sizeof(tmp));
+ return tmp;
+}
+
+/** Useful pattern, especially as void-pointer arithmetic isn't standard-compliant. */
+static inline uint8_t * knot_db_val_bound(knot_db_val_t val)
+{
+ return (uint8_t *)val.data + val.len;
+}
+
diff --git a/lib/cache/knot_pkt.c b/lib/cache/knot_pkt.c
new file mode 100644
index 0000000..31fa7e9
--- /dev/null
+++ b/lib/cache/knot_pkt.c
@@ -0,0 +1,94 @@
+/* Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+/** @file
+ * Implementation of preparing knot_pkt_t for filling with RRs.
+ * Prototypes in ./impl.h
+ */
+
+#include "lib/cache/impl.h"
+
+int pkt_renew(knot_pkt_t *pkt, const knot_dname_t *name, uint16_t type)
+{
+ /* Update packet question if needed. */
+ if (!knot_dname_is_equal(knot_pkt_qname(pkt), name)
+ || knot_pkt_qtype(pkt) != type || knot_pkt_qclass(pkt) != KNOT_CLASS_IN) {
+ int ret = kr_pkt_recycle(pkt);
+ if (ret) return kr_error(ret);
+ ret = knot_pkt_put_question(pkt, name, KNOT_CLASS_IN, type);
+ if (ret) return kr_error(ret);
+ }
+
+ pkt->parsed = pkt->size = KR_PKT_SIZE_NOWIRE;
+ knot_wire_set_qr(pkt->wire);
+ knot_wire_set_aa(pkt->wire);
+ return kr_ok();
+}
+
+/** Reserve space for additional `count` RRsets.
+ * \note pkt->rr_info gets correct length but is always zeroed
+ */
+static int pkt_alloc_space(knot_pkt_t *pkt, int count)
+{
+ size_t allocd_orig = pkt->rrset_allocd;
+ if (pkt->rrset_count + count <= allocd_orig) {
+ return kr_ok();
+ }
+ /* A simple growth strategy, amortized O(count). */
+ pkt->rrset_allocd = MAX(
+ pkt->rrset_count + count,
+ pkt->rrset_count + allocd_orig);
+
+ pkt->rr = mm_realloc(&pkt->mm, pkt->rr,
+ sizeof(pkt->rr[0]) * pkt->rrset_allocd,
+ sizeof(pkt->rr[0]) * allocd_orig);
+ if (!pkt->rr) {
+ return kr_error(ENOMEM);
+ }
+ /* Allocate pkt->rr_info to be certain, but just leave it zeroed. */
+ mm_free(&pkt->mm, pkt->rr_info);
+ pkt->rr_info = mm_calloc(&pkt->mm, pkt->rrset_allocd, sizeof(pkt->rr_info[0]));
+ if (!pkt->rr_info) {
+ return kr_error(ENOMEM);
+ }
+ return kr_ok();
+}
+
+int pkt_append(knot_pkt_t *pkt, const struct answer_rrset *rrset, uint8_t rank)
+{
+ /* allocate space, to be sure */
+ int rrset_cnt = (rrset->set.rr->rrs.count > 0) + (rrset->sig_rds.count > 0);
+ int ret = pkt_alloc_space(pkt, rrset_cnt);
+ if (ret) return kr_error(ret);
+ /* write both sets */
+ const knot_rdataset_t *rdss[2] = { &rrset->set.rr->rrs, &rrset->sig_rds };
+ for (int i = 0; i < rrset_cnt; ++i) {
+ if (kr_fails_assert(rdss[i]->count))
+ return kr_error(EINVAL);
+ /* allocate rank */
+ uint8_t *rr_rank = mm_alloc(&pkt->mm, sizeof(*rr_rank));
+ if (!rr_rank) return kr_error(ENOMEM);
+ *rr_rank = (i == 0) ? rank : (KR_RANK_OMIT | KR_RANK_AUTH);
+ /* rank for RRSIGs isn't really useful: ^^ */
+ if (i == 0) {
+ pkt->rr[pkt->rrset_count] = *rrset->set.rr;
+ pkt->rr[pkt->rrset_count].additional = rr_rank;
+ } else {
+ /* append the RR array */
+ pkt->rr[pkt->rrset_count] = (knot_rrset_t){
+ .owner = knot_dname_copy(rrset->set.rr->owner, &pkt->mm),
+ /* ^^ well, another copy isn't really needed */
+ .ttl = rrset->set.rr->ttl,
+ .type = KNOT_RRTYPE_RRSIG,
+ .rclass = KNOT_CLASS_IN,
+ .rrs = *rdss[i],
+ .additional = rr_rank,
+ };
+ }
+ ++pkt->rrset_count;
+ ++(pkt->sections[pkt->current].count);
+ }
+ return kr_ok();
+}
+
diff --git a/lib/cache/nsec1.c b/lib/cache/nsec1.c
new file mode 100644
index 0000000..4554303
--- /dev/null
+++ b/lib/cache/nsec1.c
@@ -0,0 +1,488 @@
+/* Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+/** @file
+ * Implementation of NSEC (1) handling. Prototypes in ./impl.h
+ */
+
+#include "lib/cache/impl.h"
+#include "lib/dnssec/nsec.h"
+#include "lib/layer/iterate.h"
+
+
+/** Reconstruct a name into a buffer (assuming length at least KNOT_DNAME_MAXLEN).
+ * \return kr_ok() or error code (<0). */
+static int dname_wire_reconstruct(knot_dname_t *buf, const struct key *k,
+ knot_db_val_t kwz)
+{
+ /* Reconstruct from key: first the ending, then zone name. */
+ int ret = knot_dname_lf2wire(buf, kwz.len, kwz.data);
+ if (kr_fails_assert(ret >= 0)) {
+ VERBOSE_MSG(NULL, "=> NSEC: LF2wire ret = %d\n", ret);
+ return ret;
+ }
+ /* The last written byte is the zero label for root -> overwrite. */
+ knot_dname_t *zone_start = buf + ret - 1;
+ if (kr_fails_assert(*zone_start == '\0'))
+ return kr_error(EFAULT);
+ ret = knot_dname_to_wire(zone_start, k->zname, KNOT_DNAME_MAXLEN - kwz.len);
+ if (kr_fails_assert(ret == k->zlf_len + 1))
+ return ret < 0 ? ret : kr_error(EILSEQ);
+ return kr_ok();
+}
+
+
+knot_db_val_t key_NSEC1(struct key *k, const knot_dname_t *name, bool add_wildcard)
+{
+ /* we basically need dname_lf with two bytes added
+ * on a correct place within the name (the cut) */
+ int ret;
+ const bool ok = k && name
+ && !(ret = kr_dname_lf(k->buf, name, add_wildcard));
+ if (kr_fails_assert(ok))
+ return (knot_db_val_t){ NULL, 0 };
+
+ 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 (kr_fails_assert(end >= begin))
+ 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' + '1' + dname_lf
+ * of the name within the zone without the final 0. Iff the latter is empty,
+ * there's no zero to cut and thus the key_len difference.
+ */
+ begin[0] = 0;
+ begin[1] = '1'; /* tag for NSEC1 */
+ k->type = KNOT_RRTYPE_NSEC;
+
+ /*
+ VERBOSE_MSG(NULL, "<> key_NSEC1; name: ");
+ kr_dname_print(name, add_wildcard ? "*." : "" , " ");
+ kr_log_debug(CACHE, "(zone name LF length: %d; total key length: %d)\n",
+ k->zlf_len, key_len);
+ */
+
+ return (knot_db_val_t){ k->buf + 1, key_len };
+}
+
+
+/** Assuming that k1 < k4, find where k2 is. (Considers DNS wrap-around.)
+ *
+ * \return Intuition: position of k2 among kX.
+ * 0: k2 < k1; 1: k1 == k2; 2: k1 is a prefix of k2 < k4;
+ * 3: k1 < k2 < k4 (and not 2); 4: k2 == k4; 5: k2 > k4
+ * \note k1.data may be NULL, meaning assumption that k1 < k2 and not a prefix
+ * (i.e. return code will be > 2)
+ */
+static int kwz_between(knot_db_val_t k1, knot_db_val_t k2, knot_db_val_t k4)
+{
+ kr_require(k2.data && k4.data);
+ /* CACHE_KEY_DEF; we need to beware of one key being a prefix of another */
+ int ret_maybe; /**< result, assuming we confirm k2 < k4 */
+ if (k1.data) {
+ const int cmp12 = memcmp(k1.data, k2.data, MIN(k1.len, k2.len));
+ if (cmp12 == 0 && k1.len == k2.len) /* iff k1 == k2 */
+ return 1;
+ if (cmp12 > 0 || (cmp12 == 0 && k1.len > k2.len)) /* iff k1 > k2 */
+ return 0;
+ ret_maybe = cmp12 == 0 ? 2 : 3;
+ } else {
+ ret_maybe = 3;
+ }
+ if (k4.len == 0) { /* wrap-around */
+ return k2.len > 0 ? ret_maybe : 4;
+ } else {
+ const int cmp24 = memcmp(k2.data, k4.data, MIN(k2.len, k4.len));
+ if (cmp24 == 0 && k2.len == k4.len) /* iff k2 == k4 */
+ return 4;
+ if (cmp24 > 0 || (cmp24 == 0 && k2.len > k4.len)) /* iff k2 > k4 */
+ return 5;
+ return ret_maybe;
+ }
+}
+
+
+/** NSEC1 range search.
+ *
+ * \param key Pass output of key_NSEC1(k, ...)
+ * \param value[out] The raw data of the NSEC cache record (optional; consistency checked).
+ * \param exact_match[out] Whether the key was matched exactly or just covered (optional).
+ * \param kwz_low[out] Output the low end of covering NSEC, pointing within DB (optional).
+ * \param kwz_high[in,out] Storage for the high end of covering NSEC (optional).
+ * It's only set if !exact_match.
+ * \param new_ttl[out] New TTL of the NSEC (optional).
+ * \return Error message or NULL.
+ * \note The function itself does *no* bitmap checks, e.g. RFC 6840 sec. 4.
+ */
+static const char * find_leq_NSEC1(struct kr_cache *cache, const struct kr_query *qry,
+ const knot_db_val_t key, const struct key *k, knot_db_val_t *value,
+ bool *exact_match, knot_db_val_t *kwz_low, knot_db_val_t *kwz_high,
+ uint32_t *new_ttl)
+{
+ /* Do the cache operation. */
+ const size_t nwz_off = key_nwz_off(k);
+ if (kr_fails_assert(key.data && key.len >= nwz_off))
+ return "range search ERROR";
+ knot_db_val_t key_nsec = key;
+ knot_db_val_t val = { NULL, 0 };
+ int ret = cache_op(cache, read_leq, &key_nsec, &val);
+ if (ret < 0) {
+ if (kr_fails_assert(ret == kr_error(ENOENT))) {
+ return "range search ERROR";
+ } else {
+ return "range search miss";
+ }
+ }
+ if (value) {
+ *value = val;
+ }
+ /* Check consistency, TTL, rank. */
+ const bool is_exact = (ret == 0);
+ if (exact_match) {
+ *exact_match = is_exact;
+ }
+ const struct entry_h *eh = entry_h_consistent_NSEC(val);
+ if (!eh) {
+ /* This might be just finding something else than NSEC1 entry,
+ * in case we searched before the very first one in the zone. */
+ return "range search found inconsistent entry";
+ }
+ /* Passing just zone name instead of owner, as we don't
+ * have it reconstructed at this point. */
+ int32_t new_ttl_ = get_new_ttl(eh, qry, k->zname, KNOT_RRTYPE_NSEC,
+ qry->timestamp.tv_sec);
+ if (new_ttl_ < 0 || !kr_rank_test(eh->rank, KR_RANK_SECURE)) {
+ return "range search found stale or insecure entry";
+ /* TODO: remove the stale record *and* retry,
+ * in case we haven't run off. Perhaps start by in_zone check. */
+ }
+ if (new_ttl) {
+ *new_ttl = new_ttl_;
+ }
+ if (kwz_low) {
+ *kwz_low = (knot_db_val_t){
+ .data = (uint8_t *)key_nsec.data + nwz_off,
+ .len = key_nsec.len - nwz_off,
+ }; /* CACHE_KEY_DEF */
+ }
+ if (is_exact) {
+ /* Nothing else to do. */
+ return NULL;
+ }
+ /* The NSEC starts strictly before our target name;
+ * now check that it still belongs into that zone. */
+ const bool nsec_in_zone = key_nsec.len >= nwz_off
+ /* CACHE_KEY_DEF */
+ && memcmp(key.data, key_nsec.data, nwz_off) == 0;
+ if (!nsec_in_zone) {
+ return "range search miss (!nsec_in_zone)";
+ }
+ /* We know it starts before sname, so let's check the other end.
+ * 1. construct the key for the next name - kwz_hi. */
+ /* it's *full* name ATM */
+ /* Technical complication: memcpy is safe for unaligned case (on non-x86) */
+ __typeof__(((knot_rdata_t *)NULL)->len) next_len;
+ const uint8_t *next_data;
+ { /* next points to knot_rdata_t but possibly unaligned */
+ const uint8_t *next = eh->data + KR_CACHE_RR_COUNT_SIZE;
+ memcpy(&next_len, next + offsetof(knot_rdata_t, len), sizeof(next_len));
+ next_data = next + offsetof(knot_rdata_t, data);
+ }
+ if (kr_fails_assert(KR_CACHE_RR_COUNT_SIZE == 2 && get_uint16(eh->data) != 0)) {
+ return "ERROR"; /* TODO: more checks? */
+ }
+ /*
+ WITH_VERBOSE {
+ VERBOSE_MSG(qry, "=> NSEC: next name: ");
+ kr_dname_print(next, "", "\n");
+ }
+ */
+ knot_dname_t ch_buf[KNOT_DNAME_MAXLEN];
+ knot_dname_t *chs = kwz_high ? kwz_high->data : ch_buf;
+ if (kr_fails_assert(chs))
+ return "EINVAL";
+
+ {
+ /* Lower-case chs; see also RFC 6840 5.1.
+ * LATER(optim.): we do lots of copying etc. */
+ knot_dname_t lower_buf[KNOT_DNAME_MAXLEN];
+ ret = knot_dname_to_wire(lower_buf, next_data,
+ MIN(next_len, KNOT_DNAME_MAXLEN));
+ if (ret < 0) { /* _ESPACE */
+ return "range search found record with incorrect contents";
+ }
+ knot_dname_to_lower(lower_buf);
+ ret = kr_dname_lf(chs, lower_buf, false);
+ }
+
+ if (kr_fails_assert(ret == 0))
+ return "ERROR";
+ knot_db_val_t kwz_hi = { /* skip the zone name */
+ .data = chs + 1 + k->zlf_len,
+ .len = chs[0] - k->zlf_len,
+ };
+ if (kr_fails_assert((ssize_t)(kwz_hi.len) >= 0))
+ return "ERROR";
+ /* 2. do the actual range check. */
+ const knot_db_val_t kwz_sname = {
+ .data = (void *)/*const-cast*/(k->buf + 1 + nwz_off),
+ .len = k->buf[0] - k->zlf_len,
+ };
+ if (kr_fails_assert((ssize_t)(kwz_sname.len) >= 0))
+ return "ERROR";
+ bool covers = /* we know for sure that the low end is before kwz_sname */
+ 3 == kwz_between((knot_db_val_t){ NULL, 0 }, kwz_sname, kwz_hi);
+ if (!covers) {
+ return "range search miss (!covers)";
+ }
+ if (kwz_high) {
+ *kwz_high = kwz_hi;
+ }
+ return NULL;
+}
+
+
+int nsec1_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)
+{
+ static const int ESKIP = ABS(ENOENT);
+ /* Basic sanity check. */
+ const bool ok = k && ans && clencl_labels && cover_low_kwz && cover_hi_kwz
+ && qry && cache;
+ if (kr_fails_assert(ok))
+ return kr_error(EINVAL);
+
+ /* Find a previous-or-equal name+NSEC in cache covering the QNAME,
+ * checking TTL etc. */
+ knot_db_val_t key = key_NSEC1(k, qry->sname, false);
+ knot_db_val_t val = { NULL, 0 };
+ bool exact_match;
+ uint32_t new_ttl;
+ const char *err = find_leq_NSEC1(cache, qry, key, k, &val,
+ &exact_match, cover_low_kwz, cover_hi_kwz, &new_ttl);
+ if (err) {
+ VERBOSE_MSG(qry, "=> NSEC sname: %s\n", err);
+ return ESKIP;
+ }
+
+ /* Get owner name of the record. */
+ const knot_dname_t *owner;
+ knot_dname_t owner_buf[KNOT_DNAME_MAXLEN];
+ if (exact_match) {
+ owner = qry->sname;
+ } else {
+ int ret = dname_wire_reconstruct(owner_buf, k, *cover_low_kwz);
+ if (unlikely(ret)) return ESKIP;
+ owner = owner_buf;
+ }
+ /* Basic checks OK -> materialize data. */
+ {
+ const struct entry_h *nsec_eh = val.data;
+ int ret = entry2answer(ans, AR_NSEC, nsec_eh, knot_db_val_bound(val),
+ owner, KNOT_RRTYPE_NSEC, new_ttl);
+ if (ret) return kr_error(ret);
+ }
+
+ /* Final checks, split for matching vs. covering our sname. */
+ const knot_rrset_t *nsec_rr = ans->rrsets[AR_NSEC].set.rr;
+ const uint8_t *bm = knot_nsec_bitmap(nsec_rr->rrs.rdata);
+ uint16_t bm_size = knot_nsec_bitmap_len(nsec_rr->rrs.rdata);
+ if (kr_fails_assert(bm))
+ return kr_error(EFAULT);
+
+ if (exact_match) {
+ if (kr_nsec_bitmap_nodata_check(bm, bm_size, qry->stype, nsec_rr->owner) != 0) {
+ VERBOSE_MSG(qry,
+ "=> NSEC sname: match but failed type check\n");
+ return ESKIP;
+ }
+ /* NODATA proven; just need to add SOA+RRSIG later */
+ VERBOSE_MSG(qry, "=> NSEC sname: match proved NODATA, new TTL %d\n",
+ new_ttl);
+ ans->rcode = PKT_NODATA;
+ return kr_ok();
+ } /* else */
+
+ /* Inexact match. First check if sname is delegated by that NSEC. */
+ const int nsec_matched = knot_dname_matched_labels(nsec_rr->owner, qry->sname);
+ const bool is_sub = nsec_matched == knot_dname_labels(nsec_rr->owner, NULL);
+ if (is_sub && kr_nsec_children_in_zone_check(bm, bm_size) != 0) {
+ VERBOSE_MSG(qry, "=> NSEC sname: covered but delegated (or error)\n");
+ return ESKIP;
+ }
+ /* NXDOMAIN proven *except* for wildcards. */
+ WITH_VERBOSE(qry) {
+ auto_free char *owner_str = kr_dname_text(nsec_rr->owner),
+ *next_str = kr_dname_text(knot_nsec_next(nsec_rr->rrs.rdata));
+ VERBOSE_MSG(qry, "=> NSEC sname: covered by: %s -> %s, new TTL %d\n",
+ owner_str, next_str, new_ttl);
+ }
+
+ /* Find label count of the closest encloser.
+ * Both endpoints in an NSEC do exist (though possibly in a child zone)
+ * and any prefixes of those names as well (empty non-terminals),
+ * but nothing else exists inside this "triangle".
+ *
+ * Note that we have to lower-case the next name for comparison,
+ * even though we have canonicalized NSEC already; see RFC 6840 5.1.
+ * LATER(optim.): it might be faster to use the LFs we already have.
+ */
+ knot_dname_t next[KNOT_DNAME_MAXLEN];
+ int ret = knot_dname_to_wire(next, knot_nsec_next(nsec_rr->rrs.rdata), sizeof(next));
+ if (kr_fails_assert(ret >= 0))
+ return kr_error(ret);
+ knot_dname_to_lower(next);
+ *clencl_labels = MAX(
+ nsec_matched,
+ knot_dname_matched_labels(qry->sname, next)
+ );
+
+ /* Empty non-terminals don't need to have
+ * a matching NSEC record. */
+ if (sname_labels == *clencl_labels) {
+ ans->rcode = PKT_NODATA;
+ VERBOSE_MSG(qry,
+ "=> NSEC sname: empty non-terminal by the same RR\n");
+ } else {
+ ans->rcode = PKT_NXDOMAIN;
+ }
+ return kr_ok();
+}
+
+/** Verify non-existence after kwz_between() call. */
+static bool nonexistence_ok(int cmp, const knot_rrset_t *rrs)
+{
+ if (cmp == 3) {
+ return true;
+ }
+ if (cmp != 2) {
+ return false;
+ }
+ const uint8_t *bm = knot_nsec_bitmap(rrs->rrs.rdata);
+ uint16_t bm_size = knot_nsec_bitmap_len(rrs->rrs.rdata);
+ return kr_nsec_children_in_zone_check(bm, bm_size) != 0;
+}
+
+int nsec1_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)
+{
+ /* Construct key for the source of synthesis. */
+ knot_db_val_t key = key_NSEC1(k, clencl_name, true);
+ const size_t nwz_off = key_nwz_off(k);
+ if (kr_fails_assert(key.data && key.len >= nwz_off))
+ return kr_error(1);
+ /* Check if our sname-covering NSEC also covers/matches SS. */
+ knot_db_val_t kwz = {
+ .data = (uint8_t *)key.data + nwz_off,
+ .len = key.len - nwz_off,
+ };
+ if (kr_fails_assert((ssize_t)(kwz.len) >= 0))
+ return kr_error(EINVAL);
+ const int cmp = kwz_between(cover_low_kwz, kwz, cover_hi_kwz);
+ if (nonexistence_ok(cmp, ans->rrsets[AR_NSEC].set.rr)) {
+ VERBOSE_MSG(qry, "=> NSEC wildcard: covered by the same RR\n");
+ return AR_SOA;
+ }
+ const knot_rrset_t *nsec_rr = NULL; /**< the wildcard proof NSEC */
+ bool exact_match; /**< whether it matches the source of synthesis */
+ if (cmp == 1) {
+ exact_match = true;
+ nsec_rr = ans->rrsets[AR_NSEC].set.rr;
+ } else {
+ /* Try to find the NSEC for SS. */
+ knot_db_val_t val = { NULL, 0 };
+ knot_db_val_t wild_low_kwz = { NULL, 0 };
+ uint32_t new_ttl;
+ const char *err = find_leq_NSEC1(cache, qry, key, k, &val,
+ &exact_match, &wild_low_kwz, NULL, &new_ttl);
+ if (err) {
+ VERBOSE_MSG(qry, "=> NSEC wildcard: %s\n", err);
+ return kr_ok();
+ }
+ /* Materialize the record into answer (speculatively). */
+ knot_dname_t owner[KNOT_DNAME_MAXLEN];
+ int ret = dname_wire_reconstruct(owner, k, wild_low_kwz);
+ if (ret) return kr_error(ret);
+ const struct entry_h *nsec_eh = val.data;
+ ret = entry2answer(ans, AR_WILD, nsec_eh, knot_db_val_bound(val),
+ owner, KNOT_RRTYPE_NSEC, new_ttl);
+ if (ret) return kr_error(ret);
+ nsec_rr = ans->rrsets[AR_WILD].set.rr;
+ }
+
+ if (kr_fails_assert(nsec_rr))
+ return kr_error(EFAULT);
+ const uint8_t *bm = knot_nsec_bitmap(nsec_rr->rrs.rdata);
+ uint16_t bm_size = knot_nsec_bitmap_len(nsec_rr->rrs.rdata);
+ int ret;
+ struct answer_rrset * const arw = &ans->rrsets[AR_WILD];
+ if (kr_fails_assert(bm)) {
+ ret = kr_error(EFAULT);
+ goto clean_wild;
+ }
+ if (!exact_match) {
+ /* Finish verification that the source of synthesis doesn't exist. */
+ const int nsec_matched =
+ knot_dname_matched_labels(nsec_rr->owner, clencl_name);
+ /* we don't need to use the full source of synthesis ^ */
+ const bool is_sub =
+ nsec_matched == knot_dname_labels(nsec_rr->owner, NULL);
+ if (is_sub && kr_nsec_children_in_zone_check(bm, bm_size) != 0) {
+ VERBOSE_MSG(qry,
+ "=> NSEC wildcard: covered but delegated (or error)\n");
+ ret = kr_ok();
+ goto clean_wild;
+ }
+ /* We have a record proving wildcard non-existence. */
+ WITH_VERBOSE(qry) {
+ auto_free char *owner_str = kr_dname_text(nsec_rr->owner),
+ *next_str = kr_dname_text(knot_nsec_next(nsec_rr->rrs.rdata));
+ VERBOSE_MSG(qry, "=> NSEC wildcard: covered by: %s -> %s, new TTL %d\n",
+ owner_str, next_str, nsec_rr->ttl);
+ }
+ return AR_SOA;
+ }
+
+ /* The wildcard exists. Find if it's NODATA - check type bitmap. */
+ if (kr_nsec_bitmap_nodata_check(bm, bm_size, qry->stype, nsec_rr->owner) == 0) {
+ /* NODATA proven; just need to add SOA+RRSIG later */
+ WITH_VERBOSE(qry) {
+ const char *msg_start = "=> NSEC wildcard: match proved NODATA";
+ if (arw->set.rr) {
+ auto_free char *owner_str = kr_dname_text(nsec_rr->owner);
+ VERBOSE_MSG(qry, "%s: %s, new TTL %d\n",
+ msg_start, owner_str, nsec_rr->ttl);
+ } else {
+ /* don't repeat the RR if it's the same */
+ VERBOSE_MSG(qry, "%s, by the same RR\n", msg_start);
+ }
+ }
+ ans->rcode = PKT_NODATA;
+ return AR_SOA;
+
+ } /* else */
+ /* The data probably exists -> don't add this NSEC
+ * and (later) try to find the real wildcard data */
+ VERBOSE_MSG(qry, "=> NSEC wildcard: should exist (or error)\n");
+ ans->rcode = PKT_NOERROR;
+ ret = kr_ok();
+clean_wild:
+ if (arw->set.rr) { /* we may have matched AR_NSEC */
+ knot_rrset_free(arw->set.rr, ans->mm);
+ arw->set.rr = NULL;
+ knot_rdataset_clear(&arw->sig_rds, ans->mm);
+ }
+ return ret;
+}
+
diff --git a/lib/cache/nsec3.c b/lib/cache/nsec3.c
new file mode 100644
index 0000000..0b70775
--- /dev/null
+++ b/lib/cache/nsec3.c
@@ -0,0 +1,481 @@
+/* Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+/** @file
+ * Implementation of NSEC3 handling. Prototypes in ./impl.h
+ */
+
+#include "lib/cache/impl.h"
+
+#include "contrib/base32hex.h"
+#include "lib/dnssec/nsec.h"
+#include "lib/dnssec/nsec3.h"
+#include "lib/layer/iterate.h"
+
+#include <libknot/rrtype/nsec3.h>
+
+static const knot_db_val_t VAL_EMPTY = { NULL, 0 };
+
+/** 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)
+{
+ if (kr_fails_assert(k && zname && !kr_dname_lf(k->buf, zname, false)))
+ return VAL_EMPTY;
+
+ /* CACHE_KEY_DEF: key == zone's dname_lf + '\0' + '3' + nsec_p hash (4B)
+ * + NSEC3 hash (20B == NSEC3_HASH_LEN 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),
+ };
+}
+
+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],
+ knot_db_val_bound(val), KR_CACHE_KEY_MAXLEN - val.len);
+ if (len != NSEC3_HASH_LEN) {
+ return VAL_EMPTY;
+ }
+ val.len += len;
+ return val;
+}
+
+/** 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 struct nsec_p *nsec_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];
+ 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;
+ name_len += 2;
+ } else {
+ name_len = knot_dname_size(name);
+ }
+ /* Append the NSEC3 hash. */
+ const dnssec_binary_t dname = {
+ .size = name_len,
+ .data = (uint8_t *)/*const-cast*/name,
+ };
+
+ if (kr_fails_assert(nsec_p->libknot.iterations <= KR_NSEC3_MAX_ITERATIONS)) {
+ /* This is mainly defensive; it shouldn't happen thanks to downgrades. */
+ return VAL_EMPTY;
+ }
+ #if 0 // LATER(optim.): this requires a patched libdnssec - tries to realloc()
+ dnssec_binary_t hash = {
+ .size = KR_CACHE_KEY_MAXLEN - val.len,
+ .data = val.data + val.len,
+ };
+ int ret = dnssec_nsec3_hash(&dname, &nsec_p->libknot, &hash);
+ if (ret != DNSSEC_EOK) return VAL_EMPTY;
+ if (kr_fails_assert(hash.size == NSEC3_HASH_LEN))
+ return VAL_EMPTY;
+
+ #else
+ dnssec_binary_t hash = { .size = 0, .data = NULL };
+ int ret = dnssec_nsec3_hash(&dname, &nsec_p->libknot, &hash);
+ if (ret != DNSSEC_EOK) return VAL_EMPTY;
+ if (kr_fails_assert(hash.size == NSEC3_HASH_LEN && hash.data))
+ return VAL_EMPTY;
+ memcpy(knot_db_val_bound(val), hash.data, NSEC3_HASH_LEN);
+ free(hash.data);
+ #endif
+
+ val.len += hash.size;
+ return val;
+}
+
+/** Return h1 < h2, semantically on NSEC3 hashes. */
+static inline bool nsec3_hash_ordered(const uint8_t *h1, const uint8_t *h2)
+{
+ return memcmp(h1, h2, NSEC3_HASH_LEN) < 0;
+}
+
+/** NSEC3 range search.
+ *
+ * \param key Pass output of key_NSEC3(k, ...)
+ * \param nsec_p Restrict to this NSEC3 parameter-set.
+ * \param value[out] The raw data of the NSEC3 cache record (optional; consistency checked).
+ * \param exact_match[out] Whether the key was matched exactly or just covered (optional).
+ * \param hash_low[out] Output the low end hash of covering NSEC3, pointing within DB (optional).
+ * \param new_ttl[out] New TTL of the NSEC3 (optional).
+ * \return Error message or NULL.
+ * \note The function itself does *no* bitmap checks, e.g. RFC 6840 sec. 4.
+ */
+static const char * find_leq_NSEC3(struct kr_cache *cache, const struct kr_query *qry,
+ const knot_db_val_t key, const struct key *k, const struct nsec_p *nsec_p,
+ knot_db_val_t *value, bool *exact_match, const uint8_t **hash_low,
+ uint32_t *new_ttl)
+{
+ /* Do the cache operation. */
+ const size_t hash_off = key_nsec3_hash_off(k);
+ if (kr_fails_assert(key.data && key.len >= hash_off))
+ return "range search ERROR";
+ knot_db_val_t key_found = key;
+ knot_db_val_t val = { NULL, 0 };
+ int ret = cache_op(cache, read_leq, &key_found, &val);
+ /* ^^ LATER(optim.): incrementing key and doing less-than search
+ * would probably be slightly more efficient with LMDB,
+ * but the code complexity would grow considerably. */
+ if (ret < 0) {
+ if (kr_fails_assert(ret == kr_error(ENOENT))) {
+ return "range search ERROR";
+ } else {
+ return "range search miss";
+ }
+ }
+ if (value) {
+ *value = val;
+ }
+ /* Check consistency, TTL, rank. */
+ const bool is_exact = (ret == 0);
+ if (exact_match) {
+ *exact_match = is_exact;
+ }
+ const struct entry_h *eh = entry_h_consistent_NSEC(val);
+ if (!eh) {
+ /* This might be just finding something else than NSEC3 entry,
+ * in case we searched before the very first one in the zone. */
+ return "range search found inconsistent entry";
+ }
+ /* Passing just zone name instead of owner. */
+ int32_t new_ttl_ = get_new_ttl(eh, qry, k->zname, KNOT_RRTYPE_NSEC3,
+ qry->timestamp.tv_sec);
+ if (new_ttl_ < 0 || !kr_rank_test(eh->rank, KR_RANK_SECURE)) {
+ return "range search found stale or insecure entry";
+ /* TODO: remove the stale record *and* retry,
+ * in case we haven't run off. Perhaps start by in_zone check. */
+ }
+ if (new_ttl) {
+ *new_ttl = new_ttl_;
+ }
+ if (hash_low) {
+ *hash_low = (uint8_t *)key_found.data + hash_off;
+ }
+ if (is_exact) {
+ /* Nothing else to do. */
+ return NULL;
+ }
+ /* The NSEC3 starts strictly before our target name;
+ * now check that it still belongs into that zone and chain. */
+ const uint8_t *nsec_p_raw = eh->data + KR_CACHE_RR_COUNT_SIZE
+ + 2 /* RDLENGTH from rfc1034 */;
+ const int nsec_p_len = nsec_p_rdlen(nsec_p_raw);
+ const bool same_chain = key_found.len == hash_off + NSEC3_HASH_LEN
+ /* CACHE_KEY_DEF */
+ && memcmp(key.data, key_found.data, hash_off) == 0
+ /* exact comparison of NSEC3 parameters */
+ && nsec_p_len == nsec_p_rdlen(nsec_p->raw)
+ && memcmp(nsec_p_raw, nsec_p->raw, nsec_p_len) == 0;
+ if (!same_chain) {
+ return "range search miss (!same_chain)";
+ }
+ /* We know it starts before sname, so let's check the other end.
+ * A. find the next hash and check its length. */
+ if (kr_fails_assert(KR_CACHE_RR_COUNT_SIZE == 2 && get_uint16(eh->data) != 0))
+ return "ERROR"; /* TODO: more checks? Also, `next` computation is kinda messy. */
+ const uint8_t *hash_next = nsec_p_raw + nsec_p_len
+ + sizeof(uint8_t) /* hash length from rfc5155 */;
+ if (hash_next[-1] != NSEC3_HASH_LEN) {
+ return "unexpected next hash length";
+ }
+ /* B. do the actual range check. */
+ const uint8_t * const hash_searched = (uint8_t *)key.data + hash_off;
+ bool covers = /* we know for sure that the low end is before the searched name */
+ nsec3_hash_ordered(hash_searched, hash_next)
+ /* and the wrap-around case */
+ || nsec3_hash_ordered(hash_next, (const uint8_t *)key_found.data + hash_off);
+ if (!covers) {
+ return "range search miss (!covers)";
+ }
+ return NULL;
+}
+
+/** Extract textual representation of NSEC3 hash from a cache key.
+ * \param text must have length at least NSEC3_HASH_TXT_LEN+1 (will get 0-terminated). */
+static void key_NSEC3_hash2text(const knot_db_val_t key, char *text)
+{
+ kr_require(key.data && key.len > NSEC3_HASH_LEN);
+ const uint8_t *hash_raw = knot_db_val_bound(key) - NSEC3_HASH_LEN;
+ /* CACHE_KEY_DEF ^^ */
+ int len = base32hex_encode(hash_raw, NSEC3_HASH_LEN, (uint8_t *)text,
+ NSEC3_HASH_TXT_LEN);
+ kr_assert(len == NSEC3_HASH_TXT_LEN);
+ text[NSEC3_HASH_TXT_LEN] = '\0';
+}
+
+/** Reconstruct a name into a buffer (assuming length at least KNOT_DNAME_MAXLEN).
+ * \return kr_ok() or error code (<0). */
+static int dname_wire_reconstruct(knot_dname_t *buf, const knot_dname_t *zname,
+ const uint8_t *hash_raw)
+{
+ int len = base32hex_encode(hash_raw, NSEC3_HASH_LEN, buf + 1, NSEC3_HASH_TXT_LEN);
+ if (kr_fails_assert(len == NSEC3_HASH_TXT_LEN))
+ return kr_error(EINVAL);
+ buf[0] = len;
+ int ret = knot_dname_to_wire(buf + 1 + len, zname, KNOT_DNAME_MAXLEN - 1 - len);
+ return ret < 0 ? kr_error(ret) : kr_ok();
+}
+
+static void nsec3_hash2text(const knot_dname_t *owner, char *text)
+{
+ kr_require(owner[0] == NSEC3_HASH_TXT_LEN);
+ memcpy(text, owner + 1, MIN(owner[0], NSEC3_HASH_TXT_LEN));
+ text[NSEC3_HASH_TXT_LEN] = '\0';
+}
+
+int nsec3_encloser(struct key *k, struct answer *ans,
+ const int sname_labels, int *clencl_labels,
+ const struct kr_query *qry, struct kr_cache *cache)
+{
+ static const int ESKIP = ABS(ENOENT);
+ /* Basic sanity check. */
+ const bool ok = k && k->zname && ans && clencl_labels
+ && qry && cache;
+ if (kr_fails_assert(ok))
+ return kr_error(EINVAL);
+
+ /*** 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. */
+ /* LATER(optim.): perhaps iterate in the other order - that
+ * should help significantly against deep queries where we have
+ * a shallow proof in the cache. We can also optimize by using
+ * only exact search unless we had a match in the previous iteration. */
+ const int zname_labels = knot_dname_labels(k->zname, NULL);
+ int last_nxproven_labels = -1;
+ const knot_dname_t *name = qry->sname;
+ for (int name_labels = sname_labels; name_labels >= zname_labels;
+ --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, &ans->nsec_p);
+ if (!key.data) continue;
+ WITH_VERBOSE(qry) {
+ char hash_txt[NSEC3_HASH_TXT_LEN + 1];
+ key_NSEC3_hash2text(key, hash_txt);
+ VERBOSE_MSG(qry, "=> NSEC3 depth %d: hash %s\n",
+ name_labels - zname_labels, hash_txt);
+ }
+ knot_db_val_t val = { NULL, 0 };
+ bool exact_match;
+ uint32_t new_ttl;
+ const uint8_t *hash_low;
+ const char *err = find_leq_NSEC3(cache, qry, key, k, &ans->nsec_p, &val,
+ &exact_match, &hash_low, &new_ttl);
+ if (err) {
+ WITH_VERBOSE(qry) {
+ auto_free char *name_str = kr_dname_text(name);
+ VERBOSE_MSG(qry, "=> NSEC3 encloser error for %s: %s\n",
+ name_str, err);
+ }
+ continue;
+ }
+ if (exact_match && name_labels != sname_labels
+ && name_labels + 1 != last_nxproven_labels) {
+ /* This name exists (checked rank and TTL), and it's
+ * neither of the two interesting cases, so we do not
+ * keep searching for non-existence above this name. */
+ VERBOSE_MSG(qry,
+ "=> NSEC3 encloser: only found existence of an ancestor\n");
+ return ESKIP;
+ }
+ /* Optimization: avoid the rest of the last iteration if pointless. */
+ if (!exact_match && name_labels == zname_labels
+ && last_nxproven_labels != name_labels + 1) {
+ break;
+ }
+
+ /* Basic checks OK -> materialize data, cleaning any previous
+ * records on that answer index (unsuccessful attempts). */
+ knot_dname_t owner[KNOT_DNAME_MAXLEN];
+ {
+ int ret = dname_wire_reconstruct(owner, k->zname, hash_low);
+ if (unlikely(ret)) continue;
+ }
+ const int ans_id = (exact_match && name_labels + 1 == last_nxproven_labels)
+ ? AR_CPE : AR_NSEC;
+ {
+ const struct entry_h *nsec_eh = val.data;
+ memset(&ans->rrsets[ans_id], 0, sizeof(ans->rrsets[ans_id]));
+ int ret = entry2answer(ans, ans_id, nsec_eh, knot_db_val_bound(val),
+ owner, KNOT_RRTYPE_NSEC3, new_ttl);
+ if (ret) return kr_error(ret);
+ }
+
+ if (!exact_match) {
+ /* Non-existence proven, but we don't know if `name`
+ * is the next closer name.
+ * Note: we don't need to check for the sname being
+ * delegated away by this record, as with NSEC3 only
+ * *exact* match on an ancestor could do that. */
+ last_nxproven_labels = name_labels;
+ WITH_VERBOSE(qry) {
+ char hash_low_txt[NSEC3_HASH_TXT_LEN + 1];
+ nsec3_hash2text(owner, hash_low_txt);
+ VERBOSE_MSG(qry,
+ "=> NSEC3 depth %d: covered by %s -> TODO, new TTL %d\n",
+ name_labels - zname_labels, hash_low_txt, new_ttl);
+ }
+ continue;
+ }
+
+ /* Exactly matched NSEC3: two cases, one after another. */
+ const knot_rrset_t *nsec_rr = ans->rrsets[ans_id].set.rr;
+ const uint8_t *bm = knot_nsec3_bitmap(nsec_rr->rrs.rdata);
+ uint16_t bm_size = knot_nsec3_bitmap_len(nsec_rr->rrs.rdata);
+ if (kr_fails_assert(bm))
+ return kr_error(EFAULT);
+ if (name_labels == sname_labels) {
+ if (kr_nsec_bitmap_nodata_check(bm, bm_size, qry->stype,
+ nsec_rr->owner) != 0) {
+ VERBOSE_MSG(qry,
+ "=> NSEC3 sname: match but failed type check\n");
+ return ESKIP;
+ }
+ /* NODATA proven; just need to add SOA+RRSIG later */
+ VERBOSE_MSG(qry,
+ "=> NSEC3 sname: match proved NODATA, new TTL %d\n",
+ new_ttl);
+ ans->rcode = PKT_NODATA;
+ return kr_ok();
+
+ } /* else */
+
+ if (kr_fails_assert(name_labels + 1 == last_nxproven_labels))
+ return kr_error(EINVAL);
+ if (kr_nsec_children_in_zone_check(bm, bm_size) != 0) {
+ VERBOSE_MSG(qry,
+ "=> NSEC3 encloser: found but delegated (or error)\n");
+ return ESKIP;
+ }
+ /* NXDOMAIN proven *except* for wildcards. */
+ WITH_VERBOSE(qry) {
+ auto_free char *name_str = kr_dname_text(name);
+ VERBOSE_MSG(qry,
+ "=> NSEC3 encloser: confirmed as %s, new TTL %d\n",
+ name_str, new_ttl);
+ }
+ *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).
+ * 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))) {
+ memset(&ans->rrsets[AR_CPE], 0, sizeof(ans->rrsets[AR_CPE]));
+ /* LATER(optim.): perhaps check this earlier and avoid some work? */
+ }
+ return kr_ok();
+ }
+
+ /* We've ran out of options. */
+ if (last_nxproven_labels > 0) {
+ /* We didn't manage to prove existence of the closest encloser,
+ * meaning the only chance left is a *positive* wildcard record. */
+ *clencl_labels = last_nxproven_labels - 1;
+ ans->rcode = PKT_NXDOMAIN;
+ /* FIXME: review */
+ }
+ return ESKIP;
+}
+
+int nsec3_src_synth(struct key *k, struct answer *ans, const knot_dname_t *clencl_name,
+ const struct kr_query *qry, struct kr_cache *cache)
+{
+ /* 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, &ans->nsec_p);
+ if (!key.data) return kr_error(1);
+ WITH_VERBOSE(qry) {
+ char hash_txt[NSEC3_HASH_TXT_LEN + 1];
+ key_NSEC3_hash2text(key, hash_txt);
+ VERBOSE_MSG(qry, "=> NSEC3 wildcard: hash %s\n", hash_txt);
+ }
+ knot_db_val_t val = { NULL, 0 };
+ bool exact_match;
+ uint32_t new_ttl;
+ const uint8_t *hash_low;
+ const char *err = find_leq_NSEC3(cache, qry, key, k, &ans->nsec_p, &val,
+ &exact_match, &hash_low, &new_ttl);
+ if (err) {
+ VERBOSE_MSG(qry, "=> NSEC3 wildcard: %s\n", err);
+ return kr_ok();
+ }
+
+ /* LATER(optim.): avoid duplicities in answer. */
+
+ /* Basic checks OK -> materialize the data (speculatively). */
+ knot_dname_t owner[KNOT_DNAME_MAXLEN];
+ {
+ int ret = dname_wire_reconstruct(owner, k->zname, hash_low);
+ if (unlikely(ret)) return kr_ok();
+ const struct entry_h *nsec_eh = val.data;
+ ret = entry2answer(ans, AR_WILD, nsec_eh, knot_db_val_bound(val),
+ owner, KNOT_RRTYPE_NSEC3, new_ttl);
+ if (ret) return kr_error(ret);
+ }
+ const knot_rrset_t *nsec_rr = ans->rrsets[AR_WILD].set.rr;
+
+ if (!exact_match) {
+ /* The record proves wildcard non-existence. */
+ WITH_VERBOSE(qry) {
+ char hash_low_txt[NSEC3_HASH_TXT_LEN + 1];
+ nsec3_hash2text(owner, hash_low_txt);
+ VERBOSE_MSG(qry,
+ "=> NSEC3 wildcard: covered by %s -> TODO, new TTL %d\n",
+ hash_low_txt, new_ttl);
+ }
+ return AR_SOA;
+ }
+
+ /* The wildcard exists. Find if it's NODATA - check type bitmap. */
+ const uint8_t *bm = knot_nsec3_bitmap(nsec_rr->rrs.rdata);
+ uint16_t bm_size = knot_nsec3_bitmap_len(nsec_rr->rrs.rdata);
+ if (kr_fails_assert(bm))
+ return kr_error(EFAULT);
+ 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;
+
+ } /* 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();
+}
+
diff --git a/lib/cache/overflow.test.integr/deckard.yaml b/lib/cache/overflow.test.integr/deckard.yaml
new file mode 100644
index 0000000..61032fb
--- /dev/null
+++ b/lib/cache/overflow.test.integr/deckard.yaml
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+programs:
+- name: kresd1
+ binary: kresd
+ additional:
+ - -n
+ templates:
+ - lib/cache/overflow.test.integr/kresd_config.j2
+ - tests/config/test_dns_generators.lua
+ configs:
+ - config
+ - dns_gen.lua
+- name: kresd2
+ binary: kresd
+ additional:
+ - -n
+ templates:
+ - lib/cache/overflow.test.integr/kresd_config.j2
+ - tests/config/test_dns_generators.lua
+ configs:
+ - config
+ - dns_gen.lua
diff --git a/lib/cache/overflow.test.integr/kresd_config.j2 b/lib/cache/overflow.test.integr/kresd_config.j2
new file mode 100644
index 0000000..63841ff
--- /dev/null
+++ b/lib/cache/overflow.test.integr/kresd_config.j2
@@ -0,0 +1,91 @@
+-- SPDX-License-Identifier: GPL-3.0-or-later
+
+trust_anchors.remove('.')
+{% for TAF in TRUST_ANCHOR_FILES %}
+trust_anchors.add_file('{{TAF}}')
+{% endfor %}
+
+modules.load("hints")
+hints.root({['{{ROOT_NAME}}'] = '{{ROOT_ADDR}}'})
+
+{% raw %}
+-- Disable RFC5011 TA update
+if ta_update then
+ modules.unload('ta_update')
+end
+
+-- Disable RFC8145 signaling, scenario doesn't provide expected answers
+if ta_signal_query then
+ modules.unload('ta_signal_query')
+end
+
+-- Disable RFC8109 priming, scenario doesn't provide expected answers
+if priming then
+ modules.unload('priming')
+end
+
+-- Disable this module because it make one priming query
+if detect_time_skew then
+ modules.unload('detect_time_skew')
+end
+
+log_level('debug')
+policy.add(policy.all(policy.DEBUG_ALWAYS))
+
+cache.open(1*MB)
+
+{% endraw %}
+
+{% if DO_IP6 == "true" %}
+net.ipv6 = true
+{% else %}
+net.ipv6 = false
+{% endif %}
+
+{% if DO_IP4 == "true" %}
+net.ipv4 = true
+{% else %}
+net.ipv4 = false
+{% endif %}
+
+-- both instances listen on both addresses
+-- so queries get distributed between them randomly
+net.listen('{{programs[0]["address"]}}')
+net.listen('{{programs[1]["address"]}}')
+
+{% raw %}
+-- Self-checks on globals
+assert(help() ~= nil)
+assert(worker.id ~= nil)
+-- Self-checks on facilities
+assert(cache.stats() ~= nil)
+assert(cache.backends() ~= nil)
+assert(worker.stats() ~= nil)
+assert(net.interfaces() ~= nil)
+-- Self-checks on loaded stuff
+{% endraw %}
+
+assert(net.list()[1].transport.ip == '{{programs[0]["address"]}}')
+
+{% raw %}
+assert(#modules.list() > 0)
+-- Self-check timers
+ev = event.recurrent(1 * sec, function (ev) return 1 end)
+event.cancel(ev)
+ev = event.after(0, function (ev) return 1 end)
+
+local ffi = require('ffi')
+local kr_cach = kres.context().cache
+
+-- canary for cache overflow
+local kr_rrset = kres.rrset(
+ todname('www.example.com'),
+ kres.type.A,
+ kres.class.IN,
+ 604800)
+assert(kr_rrset:add_rdata('\192\000\002\001', 4))
+assert(kr_cach:insert(kr_rrset, nil, ffi.C.KR_RANK_SECURE))
+
+local generators = dofile('./dns_gen.lua')
+event.after(0, generators.gen_batch)
+{% endraw %}
diff --git a/lib/cache/overflow.test.integr/world_cz_vutbr_www.rpl b/lib/cache/overflow.test.integr/world_cz_vutbr_www.rpl
new file mode 100644
index 0000000..eddfbd0
--- /dev/null
+++ b/lib/cache/overflow.test.integr/world_cz_vutbr_www.rpl
@@ -0,0 +1,298 @@
+do-ip4: no
+
+; test with real world Internet data
+; attempt to resolve www.vutbr.cz. A leads to CNAME piranha.ro.vutbr.cz.
+; sub-trees vutbr.cz and ro.vutbr.cz. are in separate zones
+; hosted on the same servers with different DNSKEYs
+
+val-override-date: 20170124180319
+trust-anchor: ". 172800 IN DS 19036 8 2 49aac11d7b6f6446702e54a1607371607a1a41855200fd2ce1cdde32f24e8fb5"
+stub-addr: 2001:dc3::35
+CONFIG_END
+
+SCENARIO_BEGIN www.vutbr.cz. CNAME kresd issue #130
+
+; DNS root ; M.ROOT-SERVERS.NET.
+RANGE_BEGIN 0 100
+ ADDRESS 2001:dc3::35
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA DO NOERROR
+SECTION QUESTION
+. IN DNSKEY
+SECTION ANSWER
+. 16567 IN DNSKEY 257 3 8 AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0O8gcCjF FVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0NfnfL2MTJRkxoX bfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL496M/QZxkjf5/Efucp2gaD X6RS6CXpoY68LsvPVjR0ZSwzz1apAzvN9dlzEheX7ICJBBtuA6G3LQpz W5hOA2hzCTMjJPJ8LbqF6dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relS Qageu+ipAdTTJ25AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulq QxA+Uk1ihz0=
+. 16567 IN DNSKEY 256 3 8 AwEAAYvgWbYkpeGgdPKaKTJU3Us4YSTRgy7+dzvfArIhi2tKoZ/WR1Df w883SOU6Uw7tpVRkLarN0oIMK/xbOBD1DcXnyfElBwKsz4sVVWmfyr/x +igD/UjrcJ5zEBUrUmVtHyjar7ccaVc1/3ntkhZjI1hcungAlOhPhHlk MeX+5Azx6GdX//An5OgrdyH3o/JmOPMDX1mt806JI/hf0EwAp1pBwo5e 8SrSuR1tD3sgNjr6IzCdrKSgqi92z49zcdis3EaY199WFW60DCS7ydu+ +T5Xa+GyOw1quagwf/JUC/mEpeBQYWrnpkBbpDB3sy4+P2i8iCvavehb RyVm9U0MlIc=
+. 16567 IN RRSIG DNSKEY 8 0 172800 20170201000000 20170111000000 19036 . Sh+EpofvZgk3J9szMD2B94FxFgyIUKz3hkbCjgWSTqPQyhqNgqVU8QlS EtOo8YLmS4AX98eit5Gmmb2ObpkGoXBmAzu5w/Qt5WsGsWzLQhYrsy9s lDmFQ2JKUoCyfdwqhlJ8VxjzdFdMUiVl+/GPnv4yjxjM8Ke3VAtBkn6n BO7JkcxxOfcgZdZ4MuvSr40K/SenZE+JlLLL1LF4TMCGqaZTTdOx6kFF KSSgy2AS884htWcK0tnwRc630g6nAI2wdvjlRLBeisbfXanI4v8iiPyT FnMmnV7wJGWJ4gtRJ0UH3u5RWXUPZ+s1tKytk3slXbLyQ9xkEDveuD+h b659gQ==
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR DO NOERROR
+SECTION QUESTION
+cz. IN NS
+SECTION AUTHORITY
+cz. 172800 IN NS d.ns.nic.cz.
+cz. 172800 IN NS a.ns.nic.cz.
+cz. 172800 IN NS c.ns.nic.cz.
+cz. 172800 IN NS b.ns.nic.cz.
+cz. 86400 IN DS 54576 10 2 397E50C85EDE9CDE33F363A9E66FD1B216D788F8DD438A57A423A386 869C8F06
+cz. 86400 IN RRSIG DS 8 1 86400 20170202170000 20170120160000 61045 . ig2BBmA1kOuTqhVogqLciH40Ina7BCrG/fcaNARSWoaFHGOcC/7KsBZO uMttn/hKDJkH3RPsed2Oswl9bXZ+zrhjeXluUqC0zmsUJDBkS+AkiFJL HCpMSIZaXu/w1ZMADGfyQXl7XWCRbl+eyXi2eTG0SdLtRHNhm3CGJP3C xjzVuOTr9oPEyL0U81jhhlJPCFe8xDD441wLLzpEuVX8VP9N2S1QnIjO BhCEE9OTkPgpS7fMPEl0Yq2gfpRl+DCw1Dd0VB3Hh5M3hmrXuFqNYZQK b0JqDFGYhzvcpUs3EiB9IG7rJt51n6pxCTek1M2w+s6mLYzawVfq+b1Q uQD98A==
+SECTION ADDITIONAL
+a.ns.nic.cz. 172800 IN A 194.0.12.1
+b.ns.nic.cz. 172800 IN A 194.0.13.1
+c.ns.nic.cz. 172800 IN A 194.0.14.1
+d.ns.nic.cz. 172800 IN A 193.29.206.1
+a.ns.nic.cz. 172800 IN AAAA 2001:678:f::1
+b.ns.nic.cz. 172800 IN AAAA 2001:678:10::1
+c.ns.nic.cz. 172800 IN AAAA 2001:678:11::1
+d.ns.nic.cz. 172800 IN AAAA 2001:678:1::1
+ENTRY_END
+; end of M.ROOT-SERVERS.NET.
+RANGE_END
+
+
+; domains: cz. ; ?.ns.nic.cz.
+RANGE_BEGIN 0 100
+ ADDRESS 194.0.12.1
+ ADDRESS 194.0.13.1
+ ADDRESS 194.0.14.1
+ ADDRESS 193.29.206.1
+ ADDRESS 2001:678:f::1
+ ADDRESS 2001:678:10::1
+ ADDRESS 2001:678:11::1
+ ADDRESS 2001:678:1::1
+
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+cz. IN DNSKEY
+SECTION ANSWER
+cz. 18000 IN DNSKEY 256 3 10 AwEAAc9e2YFnG56xtTXu42GLGAkwsrFOBBwOZphNat7HQdBmfi0CbmDf oywCUsaSkObNmm+Zu9MYLNJDHsD+vxsZbtHClpYaSEhMEmHrbnj0BMPV A6hwY6YDGFhKudJ62RmB/rmhQ3iwmICsEdRn2w5fu1rHZv8UJOUMkeWd 6GA48mW3
+cz. 18000 IN DNSKEY 256 3 10 AwEAAdWL2Br92Vx0dLEOOB8y02ss8LtKIyGlLJ2ymJ02WqR3AAEEZN0f NPKF77kdKsjlG8DlzmSIOR12aa9EhpXqyHOwWI0kHOMJVnn6ZKFIAl71 JP/dYIcshYUxKZZMe+zEAUrVtzlLVDtM6cDOPDuBNa1ujYec3eJl9Ipq eUEG6gAH
+cz. 18000 IN DNSKEY 257 3 10 AwEAAay0hi4HN2r/BqMQTpIPIVDyjmyF+9ZWvr5Lewx+q+947o/GrRv4 FGFfkZxf9CFfYVUf0jG5Yq4i06pGVNwJl81HS9Ux2oeHRXUvgtLnl5He RVLL+zgI5byx9HSNr4bPO8ZEn5OjoayhkNyGSFr4VWrzQk/K02vLP4d1 cCEzUQy30eyZto2/tG5ZwCU/iRkS1PJOcOW98hiFIfFDZv1XjbEpqEYh T2PATs6rt+BKwSHKGISmg1PNdg+y0rItemYMWr1f9BGAdtTWoPCPCYPj OZMPoIyA4tMscD+ww54Jf/QNoHccY4hO1yHiuAXG7SUn8jo0IKQ9W7JJ xES0aqFCX/0=
+cz. 18000 IN RRSIG DNSKEY 10 1 18000 20170127000000 20170120000000 54576 cz. Fdl//hMdLoZq8//gLt/+3a7LfWqB5/psW9YR3AWNPQGfvrEAcKRBcah+ ikbSCmpAZ6j834xZP1zPd5xMoN33PGXf23iqcgjHvUn50Uq48KRBVYwU H885xNJBl/Po0N8STeG0WNZz2mbUbBbPCGN7CI5yl08usvqOvf2fV8+D 0m//+Fa1cWaqMXpHc6OnhWZ+BN4VdcxxwNbGhH2TZxyiGEMMscEGoIxn yL1pVY8T93LOMwQmuFJ71f8Scij3vYouW/mNuEma/UUZM1bEn8vR1UrP /6JTGPGTG+snHvCxiVtAxCNnqoIJDD+xuonpZLeKN5XU7UDMZPDTtSgX vtzjww==
+cz. 18000 IN RRSIG DNSKEY 10 1 18000 20170205002523 20170123080953 58211 cz. MZ6KTtQisTde4iOBH6oasl7bVrRM5ly7Yxdv2l+2gk1YYk4zX6L3m6oB P26SKi+fj8pM77775bRK7uCI9FlyqXa3MJclLU/GmnRANm6T4sSdz0zs F3FK4UfUmHnzdnWXWTnueDfIZr44yF1y1+4I3E96/9/nEYGO+xsifvIj iks=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode subdomain
+ADJUST copy_id copy_query
+REPLY QR DO NOERROR
+SECTION QUESTION
+vutbr.cz. IN NS
+SECTION AUTHORITY
+vutbr.cz. 18000 IN NS pipit.cis.vutbr.cz.
+vutbr.cz. 18000 IN NS rhino.cis.vutbr.cz.
+vutbr.cz. 18000 IN DS 5512 5 2 78510F9433A4D536A5B9099193E9D58EE5B5CF71F14D983B4DA2EB16 29CFA1E9
+vutbr.cz. 18000 IN RRSIG DS 10 2 18000 20170204213601 20170123080953 58211 cz. lXNBswz/r/1NY7VQq+BlisC+1yqFmUBIaF30L8XDAbiHLcj/AIj0dEy6 PlBlkEeDAi4W9DvR0jo9LjHvFFJLs54cuEEd3pHTdlw8x0dLd1X7Zkh7 cezfAt2EEqdux/ce/sc86lUKOpLnDtry2piWwVf2EqFg9NlW4cHTm78U gsY=
+SECTION ADDITIONAL
+pipit.cis.vutbr.cz. 18000 IN A 77.93.219.110
+rhino.cis.vutbr.cz. 18000 IN A 147.229.3.10
+pipit.cis.vutbr.cz. 18000 IN AAAA 2a01:430:120::4d5d:db6e
+rhino.cis.vutbr.cz. 18000 IN AAAA 2001:67c:1220:e000::93e5:30a
+ENTRY_END
+
+; end of domain cz.: servers ?.ns.nic.cz.
+RANGE_END
+
+
+; domains: vutbr.cz. + ro.vutbr.cz.
+; servers: pipit.cis.vutbr.cz. + rhino.cis.vutbr.cz. + shark.ro.vutbr.cz.
+; shark.ro.vutbr.cz. in fact serves both domains but is listed only in ro.vutbr.cz NS
+RANGE_BEGIN 0 100
+ ADDRESS 77.93.219.110
+ ADDRESS 147.229.3.10
+ ADDRESS 147.229.2.59
+ ADDRESS 2a01:430:120::4d5d:db6e
+ ADDRESS 2001:67c:1220:e000::93e5:30a
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA DO
+SECTION QUESTION
+vutbr.cz. IN NS
+SECTION ANSWER
+vutbr.cz. 28800 IN NS rhino.cis.vutbr.cz.
+vutbr.cz. 28800 IN NS pipit.cis.vutbr.cz.
+vutbr.cz. 28800 IN RRSIG NS 5 2 28800 20170216060902 20170117060902 39756 vutbr.cz. y6Jj5vfvdlLeecB/++/qyhjCzfnFJyY1sX1Ja+wV0ulq3laeCVV7ICXh PKG+CjHUu/nDOrzT9QJP4qxYDCANneI0yxI82XKhhoTN5O/TxyWH/DyT k8JarRoMooHv2RwKd8jtLIxvj1SaJ+AvlP0pOPraaVgbHtn1SJ4ubxQD cFc=
+SECTION ADDITIONAL
+pipit.cis.vutbr.cz. 86400 IN A 77.93.219.110
+pipit.cis.vutbr.cz. 86400 IN AAAA 2a01:430:120::4d5d:db6e
+rhino.cis.vutbr.cz. 86400 IN A 147.229.3.10
+rhino.cis.vutbr.cz. 86400 IN AAAA 2001:67c:1220:e000::93e5:30a
+pipit.cis.vutbr.cz. 86400 IN RRSIG A 5 4 86400 20170204080646 20170105080646 28257 cis.vutbr.cz. Cz9etHnEOQTzu+6rYJEqx/SQ1tQgPOCyf8HSj4KOsx89jtgiHNC6pep6 ZE0SphMGAs3jC/uGIhlaFNZ3i38OQIMuqwacbz+XZyW5bByvV3QZrhqh dFxMDfmPuNiCAT3crFpUkvVW1OE3YfGHzZGXX7JP5wb1b8A3X6Qih7fV +nQ=
+pipit.cis.vutbr.cz. 86400 IN RRSIG AAAA 5 4 86400 20170204080646 20170105080646 28257 cis.vutbr.cz. piafjh6my2fooZRrzwCu9RQ95gYaMQkhIkDaGX/fT6wXzSdmgFZkS1Nl EMIKdDCQaPrLGMG3p32ptMkAm4esPekeyNtLSMBtXwZyUkgEGn6h1QM2 Yr3TOo8cixfk5nmRRdlYadf5krLb8yI9exiqeymgEQLa1YNRz/bWArlX bn8=
+rhino.cis.vutbr.cz. 86400 IN RRSIG A 5 4 86400 20170204080646 20170105080646 28257 cis.vutbr.cz. X/tDf8e3JEV0LxiItfpQnBzeaRIq693VG8d30iCH4/1I0uqyCfxboWmm /CBpn9A8MCJu9NEEv+4+povNlfUfqi2yjsqJEVj8ztHxD4g9cc284Cv6 ySjxrSZ9axVqoaopEXujiTwwWJUFcgF6pxqyXVksW7sgKJrboM4VSlQD +Sw=
+rhino.cis.vutbr.cz. 86400 IN RRSIG AAAA 5 4 86400 20170204080646 20170105080646 28257 cis.vutbr.cz. T3Yf5PAkSeJtoOH90ea9zZBG9FC3iFhiCSerDn6d9up8GRfzxDsavYJC zQu+3vnOySySn+3TMzQSSFcWdJC2iO7ulaDGr177Gof9QJbKSVSMW7jt YDE2f4/R4Go3NZVwjk/HfpCInoR6pHNA1s/9hMnWtiVopmBdfzyd3/sW YOU=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA DO
+SECTION QUESTION
+vutbr.cz. IN DNSKEY
+SECTION ANSWER
+vutbr.cz. 28800 IN DNSKEY 256 3 5 AwEAAfwRRuGjpt9v4fzuIWFA9MtGfxDrIKhoFA7DNq6B+iCOoQb6t0HZ I9lGDUSR5DRswDGP569NJ/uVD4tJxGnaK2SBQVxIu+bEP1Ouzk+O43iO 8odw50NBWetljjNDP32B3zHpgJRpxyEqzDQaQ6B4Zer6sDZm9wo5SVJe r9LjJV9p
+vutbr.cz. 28800 IN DNSKEY 257 3 5 AwEAAfhR+s/4SLZZNA+kD2u1UgYBUu+X3Avi60QCaE1o2STterM405s8 mWMWJOlZGtjjIky3TEMxQ0+ZtMbEeJu2wNDLdV/XglX+pJAjyy728WJH 4u2/gJR8ZWsEIc0Jwb4FjwmBiF2Koz0SGVvrzEZ9T1H7dHq2X6f8KzYB otJyrAIWr9tZi/9tHrngZJ5wXELmMPWCfEFapdQMoKWoNvzrMYFli17R Mz7gJzCmNxMRV8/WkjsNPgYsTKpsAT8qEsXiTN9987AIKPHvc5j+/njq +fTXdOqGVpIgSiso+qJMddEMBcu/MBBYVFOwRQe1ez2tMwIX7y5mwDvK 0wsmyRvHugfFuxSnfiJvQr05kSnj0wxD9s9LNhrF4PocrcYqnBN/lBx9 D6633jJ3zT3T5Foe/Vj9A/X7F2oN6FOkdwO+YSEUot980pJQut6DR22U P4bLakyDMiTdOQ31c/dRIoTsccxw+838pXFyEPgiqOHRSeN/w9km6BID cl+32Xq97kXSMQH6AxOUsx9/Mxdj7ISwbS4utaAWoP460+TMcnfJfWfB NEWhuFvnfB9l63ZjZToB2PUVhrTxRwKUlfMLegSJKoZfiae82kK1pN4x FYyquKSykm/oXsM2w4OQvpqGcTwAXzZ5s95J45f7PsCap0bscGKumxsH cDswWpUz/UVosIrr
+vutbr.cz. 28800 IN RRSIG DNSKEY 5 2 28800 20170216060902 20170117060902 5512 vutbr.cz. QHw07MAjA4NFi3On8zaMw/q4IuADXVp4TODfK5PHb8OUIX2Yy+bKLrSX /Cc9ClWUpE69x80F9dFEeRZGJiYOwstNQGQVeq/EKNytm1XmhS8cp3SW CYHBpLjZGPrlhvqPhWd0S4vqPNiD8hDzgFAgaCNfwXDDKXhF2/qtpQ0V pDnytMP6pNPLPMpF2hzaLfCMzABShxcEOAr7+KTbxbffOik4YneG8seu XDtBvCVjP8lJcSU+q+UbotLnjyOgn8vV8pliTNqcvRsJTdtvTlJKHu8B iLkFeCE1DpRhyrVT5zC9NSOcoIv7tau2NE2oUPgtRzK76el6i9L9LcSs G+59j02AINefpAtc6W2khmTnGthibeOy/F9FuFkXUy6AmqIdNszMAj++ 8Mzv3A1OHfsfpIS3tLmC4drhdSHr2ab0Pe0lYQq2a9FSeQzSk6s9gwwZ gMVPVQHbouyvn6BCHaRVDjTV8GPKlk3C8GNaHcHb1hAGSPpw3kqL41dd K92Un4tLIoOYomxUYoyMtyxxwddXyR7ivToUHF7e/yv8MACMEo72N9sf y4zLEqkL1mJ1pCp3csI1bKaaA/c7sqb7PX93iqvoY06k55Pd7kT+lAF1 7QvXGg4U1kDrwytQPyocN8wmsX3//CpWUD07v8fCUqKOcIrVNGnoPmPC PpNe3AtpJoE=
+vutbr.cz. 28800 IN RRSIG DNSKEY 5 2 28800 20170216060902 20170117060902 39756 vutbr.cz. CNDE7Ht7xm8Jo9tuOlJ8N9+vI/Htfpk53MI0HG7B1EZJws/yEV7YFOOL SIAt3rzu1OHjaxr4CG/baqGRPtsaWSBHuLSdSduivxXw8xiQcMKzP6Cz 7xhJkQZxzDJ4oO5L2K2zWHcAJ8lfP1/3NHHoH1p2RATLN5sI7ofQE//W +ck=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA DO
+SECTION QUESTION
+www.vutbr.cz. IN A
+SECTION ANSWER
+www.vutbr.cz. 300 IN CNAME piranha.ro.vutbr.cz.
+www.vutbr.cz. 300 IN RRSIG CNAME 5 3 300 20170216060902 20170117060902 39756 vutbr.cz. 9B3UC5SOEw1+yKlYlOTINEuNq0Kdglywc5IYJwzeSzQ3ykptzZo3ABSy bYhTqImVkhm/4NFM9/4HWMHPDzTmrWS0mCI/ljCd/oe/PxW/uESvo4P5 EQzlcuH6xBzc1KdEFAJOSmRzFjj3vyK1QN3k/c+1y2oMFOYOR2oOzCw+ MIE=
+piranha.ro.vutbr.cz. 3600 IN A 147.229.2.90
+piranha.ro.vutbr.cz. 3600 IN RRSIG A 5 4 3600 20170222120032 20170123120032 12150 ro.vutbr.cz. Jz8bcAADQjCKTCcF70IK1aHGQlM4ukyN0myABlxoPaqid1mHX5jwR91b kdQmUAh2xDitlgRLbFjbUUgmjSPzQ5Qt7GAFUsVmqxvjbOLZjqHER1dh zmiWO0fDvvP647Osv3RiAP822rNUJcJrUBZU9LmeP05gwIHcpJrhdVBT b7I=
+SECTION AUTHORITY
+ro.vutbr.cz. 86400 IN NS shark.ro.vutbr.cz.
+ro.vutbr.cz. 86400 IN NS rhino.cis.vutbr.cz.
+ro.vutbr.cz. 86400 IN NS pipit.cis.vutbr.cz.
+ro.vutbr.cz. 86400 IN RRSIG NS 5 3 86400 20170222120032 20170123120032 12150 ro.vutbr.cz. HAQ8A+QNsS1WIXdW/fbT3jP+IxObBBvgUmvzsmJBXo8HMtnMAcuCQGmB 2JBQsQethQXsdyLnMK8to/5A9VRkqkAa7edxUoy7SdDi/mzGeLAVhF+5 kXSPD6t1vjiNdnIYAMpiOQbodCGxAnq6jnNyrjEzffdq3qw+5IkFNdG4 7Pw=
+SECTION ADDITIONAL
+rhino.cis.vutbr.cz. 83217 IN A 147.229.3.10
+rhino.cis.vutbr.cz. 83217 IN AAAA 2001:67c:1220:e000::93e5:30a
+shark.ro.vutbr.cz. 3600 IN A 147.229.2.59
+pipit.cis.vutbr.cz. 14794 IN A 77.93.219.110
+pipit.cis.vutbr.cz. 14794 IN AAAA 2a01:430:120::4d5d:db6e
+rhino.cis.vutbr.cz. 83217 IN RRSIG A 5 4 86400 20170204080646 20170105080646 28257 cis.vutbr.cz. X/tDf8e3JEV0LxiItfpQnBzeaRIq693VG8d30iCH4/1I0uqyCfxboWmm /CBpn9A8MCJu9NEEv+4+povNlfUfqi2yjsqJEVj8ztHxD4g9cc284Cv6 ySjxrSZ9axVqoaopEXujiTwwWJUFcgF6pxqyXVksW7sgKJrboM4VSlQD +Sw=
+rhino.cis.vutbr.cz. 83217 IN RRSIG AAAA 5 4 86400 20170204080646 20170105080646 28257 cis.vutbr.cz. T3Yf5PAkSeJtoOH90ea9zZBG9FC3iFhiCSerDn6d9up8GRfzxDsavYJC zQu+3vnOySySn+3TMzQSSFcWdJC2iO7ulaDGr177Gof9QJbKSVSMW7jt YDE2f4/R4Go3NZVwjk/HfpCInoR6pHNA1s/9hMnWtiVopmBdfzyd3/sW YOU=
+shark.ro.vutbr.cz. 3600 IN RRSIG A 5 4 3600 20170222120032 20170123120032 12150 ro.vutbr.cz. SmhgyF48yX/6yH7AdSmGX60NL/xaiKH/oAzB0rnPfQZ6j+UfV57ginVV lj798K9A8jjucUpqE8ua2mZ6/aOhpqlV2iI0CZXG44zOupsCY1/OXBDx YNetBcjoXDQCBQRLLLEUL5FerDVxqT74ngdLdKubwRdrB0TLQlvpBr+F Tc8=
+pipit.cis.vutbr.cz. 85923 IN RRSIG A 5 4 86400 20170204080646 20170105080646 28257 cis.vutbr.cz. Cz9etHnEOQTzu+6rYJEqx/SQ1tQgPOCyf8HSj4KOsx89jtgiHNC6pep6 ZE0SphMGAs3jC/uGIhlaFNZ3i38OQIMuqwacbz+XZyW5bByvV3QZrhqh dFxMDfmPuNiCAT3crFpUkvVW1OE3YfGHzZGXX7JP5wb1b8A3X6Qih7fV +nQ=
+pipit.cis.vutbr.cz. 85923 IN RRSIG AAAA 5 4 86400 20170204080646 20170105080646 28257 cis.vutbr.cz. piafjh6my2fooZRrzwCu9RQ95gYaMQkhIkDaGX/fT6wXzSdmgFZkS1Nl EMIKdDCQaPrLGMG3p32ptMkAm4esPekeyNtLSMBtXwZyUkgEGn6h1QM2 Yr3TOo8cixfk5nmRRdlYadf5krLb8yI9exiqeymgEQLa1YNRz/bWArlX bn8=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA DO
+SECTION QUESTION
+ro.vutbr.cz. IN NS
+SECTION ANSWER
+ro.vutbr.cz. 86400 IN NS pipit.cis.vutbr.cz.
+ro.vutbr.cz. 86400 IN NS rhino.cis.vutbr.cz.
+ro.vutbr.cz. 86400 IN NS shark.ro.vutbr.cz.
+ro.vutbr.cz. 86400 IN RRSIG NS 5 3 86400 20170222120032 20170123120032 12150 ro.vutbr.cz. HAQ8A+QNsS1WIXdW/fbT3jP+IxObBBvgUmvzsmJBXo8HMtnMAcuCQGmB 2JBQsQethQXsdyLnMK8to/5A9VRkqkAa7edxUoy7SdDi/mzGeLAVhF+5 kXSPD6t1vjiNdnIYAMpiOQbodCGxAnq6jnNyrjEzffdq3qw+5IkFNdG4 7Pw=
+SECTION ADDITIONAL
+rhino.cis.vutbr.cz. 86400 IN A 147.229.3.10
+rhino.cis.vutbr.cz. 86400 IN AAAA 2001:67c:1220:e000::93e5:30a
+shark.ro.vutbr.cz. 3600 IN A 147.229.2.59
+pipit.cis.vutbr.cz. 86400 IN A 77.93.219.110
+pipit.cis.vutbr.cz. 86400 IN AAAA 2a01:430:120::4d5d:db6e
+rhino.cis.vutbr.cz. 86400 IN RRSIG A 5 4 86400 20170204080646 20170105080646 28257 cis.vutbr.cz. X/tDf8e3JEV0LxiItfpQnBzeaRIq693VG8d30iCH4/1I0uqyCfxboWmm /CBpn9A8MCJu9NEEv+4+povNlfUfqi2yjsqJEVj8ztHxD4g9cc284Cv6 ySjxrSZ9axVqoaopEXujiTwwWJUFcgF6pxqyXVksW7sgKJrboM4VSlQD +Sw=
+rhino.cis.vutbr.cz. 86400 IN RRSIG AAAA 5 4 86400 20170204080646 20170105080646 28257 cis.vutbr.cz. T3Yf5PAkSeJtoOH90ea9zZBG9FC3iFhiCSerDn6d9up8GRfzxDsavYJC zQu+3vnOySySn+3TMzQSSFcWdJC2iO7ulaDGr177Gof9QJbKSVSMW7jt YDE2f4/R4Go3NZVwjk/HfpCInoR6pHNA1s/9hMnWtiVopmBdfzyd3/sW YOU=
+shark.ro.vutbr.cz. 3600 IN RRSIG A 5 4 3600 20170222120032 20170123120032 12150 ro.vutbr.cz. SmhgyF48yX/6yH7AdSmGX60NL/xaiKH/oAzB0rnPfQZ6j+UfV57ginVV lj798K9A8jjucUpqE8ua2mZ6/aOhpqlV2iI0CZXG44zOupsCY1/OXBDx YNetBcjoXDQCBQRLLLEUL5FerDVxqT74ngdLdKubwRdrB0TLQlvpBr+F Tc8=
+pipit.cis.vutbr.cz. 86400 IN RRSIG A 5 4 86400 20170204080646 20170105080646 28257 cis.vutbr.cz. Cz9etHnEOQTzu+6rYJEqx/SQ1tQgPOCyf8HSj4KOsx89jtgiHNC6pep6 ZE0SphMGAs3jC/uGIhlaFNZ3i38OQIMuqwacbz+XZyW5bByvV3QZrhqh dFxMDfmPuNiCAT3crFpUkvVW1OE3YfGHzZGXX7JP5wb1b8A3X6Qih7fV +nQ=
+pipit.cis.vutbr.cz. 86400 IN RRSIG AAAA 5 4 86400 20170204080646 20170105080646 28257 cis.vutbr.cz. piafjh6my2fooZRrzwCu9RQ95gYaMQkhIkDaGX/fT6wXzSdmgFZkS1Nl EMIKdDCQaPrLGMG3p32ptMkAm4esPekeyNtLSMBtXwZyUkgEGn6h1QM2 Yr3TOo8cixfk5nmRRdlYadf5krLb8yI9exiqeymgEQLa1YNRz/bWArlX bn8=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA DO
+SECTION QUESTION
+ro.vutbr.cz. IN DS
+SECTION ANSWER
+ro.vutbr.cz. 28800 IN DS 16627 5 2 1AEE56EAF9D01A51C8C524E55A7FAE0E27207911F0FA6126052CE5B3 39335FC8
+ro.vutbr.cz. 28800 IN DS 16627 5 1 BFDFD0FB1EDFCEBFB9ECB13C93F9CA65755217BA
+ro.vutbr.cz. 28800 IN RRSIG DS 5 3 28800 20170216060902 20170117060902 39756 vutbr.cz. OOJfGI14bRHqeWhRLMOa75pfHo+clR4rMJpvO3PPjmheownqy2awA7u3 xR5FJko7A6e+difoJdAWCMzN7x1qcrd1htOOKOc7wtcb+QC2JH8B/e0G 0gNPw2UKsFL1Qw9HQkSqxyIaCGg3nMLO1hh3AVccZadw2f/jLpAzw5/1 pLA=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA DO
+SECTION QUESTION
+ro.vutbr.cz. IN DNSKEY
+SECTION ANSWER
+ro.vutbr.cz. 3600 IN DNSKEY 256 3 5 AwEAAb4tyN4pqltB48s1xQS3ZPXnTZJMvgXxiouXU9xtzj4wnhjhZp45 H7ozslWuksrwQWhZ8AASAD5kPFbQRbwpQ7xbEb3xdKHaWCFpyRCTkrqa ZQZQy4gaVqO+oRW42dIQ9K08A/WfvRuRDtw3VWDATp9pUkgpvb1n6+lp 71YK19RX
+ro.vutbr.cz. 3600 IN DNSKEY 257 3 5 AwEAAef6bqTAl94KddNHvit41gw6QBKkiYjUeS+UP58VHybV29RC7sSE +rYmkXabaMOLmoqMQRMepBEaUdM5OoZBWibHrPAbG0Wf+vlMOoWD5+EC 2mCxrUntIlOuS4XpMTh22+l0k1xSPiMGKjY0BDR95Iu3dDezCVl9PkPp tHj/rAnRTH7Q0fH9Mip8sigosd/CmsoY03I0AcZT4z1+XpGsq5Npxwtj 7cz0SRTI/eV5nynNYK+vr6kOfU1fw7p8/wxIfXkks0Xy8ktXa26DFdw1 RoqVlTS1s1diFyF5niCOT6Ei2kAlf0fggZJBypwoK+6J42wwD2OhORX+ lKrhooaN4TU9AcHwgv25XTXhUq4tYh+veazdXNWDjEb3ZyLM8fKERCa9 YtDBFoHM7yFOHbsOhHKMn8F6T2Boi73hU/+wspjL/n8taKevyyygGg+U g4ugo2pTIouAs5DNnv+nUrpctcKZ5nMEUVl+3XBsXplIyz9QEKHWdFzL gyfIZEok8WdYHebcIy1vJrxzqCNw9ixnTn+OK1lwlMToVH1AGpvRKRPo wGSFaIrDyXxKul34j2jEhP9TWRcJqncy166Ueu3c0BKmclM29N8jeWbP 3TqRJ3RRxNj/vk6c/UGmmrHEz8YdNp2L0hv3JgItr2GujCvPApUvLNPW C7DSErQ3JsjV3gah
+ro.vutbr.cz. 3600 IN RRSIG DNSKEY 5 3 3600 20170222120032 20170123120032 12150 ro.vutbr.cz. pN+8YElj24dhtnOQ20sjWxJTjx+FLTMrPms1lWIJKZtp2evQBG5AnAep 6w0QeMUTIh9ter58Dh6wu2IN4uA1h3ThxnSgwLraOChUFBtPTO8h5y8J mAq4KXSfqbEcHzZO/nBAtxSUk7aUz7yWf09xE+iozW3ORRWIXovMYci5 eEw=
+ro.vutbr.cz. 3600 IN RRSIG DNSKEY 5 3 3600 20170222120032 20170123120032 16627 ro.vutbr.cz. DSaIAl+iyToM8+ai9xuRVcRshYyI66XHWkOz0XEbIAwbc8aEMEeFCA91 1vpuBb6H92MXvM8hYsBhZHNIA0ApoIE4bdyEGZY05XN3GYgJ4BEhXJVM RR+inJf+vGGqdlRP6F2sPO+rCqfxWBvSoUFU7DpCpkl7hz2Ex0Clm9C9 YnWgL+tGmAH33s2Y8lTA3hG/0W0NxD5zy1LiyDa8Ls3vV4MC6gVxyloT Capd8FkDL9PmgW0gMRNtIWmc5Hw+j/HRMoy+oRCe8PIfUL/Dpx3iTAH8 iN3wV8apV2uPa0L8QgpixK4Tc87aSainCopVY+NOc5t0HErUzj8i7qA9 J/cRtQvlUzln5vBsrQsVIzIeNV4o8/cM3zFyfdKkHh1tWYKLJKkjfXc5 +7VMvF8PnoHceT/Zr2gCc8tnygRobypzgqy3p69bRJqiT0/eCAgpGusV 1DCOJY0sdiGDZEtpqeINbAgGKAMmmNwjIwYSFowRzdawip1wNd+90RhI +8hvx8Sc5+K5Mom2BF2wGHf/2Kv/ArzyXxqqcNozM61L1AjxIsBHjnLZ TzPlLntmiHUVaqET9Yc3G0K/RdsIpqz4M79N0BX66a58x2a3fLqQdrEC QshZPNxk2S4eCsrVRjHvU4a7e74Rbf/zXp89Y+jmwBbDMdnp+2/h9s6U J0sEBCYyo9M=
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR AA DO
+SECTION QUESTION
+piranha.ro.vutbr.cz. IN A
+SECTION ANSWER
+piranha.ro.vutbr.cz. 3600 IN A 147.229.2.90
+piranha.ro.vutbr.cz. 3600 IN RRSIG A 5 4 3600 20170222120032 20170123120032 12150 ro.vutbr.cz. Jz8bcAADQjCKTCcF70IK1aHGQlM4ukyN0myABlxoPaqid1mHX5jwR91b kdQmUAh2xDitlgRLbFjbUUgmjSPzQ5Qt7GAFUsVmqxvjbOLZjqHER1dh zmiWO0fDvvP647Osv3RiAP822rNUJcJrUBZU9LmeP05gwIHcpJrhdVBT b7I=
+SECTION AUTHORITY
+ro.vutbr.cz. 86400 IN NS shark.ro.vutbr.cz.
+ro.vutbr.cz. 86400 IN NS rhino.cis.vutbr.cz.
+ro.vutbr.cz. 86400 IN NS pipit.cis.vutbr.cz.
+ro.vutbr.cz. 86400 IN RRSIG NS 5 3 86400 20170222120032 20170123120032 12150 ro.vutbr.cz. HAQ8A+QNsS1WIXdW/fbT3jP+IxObBBvgUmvzsmJBXo8HMtnMAcuCQGmB 2JBQsQethQXsdyLnMK8to/5A9VRkqkAa7edxUoy7SdDi/mzGeLAVhF+5 kXSPD6t1vjiNdnIYAMpiOQbodCGxAnq6jnNyrjEzffdq3qw+5IkFNdG4 7Pw=
+SECTION ADDITIONAL
+rhino.cis.vutbr.cz. 86400 IN A 147.229.3.10
+rhino.cis.vutbr.cz. 86400 IN AAAA 2001:67c:1220:e000::93e5:30a
+shark.ro.vutbr.cz. 3600 IN A 147.229.2.59
+pipit.cis.vutbr.cz. 86400 IN A 77.93.219.110
+pipit.cis.vutbr.cz. 86400 IN AAAA 2a01:430:120::4d5d:db6e
+rhino.cis.vutbr.cz. 86400 IN RRSIG A 5 4 86400 20170204080646 20170105080646 28257 cis.vutbr.cz. X/tDf8e3JEV0LxiItfpQnBzeaRIq693VG8d30iCH4/1I0uqyCfxboWmm /CBpn9A8MCJu9NEEv+4+povNlfUfqi2yjsqJEVj8ztHxD4g9cc284Cv6 ySjxrSZ9axVqoaopEXujiTwwWJUFcgF6pxqyXVksW7sgKJrboM4VSlQD +Sw=
+rhino.cis.vutbr.cz. 86400 IN RRSIG AAAA 5 4 86400 20170204080646 20170105080646 28257 cis.vutbr.cz. T3Yf5PAkSeJtoOH90ea9zZBG9FC3iFhiCSerDn6d9up8GRfzxDsavYJC zQu+3vnOySySn+3TMzQSSFcWdJC2iO7ulaDGr177Gof9QJbKSVSMW7jt YDE2f4/R4Go3NZVwjk/HfpCInoR6pHNA1s/9hMnWtiVopmBdfzyd3/sW YOU=
+shark.ro.vutbr.cz. 3600 IN RRSIG A 5 4 3600 20170222120032 20170123120032 12150 ro.vutbr.cz. SmhgyF48yX/6yH7AdSmGX60NL/xaiKH/oAzB0rnPfQZ6j+UfV57ginVV lj798K9A8jjucUpqE8ua2mZ6/aOhpqlV2iI0CZXG44zOupsCY1/OXBDx YNetBcjoXDQCBQRLLLEUL5FerDVxqT74ngdLdKubwRdrB0TLQlvpBr+F Tc8=
+pipit.cis.vutbr.cz. 86400 IN RRSIG A 5 4 86400 20170204080646 20170105080646 28257 cis.vutbr.cz. Cz9etHnEOQTzu+6rYJEqx/SQ1tQgPOCyf8HSj4KOsx89jtgiHNC6pep6 ZE0SphMGAs3jC/uGIhlaFNZ3i38OQIMuqwacbz+XZyW5bByvV3QZrhqh dFxMDfmPuNiCAT3crFpUkvVW1OE3YfGHzZGXX7JP5wb1b8A3X6Qih7fV +nQ=
+pipit.cis.vutbr.cz. 86400 IN RRSIG AAAA 5 4 86400 20170204080646 20170105080646 28257 cis.vutbr.cz. piafjh6my2fooZRrzwCu9RQ95gYaMQkhIkDaGX/fT6wXzSdmgFZkS1Nl EMIKdDCQaPrLGMG3p32ptMkAm4esPekeyNtLSMBtXwZyUkgEGn6h1QM2 Yr3TOo8cixfk5nmRRdlYadf5krLb8yI9exiqeymgEQLa1YNRz/bWArlX bn8=
+ENTRY_END
+
+; end of pipit.cis.vutbr.cz. & rhino.cis.vutbr.cz.
+RANGE_END
+
+
+STEP 1 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+www.vutbr.cz. IN A
+ENTRY_END
+
+; recursion happens here.
+STEP 10 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH flags rcode question answer
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+www.vutbr.cz. IN A
+SECTION ANSWER
+www.vutbr.cz. IN CNAME piranha.ro.vutbr.cz.
+piranha.ro.vutbr.cz. IN A 147.229.2.90
+ENTRY_END
+
+STEP 20 QUERY
+ENTRY_BEGIN
+REPLY RD DO
+SECTION QUESTION
+www.vutbr.cz. IN A
+ENTRY_END
+
+STEP 21 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH flags rcode question answer
+REPLY QR RD RA AD NOERROR
+SECTION QUESTION
+www.vutbr.cz. IN A
+SECTION ANSWER
+www.vutbr.cz. IN CNAME piranha.ro.vutbr.cz.
+www.vutbr.cz. IN RRSIG CNAME 5 3 300 20170216060902 20170117060902 39756 vutbr.cz. 9B3UC5SOEw1+yKlYlOTINEuNq0Kdglywc5IYJwzeSzQ3ykptzZo3ABSy bYhTqImVkhm/4NFM9/4HWMHPDzTmrWS0mCI/ljCd/oe/PxW/uESvo4P5 EQzlcuH6xBzc1KdEFAJOSmRzFjj3vyK1QN3k/c+1y2oMFOYOR2oOzCw+ MIE=
+piranha.ro.vutbr.cz. IN A 147.229.2.90
+piranha.ro.vutbr.cz. 3600 IN RRSIG A 5 4 3600 20170222120032 20170123120032 12150 ro.vutbr.cz. Jz8bcAADQjCKTCcF70IK1aHGQlM4ukyN0myABlxoPaqid1mHX5jwR91b kdQmUAh2xDitlgRLbFjbUUgmjSPzQ5Qt7GAFUsVmqxvjbOLZjqHER1dh zmiWO0fDvvP647Osv3RiAP822rNUJcJrUBZU9LmeP05gwIHcpJrhdVBT b7I=
+ENTRY_END
+
+SCENARIO_END
diff --git a/lib/cache/peek.c b/lib/cache/peek.c
new file mode 100644
index 0000000..e1901ac
--- /dev/null
+++ b/lib/cache/peek.c
@@ -0,0 +1,774 @@
+/* Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz>
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "lib/cache/impl.h"
+
+#include "lib/dnssec/ta.h"
+#include "lib/layer/iterate.h"
+
+/* The whole file only exports peek_nosync().
+ * Forwards for larger chunks of code: */
+
+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(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 answer_dname_hit(kr_layer_t *ctx, knot_pkt_t *pkt, const knot_dname_t *dname_owner,
+ 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,
+ uint16_t type, uint8_t lowest_rank,
+ const struct kr_query *qry, struct kr_cache *cache);
+
+static int peek_encloser(
+ struct key *k, struct answer *ans, int sname_labels,
+ uint8_t lowest_rank, const struct kr_query *qry, struct kr_cache *cache);
+
+
+static int nsec_p_init(struct nsec_p *nsec_p, knot_db_val_t nsec_p_entry, bool with_knot)
+{
+ const size_t stamp_len = sizeof(uint32_t);
+ if (nsec_p_entry.len <= stamp_len) { /* plain NSEC if equal */
+ nsec_p->raw = NULL;
+ nsec_p->hash = 0;
+ return kr_ok();
+ }
+ nsec_p->raw = (uint8_t *)nsec_p_entry.data + stamp_len;
+ nsec_p->hash = nsec_p_mkHash(nsec_p->raw);
+ if (!with_knot) return kr_ok();
+ /* 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));
+}
+
+/** 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 uint32_t timestamp, int32_t *new_ttl)
+{
+ if (kr_fails_assert(entry.data))
+ return kr_error(EINVAL);
+ uint32_t stamp;
+ if (!entry.len)
+ return kr_error(ENOENT);
+ if (kr_fails_assert(entry.len >= sizeof(stamp)))
+ return kr_error(EILSEQ);
+ memcpy(&stamp, entry.data, sizeof(stamp));
+ int32_t newttl = stamp - timestamp;
+ if (new_ttl) *new_ttl = newttl;
+ return newttl < 0 ? kr_error(ESTALE) : kr_ok();
+}
+
+static uint8_t get_lowest_rank(const struct kr_query *qry, const knot_dname_t *name, const uint16_t type)
+{
+ /* Shut up linters. */
+ kr_require(qry && qry->request);
+ /* TODO: move rank handling into the iterator (DNSSEC_* flags)? */
+ const bool allow_unverified =
+ knot_wire_get_cd(qry->request->qsource.packet->wire) || qry->flags.STUB;
+ /* in stub mode we don't trust RRs anyway ^^ */
+ if (qry->flags.NONAUTH) {
+ return KR_RANK_INITIAL;
+ /* Note: there's little sense in validation status for non-auth records.
+ * In case of using NONAUTH to get NS IPs, knowing that you ask correct
+ * IP doesn't matter much for security; it matters whether you can
+ * validate the answers from the NS.
+ */
+ } else if (!allow_unverified) {
+ /* Records not present under any TA don't have their security
+ * verified at all, so we also accept low ranks in that case. */
+ const bool ta_covers = kr_ta_closest(qry->request->ctx, name, type);
+ /* ^ TODO: performance? TODO: stype - call sites */
+ if (ta_covers) {
+ return KR_RANK_INSECURE | KR_RANK_AUTH;
+ } /* else fallthrough */
+ }
+ return KR_RANK_INITIAL | KR_RANK_AUTH;
+}
+
+
+/** Almost whole .produce phase for the cache module.
+ * \note we don't transition to KR_STATE_FAIL even in case of "unexpected errors".
+ */
+int peek_nosync(kr_layer_t *ctx, knot_pkt_t *pkt)
+{
+ struct kr_request *req = ctx->req;
+ struct kr_query *qry = req->current_query;
+ struct kr_cache *cache = &req->ctx->cache;
+
+ struct key k_storage, *k = &k_storage;
+ int ret = kr_dname_lf(k->buf, qry->sname, false);
+ if (kr_fails_assert(ret == 0))
+ return ctx->state;
+
+ const uint8_t lowest_rank = get_lowest_rank(qry, qry->sname, qry->stype);
+
+ /**** 1. find the name or the closest (available) zone, not considering wildcards
+ **** 1a. exact name+type match (can be negative, mainly in insecure zones) */
+ {
+ knot_db_val_t key = key_exact_type_maypkt(k, qry->stype);
+ knot_db_val_t val = { NULL, 0 };
+ ret = cache_op(cache, read, &key, &val, 1);
+ if (!ret) {
+ /* found an entry: test conditions, materialize into pkt, etc. */
+ ret = found_exact_hit(ctx, pkt, val, lowest_rank);
+ }
+ }
+ if (!ret) {
+ return KR_STATE_DONE;
+ } else if (kr_fails_assert(ret == kr_error(ENOENT))) {
+ VERBOSE_MSG(qry, "=> exact hit error: %d %s\n", ret, kr_strerror(ret));
+ return ctx->state;
+ }
+
+ /* Avoid aggressive answers in STUB mode.
+ * As STUB mode doesn't validate, it wouldn't save the necessary records.
+ * Moreover, this special case avoids unintentional NXDOMAIN on grafted subtrees. */
+ if (qry->flags.STUB)
+ return ctx->state;
+
+ /**** 1b. otherwise, find the longest prefix zone/xNAME (with OK time+rank). [...] */
+ k->zname = qry->sname;
+ ret = kr_dname_lf(k->buf, k->zname, false); /* LATER(optim.): probably remove */
+ if (kr_fails_assert(ret == 0))
+ return ctx->state;
+ entry_list_t el;
+ ret = closest_NS(cache, k, el, qry, false, qry->stype == KNOT_RRTYPE_DS);
+ if (ret) {
+ if (kr_fails_assert(ret == kr_error(ENOENT)) || !el[0].len) {
+ return ctx->state;
+ }
+ }
+ switch (k->type) {
+ case KNOT_RRTYPE_CNAME: {
+ const knot_db_val_t v = el[EL_CNAME];
+ if (kr_fails_assert(v.data && v.len))
+ return ctx->state;
+ const int32_t new_ttl = get_new_ttl(v.data, qry, qry->sname,
+ KNOT_RRTYPE_CNAME, qry->timestamp.tv_sec);
+ ret = answer_simple_hit(ctx, pkt, KNOT_RRTYPE_CNAME, v.data,
+ knot_db_val_bound(v), new_ttl);
+ return ret == kr_ok() ? KR_STATE_DONE : ctx->state;
+ }
+ case KNOT_RRTYPE_DNAME: {
+ const knot_db_val_t v = el[EL_DNAME];
+ if (kr_fails_assert(v.data && v.len))
+ return ctx->state;
+ /* TTL: for simplicity, we just ask for TTL of the generated CNAME. */
+ const int32_t new_ttl = get_new_ttl(v.data, qry, qry->sname,
+ KNOT_RRTYPE_CNAME, qry->timestamp.tv_sec);
+ ret = answer_dname_hit(ctx, pkt, k->zname, v.data,
+ knot_db_val_bound(v), new_ttl);
+ return ret == kr_ok() ? KR_STATE_DONE : ctx->state;
+ }
+ }
+
+ /* We have to try proving from NSEC*. */
+ auto_free char *log_zname = NULL;
+ WITH_VERBOSE(qry) {
+ log_zname = kr_dname_text(k->zname);
+ if (!el[0].len) {
+ VERBOSE_MSG(qry, "=> no NSEC* cached for zone: %s\n", log_zname);
+ }
+ }
+
+#if 0
+ if (!eh) { /* fall back to root hints? */
+ ret = kr_zonecut_set_sbelt(req->ctx, &qry->zone_cut);
+ if (ret) return ctx->state;
+ kr_assert(!qry->zone_cut.parent);
+
+ //VERBOSE_MSG(qry, "=> using root hints\n");
+ //qry->flags.AWAIT_CUT = false;
+ return ctx->state;
+ }
+
+ /* Now `eh` points to the closest NS record that we've found,
+ * and that's the only place to start - we may either find
+ * a negative proof or we may query upstream from that point. */
+ kr_zonecut_set(&qry->zone_cut, k->zname);
+ ret = kr_make_query(qry, pkt); // TODO: probably not yet - qname minimization
+ if (ret) return ctx->state;
+#endif
+
+ /** Structure for collecting multiple NSEC* + RRSIG records,
+ * in preparation for the answer, and for tracking the progress. */
+ struct answer ans;
+ memset(&ans, 0, sizeof(ans));
+ ans.mm = &pkt->mm;
+ const int sname_labels = knot_dname_labels(qry->sname, NULL);
+
+ /* Try the NSEC* parameters in order, until success.
+ * 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->timestamp.tv_sec, &log_new_ttl);
+ if (!ret || kr_log_is_debug_qry(CACHE, qry)) {
+ nsec_p_init(&ans.nsec_p, el[i], !ret);
+ }
+ if (ret) {
+ VERBOSE_MSG(qry, "=> skipping zone: %s, %s, hash %x;"
+ "new TTL %d, ret %d\n",
+ log_zname, (ans.nsec_p.raw ? "NSEC3" : "NSEC"),
+ (unsigned)ans.nsec_p.hash, (int)log_new_ttl, ret);
+ /* no need for nsec_p_cleanup() in this case */
+ goto cont;
+ }
+ VERBOSE_MSG(qry, "=> trying zone: %s, %s, hash %x\n",
+ log_zname, (ans.nsec_p.raw ? "NSEC3" : "NSEC"),
+ (unsigned)ans.nsec_p.hash);
+ /**** 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:
+ /* Otherwise we try another nsec_p, if available. */
+ if (++i == ENTRY_APEX_NSECS_CNT) return ctx->state;
+ /* clear possible partial answers in `ans` (no need to deallocate) */
+ ans.rcode = 0;
+ memset(&ans.rrsets, 0, sizeof(ans.rrsets));
+ }
+
+ /**** 4. add SOA iff needed */
+ if (ans.rcode != PKT_NOERROR) {
+ /* Assuming k->buf still starts with zone's prefix,
+ * look up the SOA in cache. */
+ k->buf[0] = k->zlf_len;
+ knot_db_val_t key = key_exact_type(k, KNOT_RRTYPE_SOA);
+ knot_db_val_t val = { NULL, 0 };
+ ret = cache_op(cache, read, &key, &val, 1);
+ const struct entry_h *eh;
+ if (ret || !(eh = entry_h_consistent_E(val, KNOT_RRTYPE_SOA))) {
+ kr_assert(ret); /* only want to catch `eh` failures */
+ VERBOSE_MSG(qry, "=> SOA missed\n");
+ return ctx->state;
+ }
+ /* Check if the record is OK. */
+ int32_t new_ttl = get_new_ttl(eh, qry, k->zname, KNOT_RRTYPE_SOA,
+ qry->timestamp.tv_sec);
+ if (new_ttl < 0 || eh->rank < lowest_rank || eh->is_packet) {
+ VERBOSE_MSG(qry, "=> SOA unfit %s: rank 0%.2o, new TTL %d\n",
+ (eh->is_packet ? "packet" : "RR"),
+ eh->rank, new_ttl);
+ return ctx->state;
+ }
+ /* Add the SOA into the answer. */
+ ret = entry2answer(&ans, AR_SOA, eh, knot_db_val_bound(val),
+ k->zname, KNOT_RRTYPE_SOA, new_ttl);
+ if (ret) return ctx->state;
+ }
+
+ /* Find our target RCODE. */
+ int real_rcode;
+ switch (ans.rcode) {
+ case PKT_NODATA:
+ case PKT_NOERROR: /* positive wildcarded response */
+ real_rcode = KNOT_RCODE_NOERROR;
+ break;
+ case PKT_NXDOMAIN:
+ real_rcode = KNOT_RCODE_NXDOMAIN;
+ break;
+ default:
+ kr_assert(false);
+ case 0: /* i.e. nothing was found */
+ /* LATER(optim.): zone cut? */
+ VERBOSE_MSG(qry, "=> cache miss\n");
+ return ctx->state;
+ }
+
+ if (pkt_renew(pkt, qry->sname, qry->stype)
+ || knot_pkt_begin(pkt, KNOT_ANSWER)
+ ) {
+ kr_assert(false);
+ return ctx->state;
+ }
+ knot_wire_set_rcode(pkt->wire, real_rcode);
+
+ bool expiring = false; // TODO
+ for (int i = 0; i < sizeof(ans.rrsets) / sizeof(ans.rrsets[0]); ++i) {
+ if (i == 1) knot_pkt_begin(pkt, KNOT_AUTHORITY);
+ if (!ans.rrsets[i].set.rr) continue;
+ expiring = expiring || ans.rrsets[i].set.expiring;
+ ret = pkt_append(pkt, &ans.rrsets[i], ans.rrsets[i].set.rank);
+ if (kr_fails_assert(ret == 0))
+ return ctx->state;
+ }
+
+ /* Finishing touches. */
+ struct kr_qflags * const qf = &qry->flags;
+ qf->EXPIRING = expiring;
+ qf->CACHED = true;
+ qf->NO_MINIMIZE = true;
+
+ return KR_STATE_DONE;
+}
+
+/**
+ * This is where the high-level "business logic" of aggressive cache is.
+ * \return 0: success (may need SOA); >0: try other nsec_p; <0: exit cache immediately.
+ */
+static int peek_encloser(
+ struct key *k, struct answer *ans, const int sname_labels,
+ uint8_t lowest_rank, const struct kr_query *qry, struct kr_cache *cache)
+{
+ /** Start of NSEC* covering the sname;
+ * it's part of key - the one within zone (read only) */
+ knot_db_val_t cover_low_kwz = { NULL, 0 };
+ knot_dname_t cover_hi_storage[KNOT_DNAME_MAXLEN];
+ /** End of NSEC* covering the sname. */
+ knot_db_val_t cover_hi_kwz = {
+ .data = cover_hi_storage,
+ .len = sizeof(cover_hi_storage),
+ };
+
+ /**** 2. Find a closest (provable) encloser (of sname). */
+ int clencl_labels = -1;
+ bool clencl_is_tentative = false;
+ 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,
+ 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;
+ }
+
+ /* We should have either a match or a cover at this point. */
+ if (kr_fails_assert(ans->rcode == PKT_NODATA || ans->rcode == PKT_NXDOMAIN))
+ return kr_error(EINVAL);
+ const bool ncloser_covered = ans->rcode == PKT_NXDOMAIN;
+
+ /** Name of the closest (provable) encloser. */
+ const knot_dname_t *clencl_name = qry->sname;
+ for (int l = sname_labels; l > clencl_labels; --l)
+ clencl_name = knot_wire_next_label(clencl_name, NULL);
+
+ /**** 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.raw) {
+ int ret = nsec1_src_synth(k, ans, clencl_name,
+ cover_low_kwz, cover_hi_kwz, qry, cache);
+ if (ret == AR_SOA) return 0;
+ kr_assert(ret <= 0);
+ if (ret) return ret;
+
+ } 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;
+ kr_assert(ret <= 0);
+ if (ret) return ret;
+
+ } /* else (!ncloser_covered) so no wildcard checks needed,
+ * as we proved that sname exists. */
+
+ /**** 3b. find wildcarded answer, if next closer name was covered
+ * and we don't have a full proof yet. (common for NSEC*) */
+ if (!ncloser_covered)
+ return kr_ok(); /* decrease indentation */
+ /* Construct key for exact qry->stype + source of synthesis. */
+ int ret = kr_dname_lf(k->buf, clencl_name, true);
+ if (kr_fails_assert(ret == 0))
+ return kr_error(ret);
+ const uint16_t types[] = { qry->stype, KNOT_RRTYPE_CNAME };
+ for (int i = 0; i < (2 - (qry->stype == KNOT_RRTYPE_CNAME)); ++i) {
+ ret = try_wild(k, ans, clencl_name, types[i],
+ lowest_rank, qry, cache);
+ if (ret == kr_ok()) {
+ return kr_ok();
+ } else if (kr_fails_assert(ret == kr_error(ENOENT) || ret == kr_error(ESTALE))) {
+ return kr_error(ret);
+ }
+ /* else continue */
+ }
+ /* Neither attempt succeeded, but the NSEC* proofs were found,
+ * so skip trying other parameters, as it seems very unlikely
+ * to turn out differently than by the same wildcard search. */
+ return kr_error(ENOENT);
+}
+
+static void answer_simple_qflags(struct kr_qflags *qf, const struct entry_h *eh,
+ uint32_t new_ttl)
+{
+ /* Finishing touches. */
+ qf->EXPIRING = is_expiring(eh->ttl, new_ttl);
+ qf->CACHED = true;
+ qf->NO_MINIMIZE = true;
+ qf->DNSSEC_INSECURE = kr_rank_test(eh->rank, KR_RANK_INSECURE);
+ if (qf->DNSSEC_INSECURE) {
+ qf->DNSSEC_WANT = false;
+ }
+}
+
+#define CHECK_RET(ret) do { \
+ if (kr_fails_assert((ret) >= 0)) return kr_error((ret)); \
+} while (false)
+
+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)
+{
+ struct kr_request *req = ctx->req;
+ struct kr_query *qry = req->current_query;
+
+ /* All OK, so start constructing the (pseudo-)packet. */
+ int ret = pkt_renew(pkt, qry->sname, qry->stype);
+ CHECK_RET(ret);
+
+ /* Materialize the sets for the answer in (pseudo-)packet. */
+ struct answer ans;
+ memset(&ans, 0, sizeof(ans));
+ ans.mm = &pkt->mm;
+ ret = entry2answer(&ans, AR_ANSWER, eh, eh_bound,
+ qry->sname, type, new_ttl);
+ CHECK_RET(ret);
+ /* Put links to the materialized data into the pkt. */
+ ret = pkt_append(pkt, &ans.rrsets[AR_ANSWER], eh->rank);
+ CHECK_RET(ret);
+
+ answer_simple_qflags(&qry->flags, eh, new_ttl);
+
+ VERBOSE_MSG(qry, "=> satisfied by exact %s: rank 0%.2o, new TTL %d\n",
+ (type == KNOT_RRTYPE_CNAME ? "CNAME" : "RRset"),
+ eh->rank, new_ttl);
+ return kr_ok();
+}
+
+static int answer_dname_hit(kr_layer_t *ctx, knot_pkt_t *pkt, const knot_dname_t *dname_owner,
+ const struct entry_h *eh, const void *eh_bound, uint32_t new_ttl)
+{
+ struct kr_request *req = ctx->req;
+ struct kr_query *qry = req->current_query;
+
+ /* All OK, so start constructing the (pseudo-)packet. */
+ int ret = pkt_renew(pkt, qry->sname, qry->stype);
+ CHECK_RET(ret);
+
+ /* Materialize the DNAME for the answer in (pseudo-)packet. */
+ struct answer ans;
+ memset(&ans, 0, sizeof(ans));
+ ans.mm = &pkt->mm;
+ ret = entry2answer(&ans, AR_ANSWER, eh, eh_bound,
+ dname_owner, KNOT_RRTYPE_DNAME, new_ttl);
+ CHECK_RET(ret);
+ /* Put link to the RRset into the pkt. */
+ ret = pkt_append(pkt, &ans.rrsets[AR_ANSWER], eh->rank);
+ CHECK_RET(ret);
+ const knot_dname_t *dname_target =
+ knot_dname_target(ans.rrsets[AR_ANSWER].set.rr->rrs.rdata);
+
+ /* Generate CNAME RRset for the answer in (pseudo-)packet. */
+ const int AR_CNAME = AR_SOA;
+ knot_rrset_t *rr = ans.rrsets[AR_CNAME].set.rr
+ = knot_rrset_new(qry->sname, KNOT_RRTYPE_CNAME, KNOT_CLASS_IN,
+ new_ttl, ans.mm);
+ CHECK_RET(rr ? kr_ok() : -ENOMEM);
+ const knot_dname_t *cname_target = knot_dname_replace_suffix(qry->sname,
+ knot_dname_labels(dname_owner, NULL), dname_target, ans.mm);
+ CHECK_RET(cname_target ? kr_ok() : -ENOMEM);
+ const int rdata_len = knot_dname_size(cname_target);
+
+ if (rdata_len <= KNOT_DNAME_MAXLEN
+ && knot_dname_labels(cname_target, NULL) <= KNOT_DNAME_MAXLABELS) {
+ /* Normal case: the target name fits. */
+ rr->rrs.count = 1;
+ rr->rrs.size = knot_rdata_size(rdata_len);
+ rr->rrs.rdata = mm_alloc(ans.mm, rr->rrs.size);
+ CHECK_RET(rr->rrs.rdata ? kr_ok() : -ENOMEM);
+ knot_rdata_init(rr->rrs.rdata, rdata_len, cname_target);
+ /* Put link to the RRset into the pkt. */
+ ret = pkt_append(pkt, &ans.rrsets[AR_CNAME], eh->rank);
+ CHECK_RET(ret);
+ } else {
+ /* Note that it's basically a successful answer; name just doesn't fit. */
+ knot_wire_set_rcode(pkt->wire, KNOT_RCODE_YXDOMAIN);
+ }
+
+ answer_simple_qflags(&qry->flags, eh, new_ttl);
+ VERBOSE_MSG(qry, "=> satisfied by DNAME+CNAME: rank 0%.2o, new TTL %d\n",
+ eh->rank, new_ttl);
+ return kr_ok();
+}
+
+#undef CHECK_RET
+
+/** TODO: description; see the single call site for now. */
+static int found_exact_hit(kr_layer_t *ctx, knot_pkt_t *pkt, knot_db_val_t val,
+ uint8_t lowest_rank)
+{
+ struct kr_request *req = ctx->req;
+ struct kr_query *qry = req->current_query;
+
+ int ret = entry_h_seek(&val, qry->stype);
+ if (ret) return ret;
+ const struct entry_h *eh = entry_h_consistent_E(val, qry->stype);
+ if (kr_fails_assert(eh))
+ return kr_error(ENOENT);
+ // LATER: recovery in case of error, perhaps via removing the entry?
+ // LATER(optim): perhaps optimize the zone cut search
+
+ int32_t new_ttl = get_new_ttl(eh, qry, qry->sname, qry->stype,
+ qry->timestamp.tv_sec);
+ if (new_ttl < 0 || eh->rank < lowest_rank) {
+ /* Positive record with stale TTL or bad rank.
+ * LATER(optim.): It's unlikely that we find a negative one,
+ * so we might theoretically skip all the cache code. */
+
+ VERBOSE_MSG(qry, "=> skipping exact %s: rank 0%.2o (min. 0%.2o), new TTL %d\n",
+ eh->is_packet ? "packet" : "RR", eh->rank, lowest_rank, new_ttl);
+ return kr_error(ENOENT);
+ }
+
+ const uint8_t *eh_bound = knot_db_val_bound(val);
+ if (eh->is_packet) {
+ /* Note: we answer here immediately, even if it's (theoretically)
+ * possible that we could generate a higher-security negative proof.
+ * Rank is high-enough so we take it to save time searching;
+ * in practice this also helps in some incorrect zones (live-signed). */
+ return answer_from_pkt (ctx, pkt, qry->stype, eh, eh_bound, new_ttl);
+ } else {
+ return answer_simple_hit(ctx, pkt, qry->stype, eh, eh_bound, new_ttl);
+ }
+}
+
+
+/** 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)
+{
+ knot_db_val_t key = key_exact_type(k, type);
+ /* Find the record. */
+ knot_db_val_t val = { NULL, 0 };
+ int ret = cache_op(cache, read, &key, &val, 1);
+ if (!ret) {
+ ret = entry_h_seek(&val, type);
+ }
+ if (ret) {
+ if (kr_fails_assert(ret == kr_error(ENOENT)))
+ VERBOSE_MSG(qry, "=> wildcard: hit error %d %s\n",
+ ret, strerror(abs(ret)));
+ WITH_VERBOSE(qry) {
+ auto_free char *clencl_str = kr_dname_text(clencl_name),
+ *type_str = kr_rrtype_text(type);
+ VERBOSE_MSG(qry, "=> wildcard: not found: *.%s %s\n",
+ clencl_str, type_str);
+ }
+ return ret;
+ }
+ /* Check if the record is OK. */
+ const struct entry_h *eh = entry_h_consistent_E(val, type);
+ if (kr_fails_assert(eh))
+ return kr_error(ret);
+ // LATER: recovery in case of error, perhaps via removing the entry?
+ int32_t new_ttl = get_new_ttl(eh, qry, qry->sname, type, qry->timestamp.tv_sec);
+ /* ^^ here we use the *expanded* wildcard name */
+ if (new_ttl < 0 || eh->rank < lowest_rank || eh->is_packet) {
+ /* Wildcard record with stale TTL, bad rank or packet. */
+ VERBOSE_MSG(qry, "=> wildcard: skipping %s, rank 0%.2o, new TTL %d\n",
+ eh->is_packet ? "packet" : "RR", eh->rank, new_ttl);
+ return kr_error(ESTALE);
+ }
+ /* Add the RR into the answer. */
+ ret = entry2answer(ans, AR_ANSWER, eh, knot_db_val_bound(val),
+ qry->sname, type, new_ttl);
+ VERBOSE_MSG(qry, "=> wildcard: answer expanded, ret = %d, new TTL %d\n",
+ ret, (int)new_ttl);
+ if (ret) return kr_error(ret);
+ ans->rcode = PKT_NOERROR;
+ return kr_ok();
+}
+
+int kr_cache_closest_apex(struct kr_cache *cache, const knot_dname_t *name, bool is_DS,
+ knot_dname_t ** apex)
+{
+ if (kr_fails_assert(cache && cache->db && name && apex && *apex == NULL))
+ 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;
+ *apex = knot_dname_copy(k->zname, NULL);
+ if (!*apex)
+ return kr_error(ENOMEM);
+ return kr_ok();
+}
+
+/** \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(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->*.
+ *
+ * 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(struct kr_cache *cache, struct key *k, entry_list_t el,
+ struct kr_query *qry, const bool only_NS, const bool is_DS)
+{
+ /* 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];
+
+ // LATER(optim): if stype is NS, we check the same value again
+ bool exact_match = true;
+ bool need_zero = true;
+ /* Inspect the NS/xNAME entries, shortening by a label on each iteration. */
+ do {
+ k->buf[0] = zlf_len;
+ knot_db_val_t key = key_exact_type(k, KNOT_RRTYPE_NS);
+ knot_db_val_t val;
+ int ret = cache_op(cache, read, &key, &val, 1);
+ if (ret == kr_error(ENOENT)) goto next_label;
+ if (kr_fails_assert(ret == 0)) {
+ if (need_zero) memset(el, 0, sizeof(entry_list_t));
+ return kr_error(ret);
+ }
+
+ /* Check consistency, find any type;
+ * using `goto` for shortening by another label. */
+ ret = entry_list_parse(val, el);
+ if (kr_fails_assert(ret == 0)) // do something about it?
+ goto next_label;
+ need_zero = false;
+ /* More types are possible; try in order.
+ * For non-fatal failures just "continue;" to try the next type. */
+ /* Now a complication - we need to try EL_DNAME before NSEC*
+ * (Unfortunately that's not easy to write very nicely.) */
+ if (!only_NS) {
+ const int i = EL_DNAME;
+ 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. */
+ k->zlf_len = zlf_len;
+ return kr_ok();
+ }
+ }
+ const int el_count = only_NS ? EL_NS + 1 : EL_LENGTH;
+ for (int i = 0; i < el_count; ++i) {
+ if (i == EL_DNAME) continue;
+ 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. */
+ k->zlf_len = zlf_len;
+ return kr_ok();
+ }
+ }
+
+ next_label:
+ /* remove one more label */
+ exact_match = false;
+ if (k->zname[0] == 0) {
+ /* We miss root NS in cache, but let's at least assume it exists. */
+ k->type = KNOT_RRTYPE_NS;
+ k->zlf_len = zlf_len;
+ kr_assert(zlf_len == 0);
+ if (need_zero) memset(el, 0, sizeof(entry_list_t));
+ return kr_error(ENOENT);
+ }
+ zlf_len -= (k->zname[0] + 1);
+ k->zname += (k->zname[0] + 1);
+ k->buf[zlf_len + 1] = 0;
+ } while (true);
+}
+
+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. */
+ || (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. */
+ || (i == EL_CNAME && !exact_match)
+ /* DNAME is interesting only if we did NOT
+ * directly hit the name that was asked. */
+ || (i == EL_DNAME && exact_match)
+ ) {
+ return ESKIP;
+ }
+
+ uint16_t type;
+ 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, timestamp, &log_new_ttl);
+ if (err) {
+ VERBOSE_MSG(qry,
+ "=> skipping unfit nsec_p: new TTL %d, error %d\n",
+ (int)log_new_ttl, err);
+ return ESKIP;
+ }
+ } else {
+ type = EL2RRTYPE(i);
+ /* Find the entry for the type, check positivity, TTL */
+ const struct entry_h *eh = entry_h_consistent_E(entry, type);
+ if (kr_fails_assert(eh)) {
+ VERBOSE_MSG(qry, "=> EH not consistent\n");
+ return kr_error(EILSEQ);
+ }
+ const int32_t log_new_ttl = get_new_ttl(eh, qry, k->zname, type, timestamp);
+
+ const bool ok = /* Not interested in negative bogus or outdated RRs. */
+ !eh->is_packet && log_new_ttl >= 0
+ /* For NS any kr_rank is accepted, as insecure or even nonauth is OK */
+ && (type == KNOT_RRTYPE_NS
+ || eh->rank >= get_lowest_rank(qry, k->zname, type));
+
+ WITH_VERBOSE(qry) { if (!ok) {
+ auto_free char *type_str = kr_rrtype_text(type);
+ const char *packet_str = eh->is_packet ? "packet" : "RR";
+ VERBOSE_MSG(qry,
+ "=> skipping unfit %s %s: rank 0%.2o, new TTL %d\n",
+ type_str, packet_str, eh->rank, (int)log_new_ttl);
+ } }
+ if (!ok) return ESKIP;
+ }
+ k->type = type;
+ return kr_ok();
+}
+
diff --git a/lib/cache/test.integr/cache_minimal_nsec3.rpl b/lib/cache/test.integr/cache_minimal_nsec3.rpl
new file mode 100644
index 0000000..7c4a5cf
--- /dev/null
+++ b/lib/cache/test.integr/cache_minimal_nsec3.rpl
@@ -0,0 +1,4120 @@
+; SPDX-License-Identifier: GPL-3.0-or-later
+ trust-anchor: ". IN DS 20326 8 2 E06D44B80B8F1D39A95C0B0D7C65D08458E880409BBC683457104237C7F8EC8D"
+ val-override-date: 20190625160934
+ stub-addr: 2001:503:ba3e::2:30
+CONFIG_END
+
+SCENARIO_BEGIN Test that minimal NSEC3 range does not trigger agressive cache (workaround for buggy auths, optimization to improve cache hit rate on correct auths using black lies)
+
+; Group's zones:
+; .
+; root-servers.net.
+; Server names:
+; f.root-servers.net.
+; a.root-servers.net.
+; j.root-servers.net.
+; e.root-servers.net.
+; i.root-servers.net.
+; d.root-servers.net.
+; m.root-servers.net.
+; h.root-servers.net.
+; c.root-servers.net.
+; l.root-servers.net.
+; g.root-servers.net.
+; b.root-servers.net.
+; k.root-servers.net.
+RANGE_BEGIN 0 1000
+ ADDRESS 2001:500:2f::f
+ ADDRESS 2001:503:ba3e::2:30
+ ADDRESS 2001:500:12::d0d
+ ADDRESS 202.12.27.33
+ ADDRESS 2001:7fd::1
+ ADDRESS 2001:503:c27::2:30
+ ADDRESS 2001:500:200::b
+ ADDRESS 198.97.190.53
+ ADDRESS 192.58.128.30
+ ADDRESS 198.41.0.4
+ ADDRESS 199.7.91.13
+ ADDRESS 2001:dc3::35
+ ADDRESS 192.36.148.17
+ ADDRESS 192.203.230.10
+ ADDRESS 192.5.5.241
+ ADDRESS 199.9.14.201
+ ADDRESS 193.0.14.129
+ ADDRESS 2001:7fe::53
+ ADDRESS 2001:500:9f::42
+ ADDRESS 2001:500:a8::e
+ ADDRESS 2001:500:2d::d
+ ADDRESS 192.112.36.4
+ ADDRESS 2001:500:2::c
+ ADDRESS 192.33.4.12
+ ADDRESS 199.7.83.42
+ ADDRESS 2001:500:1::53
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+i.root-servers.net. IN AAAA
+SECTION ANSWER
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+g.root-servers.net. IN NS
+SECTION AUTHORITY
+root-servers.net. 3600000 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2019061700 14400 7200 1209600 3600000
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+e.root-servers.net. IN A
+SECTION ANSWER
+e.root-servers.net. 3600000 IN A 192.203.230.10
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+f.root-servers.net. IN NS
+SECTION AUTHORITY
+root-servers.net. 3600000 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2019061700 14400 7200 1209600 3600000
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+i.root-servers.net. IN A
+SECTION ANSWER
+i.root-servers.net. 3600000 IN A 192.36.148.17
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+c.root-servers.net. IN NS
+SECTION AUTHORITY
+root-servers.net. 3600000 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2019061700 14400 7200 1209600 3600000
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+root-servers.net. IN DS
+SECTION AUTHORITY
+root-servers.net. 3600000 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2019061700 14400 7200 1209600 3600000
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+c.root-servers.net. IN A
+SECTION ANSWER
+c.root-servers.net. 3600000 IN A 192.33.4.12
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+d.root-servers.net. IN A
+SECTION ANSWER
+d.root-servers.net. 3600000 IN A 199.7.91.13
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+f.root-servers.net. IN AAAA
+SECTION ANSWER
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+. IN NS
+SECTION ANSWER
+. 518400 IN NS a.root-servers.net.
+. 518400 IN NS b.root-servers.net.
+. 518400 IN NS c.root-servers.net.
+. 518400 IN NS d.root-servers.net.
+. 518400 IN NS e.root-servers.net.
+. 518400 IN NS f.root-servers.net.
+. 518400 IN NS g.root-servers.net.
+. 518400 IN NS h.root-servers.net.
+. 518400 IN NS i.root-servers.net.
+. 518400 IN NS j.root-servers.net.
+. 518400 IN NS k.root-servers.net.
+. 518400 IN NS l.root-servers.net.
+. 518400 IN NS m.root-servers.net.
+. 518400 IN RRSIG NS 8 0 518400 20190708050000 20190625040000 25266 . IwbmJVqFUjJz5WwRbYqOWejRck85QWW8 eIGID2J+Qhw89iUDDz2lgvysed4WQfks 8Y2XZu79T0+RJF+mj1UUiE+Y6RdOmFDU Qx3ovGkYwOXcr1anreBD+Wn5tv1WW6El NbKf40pXdtDX6Ad1qx6hCHHR4hieQPww psNHmrGDg+Eog+VqYjwwRj9EaYEms5dU PRJmiHiACe85DZMCjxl6f+kp7ZXyFD/L coLi7QzXiRWYOPHhWKk3pqYGD1j7I7YB Oq7UujK+jPscWCDuArGmZwlhAtAPaPLe 5TZHIGE39c6eYpuXwSXZ1EPM545/9WsI HihzUQ75ltuiPXwjv0OpQg==
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+j.root-servers.net. IN NS
+SECTION AUTHORITY
+root-servers.net. 3600000 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2019061700 14400 7200 1209600 3600000
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+a.root-servers.net. IN A
+SECTION ANSWER
+a.root-servers.net. 3600000 IN A 198.41.0.4
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+h.root-servers.net. IN NS
+SECTION AUTHORITY
+root-servers.net. 3600000 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2019061700 14400 7200 1209600 3600000
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+g.root-servers.net. IN A
+SECTION ANSWER
+g.root-servers.net. 3600000 IN A 192.112.36.4
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+k.root-servers.net. IN A
+SECTION ANSWER
+k.root-servers.net. 3600000 IN A 193.0.14.129
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+m.root-servers.net. IN AAAA
+SECTION ANSWER
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+. IN DNSKEY
+SECTION ANSWER
+. 172800 IN DNSKEY 256 3 8 AwEAAcTQyaIe6nt3xSPOG2L/YfwBkOVT JN6mlnZ249O5Rtt3ZSRQHxQSW61AODYw 6bvgxrrGq8eeOuenFjcSYgNAMcBYoEYY mKDW6e9EryW4ZaT/MCq+8Am06oR40xAA 3fClOM6QjRcT85tP41Go946AicBGP8XO P/Aj1aI/oPRGzRnboUPUok/AzTNnW5np BU69+BuiIwYE7mQOiNBFePyvjQBdoiuY bmuD3Py0IyjlBxzZUXbqLsRL9gYFkCqe TY29Ik7usuzMTa+JRSLz6KGS5RSJ7CTS MjZg8aNaUbN2dvGhakJPh92HnLvMA3Te fFgbKJphFNPA3BWSKLZ02cRWXqM=
+. 172800 IN DNSKEY 256 3 8 AwEAAeVDC34GZILwsQJy97K2Fst4P3XY ZrXLyrkausYzSqEjSUulgh+iLgHg0y7F IF890+sIjXsk7KLJUmCOWfYWPorNKEOK Lk5Zx/4M6D3IHZE3O3m/Eahrc28qQzmT LxiMZAW65MvR2UO3LxVtYOPBEBiDgAQD 47x2JLsJYtavCzNL5WiUk59OgvHmDqmc C7VXYBhK8V8Tic089XJgExGeplKWUt9y yc31ra1swJX51XsOaQz17+vyLVH8AZP2 6KvKFiZeoRbaq6vl+hc8HQnI2ug5rA2z oz3MsSQBvP1f/HvqsWxLqwXXKyDD1QM6 39U+XzVB8CYigyscRP22QCnwKIU=
+. 172800 IN DNSKEY 257 3 8 AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexT BAvkMgJzkKTOiW1vkIbzxeF3+/4RgWOq 7HrxRixHlFlExOLAJr5emLvN7SWXgnLh 4+B5xQlNVz8Og8kvArMtNROxVQuCaSnI DdD5LKyWbRd2n9WGe2R8PzgCmr3EgVLr jyBxWezF0jLHwVN8efS3rCj/EWgvIWgb 9tarpVUDK/b58Da+sqqls3eNbuv7pr+e oZG+SrDK6nWeL3c6H5Apxz7LjVc1uTId sIXxuOLYA4/ilBmSVIzuDWfdRUfhHdY6 +cn8HFRm+2hM8AnXGXws9555KrUB5qih ylGa8subX2Nn6UwNR1AkUTV74bU=
+. 172800 IN RRSIG DNSKEY 8 0 172800 20190711000000 20190620000000 20326 . LeNUOIxGGe+xAKxr13YIXNqMAxVH7RuD XQyVclUuxA9aENp0+yYkeIL+/lkTteEh dHXNVZqYch8QrvcsuCpDN2gKx5D5M04g KAjR5ywgvEdsZHr9DhjCZ3uvXKvbPsi6 14QpjYCxxvtq/ZZE6dhm59K3N3T8Mhm5 l36b6w+fR1F3Kc+eeJqy2ZjVxNe9CClE 4Qy6q78Yu6rS1vZkuzG1l2AT9Gko72St WbdsU2Ry9fBk+uCJOLxej37z5Rfi5EAz FcnfwQYryqCRt2go9PuD0/AulqG8wmTV z23tnwnaxowkYKxFH2yE0d7pDiFjvOyU HdGPXYwl/+GDmjrQsN6JPQ==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+b.root-servers.net. IN NS
+SECTION AUTHORITY
+root-servers.net. 3600000 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2019061700 14400 7200 1209600 3600000
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+k.root-servers.net. IN NS
+SECTION AUTHORITY
+root-servers.net. 3600000 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2019061700 14400 7200 1209600 3600000
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+. IN DS
+SECTION AUTHORITY
+. 86400 IN NSEC aaa. NS SOA RRSIG NSEC DNSKEY
+. 86400 IN RRSIG NSEC 8 0 86400 20190708050000 20190625040000 25266 . fAYegvNXOW8j+x++y5EWtNQlie56/WO+ w6PlDWJ87oZPgUJuYPxqCIpoKJttfUBR o1nOzZaUlxQeOE0Daep/fnlo8OtAfauK w5J+l5rZqcaM6C9MA7cB7ZswPVd1p609 rPqgGoxSvuNuX/iFPBqPQhRw5JyiVuwF Q4PSB3Etq85BXUEhlpfcQAt6z3scHlLa ARoZoea3/u9z/xuB+296IgZHOQkp3WJL zJivnrQFisO7vQ7o01t0x6WxtskBwbf3 GXwHg/2DbHY/7QJ4hVWO0/L+tdeJciTM 92+RC/U7GkUPDb0rvfOfntB2MKz0rZhU g5m+qJOJYpG8HGN69f4dyQ==
+. 86400 IN RRSIG SOA 8 0 86400 20190708050000 20190625040000 25266 . kYJsFlFDsY3FO94BM5DRROo34/8EZODz iOXejYh397rIJqr5bjx315WJabGoAf3p gtQ5U6QXDJnrKnuZYK/4b+mYyef722if vfNdKclJxKp5vwdDGKLEu7Z2Ey09K4WD MPeyemaIIlbDw3F7lYzz0ZiZubagtrZu OeD2CUOJO4qauzUpGtXf4cx0r+aQJkPq 4eXQyBQ4gg6Mdh4iBNgjGhYB9SLFNMtb eRMNpJG2ifhjP+pNWd27+TGHOhHTu082 osz2lNYKibuMoEfQeHNlINGIU+8oTa/K 3O7IlOAp1APvDmbKnLgy9FFf+6yCMo5y r+A0RVMZheQA3iEXBGug+g==
+. 86400 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2019062500 1800 900 604800 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+c.root-servers.net. IN AAAA
+SECTION ANSWER
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+l.root-servers.net. IN NS
+SECTION AUTHORITY
+root-servers.net. 3600000 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2019061700 14400 7200 1209600 3600000
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+b.root-servers.net. IN A
+SECTION ANSWER
+b.root-servers.net. 3600000 IN A 199.9.14.201
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+m.root-servers.net. IN NS
+SECTION AUTHORITY
+root-servers.net. 3600000 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2019061700 14400 7200 1209600 3600000
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR RD NOERROR
+SECTION QUESTION
+csas.cz. IN DS
+SECTION AUTHORITY
+cz. 172800 IN NS a.ns.nic.cz.
+cz. 172800 IN NS b.ns.nic.cz.
+cz. 172800 IN NS c.ns.nic.cz.
+cz. 172800 IN NS d.ns.nic.cz.
+cz. 86400 IN DS 20237 13 2 cff0f3ecdbc529c1f0031ba1840bfb835853b9209ed1e508fff48451d7b778e2
+cz. 86400 IN RRSIG DS 8 1 86400 20190708050000 20190625040000 25266 . r7Lxqu4C80oW46tP7BNfJWrXs2K5YEqn IkEKfzXSFqur0cSfnj630EPQfokTYO2Q RCOT/JaNpbUi69MS+d81xFZb5efzzoYE tL3tCE8axm39kzuHKhk2EOSIN8sQPCTC isLppgCbLRPbzKima8Jk5kGs7pV+FK9K vCExdukQ4aB7MYvIZaKzHKP8NAOgKdVk x/BrrGl8IV0T+YvUDo9e8gpdcbhLFXoN w+qZ9xVNIvhSsjzzL1fxrkjJIEdTPzrS HXdUjK8v56KppQJ0pr+XSq2CicRbcn5b ur5HQz4yKfIr2q7aH9CMGuwbMLNDWnjO G+iHdA/ekKLYQ5afWOxaqw==
+SECTION ADDITIONAL
+a.ns.nic.cz. 172800 IN A 194.0.12.1
+a.ns.nic.cz. 172800 IN AAAA 2001:678:f::1
+b.ns.nic.cz. 172800 IN A 194.0.13.1
+b.ns.nic.cz. 172800 IN AAAA 2001:678:10::1
+c.ns.nic.cz. 172800 IN A 194.0.14.1
+c.ns.nic.cz. 172800 IN AAAA 2001:678:11::1
+d.ns.nic.cz. 172800 IN A 193.29.206.1
+d.ns.nic.cz. 172800 IN AAAA 2001:678:1::1
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+a.root-servers.net. IN NS
+SECTION AUTHORITY
+root-servers.net. 3600000 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2019061700 14400 7200 1209600 3600000
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+g.root-servers.net. IN AAAA
+SECTION ANSWER
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+cz. IN DS
+SECTION ANSWER
+cz. 86400 IN DS 20237 13 2 cff0f3ecdbc529c1f0031ba1840bfb835853b9209ed1e508fff48451d7b778e2
+cz. 86400 IN RRSIG DS 8 1 86400 20190708050000 20190625040000 25266 . r7Lxqu4C80oW46tP7BNfJWrXs2K5YEqn IkEKfzXSFqur0cSfnj630EPQfokTYO2Q RCOT/JaNpbUi69MS+d81xFZb5efzzoYE tL3tCE8axm39kzuHKhk2EOSIN8sQPCTC isLppgCbLRPbzKima8Jk5kGs7pV+FK9K vCExdukQ4aB7MYvIZaKzHKP8NAOgKdVk x/BrrGl8IV0T+YvUDo9e8gpdcbhLFXoN w+qZ9xVNIvhSsjzzL1fxrkjJIEdTPzrS HXdUjK8v56KppQJ0pr+XSq2CicRbcn5b ur5HQz4yKfIr2q7aH9CMGuwbMLNDWnjO G+iHdA/ekKLYQ5afWOxaqw==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+j.root-servers.net. IN AAAA
+SECTION ANSWER
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+d.root-servers.net. IN AAAA
+SECTION ANSWER
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+l.root-servers.net. IN AAAA
+SECTION ANSWER
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+a.root-servers.net. IN AAAA
+SECTION ANSWER
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+e.root-servers.net. IN AAAA
+SECTION ANSWER
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+j.root-servers.net. IN A
+SECTION ANSWER
+j.root-servers.net. 3600000 IN A 192.58.128.30
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+i.root-servers.net. IN NS
+SECTION AUTHORITY
+root-servers.net. 3600000 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2019061700 14400 7200 1209600 3600000
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+k.root-servers.net. IN AAAA
+SECTION ANSWER
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+net. IN DS
+SECTION ANSWER
+net. 86400 IN DS 35886 8 2 7862b27f5f516ebe19680444d4ce5e762981931842c465f00236401d8bd973ee
+net. 86400 IN RRSIG DS 8 1 86400 20190708050000 20190625040000 25266 . EK4wI33V5RQyA5SAxBfX1oTiDeGfOzXr u0OA6KaXALQOMELkugzUD3NipvVpzO7B 0ZYSsnNn+Kk1h0qJBE/ZWpHHZyvZCg1o zo+kq1Z7gGJvlV4Y9XfuwIGPZKL0tlkm LBVSBd36yQy/x4gFyBKvRgIDd1IyKrjT xJYENyNwvtj3MkrT+Njsg1NWXP5ORRx1 r0zVlq2snbJsp8ze+sLYrSqVXbihg4mq JoMe7NB4M9EYEMfBOUcWo8Wrj73jiYRx 0uJ3HfvOHBqBgVFyhMcr4FeCiN9F9V6C xTQBQnL3lQF1TnOhN//Z7h7TvLulxHRu DeKEsZDcoC4el8u1Fx7t/w==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+f.root-servers.net. IN A
+SECTION ANSWER
+f.root-servers.net. 3600000 IN A 192.5.5.241
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+f.root-servers.net. IN A
+SECTION ANSWER
+f.root-servers.net. 3600000 IN A 192.5.5.241
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+f.root-servers.net. IN AAAA
+SECTION ANSWER
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+h.root-servers.net. IN AAAA
+SECTION ANSWER
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+e.root-servers.net. IN NS
+SECTION AUTHORITY
+root-servers.net. 3600000 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2019061700 14400 7200 1209600 3600000
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+b.root-servers.net. IN AAAA
+SECTION ANSWER
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR RD NOERROR
+SECTION QUESTION
+gtld-servers.net. IN DS
+SECTION AUTHORITY
+net. 172800 IN NS a.gtld-servers.net.
+net. 172800 IN NS b.gtld-servers.net.
+net. 172800 IN NS c.gtld-servers.net.
+net. 172800 IN NS d.gtld-servers.net.
+net. 172800 IN NS e.gtld-servers.net.
+net. 172800 IN NS f.gtld-servers.net.
+net. 172800 IN NS g.gtld-servers.net.
+net. 172800 IN NS h.gtld-servers.net.
+net. 172800 IN NS i.gtld-servers.net.
+net. 172800 IN NS j.gtld-servers.net.
+net. 172800 IN NS k.gtld-servers.net.
+net. 172800 IN NS l.gtld-servers.net.
+net. 172800 IN NS m.gtld-servers.net.
+net. 86400 IN DS 35886 8 2 7862b27f5f516ebe19680444d4ce5e762981931842c465f00236401d8bd973ee
+net. 86400 IN RRSIG DS 8 1 86400 20190708050000 20190625040000 25266 . EK4wI33V5RQyA5SAxBfX1oTiDeGfOzXr u0OA6KaXALQOMELkugzUD3NipvVpzO7B 0ZYSsnNn+Kk1h0qJBE/ZWpHHZyvZCg1o zo+kq1Z7gGJvlV4Y9XfuwIGPZKL0tlkm LBVSBd36yQy/x4gFyBKvRgIDd1IyKrjT xJYENyNwvtj3MkrT+Njsg1NWXP5ORRx1 r0zVlq2snbJsp8ze+sLYrSqVXbihg4mq JoMe7NB4M9EYEMfBOUcWo8Wrj73jiYRx 0uJ3HfvOHBqBgVFyhMcr4FeCiN9F9V6C xTQBQnL3lQF1TnOhN//Z7h7TvLulxHRu DeKEsZDcoC4el8u1Fx7t/w==
+SECTION ADDITIONAL
+a.gtld-servers.net. 172800 IN A 192.5.6.30
+a.gtld-servers.net. 172800 IN AAAA 2001:503:a83e::2:30
+b.gtld-servers.net. 172800 IN A 192.33.14.30
+b.gtld-servers.net. 172800 IN AAAA 2001:503:231d::2:30
+c.gtld-servers.net. 172800 IN A 192.26.92.30
+c.gtld-servers.net. 172800 IN AAAA 2001:503:83eb::30
+d.gtld-servers.net. 172800 IN A 192.31.80.30
+d.gtld-servers.net. 172800 IN AAAA 2001:500:856e::30
+e.gtld-servers.net. 172800 IN A 192.12.94.30
+e.gtld-servers.net. 172800 IN AAAA 2001:502:1ca1::30
+f.gtld-servers.net. 172800 IN A 192.35.51.30
+f.gtld-servers.net. 172800 IN AAAA 2001:503:d414::30
+g.gtld-servers.net. 172800 IN A 192.42.93.30
+g.gtld-servers.net. 172800 IN AAAA 2001:503:eea3::30
+h.gtld-servers.net. 172800 IN A 192.54.112.30
+h.gtld-servers.net. 172800 IN AAAA 2001:502:8cc::30
+i.gtld-servers.net. 172800 IN A 192.43.172.30
+i.gtld-servers.net. 172800 IN AAAA 2001:503:39c1::30
+j.gtld-servers.net. 172800 IN A 192.48.79.30
+j.gtld-servers.net. 172800 IN AAAA 2001:502:7094::30
+k.gtld-servers.net. 172800 IN A 192.52.178.30
+k.gtld-servers.net. 172800 IN AAAA 2001:503:d2d::30
+l.gtld-servers.net. 172800 IN A 192.41.162.30
+l.gtld-servers.net. 172800 IN AAAA 2001:500:d937::30
+m.gtld-servers.net. 172800 IN A 192.55.83.30
+m.gtld-servers.net. 172800 IN AAAA 2001:501:b1f9::30
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR RD NOERROR
+SECTION QUESTION
+nstld.com. IN DS
+SECTION AUTHORITY
+com. 172800 IN NS a.gtld-servers.net.
+com. 172800 IN NS b.gtld-servers.net.
+com. 172800 IN NS c.gtld-servers.net.
+com. 172800 IN NS d.gtld-servers.net.
+com. 172800 IN NS e.gtld-servers.net.
+com. 172800 IN NS f.gtld-servers.net.
+com. 172800 IN NS g.gtld-servers.net.
+com. 172800 IN NS h.gtld-servers.net.
+com. 172800 IN NS i.gtld-servers.net.
+com. 172800 IN NS j.gtld-servers.net.
+com. 172800 IN NS k.gtld-servers.net.
+com. 172800 IN NS l.gtld-servers.net.
+com. 172800 IN NS m.gtld-servers.net.
+com. 86400 IN DS 30909 8 2 e2d3c916f6deeac73294e8268fb5885044a833fc5459588f4a9184cfc41a5766
+com. 86400 IN RRSIG DS 8 1 86400 20190708050000 20190625040000 25266 . h8CYVMqouUO2IAPlG4Iqf06ykpl07wny KuM2dRGhrfx5hQbF0CpzGRwT2B6i2drI td9i7BSA4GVKLlTYr9n3Xd+BcAHKwywv 44A2WmTAo3xWMv4THwowwu29B4bAKe0V WQKDfmZ92m1yn8T3MCNZWtuGGaLcY6+g fKgyuHu5fEakVn2GFMdAMayBBFTF0bp4 hVFuNSJBe/1EnFZMcxU9aNuCyC8xup25 7K3x1rcM0hthHr8o0Vevpima1YXsWDGb RDIkDyStPDIQ1c0C9LHMaaGR+MA+fxoL 2x4w2lwOptCK//zpfyPvj11oIyouwgdh Fe3PCf9hS03Y1FsiY+mtWw==
+SECTION ADDITIONAL
+a.gtld-servers.net. 172800 IN A 192.5.6.30
+a.gtld-servers.net. 172800 IN AAAA 2001:503:a83e::2:30
+b.gtld-servers.net. 172800 IN A 192.33.14.30
+b.gtld-servers.net. 172800 IN AAAA 2001:503:231d::2:30
+c.gtld-servers.net. 172800 IN A 192.26.92.30
+c.gtld-servers.net. 172800 IN AAAA 2001:503:83eb::30
+d.gtld-servers.net. 172800 IN A 192.31.80.30
+d.gtld-servers.net. 172800 IN AAAA 2001:500:856e::30
+e.gtld-servers.net. 172800 IN A 192.12.94.30
+e.gtld-servers.net. 172800 IN AAAA 2001:502:1ca1::30
+f.gtld-servers.net. 172800 IN A 192.35.51.30
+f.gtld-servers.net. 172800 IN AAAA 2001:503:d414::30
+g.gtld-servers.net. 172800 IN A 192.42.93.30
+g.gtld-servers.net. 172800 IN AAAA 2001:503:eea3::30
+h.gtld-servers.net. 172800 IN A 192.54.112.30
+h.gtld-servers.net. 172800 IN AAAA 2001:502:8cc::30
+i.gtld-servers.net. 172800 IN A 192.43.172.30
+i.gtld-servers.net. 172800 IN AAAA 2001:503:39c1::30
+j.gtld-servers.net. 172800 IN A 192.48.79.30
+j.gtld-servers.net. 172800 IN AAAA 2001:502:7094::30
+k.gtld-servers.net. 172800 IN A 192.52.178.30
+k.gtld-servers.net. 172800 IN AAAA 2001:503:d2d::30
+l.gtld-servers.net. 172800 IN A 192.41.162.30
+l.gtld-servers.net. 172800 IN AAAA 2001:500:d937::30
+m.gtld-servers.net. 172800 IN A 192.55.83.30
+m.gtld-servers.net. 172800 IN AAAA 2001:501:b1f9::30
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+m.root-servers.net. IN A
+SECTION ANSWER
+m.root-servers.net. 3600000 IN A 202.12.27.33
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+h.root-servers.net. IN A
+SECTION ANSWER
+h.root-servers.net. 3600000 IN A 198.97.190.53
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+com. IN DS
+SECTION ANSWER
+com. 86400 IN DS 30909 8 2 e2d3c916f6deeac73294e8268fb5885044a833fc5459588f4a9184cfc41a5766
+com. 86400 IN RRSIG DS 8 1 86400 20190708050000 20190625040000 25266 . h8CYVMqouUO2IAPlG4Iqf06ykpl07wny KuM2dRGhrfx5hQbF0CpzGRwT2B6i2drI td9i7BSA4GVKLlTYr9n3Xd+BcAHKwywv 44A2WmTAo3xWMv4THwowwu29B4bAKe0V WQKDfmZ92m1yn8T3MCNZWtuGGaLcY6+g fKgyuHu5fEakVn2GFMdAMayBBFTF0bp4 hVFuNSJBe/1EnFZMcxU9aNuCyC8xup25 7K3x1rcM0hthHr8o0Vevpima1YXsWDGb RDIkDyStPDIQ1c0C9LHMaaGR+MA+fxoL 2x4w2lwOptCK//zpfyPvj11oIyouwgdh Fe3PCf9hS03Y1FsiY+mtWw==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR RD NOERROR
+SECTION QUESTION
+nic.cz. IN DS
+SECTION AUTHORITY
+cz. 172800 IN NS a.ns.nic.cz.
+cz. 172800 IN NS b.ns.nic.cz.
+cz. 172800 IN NS c.ns.nic.cz.
+cz. 172800 IN NS d.ns.nic.cz.
+cz. 86400 IN DS 20237 13 2 cff0f3ecdbc529c1f0031ba1840bfb835853b9209ed1e508fff48451d7b778e2
+cz. 86400 IN RRSIG DS 8 1 86400 20190708050000 20190625040000 25266 . r7Lxqu4C80oW46tP7BNfJWrXs2K5YEqn IkEKfzXSFqur0cSfnj630EPQfokTYO2Q RCOT/JaNpbUi69MS+d81xFZb5efzzoYE tL3tCE8axm39kzuHKhk2EOSIN8sQPCTC isLppgCbLRPbzKima8Jk5kGs7pV+FK9K vCExdukQ4aB7MYvIZaKzHKP8NAOgKdVk x/BrrGl8IV0T+YvUDo9e8gpdcbhLFXoN w+qZ9xVNIvhSsjzzL1fxrkjJIEdTPzrS HXdUjK8v56KppQJ0pr+XSq2CicRbcn5b ur5HQz4yKfIr2q7aH9CMGuwbMLNDWnjO G+iHdA/ekKLYQ5afWOxaqw==
+SECTION ADDITIONAL
+a.ns.nic.cz. 172800 IN A 194.0.12.1
+a.ns.nic.cz. 172800 IN AAAA 2001:678:f::1
+b.ns.nic.cz. 172800 IN A 194.0.13.1
+b.ns.nic.cz. 172800 IN AAAA 2001:678:10::1
+c.ns.nic.cz. 172800 IN A 194.0.14.1
+c.ns.nic.cz. 172800 IN AAAA 2001:678:11::1
+d.ns.nic.cz. 172800 IN A 193.29.206.1
+d.ns.nic.cz. 172800 IN AAAA 2001:678:1::1
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+l.root-servers.net. IN A
+SECTION ANSWER
+l.root-servers.net. 3600000 IN A 199.7.83.42
+SECTION AUTHORITY
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+d.root-servers.net. IN NS
+SECTION AUTHORITY
+root-servers.net. 3600000 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2019061700 14400 7200 1209600 3600000
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH subdomain
+ADJUST copy_id copy_query
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+root-servers.net. IN NS
+SECTION ANSWER
+root-servers.net. 3600000 IN NS a.root-servers.net.
+root-servers.net. 3600000 IN NS b.root-servers.net.
+root-servers.net. 3600000 IN NS c.root-servers.net.
+root-servers.net. 3600000 IN NS d.root-servers.net.
+root-servers.net. 3600000 IN NS e.root-servers.net.
+root-servers.net. 3600000 IN NS f.root-servers.net.
+root-servers.net. 3600000 IN NS g.root-servers.net.
+root-servers.net. 3600000 IN NS h.root-servers.net.
+root-servers.net. 3600000 IN NS i.root-servers.net.
+root-servers.net. 3600000 IN NS j.root-servers.net.
+root-servers.net. 3600000 IN NS k.root-servers.net.
+root-servers.net. 3600000 IN NS l.root-servers.net.
+root-servers.net. 3600000 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 3600000 IN A 198.41.0.4
+a.root-servers.net. 3600000 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 3600000 IN A 199.9.14.201
+b.root-servers.net. 3600000 IN AAAA 2001:500:200::b
+c.root-servers.net. 3600000 IN A 192.33.4.12
+c.root-servers.net. 3600000 IN AAAA 2001:500:2::c
+d.root-servers.net. 3600000 IN A 199.7.91.13
+d.root-servers.net. 3600000 IN AAAA 2001:500:2d::d
+e.root-servers.net. 3600000 IN A 192.203.230.10
+e.root-servers.net. 3600000 IN AAAA 2001:500:a8::e
+f.root-servers.net. 3600000 IN A 192.5.5.241
+f.root-servers.net. 3600000 IN AAAA 2001:500:2f::f
+g.root-servers.net. 3600000 IN A 192.112.36.4
+g.root-servers.net. 3600000 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 3600000 IN A 198.97.190.53
+h.root-servers.net. 3600000 IN AAAA 2001:500:1::53
+i.root-servers.net. 3600000 IN A 192.36.148.17
+i.root-servers.net. 3600000 IN AAAA 2001:7fe::53
+j.root-servers.net. 3600000 IN A 192.58.128.30
+j.root-servers.net. 3600000 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 3600000 IN A 193.0.14.129
+k.root-servers.net. 3600000 IN AAAA 2001:7fd::1
+l.root-servers.net. 3600000 IN A 199.7.83.42
+l.root-servers.net. 3600000 IN AAAA 2001:500:9f::42
+m.root-servers.net. 3600000 IN A 202.12.27.33
+m.root-servers.net. 3600000 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH subdomain
+ADJUST copy_id copy_query
+REPLY QR RD NOERROR
+SECTION QUESTION
+cz. IN NS
+SECTION AUTHORITY
+cz. 172800 IN NS a.ns.nic.cz.
+cz. 172800 IN NS b.ns.nic.cz.
+cz. 172800 IN NS c.ns.nic.cz.
+cz. 172800 IN NS d.ns.nic.cz.
+cz. 86400 IN DS 20237 13 2 cff0f3ecdbc529c1f0031ba1840bfb835853b9209ed1e508fff48451d7b778e2
+cz. 86400 IN RRSIG DS 8 1 86400 20190708050000 20190625040000 25266 . r7Lxqu4C80oW46tP7BNfJWrXs2K5YEqn IkEKfzXSFqur0cSfnj630EPQfokTYO2Q RCOT/JaNpbUi69MS+d81xFZb5efzzoYE tL3tCE8axm39kzuHKhk2EOSIN8sQPCTC isLppgCbLRPbzKima8Jk5kGs7pV+FK9K vCExdukQ4aB7MYvIZaKzHKP8NAOgKdVk x/BrrGl8IV0T+YvUDo9e8gpdcbhLFXoN w+qZ9xVNIvhSsjzzL1fxrkjJIEdTPzrS HXdUjK8v56KppQJ0pr+XSq2CicRbcn5b ur5HQz4yKfIr2q7aH9CMGuwbMLNDWnjO G+iHdA/ekKLYQ5afWOxaqw==
+SECTION ADDITIONAL
+a.ns.nic.cz. 172800 IN A 194.0.12.1
+a.ns.nic.cz. 172800 IN AAAA 2001:678:f::1
+b.ns.nic.cz. 172800 IN A 194.0.13.1
+b.ns.nic.cz. 172800 IN AAAA 2001:678:10::1
+c.ns.nic.cz. 172800 IN A 194.0.14.1
+c.ns.nic.cz. 172800 IN AAAA 2001:678:11::1
+d.ns.nic.cz. 172800 IN A 193.29.206.1
+d.ns.nic.cz. 172800 IN AAAA 2001:678:1::1
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH subdomain
+ADJUST copy_id copy_query
+REPLY QR RD NOERROR
+SECTION QUESTION
+net. IN NS
+SECTION AUTHORITY
+net. 172800 IN NS a.gtld-servers.net.
+net. 172800 IN NS b.gtld-servers.net.
+net. 172800 IN NS c.gtld-servers.net.
+net. 172800 IN NS d.gtld-servers.net.
+net. 172800 IN NS e.gtld-servers.net.
+net. 172800 IN NS f.gtld-servers.net.
+net. 172800 IN NS g.gtld-servers.net.
+net. 172800 IN NS h.gtld-servers.net.
+net. 172800 IN NS i.gtld-servers.net.
+net. 172800 IN NS j.gtld-servers.net.
+net. 172800 IN NS k.gtld-servers.net.
+net. 172800 IN NS l.gtld-servers.net.
+net. 172800 IN NS m.gtld-servers.net.
+net. 86400 IN DS 35886 8 2 7862b27f5f516ebe19680444d4ce5e762981931842c465f00236401d8bd973ee
+net. 86400 IN RRSIG DS 8 1 86400 20190708050000 20190625040000 25266 . EK4wI33V5RQyA5SAxBfX1oTiDeGfOzXr u0OA6KaXALQOMELkugzUD3NipvVpzO7B 0ZYSsnNn+Kk1h0qJBE/ZWpHHZyvZCg1o zo+kq1Z7gGJvlV4Y9XfuwIGPZKL0tlkm LBVSBd36yQy/x4gFyBKvRgIDd1IyKrjT xJYENyNwvtj3MkrT+Njsg1NWXP5ORRx1 r0zVlq2snbJsp8ze+sLYrSqVXbihg4mq JoMe7NB4M9EYEMfBOUcWo8Wrj73jiYRx 0uJ3HfvOHBqBgVFyhMcr4FeCiN9F9V6C xTQBQnL3lQF1TnOhN//Z7h7TvLulxHRu DeKEsZDcoC4el8u1Fx7t/w==
+SECTION ADDITIONAL
+a.gtld-servers.net. 172800 IN A 192.5.6.30
+a.gtld-servers.net. 172800 IN AAAA 2001:503:a83e::2:30
+b.gtld-servers.net. 172800 IN A 192.33.14.30
+b.gtld-servers.net. 172800 IN AAAA 2001:503:231d::2:30
+c.gtld-servers.net. 172800 IN A 192.26.92.30
+c.gtld-servers.net. 172800 IN AAAA 2001:503:83eb::30
+d.gtld-servers.net. 172800 IN A 192.31.80.30
+d.gtld-servers.net. 172800 IN AAAA 2001:500:856e::30
+e.gtld-servers.net. 172800 IN A 192.12.94.30
+e.gtld-servers.net. 172800 IN AAAA 2001:502:1ca1::30
+f.gtld-servers.net. 172800 IN A 192.35.51.30
+f.gtld-servers.net. 172800 IN AAAA 2001:503:d414::30
+g.gtld-servers.net. 172800 IN A 192.42.93.30
+g.gtld-servers.net. 172800 IN AAAA 2001:503:eea3::30
+h.gtld-servers.net. 172800 IN A 192.54.112.30
+h.gtld-servers.net. 172800 IN AAAA 2001:502:8cc::30
+i.gtld-servers.net. 172800 IN A 192.43.172.30
+i.gtld-servers.net. 172800 IN AAAA 2001:503:39c1::30
+j.gtld-servers.net. 172800 IN A 192.48.79.30
+j.gtld-servers.net. 172800 IN AAAA 2001:502:7094::30
+k.gtld-servers.net. 172800 IN A 192.52.178.30
+k.gtld-servers.net. 172800 IN AAAA 2001:503:d2d::30
+l.gtld-servers.net. 172800 IN A 192.41.162.30
+l.gtld-servers.net. 172800 IN AAAA 2001:500:d937::30
+m.gtld-servers.net. 172800 IN A 192.55.83.30
+m.gtld-servers.net. 172800 IN AAAA 2001:501:b1f9::30
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH subdomain
+ADJUST copy_id copy_query
+REPLY QR RD NOERROR
+SECTION QUESTION
+com. IN NS
+SECTION AUTHORITY
+com. 172800 IN NS a.gtld-servers.net.
+com. 172800 IN NS b.gtld-servers.net.
+com. 172800 IN NS c.gtld-servers.net.
+com. 172800 IN NS d.gtld-servers.net.
+com. 172800 IN NS e.gtld-servers.net.
+com. 172800 IN NS f.gtld-servers.net.
+com. 172800 IN NS g.gtld-servers.net.
+com. 172800 IN NS h.gtld-servers.net.
+com. 172800 IN NS i.gtld-servers.net.
+com. 172800 IN NS j.gtld-servers.net.
+com. 172800 IN NS k.gtld-servers.net.
+com. 172800 IN NS l.gtld-servers.net.
+com. 172800 IN NS m.gtld-servers.net.
+com. 86400 IN DS 30909 8 2 e2d3c916f6deeac73294e8268fb5885044a833fc5459588f4a9184cfc41a5766
+com. 86400 IN RRSIG DS 8 1 86400 20190708050000 20190625040000 25266 . h8CYVMqouUO2IAPlG4Iqf06ykpl07wny KuM2dRGhrfx5hQbF0CpzGRwT2B6i2drI td9i7BSA4GVKLlTYr9n3Xd+BcAHKwywv 44A2WmTAo3xWMv4THwowwu29B4bAKe0V WQKDfmZ92m1yn8T3MCNZWtuGGaLcY6+g fKgyuHu5fEakVn2GFMdAMayBBFTF0bp4 hVFuNSJBe/1EnFZMcxU9aNuCyC8xup25 7K3x1rcM0hthHr8o0Vevpima1YXsWDGb RDIkDyStPDIQ1c0C9LHMaaGR+MA+fxoL 2x4w2lwOptCK//zpfyPvj11oIyouwgdh Fe3PCf9hS03Y1FsiY+mtWw==
+SECTION ADDITIONAL
+a.gtld-servers.net. 172800 IN A 192.5.6.30
+a.gtld-servers.net. 172800 IN AAAA 2001:503:a83e::2:30
+b.gtld-servers.net. 172800 IN A 192.33.14.30
+b.gtld-servers.net. 172800 IN AAAA 2001:503:231d::2:30
+c.gtld-servers.net. 172800 IN A 192.26.92.30
+c.gtld-servers.net. 172800 IN AAAA 2001:503:83eb::30
+d.gtld-servers.net. 172800 IN A 192.31.80.30
+d.gtld-servers.net. 172800 IN AAAA 2001:500:856e::30
+e.gtld-servers.net. 172800 IN A 192.12.94.30
+e.gtld-servers.net. 172800 IN AAAA 2001:502:1ca1::30
+f.gtld-servers.net. 172800 IN A 192.35.51.30
+f.gtld-servers.net. 172800 IN AAAA 2001:503:d414::30
+g.gtld-servers.net. 172800 IN A 192.42.93.30
+g.gtld-servers.net. 172800 IN AAAA 2001:503:eea3::30
+h.gtld-servers.net. 172800 IN A 192.54.112.30
+h.gtld-servers.net. 172800 IN AAAA 2001:502:8cc::30
+i.gtld-servers.net. 172800 IN A 192.43.172.30
+i.gtld-servers.net. 172800 IN AAAA 2001:503:39c1::30
+j.gtld-servers.net. 172800 IN A 192.48.79.30
+j.gtld-servers.net. 172800 IN AAAA 2001:502:7094::30
+k.gtld-servers.net. 172800 IN A 192.52.178.30
+k.gtld-servers.net. 172800 IN AAAA 2001:503:d2d::30
+l.gtld-servers.net. 172800 IN A 192.41.162.30
+l.gtld-servers.net. 172800 IN AAAA 2001:500:d937::30
+m.gtld-servers.net. 172800 IN A 192.55.83.30
+m.gtld-servers.net. 172800 IN AAAA 2001:501:b1f9::30
+ENTRY_END
+
+
+
+
+RANGE_END
+
+
+
+; Group's zones:
+; cz.
+; nic.cz.
+; Server names:
+; a.ns.nic.cz.
+; b.ns.nic.cz.
+; c.ns.nic.cz.
+; d.ns.nic.cz.
+RANGE_BEGIN 0 1000
+ ADDRESS 194.0.14.1
+ ADDRESS 194.0.13.1
+ ADDRESS 193.29.206.1
+ ADDRESS 2001:678:1::1
+ ADDRESS 2001:678:11::1
+ ADDRESS 2001:678:10::1
+ ADDRESS 2001:678:f::1
+ ADDRESS 194.0.12.1
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+ns.nic.cz. IN NS
+SECTION AUTHORITY
+jnp2uc34hha9de64l3rjf6ulp4pra74n.nic.cz. 7200 IN NSEC3 1 0 10 879ec89c91d874a8 jsdlj2k5hipr7eb12ne8bads7lshvo1k
+jnp2uc34hha9de64l3rjf6ulp4pra74n.nic.cz. 7200 IN RRSIG NSEC3 13 3 7200 20190707164247 20190624124001 10486 nic.cz. lrFJPPGpHyoC5l4uM8l94ye/HG1kTVw7 dR98um06iG+2XK82Dib+wnzqoNNIqbaA FeaAkjfqgCHA8kDySAP+5g==
+nic.cz. 1800 IN RRSIG SOA 13 2 1800 20190708100906 20190624124001 10486 nic.cz. 1mDJpihqjobv42BXF8H1dT0/vLtPTpb/ k7flS9wr8tEPe57o6GrkimcSWZlS/lm5 OyhvjIpvU9Da8n2ezGiGHw==
+nic.cz. 1800 IN SOA a.ns.nic.cz. hostmaster.nic.cz. 1561383601 10800 3600 1209600 7200
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+b.ns.nic.cz. IN A
+SECTION ANSWER
+b.ns.nic.cz. 1800 IN A 194.0.13.1
+b.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708030702 20190624124001 10486 nic.cz. bV+9iqB6KDNUCZrcoo9fXj3X1BHhCpgh MGSXx8q4JWJ9mm9Hz6h63UfXTWPthvJy +J18PantZQVPScwMoXVzuw==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+nic.cz. IN DNSKEY
+SECTION ANSWER
+nic.cz. 1800 IN DNSKEY 256 3 13 SmMYG4VjCgj4rAxB4sqgvIzcGtESoX1H m7Dsoekap6HJwj8WOEiFciSg537caOPl 4+7Dyp/b5JwkBemxQQRL9Q==
+nic.cz. 1800 IN DNSKEY 257 3 13 LM4zvjUgZi2XZKsYooDE0HFYGfWp242f KB+O8sLsuox8S6MJTowY8lBDjZD7JKbm aNot3+1H8zU9TrDzWmmHwQ==
+nic.cz. 1800 IN RRSIG DNSKEY 13 2 1800 20190707163411 20190624124001 61281 nic.cz. ggHlmuzLOTZOCYcbZ8TrNoTXOAg7xJ9N B+QLdmZYyny53ODMkRfDv28SSMkwtuc1 rZXfC+/c7oArzsBbbncTRA==
+nic.cz. 1800 IN RRSIG DNSKEY 13 2 1800 20190708092836 20190624124001 10486 nic.cz. lFYLLcm5ICS0BSdB0+dA8m7XxdRbB49+ 5N1w8AHOaPNDTWp9GlXA935IUk18C2to 1ghYmP2RZaNOTchSVRgWzA==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+b.ns.nic.cz. IN A
+SECTION ANSWER
+b.ns.nic.cz. 1800 IN A 194.0.13.1
+b.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708030702 20190624124001 10486 nic.cz. bV+9iqB6KDNUCZrcoo9fXj3X1BHhCpgh MGSXx8q4JWJ9mm9Hz6h63UfXTWPthvJy +J18PantZQVPScwMoXVzuw==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+b.ns.nic.cz. IN AAAA
+SECTION ANSWER
+b.ns.nic.cz. 1800 IN AAAA 2001:678:10::1
+b.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190707133636 20190624124001 10486 nic.cz. OuH2sPy1tH6CENbjioxaaYzCB8yxB1sP FyQXAcY4VpNmLnqthfGKTn5dONZuG4UD I9ihrEaPsV3RsDse0GpMqg==
+SECTION AUTHORITY
+nic.cz. 1800 IN NS a.ns.nic.cz.
+nic.cz. 1800 IN NS b.ns.nic.cz.
+nic.cz. 1800 IN NS d.ns.nic.cz.
+nic.cz. 1800 IN RRSIG NS 13 2 1800 20190707221726 20190624124001 10486 nic.cz. JhCrQB0nVFkti/j3weaalBPxqDG7PyiC KLV7hj61SLdRGcue9/fI9IN7lIanFWhL A1b7/L5DYejIY7WpHVU3Jg==
+SECTION ADDITIONAL
+a.ns.nic.cz. 1800 IN A 194.0.12.1
+a.ns.nic.cz. 1800 IN AAAA 2001:678:f::1
+a.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708050633 20190624124001 10486 nic.cz. 18u1P3Wvg0xoz3fTRtqVNlTHiZPOuGW7 C8nsMIBTCTT9mPYN0z+CcBDfRwVLNnfJ eNTfHXA9zERxbAT3WCHEXg==
+a.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190707232622 20190624124001 10486 nic.cz. qY1Rm171qERHJwykmMYDKXlIGUnHdMhX gYlvOZPGONNuapbsqzTQos9Vd7v4IQfp k6j8sVTjSId1/q/75D4vNQ==
+b.ns.nic.cz. 1800 IN A 194.0.13.1
+b.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708030702 20190624124001 10486 nic.cz. bV+9iqB6KDNUCZrcoo9fXj3X1BHhCpgh MGSXx8q4JWJ9mm9Hz6h63UfXTWPthvJy +J18PantZQVPScwMoXVzuw==
+d.ns.nic.cz. 1800 IN A 193.29.206.1
+d.ns.nic.cz. 1800 IN AAAA 2001:678:1::1
+d.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708114823 20190624124001 10486 nic.cz. p2nhRTWBo56GXRdL19wT+y/XyNb6wjrz Oy3AndSR2/L9BDZrX/mkGYh20x5KpdUV +r+DPy9XFXEmvGrwAD5meA==
+d.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190708121635 20190624124001 10486 nic.cz. QeqTWoaOuL+L+QdiGOIne/WCi+D0V6EH 0h96aDuMs2eySLXSWPC54ICz28gwudmh wX4oEdQf1nYVneO7iEDFew==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+c.ns.nic.cz. IN A
+SECTION ANSWER
+c.ns.nic.cz. 1800 IN A 194.0.14.1
+c.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708123232 20190624124001 10486 nic.cz. ln7Q9H73Ba6dEbIrhA6QrK3OMMEIu4QA h4fJ3xeUIW4US+XU21wylj09Zaf6ALE+ V3E9jTWdPfo1UTGnuW1VUw==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+d.ns.nic.cz. IN AAAA
+SECTION ANSWER
+d.ns.nic.cz. 1800 IN AAAA 2001:678:1::1
+d.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190708121635 20190624124001 10486 nic.cz. QeqTWoaOuL+L+QdiGOIne/WCi+D0V6EH 0h96aDuMs2eySLXSWPC54ICz28gwudmh wX4oEdQf1nYVneO7iEDFew==
+SECTION AUTHORITY
+nic.cz. 1800 IN NS a.ns.nic.cz.
+nic.cz. 1800 IN NS b.ns.nic.cz.
+nic.cz. 1800 IN NS d.ns.nic.cz.
+nic.cz. 1800 IN RRSIG NS 13 2 1800 20190707221726 20190624124001 10486 nic.cz. JhCrQB0nVFkti/j3weaalBPxqDG7PyiC KLV7hj61SLdRGcue9/fI9IN7lIanFWhL A1b7/L5DYejIY7WpHVU3Jg==
+SECTION ADDITIONAL
+a.ns.nic.cz. 1800 IN A 194.0.12.1
+a.ns.nic.cz. 1800 IN AAAA 2001:678:f::1
+a.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708050633 20190624124001 10486 nic.cz. 18u1P3Wvg0xoz3fTRtqVNlTHiZPOuGW7 C8nsMIBTCTT9mPYN0z+CcBDfRwVLNnfJ eNTfHXA9zERxbAT3WCHEXg==
+a.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190707232622 20190624124001 10486 nic.cz. qY1Rm171qERHJwykmMYDKXlIGUnHdMhX gYlvOZPGONNuapbsqzTQos9Vd7v4IQfp k6j8sVTjSId1/q/75D4vNQ==
+b.ns.nic.cz. 1800 IN A 194.0.13.1
+b.ns.nic.cz. 1800 IN AAAA 2001:678:10::1
+b.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708030702 20190624124001 10486 nic.cz. bV+9iqB6KDNUCZrcoo9fXj3X1BHhCpgh MGSXx8q4JWJ9mm9Hz6h63UfXTWPthvJy +J18PantZQVPScwMoXVzuw==
+b.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190707133636 20190624124001 10486 nic.cz. OuH2sPy1tH6CENbjioxaaYzCB8yxB1sP FyQXAcY4VpNmLnqthfGKTn5dONZuG4UD I9ihrEaPsV3RsDse0GpMqg==
+d.ns.nic.cz. 1800 IN A 193.29.206.1
+d.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708114823 20190624124001 10486 nic.cz. p2nhRTWBo56GXRdL19wT+y/XyNb6wjrz Oy3AndSR2/L9BDZrX/mkGYh20x5KpdUV +r+DPy9XFXEmvGrwAD5meA==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+b.ns.nic.cz. IN AAAA
+SECTION ANSWER
+b.ns.nic.cz. 1800 IN AAAA 2001:678:10::1
+b.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190707133636 20190624124001 10486 nic.cz. OuH2sPy1tH6CENbjioxaaYzCB8yxB1sP FyQXAcY4VpNmLnqthfGKTn5dONZuG4UD I9ihrEaPsV3RsDse0GpMqg==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+a.ns.nic.cz. IN NS
+SECTION AUTHORITY
+51npp2qit2otcucer39ql8d4q4h9mr5d.nic.cz. 7200 IN NSEC3 1 0 10 879ec89c91d874a8 52jm0s7pifluesur7b9p840f8fkcpcsi A AAAA RRSIG
+51npp2qit2otcucer39ql8d4q4h9mr5d.nic.cz. 7200 IN RRSIG NSEC3 13 3 7200 20190708102945 20190624124001 10486 nic.cz. ScbUA0IlzL0o1h34t007ViOD53YFHe+V zn2ge8gqiNeT29FW/sCwiyVsrUpMZ7nW O9gmXfdNjjtmyTA7iWbVTA==
+nic.cz. 1800 IN RRSIG SOA 13 2 1800 20190708100906 20190624124001 10486 nic.cz. 1mDJpihqjobv42BXF8H1dT0/vLtPTpb/ k7flS9wr8tEPe57o6GrkimcSWZlS/lm5 OyhvjIpvU9Da8n2ezGiGHw==
+nic.cz. 1800 IN SOA a.ns.nic.cz. hostmaster.nic.cz. 1561383601 10800 3600 1209600 7200
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+c.ns.nic.cz. IN A
+SECTION ANSWER
+c.ns.nic.cz. 1800 IN A 194.0.14.1
+c.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708123232 20190624124001 10486 nic.cz. ln7Q9H73Ba6dEbIrhA6QrK3OMMEIu4QA h4fJ3xeUIW4US+XU21wylj09Zaf6ALE+ V3E9jTWdPfo1UTGnuW1VUw==
+SECTION AUTHORITY
+nic.cz. 1800 IN NS a.ns.nic.cz.
+nic.cz. 1800 IN NS b.ns.nic.cz.
+nic.cz. 1800 IN NS d.ns.nic.cz.
+nic.cz. 1800 IN RRSIG NS 13 2 1800 20190707221726 20190624124001 10486 nic.cz. JhCrQB0nVFkti/j3weaalBPxqDG7PyiC KLV7hj61SLdRGcue9/fI9IN7lIanFWhL A1b7/L5DYejIY7WpHVU3Jg==
+SECTION ADDITIONAL
+a.ns.nic.cz. 1800 IN A 194.0.12.1
+a.ns.nic.cz. 1800 IN AAAA 2001:678:f::1
+a.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708050633 20190624124001 10486 nic.cz. 18u1P3Wvg0xoz3fTRtqVNlTHiZPOuGW7 C8nsMIBTCTT9mPYN0z+CcBDfRwVLNnfJ eNTfHXA9zERxbAT3WCHEXg==
+a.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190707232622 20190624124001 10486 nic.cz. qY1Rm171qERHJwykmMYDKXlIGUnHdMhX gYlvOZPGONNuapbsqzTQos9Vd7v4IQfp k6j8sVTjSId1/q/75D4vNQ==
+b.ns.nic.cz. 1800 IN A 194.0.13.1
+b.ns.nic.cz. 1800 IN AAAA 2001:678:10::1
+b.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708030702 20190624124001 10486 nic.cz. bV+9iqB6KDNUCZrcoo9fXj3X1BHhCpgh MGSXx8q4JWJ9mm9Hz6h63UfXTWPthvJy +J18PantZQVPScwMoXVzuw==
+b.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190707133636 20190624124001 10486 nic.cz. OuH2sPy1tH6CENbjioxaaYzCB8yxB1sP FyQXAcY4VpNmLnqthfGKTn5dONZuG4UD I9ihrEaPsV3RsDse0GpMqg==
+d.ns.nic.cz. 1800 IN A 193.29.206.1
+d.ns.nic.cz. 1800 IN AAAA 2001:678:1::1
+d.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708114823 20190624124001 10486 nic.cz. p2nhRTWBo56GXRdL19wT+y/XyNb6wjrz Oy3AndSR2/L9BDZrX/mkGYh20x5KpdUV +r+DPy9XFXEmvGrwAD5meA==
+d.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190708121635 20190624124001 10486 nic.cz. QeqTWoaOuL+L+QdiGOIne/WCi+D0V6EH 0h96aDuMs2eySLXSWPC54ICz28gwudmh wX4oEdQf1nYVneO7iEDFew==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+nic.cz. IN DS
+SECTION ANSWER
+nic.cz. 3600 IN DS 61281 13 2 4104d40c8fe2030bf7a09a199fcf37b36f7ec8ddd16f5a84f2e61c248d3afd0f
+nic.cz. 3600 IN RRSIG DS 13 2 3600 20190705064642 20190622210528 6318 cz. h4tSy9MopxkbCg2mPu0s/CoE+DtoKUTL 5iw1cpQZOF1MJMZhTYo3yZjYiIkIrih8 xigA0UNFXtZEAxzsqI6omA==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+c.ns.nic.cz. IN AAAA
+SECTION ANSWER
+c.ns.nic.cz. 1800 IN AAAA 2001:678:11::1
+c.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190707153808 20190624124001 10486 nic.cz. 2n+SYd+Eh6pFujzSb5u/ZFbJkfHGB3aB wo5vSKAp+s8RgEtwMawcs54psA6LWKc5 swrxP1C1xVyMLQ6L7eifGA==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+a.ns.nic.cz. IN AAAA
+SECTION ANSWER
+a.ns.nic.cz. 1800 IN AAAA 2001:678:f::1
+a.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190707232622 20190624124001 10486 nic.cz. qY1Rm171qERHJwykmMYDKXlIGUnHdMhX gYlvOZPGONNuapbsqzTQos9Vd7v4IQfp k6j8sVTjSId1/q/75D4vNQ==
+SECTION AUTHORITY
+nic.cz. 1800 IN NS a.ns.nic.cz.
+nic.cz. 1800 IN NS b.ns.nic.cz.
+nic.cz. 1800 IN NS d.ns.nic.cz.
+nic.cz. 1800 IN RRSIG NS 13 2 1800 20190707221726 20190624124001 10486 nic.cz. JhCrQB0nVFkti/j3weaalBPxqDG7PyiC KLV7hj61SLdRGcue9/fI9IN7lIanFWhL A1b7/L5DYejIY7WpHVU3Jg==
+SECTION ADDITIONAL
+a.ns.nic.cz. 1800 IN A 194.0.12.1
+a.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708050633 20190624124001 10486 nic.cz. 18u1P3Wvg0xoz3fTRtqVNlTHiZPOuGW7 C8nsMIBTCTT9mPYN0z+CcBDfRwVLNnfJ eNTfHXA9zERxbAT3WCHEXg==
+b.ns.nic.cz. 1800 IN A 194.0.13.1
+b.ns.nic.cz. 1800 IN AAAA 2001:678:10::1
+b.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708030702 20190624124001 10486 nic.cz. bV+9iqB6KDNUCZrcoo9fXj3X1BHhCpgh MGSXx8q4JWJ9mm9Hz6h63UfXTWPthvJy +J18PantZQVPScwMoXVzuw==
+b.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190707133636 20190624124001 10486 nic.cz. OuH2sPy1tH6CENbjioxaaYzCB8yxB1sP FyQXAcY4VpNmLnqthfGKTn5dONZuG4UD I9ihrEaPsV3RsDse0GpMqg==
+d.ns.nic.cz. 1800 IN A 193.29.206.1
+d.ns.nic.cz. 1800 IN AAAA 2001:678:1::1
+d.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708114823 20190624124001 10486 nic.cz. p2nhRTWBo56GXRdL19wT+y/XyNb6wjrz Oy3AndSR2/L9BDZrX/mkGYh20x5KpdUV +r+DPy9XFXEmvGrwAD5meA==
+d.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190708121635 20190624124001 10486 nic.cz. QeqTWoaOuL+L+QdiGOIne/WCi+D0V6EH 0h96aDuMs2eySLXSWPC54ICz28gwudmh wX4oEdQf1nYVneO7iEDFew==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+c.ns.nic.cz. IN NS
+SECTION AUTHORITY
+CNTVMLLA2O27TCBC4MEP7IV9P54L7FLE.nic.cz. 7200 IN NSEC3 1 0 10 879ec89c91d874a8 co07u5iiiqhl96t3hlmgkchj3203eqqj A AAAA RRSIG
+CNTVMLLA2O27TCBC4MEP7IV9P54L7FLE.nic.cz. 7200 IN RRSIG NSEC3 13 3 7200 20190707155010 20190624124001 10486 nic.cz. osfB/CgwWbwa/BX/fYo+gzrImuam0bhT bD9xmAH6w+acJ8GrCNHNcCgFdimdacEA rSx2ztVVWCiALLlqzFP1WQ==
+nic.cz. 1800 IN RRSIG SOA 13 2 1800 20190708100906 20190624124001 10486 nic.cz. 1mDJpihqjobv42BXF8H1dT0/vLtPTpb/ k7flS9wr8tEPe57o6GrkimcSWZlS/lm5 OyhvjIpvU9Da8n2ezGiGHw==
+nic.cz. 1800 IN SOA a.ns.nic.cz. hostmaster.nic.cz. 1561383601 10800 3600 1209600 7200
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+d.ns.nic.cz. IN A
+SECTION ANSWER
+d.ns.nic.cz. 1800 IN A 193.29.206.1
+d.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708114823 20190624124001 10486 nic.cz. p2nhRTWBo56GXRdL19wT+y/XyNb6wjrz Oy3AndSR2/L9BDZrX/mkGYh20x5KpdUV +r+DPy9XFXEmvGrwAD5meA==
+SECTION AUTHORITY
+nic.cz. 1800 IN NS a.ns.nic.cz.
+nic.cz. 1800 IN NS b.ns.nic.cz.
+nic.cz. 1800 IN NS d.ns.nic.cz.
+nic.cz. 1800 IN RRSIG NS 13 2 1800 20190707221726 20190624124001 10486 nic.cz. JhCrQB0nVFkti/j3weaalBPxqDG7PyiC KLV7hj61SLdRGcue9/fI9IN7lIanFWhL A1b7/L5DYejIY7WpHVU3Jg==
+SECTION ADDITIONAL
+a.ns.nic.cz. 1800 IN A 194.0.12.1
+a.ns.nic.cz. 1800 IN AAAA 2001:678:f::1
+a.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708050633 20190624124001 10486 nic.cz. 18u1P3Wvg0xoz3fTRtqVNlTHiZPOuGW7 C8nsMIBTCTT9mPYN0z+CcBDfRwVLNnfJ eNTfHXA9zERxbAT3WCHEXg==
+a.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190707232622 20190624124001 10486 nic.cz. qY1Rm171qERHJwykmMYDKXlIGUnHdMhX gYlvOZPGONNuapbsqzTQos9Vd7v4IQfp k6j8sVTjSId1/q/75D4vNQ==
+b.ns.nic.cz. 1800 IN A 194.0.13.1
+b.ns.nic.cz. 1800 IN AAAA 2001:678:10::1
+b.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708030702 20190624124001 10486 nic.cz. bV+9iqB6KDNUCZrcoo9fXj3X1BHhCpgh MGSXx8q4JWJ9mm9Hz6h63UfXTWPthvJy +J18PantZQVPScwMoXVzuw==
+b.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190707133636 20190624124001 10486 nic.cz. OuH2sPy1tH6CENbjioxaaYzCB8yxB1sP FyQXAcY4VpNmLnqthfGKTn5dONZuG4UD I9ihrEaPsV3RsDse0GpMqg==
+d.ns.nic.cz. 1800 IN AAAA 2001:678:1::1
+d.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190708121635 20190624124001 10486 nic.cz. QeqTWoaOuL+L+QdiGOIne/WCi+D0V6EH 0h96aDuMs2eySLXSWPC54ICz28gwudmh wX4oEdQf1nYVneO7iEDFew==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+nic.cz. IN DNSKEY
+SECTION ANSWER
+nic.cz. 1800 IN DNSKEY 256 3 13 SmMYG4VjCgj4rAxB4sqgvIzcGtESoX1H m7Dsoekap6HJwj8WOEiFciSg537caOPl 4+7Dyp/b5JwkBemxQQRL9Q==
+nic.cz. 1800 IN DNSKEY 257 3 13 LM4zvjUgZi2XZKsYooDE0HFYGfWp242f KB+O8sLsuox8S6MJTowY8lBDjZD7JKbm aNot3+1H8zU9TrDzWmmHwQ==
+nic.cz. 1800 IN RRSIG DNSKEY 13 2 1800 20190707163411 20190624124001 61281 nic.cz. ggHlmuzLOTZOCYcbZ8TrNoTXOAg7xJ9N B+QLdmZYyny53ODMkRfDv28SSMkwtuc1 rZXfC+/c7oArzsBbbncTRA==
+nic.cz. 1800 IN RRSIG DNSKEY 13 2 1800 20190708092836 20190624124001 10486 nic.cz. lFYLLcm5ICS0BSdB0+dA8m7XxdRbB49+ 5N1w8AHOaPNDTWp9GlXA935IUk18C2to 1ghYmP2RZaNOTchSVRgWzA==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+c.ns.nic.cz. IN NS
+SECTION AUTHORITY
+cntvmlla2o27tcbc4mep7iv9p54l7fle.nic.cz. 7200 IN NSEC3 1 0 10 879ec89c91d874a8 co07u5iiiqhl96t3hlmgkchj3203eqqj A AAAA RRSIG
+cntvmlla2o27tcbc4mep7iv9p54l7fle.nic.cz. 7200 IN RRSIG NSEC3 13 3 7200 20190707155010 20190624124001 10486 nic.cz. osfB/CgwWbwa/BX/fYo+gzrImuam0bhT bD9xmAH6w+acJ8GrCNHNcCgFdimdacEA rSx2ztVVWCiALLlqzFP1WQ==
+nic.cz. 1800 IN RRSIG SOA 13 2 1800 20190708100906 20190624124001 10486 nic.cz. 1mDJpihqjobv42BXF8H1dT0/vLtPTpb/ k7flS9wr8tEPe57o6GrkimcSWZlS/lm5 OyhvjIpvU9Da8n2ezGiGHw==
+nic.cz. 1800 IN SOA a.ns.nic.cz. hostmaster.nic.cz. 1561383601 10800 3600 1209600 7200
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+b.ns.nic.cz. IN NS
+SECTION AUTHORITY
+cu82t3qracdj063olk907dv20ine9dea.nic.cz. 7200 IN NSEC3 1 0 10 879ec89c91d874a8 d2749lueihj9moq02lt0k9i8tnbgest1 A AAAA RRSIG
+cu82t3qracdj063olk907dv20ine9dea.nic.cz. 7200 IN RRSIG NSEC3 13 3 7200 20190708122905 20190624124001 10486 nic.cz. fg5ypFDXqZlnzSbndkPm2VjZieL0t5NT zKu0cfcWHu4TlWB/OxxuaD4C2oGx5nki Pchj+FQNobNZJfCXKOa4ug==
+nic.cz. 1800 IN RRSIG SOA 13 2 1800 20190708100906 20190624124001 10486 nic.cz. 1mDJpihqjobv42BXF8H1dT0/vLtPTpb/ k7flS9wr8tEPe57o6GrkimcSWZlS/lm5 OyhvjIpvU9Da8n2ezGiGHw==
+nic.cz. 1800 IN SOA a.ns.nic.cz. hostmaster.nic.cz. 1561383601 10800 3600 1209600 7200
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+csas.cz. IN DS
+SECTION ANSWER
+csas.cz. 3600 IN DS 8196 7 2 c5c7974e1dc3bf036f8744a4d919e03ef01d8d6167db6201940ca87059558ee3
+csas.cz. 3600 IN RRSIG DS 13 2 3600 20190706080140 20190622110535 6318 cz. 5V0ZvjpT8zWMsVwPpyhsMc9DRFVMQtP2 D2o7S/dLbZ7YL4Mqd8P9n+o+4NQgaqQw 7VPBHnN3VzVDYvWjmr+rfw==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+ns.nic.cz. IN NS
+SECTION AUTHORITY
+JNP2UC34HHA9DE64L3RJF6ULP4PRA74N.nic.cz. 7200 IN NSEC3 1 0 10 879ec89c91d874a8 jsdlj2k5hipr7eb12ne8bads7lshvo1k
+JNP2UC34HHA9DE64L3RJF6ULP4PRA74N.nic.cz. 7200 IN RRSIG NSEC3 13 3 7200 20190707164247 20190624124001 10486 nic.cz. lrFJPPGpHyoC5l4uM8l94ye/HG1kTVw7 dR98um06iG+2XK82Dib+wnzqoNNIqbaA FeaAkjfqgCHA8kDySAP+5g==
+nic.cz. 1800 IN RRSIG SOA 13 2 1800 20190708100906 20190624124001 10486 nic.cz. 1mDJpihqjobv42BXF8H1dT0/vLtPTpb/ k7flS9wr8tEPe57o6GrkimcSWZlS/lm5 OyhvjIpvU9Da8n2ezGiGHw==
+nic.cz. 1800 IN SOA a.ns.nic.cz. hostmaster.nic.cz. 1561383601 10800 3600 1209600 7200
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+d.ns.nic.cz. IN NS
+SECTION AUTHORITY
+nic.cz. 1800 IN RRSIG SOA 13 2 1800 20190708100906 20190624124001 10486 nic.cz. 1mDJpihqjobv42BXF8H1dT0/vLtPTpb/ k7flS9wr8tEPe57o6GrkimcSWZlS/lm5 OyhvjIpvU9Da8n2ezGiGHw==
+nic.cz. 1800 IN SOA a.ns.nic.cz. hostmaster.nic.cz. 1561383601 10800 3600 1209600 7200
+on20qsre8qs9a2asfdatp5cs6g2i5ssq.nic.cz. 7200 IN NSEC3 1 0 10 879ec89c91d874a8 onv9qnjm1krm9qdk0n6o6o23doo5jfug A AAAA RRSIG
+on20qsre8qs9a2asfdatp5cs6g2i5ssq.nic.cz. 7200 IN RRSIG NSEC3 13 3 7200 20190708041440 20190624124001 10486 nic.cz. WkMEKZUDwPTv5Y3KG/C9LTVTynACPb16 1OuoxTij1reZR4LzHVoGQKDf0Dbj2Rau 9LrBW5PI5PSDQ6BmUKRj6A==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+a.ns.nic.cz. IN AAAA
+SECTION ANSWER
+a.ns.nic.cz. 1800 IN AAAA 2001:678:f::1
+a.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190707232622 20190624124001 10486 nic.cz. qY1Rm171qERHJwykmMYDKXlIGUnHdMhX gYlvOZPGONNuapbsqzTQos9Vd7v4IQfp k6j8sVTjSId1/q/75D4vNQ==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+a.ns.nic.cz. IN A
+SECTION ANSWER
+a.ns.nic.cz. 1800 IN A 194.0.12.1
+a.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708050633 20190624124001 10486 nic.cz. 18u1P3Wvg0xoz3fTRtqVNlTHiZPOuGW7 C8nsMIBTCTT9mPYN0z+CcBDfRwVLNnfJ eNTfHXA9zERxbAT3WCHEXg==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+cz. IN DS
+SECTION AUTHORITY
+cz. 3600 IN RRSIG SOA 13 1 3600 20190707192652 20190625123528 6318 cz. BYXtAj/BIXIb5xlT6TBQYaFhbloeuo0H RqJTdPu9gVVyuBKbvV6YmQbS4BBMM4qA Cp2Vw7yBK9+dONHp9JAmuA==
+cz. 3600 IN SOA a.ns.nic.cz. hostmaster.nic.cz. 1561469728 900 300 604800 900
+fu65o5n6kmh8a04mps1e4a73s37jr72u.cz. 900 IN NSEC3 1 0 10 357dda080afe0ef8 fu677p5qqp6ihbeeloacm3sr4ieklu7m NS SOA RRSIG DNSKEY NSEC3PARAM
+fu65o5n6kmh8a04mps1e4a73s37jr72u.cz. 900 IN RRSIG NSEC3 13 2 900 20190706134746 20190622170523 6318 cz. EsElag8LQ5TcunX40efTh35IN3GoQnPq XAZZ0cSPHT6GOohzp8iD1LSLLbwZUiNE yB4hCp1yqEi0pINRoHglNA==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+cz. IN DNSKEY
+SECTION ANSWER
+cz. 18000 IN DNSKEY 256 3 13 7t+ZoZGIrV27M/PEAH8OKSjEXVAJhV6O o5ESS+Vry5ZhfoWogIKAXzvda/qY/WTA L09BEk+ko16oGRRktvzWEw==
+cz. 18000 IN DNSKEY 257 3 13 nqzH7xP1QU5UOVy/VvxFSlrB/XgX9JDJ zj51PzIj35TXjZTyalTlAT/f7PAfaSD5 mEG1N8Vk9NmI2nxgQqhzDQ==
+cz. 18000 IN RRSIG DNSKEY 13 1 18000 20190705000000 20190621000000 20237 cz. kJ1zRR76FpPS4SLyFuLbrQBvVnq6GY+x 5sOV2ayq6rt4D1sjpxROufFfBfi/6wAv qo3VZ0iUJSB03djeX8gk5A==
+cz. 18000 IN RRSIG DNSKEY 13 1 18000 20190709092856 20190625123528 6318 cz. Lpz5UZi8lVH1TCdz6DyjWvoUciOVqA4Z d+3TVxNF2GsLzM15nwc34FnaQF3dxhJZ mdf6dET7iOUmy2SN3majVg==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+c.ns.nic.cz. IN AAAA
+SECTION ANSWER
+c.ns.nic.cz. 1800 IN AAAA 2001:678:11::1
+c.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190707153808 20190624124001 10486 nic.cz. 2n+SYd+Eh6pFujzSb5u/ZFbJkfHGB3aB wo5vSKAp+s8RgEtwMawcs54psA6LWKc5 swrxP1C1xVyMLQ6L7eifGA==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+d.ns.nic.cz. IN A
+SECTION ANSWER
+d.ns.nic.cz. 1800 IN A 193.29.206.1
+d.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708114823 20190624124001 10486 nic.cz. p2nhRTWBo56GXRdL19wT+y/XyNb6wjrz Oy3AndSR2/L9BDZrX/mkGYh20x5KpdUV +r+DPy9XFXEmvGrwAD5meA==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+d.ns.nic.cz. IN AAAA
+SECTION ANSWER
+d.ns.nic.cz. 1800 IN AAAA 2001:678:1::1
+d.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190708121635 20190624124001 10486 nic.cz. QeqTWoaOuL+L+QdiGOIne/WCi+D0V6EH 0h96aDuMs2eySLXSWPC54ICz28gwudmh wX4oEdQf1nYVneO7iEDFew==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH subdomain
+ADJUST copy_id copy_query
+REPLY QR RD NOERROR
+SECTION QUESTION
+csas.cz. IN NS
+SECTION AUTHORITY
+csas.cz. 3600 IN DS 8196 7 2 c5c7974e1dc3bf036f8744a4d919e03ef01d8d6167db6201940ca87059558ee3
+csas.cz. 3600 IN NS ddnsa.csas.cz.
+csas.cz. 3600 IN NS ddnsb.csas.cz.
+csas.cz. 3600 IN RRSIG DS 13 2 3600 20190706080140 20190622110535 6318 cz. 5V0ZvjpT8zWMsVwPpyhsMc9DRFVMQtP2 D2o7S/dLbZ7YL4Mqd8P9n+o+4NQgaqQw 7VPBHnN3VzVDYvWjmr+rfw==
+SECTION ADDITIONAL
+ddnsa.csas.cz. 3600 IN A 194.50.240.64
+ddnsb.csas.cz. 3600 IN A 194.50.240.192
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH subdomain
+ADJUST copy_id copy_query
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+nic.cz. IN NS
+SECTION ANSWER
+nic.cz. 1800 IN NS a.ns.nic.cz.
+nic.cz. 1800 IN NS b.ns.nic.cz.
+nic.cz. 1800 IN NS d.ns.nic.cz.
+nic.cz. 1800 IN RRSIG NS 13 2 1800 20190707221726 20190624124001 10486 nic.cz. JhCrQB0nVFkti/j3weaalBPxqDG7PyiC KLV7hj61SLdRGcue9/fI9IN7lIanFWhL A1b7/L5DYejIY7WpHVU3Jg==
+SECTION ADDITIONAL
+a.ns.nic.cz. 1800 IN A 194.0.12.1
+a.ns.nic.cz. 1800 IN AAAA 2001:678:f::1
+a.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708050633 20190624124001 10486 nic.cz. 18u1P3Wvg0xoz3fTRtqVNlTHiZPOuGW7 C8nsMIBTCTT9mPYN0z+CcBDfRwVLNnfJ eNTfHXA9zERxbAT3WCHEXg==
+a.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190707232622 20190624124001 10486 nic.cz. qY1Rm171qERHJwykmMYDKXlIGUnHdMhX gYlvOZPGONNuapbsqzTQos9Vd7v4IQfp k6j8sVTjSId1/q/75D4vNQ==
+b.ns.nic.cz. 1800 IN A 194.0.13.1
+b.ns.nic.cz. 1800 IN AAAA 2001:678:10::1
+b.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708030702 20190624124001 10486 nic.cz. bV+9iqB6KDNUCZrcoo9fXj3X1BHhCpgh MGSXx8q4JWJ9mm9Hz6h63UfXTWPthvJy +J18PantZQVPScwMoXVzuw==
+b.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190707133636 20190624124001 10486 nic.cz. OuH2sPy1tH6CENbjioxaaYzCB8yxB1sP FyQXAcY4VpNmLnqthfGKTn5dONZuG4UD I9ihrEaPsV3RsDse0GpMqg==
+d.ns.nic.cz. 1800 IN A 193.29.206.1
+d.ns.nic.cz. 1800 IN AAAA 2001:678:1::1
+d.ns.nic.cz. 1800 IN RRSIG A 13 4 1800 20190708114823 20190624124001 10486 nic.cz. p2nhRTWBo56GXRdL19wT+y/XyNb6wjrz Oy3AndSR2/L9BDZrX/mkGYh20x5KpdUV +r+DPy9XFXEmvGrwAD5meA==
+d.ns.nic.cz. 1800 IN RRSIG AAAA 13 4 1800 20190708121635 20190624124001 10486 nic.cz. QeqTWoaOuL+L+QdiGOIne/WCi+D0V6EH 0h96aDuMs2eySLXSWPC54ICz28gwudmh wX4oEdQf1nYVneO7iEDFew==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH subdomain
+ADJUST copy_id copy_query
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+cz. IN NS
+SECTION ANSWER
+cz. 3600 IN NS a.ns.nic.cz.
+cz. 3600 IN NS b.ns.nic.cz.
+cz. 3600 IN NS c.ns.nic.cz.
+cz. 3600 IN NS d.ns.nic.cz.
+cz. 3600 IN RRSIG NS 13 1 3600 20190705184721 20190622030526 6318 cz. SzhZGIFskUTnlxipSleB+IghUpyhS1eV PubDzCU/CC0LmDBoAVwfiY8zKWdPSu0X 5544N2KzZ5JrPoasQkOLzg==
+SECTION ADDITIONAL
+a.ns.nic.cz. 3600 IN A 194.0.12.1
+a.ns.nic.cz. 3600 IN AAAA 2001:678:f::1
+b.ns.nic.cz. 3600 IN A 194.0.13.1
+b.ns.nic.cz. 3600 IN AAAA 2001:678:10::1
+d.ns.nic.cz. 3600 IN A 193.29.206.1
+d.ns.nic.cz. 3600 IN AAAA 2001:678:1::1
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH subdomain
+ADJUST copy_id copy_query
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+cz. IN NS
+SECTION ANSWER
+cz. 3600 IN NS a.ns.nic.cz.
+cz. 3600 IN NS b.ns.nic.cz.
+cz. 3600 IN NS c.ns.nic.cz.
+cz. 3600 IN NS d.ns.nic.cz.
+cz. 3600 IN RRSIG NS 13 1 3600 20190705184721 20190622030526 6318 cz. SzhZGIFskUTnlxipSleB+IghUpyhS1eV PubDzCU/CC0LmDBoAVwfiY8zKWdPSu0X 5544N2KzZ5JrPoasQkOLzg==
+ENTRY_END
+
+
+
+
+RANGE_END
+
+
+
+; Group's zones:
+; csas.cz.
+; Server names:
+; ddnsa.csas.cz.
+; ddnsb.csas.cz.
+; ddnsc.csas.cz.
+; ddnsd.csas.cz.
+RANGE_BEGIN 0 1000
+ ADDRESS 194.50.240.64
+ ADDRESS 194.50.240.192
+ ADDRESS 194.50.240.194
+ ADDRESS 194.50.240.66
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+ddnsd.csas.cz. IN NS
+SECTION AUTHORITY
+csas.cz. 120 IN RRSIG SOA 7 2 120 20190630054550 20190623054550 26663 csas.cz. c/sxvp5WLJOsDGgnhxPOk9oBwXRtsUXa enyWg5rd8yBcquHqfFKQu1v8wEPjJjAH B6joG1tJXq99nxtCN4jlDipPKLIzWxba aYIxE8Pab199qiHrR5vxO4KgPxRXbg5d gzIVrrhB+h23DZDacQ+l+kQWSAcycjPh xFvNjAZrH4obU/F+jHt4ix5XqEVuDrPQ YTGBGEUpl7YbcyaROzVP3dtCQZamkfaB CQYoNAJlNw6YFG1qulPm3pn3jJHhu88f dFgCisWfp7TjMYn7Id7aYJtliagE47xu ASnhOtaeXAVxDGUIkOI5u8uUCC/jAiHr MgARE5rcqh2AIZeSv0BiMQ==
+csas.cz. 120 IN SOA ddnsa.csas.cz. domainservices.csas.cz. 2019061320 28800 1800 2592000 120
+gfr9qt699hmcloa9radenpk7pqeikiu8.csas.cz. 120 IN NSEC3 1 0 1 31245099125aedf7 gfr9qt699hmcloa9radenpk7pqeikiu9 TXT
+gfr9qt699hmcloa9radenpk7pqeikiu8.csas.cz. 120 IN RRSIG NSEC3 7 3 120 20190702130338 20190625130338 26663 csas.cz. OWtiEsmO7VnUV2MQp3gZJmOAQw4n81DH 9c5FFJW6MBE3afaIqGTvWYCgRipEEvZF qPBVxGpptVsMbuELagewwZYtR+EEh2A/ qMf/wVC//t2c67YFIxMILi9ijleYS5y8 m5Mu+logobk2Resxs0kC47kwNP9KSh7s gm3SFjK1LXRXg19UmiabMIINoOoAE1M0 XePGhiaqhFwros32p++2JrCdaYrPXLWy VuENN0chZ/hE55ic4M7KpxZ12+oPzigk tIeh9sqTaKpGJBZk4vlJQLq2zfL/gnKZ CRRN8bJQ/ZsSZG//rL0nqZcgyxQqXI9w As8TBPtQ9IQWq2K5MxjKHg==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+csas.cz. IN AAAA
+SECTION AUTHORITY
+8b6896cv5m6qpdd29hb4s12lagep7utq.csas.cz. 120 IN NSEC3 1 0 1 31245099125aedf7 8b6896cv5m6qpdd29hb4s12lagep7utr NS SOA RRSIG DNSKEY NSEC3PARAM
+8b6896cv5m6qpdd29hb4s12lagep7utq.csas.cz. 120 IN RRSIG NSEC3 7 3 120 20190702130338 20190625130338 26663 csas.cz. SNkUAfA3do4t3pyNw1I0zfdiGnWufjIW S4DnHV7Sz+LNOfbe36ipmpUevus+12DG qgG+fQNzxAbCByk7e5fqieyXLVyGfRla 1H9UwCj42/TWATKqDQUFADVEaZ4nHrnN E2yZWkaNNW3jBX7LTIvgwHHVXuM5HQwd Q3/be9B6oz92QLs7ds2zhtjB1NYCUeFD OwYOxSekxZV/ePEfytrXbw1NPcji9GsO v6+HLgYLLy2qIQKMS5xavb4+4/eDMsq4 vJ+uvrmc66JHL7rFyrwd/x1NNsHXwqac czV+GifY3m8svOydXETd9tTC8sTsiU9x ZFTAOcTlxlo211UwuHnwkA==
+csas.cz. 120 IN RRSIG SOA 7 2 120 20190630054550 20190623054550 26663 csas.cz. c/sxvp5WLJOsDGgnhxPOk9oBwXRtsUXa enyWg5rd8yBcquHqfFKQu1v8wEPjJjAH B6joG1tJXq99nxtCN4jlDipPKLIzWxba aYIxE8Pab199qiHrR5vxO4KgPxRXbg5d gzIVrrhB+h23DZDacQ+l+kQWSAcycjPh xFvNjAZrH4obU/F+jHt4ix5XqEVuDrPQ YTGBGEUpl7YbcyaROzVP3dtCQZamkfaB CQYoNAJlNw6YFG1qulPm3pn3jJHhu88f dFgCisWfp7TjMYn7Id7aYJtliagE47xu ASnhOtaeXAVxDGUIkOI5u8uUCC/jAiHr MgARE5rcqh2AIZeSv0BiMQ==
+csas.cz. 120 IN SOA ddnsa.csas.cz. domainservices.csas.cz. 2019061320 28800 1800 2592000 120
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+ddnsc.csas.cz. IN NS
+SECTION AUTHORITY
+c1c03am0n36kncp4iqb4buoqo1ectql4.csas.cz. 120 IN NSEC3 1 0 1 31245099125aedf7 c1c03am0n36kncp4iqb4buoqo1ectql5 TXT
+c1c03am0n36kncp4iqb4buoqo1ectql4.csas.cz. 120 IN RRSIG NSEC3 7 3 120 20190702130338 20190625130338 26663 csas.cz. FKjWbcw5aP2HzHFy2t+M462dxM1ph0FW 02Tohh/aJQOp1iKQOi6u1V2tI3H9CMXW xeIAktZ+xiUDRYLX50fNuJZMaSsn7r5A LYjVAKGzwMPncIf6IlEDYkj1I1rdp6z8 LvWsWNO1wfIPq1Dw2geN60bcz3D7r/sY WfjU/7jO9f0nekZZXI2qFsMSYd9Dkaq7 mlpP0NrWnUbCjL+BfuLFNebh8g3D8f5w Tq3R9czwW5YTVXUquBIrjiZ0Ko9INgQ/ 4pvJqJ1bsTpmzdODfAssEtpu+es4wLwt ZTe8Ll9VeDB20RqEnAyHZwQRXXVF2t+F vdJU7Desbpu6rElA7IXwRw==
+csas.cz. 120 IN RRSIG SOA 7 2 120 20190630054550 20190623054550 26663 csas.cz. c/sxvp5WLJOsDGgnhxPOk9oBwXRtsUXa enyWg5rd8yBcquHqfFKQu1v8wEPjJjAH B6joG1tJXq99nxtCN4jlDipPKLIzWxba aYIxE8Pab199qiHrR5vxO4KgPxRXbg5d gzIVrrhB+h23DZDacQ+l+kQWSAcycjPh xFvNjAZrH4obU/F+jHt4ix5XqEVuDrPQ YTGBGEUpl7YbcyaROzVP3dtCQZamkfaB CQYoNAJlNw6YFG1qulPm3pn3jJHhu88f dFgCisWfp7TjMYn7Id7aYJtliagE47xu ASnhOtaeXAVxDGUIkOI5u8uUCC/jAiHr MgARE5rcqh2AIZeSv0BiMQ==
+csas.cz. 120 IN SOA ddnsa.csas.cz. domainservices.csas.cz. 2019061320 28800 1800 2592000 120
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+ddnsd.csas.cz. IN AAAA
+SECTION AUTHORITY
+csas.cz. 120 IN RRSIG SOA 7 2 120 20190630054550 20190623054550 26663 csas.cz. c/sxvp5WLJOsDGgnhxPOk9oBwXRtsUXa enyWg5rd8yBcquHqfFKQu1v8wEPjJjAH B6joG1tJXq99nxtCN4jlDipPKLIzWxba aYIxE8Pab199qiHrR5vxO4KgPxRXbg5d gzIVrrhB+h23DZDacQ+l+kQWSAcycjPh xFvNjAZrH4obU/F+jHt4ix5XqEVuDrPQ YTGBGEUpl7YbcyaROzVP3dtCQZamkfaB CQYoNAJlNw6YFG1qulPm3pn3jJHhu88f dFgCisWfp7TjMYn7Id7aYJtliagE47xu ASnhOtaeXAVxDGUIkOI5u8uUCC/jAiHr MgARE5rcqh2AIZeSv0BiMQ==
+csas.cz. 120 IN SOA ddnsa.csas.cz. domainservices.csas.cz. 2019061320 28800 1800 2592000 120
+gfr9qt699hmcloa9radenpk7pqeikiu8.csas.cz. 120 IN NSEC3 1 0 1 31245099125aedf7 gfr9qt699hmcloa9radenpk7pqeikiu9 TXT
+gfr9qt699hmcloa9radenpk7pqeikiu8.csas.cz. 120 IN RRSIG NSEC3 7 3 120 20190702130338 20190625130338 26663 csas.cz. OWtiEsmO7VnUV2MQp3gZJmOAQw4n81DH 9c5FFJW6MBE3afaIqGTvWYCgRipEEvZF qPBVxGpptVsMbuELagewwZYtR+EEh2A/ qMf/wVC//t2c67YFIxMILi9ijleYS5y8 m5Mu+logobk2Resxs0kC47kwNP9KSh7s gm3SFjK1LXRXg19UmiabMIINoOoAE1M0 XePGhiaqhFwros32p++2JrCdaYrPXLWy VuENN0chZ/hE55ic4M7KpxZ12+oPzigk tIeh9sqTaKpGJBZk4vlJQLq2zfL/gnKZ CRRN8bJQ/ZsSZG//rL0nqZcgyxQqXI9w As8TBPtQ9IQWq2K5MxjKHg==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+csas.cz. IN DNSKEY
+SECTION ANSWER
+csas.cz. 7200 IN DNSKEY 256 3 7 AwEAAaNjFdWEB091Zv/uWznXJXbFaDYD cG4GvutyTPMM1nWDLu1ZTR/ujYhwEoWM 1DYyq8QkIFJS7PVnu312O8pkiWcvV9Fl hVv9AYJ8OCbixXjSrwXL1yfBhhzJxxjA RXi49Xn/NTPNiTeK6lVed2QMLbwucpTy 4GEduAcXWDi7/OnDD3UmaFtxXQ2LKc7d +of4okGQWYdka9b+KeyJtXwhDuuzGf/v m8E3Tdjt5ldgOpofh/BO5lifl6mAXgnW E6z+p0fb1ksyq1hGu9ssizxr8A10amUa repR+zcOFoDJNv5IxGWi5rriAvBW4NAl U1wy1P6BSDgMZuc8JBj3VikbI6U=
+csas.cz. 7200 IN DNSKEY 256 3 7 AwEAAbk21ZXai9JsSCmuW8InRPINGI+o 2vxokpQ0imk6iDPHqF3QhJSs5QcFG+Hq yZ3mWLkb5cT/u0zKZ+Onri0s2zSm4ASk /A86BQSEaPXG90GiD+waH7qF5vorF5Gx 1BvzdtLz9vtbsQ0G1GfdbvlouvlU05t2 GlSuAXqsj6RI5WaWHejKJ1fcOtR7hQTt tH5+oir5t1eJ1riQsOyPzC2y9V+Q28Tf cD5F6oxghhn9+YieAIqMMp5r7txouxp0 DFG+oVMbTmt07B9MIClXOMMTOYDTOj0c fpdx5/WHoigkgNdcUh5ulsva9OK9EWZX WkicdtzfYfe7fi3LqFxWc0DMiY0=
+csas.cz. 7200 IN DNSKEY 257 3 7 AwEAAcMXtJYlvIshn+O541gOW48wNlgh szwYVFeSUd+qB+BfejKueV+4vo9IY1A8 cKxfLcOwT0F/XyEZXhpigZPXf2OQrLWi R6aK0cDErhLUp30AWdEwB/T8QnfePzM1 LX30rgAP5JhGLckrfoVbSZi28S6vvuxA GbFmgEpGkKVgMg9pKAcjrRUd/bmyNaQR yECq40cwgHFaDm9SPeAavgMxn1l88dAv qIwKDvpN2Er+K/Gl5GRApDFxSt9x+7rt NIrpFV4Apl/j81Rcxyj7v7HXEu3P8BNQ 6s0cVg8RmtY+R0J59sTsZyJGI2krq5Ap k2K1S2RA7QZxHQCMKx+caRyLwk6KqjmF EYMILxpYWER+iPddpeo5w0AYJNxDYYeE 2cUYuBXNi7SM4UZGDbMZ+j2xlzGNyAsE mWXlrR4qCgYKO7JxK0Yw3otZzNyrcJhS fT1E0tNvDv3zH/j8riqIyW36EK1yjVav dcI3a+GGSh5oylb/7SuLFNKEW0g2fo5q W+rITI77k+MRR798XNXqSKTT19LNiqWc xhlA4aGzHzKZieEWR4d6FHhOKzNoo+Ce j7b00rg5v2hwSAEEHcC3lwuStya1J5IX g6sfdNxWqJ0yydI/PGOn0ZgakX2oEE4b zGJchx/aHKogs2L+bZJfi7N1OmU7AU0D mY6kTxEYC1lBFb1h
+csas.cz. 7200 IN DNSKEY 257 3 7 AwEAAcoflVKUA6KreqNnC7qYr0B+UiYS Fqoja50or7jBmrrmxok5mR9Ea+L3D0PK ynffMxFMMQm1JekaJYH66eUGgWWqTHRQ nAKVQchHCv37Bf0nFEetKo/qf4KJbdDD Ar3sXjfkClaQQlqMPDeCQQbfxSWpdvQo ip7pX35KsatTObINwqnMsl3tsvsugybw 6+xujlYWOpmJcjHri7cdZA5NSx3k3Sdb 16/GEpcwFe0Z8Oi4TgbcVEaAziyOm0zC to1SW1L4VovdZkadAa3RMQ7QpyR/wIOr TjqS/weDkOyKgGNnbVL5l8dUAD8rk/Do cXhQuXxNqHB9PVNxBCsfnVVj6fbk09eo 6stXAdJbwoa1NoPBlHsCV5+EN65XXsGO eLZneUt213RDGkphcKTWaF3dvIRXtWbt Rz2bCrxs12ADhhXisyH2EGntyI3LX3zY ISbKaZnRzbU1nKIdcNzFJ1p8aoUPgzX7 YhpXVkhfcaB8aAG38Ys6EXvcACFdoqma V7b0VnvU1tPsI9bAesU4d5K4EjCNrana yfvFgakYdmoi3GrpWeHim7CDK9s5yrh3 Dou59pU7a/1xugGvuCkDllo8Z70hWzJq tVNFrSv7jwLA7+77pRKBF7Vl88Y0i/6h zUkllh7mBCMilyU50AX9bGJsd6PFJn6P iZ8x+XoCel0oZqz3
+csas.cz. 7200 IN RRSIG DNSKEY 7 2 7200 20190630181024 20190623181024 26663 csas.cz. cPZVp/k5lPxsjnRhCc8zXkKGf2VQjg93 Rwyrwjm6wPg/B7n3iTzLA+TUROwMgcAB rlEru/TNaySpWR36rDQdg/w8JZsB17Wf HIO0t1GxjQdEjPYD9T4x0b5u/Ra/ienZ XgHwuto1tQCghttwv7ioECzf1+52asf+ oxe8il1W4HdMH8/wiEyOyPm8n9ou6siX tcVjqbRTy0xLcPoFm/ATvUBMGBrbMedy hGWn88cLoIQA4IPm4zAIAWunPV8sFNKY l12HDNzQlfrO6ukJqtFTjQREeTWFC0qP KXWSPJeX9fTfrT6zHfyV/YQd3tGRP0J8 KTzXmUMYi2vrVbeagR00Vg==
+csas.cz. 7200 IN RRSIG DNSKEY 7 2 7200 20190630181024 20190623181024 8196 csas.cz. t8HaIHf6FCi91a3ppWC4bAiN+WvZPdbf ESinQ+iYFSWk7NlCw45eT/0SpRWNQ5jQ fvWkkvBDDuHDv9FVdmqkvAuMCf0/GgnM 2bdOQt/q2Hp3E91eFpHW1fx7YtQabj+r 9Ww30ewUplDE2v6JlHnJzm53mYsbUUum l+rAtq+QJnb8sjjn2JceDtQLBkZaLsLe vUuFL/Hz/WvvMgjYUyuxbK4xxJByiymo hZIDxA8TWcaoFFyiP+Rv4leqaxVLXun4 VsWsCE2YYtOqrYRaq2UJvbSIFAPdix5Q EL44TXYlJ00NbngD480tJ8TwyNTm4CLp 8Z85xtmpYfKO3VFAycL0zV/7fOJRkoPQ LrBxClIbeQJlQapm1FMQQK/FFfHKSVRq 659VLfDbxfbTU/yWOmlUldaB8r7y6BhD iq4u/IZqIU5eTIbeoMd3HBerKREo0vOy UPCoW4OJ3Q9/WQ18cPsVW+BKjkKRrV4T VQKc52jwkPufUq8fNuVeuZ+8cvgIaUfD 8Xie+N2Trlh5tfaAAg9etgu0EmoEAP8V 1mTzT54losWySfSh5JNx5fDtUaxZI/q3 2+mbgnO4QlGB9eAhoA6JRHByWf+Gf9rR hEktuZqg2Uw4ifOebJsQE4atFr8Tr910 xihtrgtx/y6HwpB9nIr7V91ewn6lKMEz d4ordmuS+1Q=
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+ddnsa.csas.cz. IN A
+SECTION ANSWER
+ddnsa.csas.cz. 7200 IN A 194.50.240.64
+ddnsa.csas.cz. 7200 IN RRSIG A 7 3 7200 20190630180929 20190623180929 26663 csas.cz. QJCNptf+bgoFFzW6vh6lMnevBqaHq1Qk p7UB7hJZfqewhVJsf4/aZlUJg9Ulq990 xe1K+Vw2H7zFKRmS+BhLL0NVS6F/uo3g VWU7UkiLCUdICMNmBlUfv6dTJmovHydF DeCtS8eunKTYKnvSklmr/aLKnFFEaeoi SUF8hkHM2fADZekxqTEMS2ATjlY0rbTb biDd4c1tZdSDeUV7z4B4pHVdgVFBOi6+ kL4MtMM2AY4o9h31jOUGFnfA0cJPmxNN Cx+qgBAl0zKL9+uFrBqB6nYgmd0a1pRa UEQCcVVKkSjDX3gWHtO/nqflFmyDNV4Y OlVLcHVCDNqRtwIRwucUOg==
+SECTION AUTHORITY
+csas.cz. 7200 IN NS ddnsa.csas.cz.
+csas.cz. 7200 IN NS ddnsb.csas.cz.
+csas.cz. 7200 IN NS ddnsc.csas.cz.
+csas.cz. 7200 IN NS ddnsd.csas.cz.
+csas.cz. 7200 IN RRSIG NS 7 2 7200 20190630180929 20190623180929 26663 csas.cz. PLqM9UHNFbb8GmE+SlzSCjAEKYsklbgt CnWf9G26HkwtacOyJkIHe+T0m94rJZTd 6Mnn32Sw/at6idSvVNGQfE6DIKr2rtK6 lJNe0HPMxYWC9Tr5zpzW1/SjLVooMw6n m8K+18RBI33PBI69UgXyuePnWefdTYOJ g4SK3rR2wUlFxnELEFGfYkytZ6tLi1Cd bTgch93lDnXNBRZ2t/mu5jPyv4NTdKCo WgIMJJcuFdPr/YRVRaemkVEup7qVYImk pa4n+7MMERTL/dw+GxtnZ2YKqyxcepYo rPib3FSTaOFZjEPqNPDNfXXYW+bPmWFP 9ESqUtgmvZ1rMDZbr8lbgQ==
+SECTION ADDITIONAL
+ddnsb.csas.cz. 7200 IN A 194.50.240.192
+ddnsb.csas.cz. 7200 IN RRSIG A 7 3 7200 20190630180929 20190623180929 26663 csas.cz. CXelkXBmt3nR60+gTwRcTXTVH1OBpfAE McYGfcEmxk8t+wFwLrCfM+6mJUWbV3a8 cIggoBHU8gJxarnIX4K5bXNel2QRzlTa +qTTPPTxH5LwHayDwoo5edk6c2HkCrY3 qChg5SyjuNxxsF4ybqvqIU0d/kM6wqG7 pKPmplD9BNJmzVIVQ8aTBMhdrvIcqK/f 81TGgNxMqJxfpTYKmnA8vVqpJ3C1kbfn no+ux39NY7Wj58NwI+UIcDlmBj414MSz Z4wEfYSgtVnEA8fO+ufZ3jaxjk6NClz+ XMP1gYj/y08bj0h5ACIKJqci2uqPujoi TNBYzQWn6LVPqNIM8O7eSg==
+ddnsc.csas.cz. 7200 IN A 194.50.240.66
+ddnsc.csas.cz. 7200 IN RRSIG A 7 3 7200 20190630180929 20190623180929 26663 csas.cz. AHQJp3i/UzKmjm/hhmEM1mhV7gPAq2rX 0z4ZOF+ZDyL57nXSHnzGqz4sdd3Q0E1H pmGENdgiOR1Grabo6X3QIp7mZbuAR14T 5TQYHSDoTZ+aTOkqvxCxfUCpEYLVHlbP whE+ntazt0gmkko3eGUBMefMv+JVmuwy tirS7pxlNL1VRnKtbfDsWJ2zmJuur/WK wGzHCMybt4fITB0Og/I9pnwMwykdxhpF bo/MQAa35oTefzvWsD3uFKOhrAc7CP2N MyqDFzv0QDN00s0yFXHHxNg3QFXLAg16 4khZaKT076k+F5N/ufsoIeU/AbByx82T PxpLg8NCh9nNvzgqoCEccw==
+ddnsd.csas.cz. 7200 IN A 194.50.240.194
+ddnsd.csas.cz. 7200 IN RRSIG A 7 3 7200 20190630180929 20190623180929 26663 csas.cz. nsWIVa/SusXOatYzHtX8IPkETOBo90yd Zz8ce1PQhUawbQamihm1di90qJSQJ/i4 QCdL5ulxKJdMv8jLBjIBGe1H08d43luD OmLwkiBNoROZ1apKKabSQAmJTuwIxZCD sqYti2+rEbmOaRC1n96fIH2HWL9pYAnn C0GrvoWEDeVkSHI70Ei9CUCpUNOrPzhS BZc3PrB0DhojkzlXj359e4OhO1gH2QDp 2Uj05suhlIEzQf3lsvvIRUOrMPG2i6Fh j3yThN21+kuVyasrsN5Pv6Dp52U1k60l Y7AuwQwMUXrsdrK3/15DyxSS+pHenpsq cBI3Rb8P4Z6uVxZv9sQ4rQ==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+ddnsb.csas.cz. IN AAAA
+SECTION AUTHORITY
+csas.cz. 120 IN RRSIG SOA 7 2 120 20190630054550 20190623054550 26663 csas.cz. c/sxvp5WLJOsDGgnhxPOk9oBwXRtsUXa enyWg5rd8yBcquHqfFKQu1v8wEPjJjAH B6joG1tJXq99nxtCN4jlDipPKLIzWxba aYIxE8Pab199qiHrR5vxO4KgPxRXbg5d gzIVrrhB+h23DZDacQ+l+kQWSAcycjPh xFvNjAZrH4obU/F+jHt4ix5XqEVuDrPQ YTGBGEUpl7YbcyaROzVP3dtCQZamkfaB CQYoNAJlNw6YFG1qulPm3pn3jJHhu88f dFgCisWfp7TjMYn7Id7aYJtliagE47xu ASnhOtaeXAVxDGUIkOI5u8uUCC/jAiHr MgARE5rcqh2AIZeSv0BiMQ==
+csas.cz. 120 IN SOA ddnsa.csas.cz. domainservices.csas.cz. 2019061320 28800 1800 2592000 120
+kl8ko9vcu5os0r0marmli019btprhvdr.csas.cz. 120 IN NSEC3 1 0 1 31245099125aedf7 kl8ko9vcu5os0r0marmli019btprhvds TXT
+kl8ko9vcu5os0r0marmli019btprhvdr.csas.cz. 120 IN RRSIG NSEC3 7 3 120 20190702130338 20190625130338 26663 csas.cz. ebbykapJt+h+uDJlz84Yu4rpx7spx8aY bbR/BCMIVJ6HjziYnwwbBQuyyd6t281+ pdn+2Dxo5tUJ0Kw4oatMPVhID8Psasd3 2Za8bZrouTk8RcQislJCj1jPi2HMIQUI dvJ1aCMC6vn1vI++ZMvcxfptxgmWyL46 i4P3xZAwtrB6hCVrctQ0dbbp1nswh1go YFIf3Hzxu2NHfXZYMdXXb1cLuOZ5L17g UZlqqgcrudLORc2cHj0NcjVT2PscMeoy a/jFNJwCHmkfI3nCAeXmemz/txQUY01u SxBNjkd/y2DVSIgvDPY/Zz0dW4gYdcMG 4T4D43oBTG6w06CgBg1QQw==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+csas.cz. IN A
+SECTION ANSWER
+csas.cz. 120 IN A 194.50.240.198
+csas.cz. 120 IN A 194.50.240.70
+csas.cz. 120 IN RRSIG A 7 2 120 20190701063211 20190624063211 26663 csas.cz. UXxlRUL6nBVmcrcP4kkryr7lfVxnQHs4 z2WahLZEIaQdf56Iw/+bxddThPD9l3a0 rBCwURI8QMspgPks+7UprWN5TESIifiP W9qJLDuvtD+sVoLgunBAwgi1sE8KfRas asbiISaRpot+3IqJYzYi9X9O5JMdYCuS H9nfayDebVlbC4ChAo5Rcdpkzfb7DwFp gDFKdn+Lmp7IdImSlvJQQT2Mqxpew+gd vMBr5ZN82G8zlsrrHz4n2/kF/SqCYTCG q1WLZUsMvLsP+ha3TAR1t/iG9ayw5Mll 8N2c+AejB2lMwTIlBX+zLlJYT0MoNCyF cMNoCxwjENtDMbq9QZKowA==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+ddnsc.csas.cz. IN A
+SECTION ANSWER
+ddnsc.csas.cz. 7200 IN A 194.50.240.66
+ddnsc.csas.cz. 7200 IN RRSIG A 7 3 7200 20190630180929 20190623180929 26663 csas.cz. AHQJp3i/UzKmjm/hhmEM1mhV7gPAq2rX 0z4ZOF+ZDyL57nXSHnzGqz4sdd3Q0E1H pmGENdgiOR1Grabo6X3QIp7mZbuAR14T 5TQYHSDoTZ+aTOkqvxCxfUCpEYLVHlbP whE+ntazt0gmkko3eGUBMefMv+JVmuwy tirS7pxlNL1VRnKtbfDsWJ2zmJuur/WK wGzHCMybt4fITB0Og/I9pnwMwykdxhpF bo/MQAa35oTefzvWsD3uFKOhrAc7CP2N MyqDFzv0QDN00s0yFXHHxNg3QFXLAg16 4khZaKT076k+F5N/ufsoIeU/AbByx82T PxpLg8NCh9nNvzgqoCEccw==
+SECTION AUTHORITY
+csas.cz. 7200 IN NS ddnsa.csas.cz.
+csas.cz. 7200 IN NS ddnsb.csas.cz.
+csas.cz. 7200 IN NS ddnsc.csas.cz.
+csas.cz. 7200 IN NS ddnsd.csas.cz.
+csas.cz. 7200 IN RRSIG NS 7 2 7200 20190630180929 20190623180929 26663 csas.cz. PLqM9UHNFbb8GmE+SlzSCjAEKYsklbgt CnWf9G26HkwtacOyJkIHe+T0m94rJZTd 6Mnn32Sw/at6idSvVNGQfE6DIKr2rtK6 lJNe0HPMxYWC9Tr5zpzW1/SjLVooMw6n m8K+18RBI33PBI69UgXyuePnWefdTYOJ g4SK3rR2wUlFxnELEFGfYkytZ6tLi1Cd bTgch93lDnXNBRZ2t/mu5jPyv4NTdKCo WgIMJJcuFdPr/YRVRaemkVEup7qVYImk pa4n+7MMERTL/dw+GxtnZ2YKqyxcepYo rPib3FSTaOFZjEPqNPDNfXXYW+bPmWFP 9ESqUtgmvZ1rMDZbr8lbgQ==
+SECTION ADDITIONAL
+ddnsa.csas.cz. 7200 IN A 194.50.240.64
+ddnsa.csas.cz. 7200 IN RRSIG A 7 3 7200 20190630180929 20190623180929 26663 csas.cz. QJCNptf+bgoFFzW6vh6lMnevBqaHq1Qk p7UB7hJZfqewhVJsf4/aZlUJg9Ulq990 xe1K+Vw2H7zFKRmS+BhLL0NVS6F/uo3g VWU7UkiLCUdICMNmBlUfv6dTJmovHydF DeCtS8eunKTYKnvSklmr/aLKnFFEaeoi SUF8hkHM2fADZekxqTEMS2ATjlY0rbTb biDd4c1tZdSDeUV7z4B4pHVdgVFBOi6+ kL4MtMM2AY4o9h31jOUGFnfA0cJPmxNN Cx+qgBAl0zKL9+uFrBqB6nYgmd0a1pRa UEQCcVVKkSjDX3gWHtO/nqflFmyDNV4Y OlVLcHVCDNqRtwIRwucUOg==
+ddnsb.csas.cz. 7200 IN A 194.50.240.192
+ddnsb.csas.cz. 7200 IN RRSIG A 7 3 7200 20190630180929 20190623180929 26663 csas.cz. CXelkXBmt3nR60+gTwRcTXTVH1OBpfAE McYGfcEmxk8t+wFwLrCfM+6mJUWbV3a8 cIggoBHU8gJxarnIX4K5bXNel2QRzlTa +qTTPPTxH5LwHayDwoo5edk6c2HkCrY3 qChg5SyjuNxxsF4ybqvqIU0d/kM6wqG7 pKPmplD9BNJmzVIVQ8aTBMhdrvIcqK/f 81TGgNxMqJxfpTYKmnA8vVqpJ3C1kbfn no+ux39NY7Wj58NwI+UIcDlmBj414MSz Z4wEfYSgtVnEA8fO+ufZ3jaxjk6NClz+ XMP1gYj/y08bj0h5ACIKJqci2uqPujoi TNBYzQWn6LVPqNIM8O7eSg==
+ddnsd.csas.cz. 7200 IN A 194.50.240.194
+ddnsd.csas.cz. 7200 IN RRSIG A 7 3 7200 20190630180929 20190623180929 26663 csas.cz. nsWIVa/SusXOatYzHtX8IPkETOBo90yd Zz8ce1PQhUawbQamihm1di90qJSQJ/i4 QCdL5ulxKJdMv8jLBjIBGe1H08d43luD OmLwkiBNoROZ1apKKabSQAmJTuwIxZCD sqYti2+rEbmOaRC1n96fIH2HWL9pYAnn C0GrvoWEDeVkSHI70Ei9CUCpUNOrPzhS BZc3PrB0DhojkzlXj359e4OhO1gH2QDp 2Uj05suhlIEzQf3lsvvIRUOrMPG2i6Fh j3yThN21+kuVyasrsN5Pv6Dp52U1k60l Y7AuwQwMUXrsdrK3/15DyxSS+pHenpsq cBI3Rb8P4Z6uVxZv9sQ4rQ==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NXDOMAIN
+SECTION QUESTION
+csas.cz. IN DS
+SECTION AUTHORITY
+cz. 60 IN SOA cecf53-ant-MS2A-1.csin.cz. hostmaster.cecf53-ant-MS2A-1.csin.cz. 2019061307 10800 3600 604800 60
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+ddnsb.csas.cz. IN NS
+SECTION AUTHORITY
+csas.cz. 120 IN RRSIG SOA 7 2 120 20190630054550 20190623054550 26663 csas.cz. c/sxvp5WLJOsDGgnhxPOk9oBwXRtsUXa enyWg5rd8yBcquHqfFKQu1v8wEPjJjAH B6joG1tJXq99nxtCN4jlDipPKLIzWxba aYIxE8Pab199qiHrR5vxO4KgPxRXbg5d gzIVrrhB+h23DZDacQ+l+kQWSAcycjPh xFvNjAZrH4obU/F+jHt4ix5XqEVuDrPQ YTGBGEUpl7YbcyaROzVP3dtCQZamkfaB CQYoNAJlNw6YFG1qulPm3pn3jJHhu88f dFgCisWfp7TjMYn7Id7aYJtliagE47xu ASnhOtaeXAVxDGUIkOI5u8uUCC/jAiHr MgARE5rcqh2AIZeSv0BiMQ==
+csas.cz. 120 IN SOA ddnsa.csas.cz. domainservices.csas.cz. 2019061320 28800 1800 2592000 120
+kl8ko9vcu5os0r0marmli019btprhvdr.csas.cz. 120 IN NSEC3 1 0 1 31245099125aedf7 kl8ko9vcu5os0r0marmli019btprhvds TXT
+kl8ko9vcu5os0r0marmli019btprhvdr.csas.cz. 120 IN RRSIG NSEC3 7 3 120 20190702130338 20190625130338 26663 csas.cz. ebbykapJt+h+uDJlz84Yu4rpx7spx8aY bbR/BCMIVJ6HjziYnwwbBQuyyd6t281+ pdn+2Dxo5tUJ0Kw4oatMPVhID8Psasd3 2Za8bZrouTk8RcQislJCj1jPi2HMIQUI dvJ1aCMC6vn1vI++ZMvcxfptxgmWyL46 i4P3xZAwtrB6hCVrctQ0dbbp1nswh1go YFIf3Hzxu2NHfXZYMdXXb1cLuOZ5L17g UZlqqgcrudLORc2cHj0NcjVT2PscMeoy a/jFNJwCHmkfI3nCAeXmemz/txQUY01u SxBNjkd/y2DVSIgvDPY/Zz0dW4gYdcMG 4T4D43oBTG6w06CgBg1QQw==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+ddnsb.csas.cz. IN A
+SECTION ANSWER
+ddnsb.csas.cz. 7200 IN A 194.50.240.192
+ddnsb.csas.cz. 7200 IN RRSIG A 7 3 7200 20190630180929 20190623180929 26663 csas.cz. CXelkXBmt3nR60+gTwRcTXTVH1OBpfAE McYGfcEmxk8t+wFwLrCfM+6mJUWbV3a8 cIggoBHU8gJxarnIX4K5bXNel2QRzlTa +qTTPPTxH5LwHayDwoo5edk6c2HkCrY3 qChg5SyjuNxxsF4ybqvqIU0d/kM6wqG7 pKPmplD9BNJmzVIVQ8aTBMhdrvIcqK/f 81TGgNxMqJxfpTYKmnA8vVqpJ3C1kbfn no+ux39NY7Wj58NwI+UIcDlmBj414MSz Z4wEfYSgtVnEA8fO+ufZ3jaxjk6NClz+ XMP1gYj/y08bj0h5ACIKJqci2uqPujoi TNBYzQWn6LVPqNIM8O7eSg==
+SECTION AUTHORITY
+csas.cz. 7200 IN NS ddnsa.csas.cz.
+csas.cz. 7200 IN NS ddnsb.csas.cz.
+csas.cz. 7200 IN NS ddnsc.csas.cz.
+csas.cz. 7200 IN NS ddnsd.csas.cz.
+csas.cz. 7200 IN RRSIG NS 7 2 7200 20190630180929 20190623180929 26663 csas.cz. PLqM9UHNFbb8GmE+SlzSCjAEKYsklbgt CnWf9G26HkwtacOyJkIHe+T0m94rJZTd 6Mnn32Sw/at6idSvVNGQfE6DIKr2rtK6 lJNe0HPMxYWC9Tr5zpzW1/SjLVooMw6n m8K+18RBI33PBI69UgXyuePnWefdTYOJ g4SK3rR2wUlFxnELEFGfYkytZ6tLi1Cd bTgch93lDnXNBRZ2t/mu5jPyv4NTdKCo WgIMJJcuFdPr/YRVRaemkVEup7qVYImk pa4n+7MMERTL/dw+GxtnZ2YKqyxcepYo rPib3FSTaOFZjEPqNPDNfXXYW+bPmWFP 9ESqUtgmvZ1rMDZbr8lbgQ==
+SECTION ADDITIONAL
+ddnsa.csas.cz. 7200 IN A 194.50.240.64
+ddnsa.csas.cz. 7200 IN RRSIG A 7 3 7200 20190630180929 20190623180929 26663 csas.cz. QJCNptf+bgoFFzW6vh6lMnevBqaHq1Qk p7UB7hJZfqewhVJsf4/aZlUJg9Ulq990 xe1K+Vw2H7zFKRmS+BhLL0NVS6F/uo3g VWU7UkiLCUdICMNmBlUfv6dTJmovHydF DeCtS8eunKTYKnvSklmr/aLKnFFEaeoi SUF8hkHM2fADZekxqTEMS2ATjlY0rbTb biDd4c1tZdSDeUV7z4B4pHVdgVFBOi6+ kL4MtMM2AY4o9h31jOUGFnfA0cJPmxNN Cx+qgBAl0zKL9+uFrBqB6nYgmd0a1pRa UEQCcVVKkSjDX3gWHtO/nqflFmyDNV4Y OlVLcHVCDNqRtwIRwucUOg==
+ddnsc.csas.cz. 7200 IN A 194.50.240.66
+ddnsc.csas.cz. 7200 IN RRSIG A 7 3 7200 20190630180929 20190623180929 26663 csas.cz. AHQJp3i/UzKmjm/hhmEM1mhV7gPAq2rX 0z4ZOF+ZDyL57nXSHnzGqz4sdd3Q0E1H pmGENdgiOR1Grabo6X3QIp7mZbuAR14T 5TQYHSDoTZ+aTOkqvxCxfUCpEYLVHlbP whE+ntazt0gmkko3eGUBMefMv+JVmuwy tirS7pxlNL1VRnKtbfDsWJ2zmJuur/WK wGzHCMybt4fITB0Og/I9pnwMwykdxhpF bo/MQAa35oTefzvWsD3uFKOhrAc7CP2N MyqDFzv0QDN00s0yFXHHxNg3QFXLAg16 4khZaKT076k+F5N/ufsoIeU/AbByx82T PxpLg8NCh9nNvzgqoCEccw==
+ddnsd.csas.cz. 7200 IN A 194.50.240.194
+ddnsd.csas.cz. 7200 IN RRSIG A 7 3 7200 20190630180929 20190623180929 26663 csas.cz. nsWIVa/SusXOatYzHtX8IPkETOBo90yd Zz8ce1PQhUawbQamihm1di90qJSQJ/i4 QCdL5ulxKJdMv8jLBjIBGe1H08d43luD OmLwkiBNoROZ1apKKabSQAmJTuwIxZCD sqYti2+rEbmOaRC1n96fIH2HWL9pYAnn C0GrvoWEDeVkSHI70Ei9CUCpUNOrPzhS BZc3PrB0DhojkzlXj359e4OhO1gH2QDp 2Uj05suhlIEzQf3lsvvIRUOrMPG2i6Fh j3yThN21+kuVyasrsN5Pv6Dp52U1k60l Y7AuwQwMUXrsdrK3/15DyxSS+pHenpsq cBI3Rb8P4Z6uVxZv9sQ4rQ==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+ddnsd.csas.cz. IN A
+SECTION ANSWER
+ddnsd.csas.cz. 7200 IN A 194.50.240.194
+ddnsd.csas.cz. 7200 IN RRSIG A 7 3 7200 20190630180929 20190623180929 26663 csas.cz. nsWIVa/SusXOatYzHtX8IPkETOBo90yd Zz8ce1PQhUawbQamihm1di90qJSQJ/i4 QCdL5ulxKJdMv8jLBjIBGe1H08d43luD OmLwkiBNoROZ1apKKabSQAmJTuwIxZCD sqYti2+rEbmOaRC1n96fIH2HWL9pYAnn C0GrvoWEDeVkSHI70Ei9CUCpUNOrPzhS BZc3PrB0DhojkzlXj359e4OhO1gH2QDp 2Uj05suhlIEzQf3lsvvIRUOrMPG2i6Fh j3yThN21+kuVyasrsN5Pv6Dp52U1k60l Y7AuwQwMUXrsdrK3/15DyxSS+pHenpsq cBI3Rb8P4Z6uVxZv9sQ4rQ==
+SECTION AUTHORITY
+csas.cz. 7200 IN NS ddnsa.csas.cz.
+csas.cz. 7200 IN NS ddnsb.csas.cz.
+csas.cz. 7200 IN NS ddnsc.csas.cz.
+csas.cz. 7200 IN NS ddnsd.csas.cz.
+csas.cz. 7200 IN RRSIG NS 7 2 7200 20190630180929 20190623180929 26663 csas.cz. PLqM9UHNFbb8GmE+SlzSCjAEKYsklbgt CnWf9G26HkwtacOyJkIHe+T0m94rJZTd 6Mnn32Sw/at6idSvVNGQfE6DIKr2rtK6 lJNe0HPMxYWC9Tr5zpzW1/SjLVooMw6n m8K+18RBI33PBI69UgXyuePnWefdTYOJ g4SK3rR2wUlFxnELEFGfYkytZ6tLi1Cd bTgch93lDnXNBRZ2t/mu5jPyv4NTdKCo WgIMJJcuFdPr/YRVRaemkVEup7qVYImk pa4n+7MMERTL/dw+GxtnZ2YKqyxcepYo rPib3FSTaOFZjEPqNPDNfXXYW+bPmWFP 9ESqUtgmvZ1rMDZbr8lbgQ==
+SECTION ADDITIONAL
+ddnsa.csas.cz. 7200 IN A 194.50.240.64
+ddnsa.csas.cz. 7200 IN RRSIG A 7 3 7200 20190630180929 20190623180929 26663 csas.cz. QJCNptf+bgoFFzW6vh6lMnevBqaHq1Qk p7UB7hJZfqewhVJsf4/aZlUJg9Ulq990 xe1K+Vw2H7zFKRmS+BhLL0NVS6F/uo3g VWU7UkiLCUdICMNmBlUfv6dTJmovHydF DeCtS8eunKTYKnvSklmr/aLKnFFEaeoi SUF8hkHM2fADZekxqTEMS2ATjlY0rbTb biDd4c1tZdSDeUV7z4B4pHVdgVFBOi6+ kL4MtMM2AY4o9h31jOUGFnfA0cJPmxNN Cx+qgBAl0zKL9+uFrBqB6nYgmd0a1pRa UEQCcVVKkSjDX3gWHtO/nqflFmyDNV4Y OlVLcHVCDNqRtwIRwucUOg==
+ddnsb.csas.cz. 7200 IN A 194.50.240.192
+ddnsb.csas.cz. 7200 IN RRSIG A 7 3 7200 20190630180929 20190623180929 26663 csas.cz. CXelkXBmt3nR60+gTwRcTXTVH1OBpfAE McYGfcEmxk8t+wFwLrCfM+6mJUWbV3a8 cIggoBHU8gJxarnIX4K5bXNel2QRzlTa +qTTPPTxH5LwHayDwoo5edk6c2HkCrY3 qChg5SyjuNxxsF4ybqvqIU0d/kM6wqG7 pKPmplD9BNJmzVIVQ8aTBMhdrvIcqK/f 81TGgNxMqJxfpTYKmnA8vVqpJ3C1kbfn no+ux39NY7Wj58NwI+UIcDlmBj414MSz Z4wEfYSgtVnEA8fO+ufZ3jaxjk6NClz+ XMP1gYj/y08bj0h5ACIKJqci2uqPujoi TNBYzQWn6LVPqNIM8O7eSg==
+ddnsc.csas.cz. 7200 IN A 194.50.240.66
+ddnsc.csas.cz. 7200 IN RRSIG A 7 3 7200 20190630180929 20190623180929 26663 csas.cz. AHQJp3i/UzKmjm/hhmEM1mhV7gPAq2rX 0z4ZOF+ZDyL57nXSHnzGqz4sdd3Q0E1H pmGENdgiOR1Grabo6X3QIp7mZbuAR14T 5TQYHSDoTZ+aTOkqvxCxfUCpEYLVHlbP whE+ntazt0gmkko3eGUBMefMv+JVmuwy tirS7pxlNL1VRnKtbfDsWJ2zmJuur/WK wGzHCMybt4fITB0Og/I9pnwMwykdxhpF bo/MQAa35oTefzvWsD3uFKOhrAc7CP2N MyqDFzv0QDN00s0yFXHHxNg3QFXLAg16 4khZaKT076k+F5N/ufsoIeU/AbByx82T PxpLg8NCh9nNvzgqoCEccw==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+ddnsa.csas.cz. IN AAAA
+SECTION AUTHORITY
+csas.cz. 120 IN RRSIG SOA 7 2 120 20190630054550 20190623054550 26663 csas.cz. c/sxvp5WLJOsDGgnhxPOk9oBwXRtsUXa enyWg5rd8yBcquHqfFKQu1v8wEPjJjAH B6joG1tJXq99nxtCN4jlDipPKLIzWxba aYIxE8Pab199qiHrR5vxO4KgPxRXbg5d gzIVrrhB+h23DZDacQ+l+kQWSAcycjPh xFvNjAZrH4obU/F+jHt4ix5XqEVuDrPQ YTGBGEUpl7YbcyaROzVP3dtCQZamkfaB CQYoNAJlNw6YFG1qulPm3pn3jJHhu88f dFgCisWfp7TjMYn7Id7aYJtliagE47xu ASnhOtaeXAVxDGUIkOI5u8uUCC/jAiHr MgARE5rcqh2AIZeSv0BiMQ==
+csas.cz. 120 IN SOA ddnsa.csas.cz. domainservices.csas.cz. 2019061320 28800 1800 2592000 120
+j0hp68elhot3j046r6mr0tnqlns1dbc7.csas.cz. 120 IN NSEC3 1 0 1 31245099125aedf7 j0hp68elhot3j046r6mr0tnqlns1dbc8 TXT
+j0hp68elhot3j046r6mr0tnqlns1dbc7.csas.cz. 120 IN RRSIG NSEC3 7 3 120 20190702130338 20190625130338 26663 csas.cz. gUyltGyzdD2L6M29xgqWXMO834aavtFc Si2oAbET0rEJZ5w9ewhEJdVT65MMUUlK wvVX239N7PtsyL+fQvxu5TZ8du0ML8Oi KBp3gao/stajg/lZFd6zVvDWliC3+psL 7PFmD5au5qcrYc6HLc8m8D4hHFPREyd6 1tLGA98RevbQGfrDYODXi6G28vwbxoYU POn4mo82MnVVTZhh58cu7nKRRvKAtay6 VZVWZBOuxy8u+LNsrj3vpDbaOIiWzHd0 pRACsv3LqGpxQNH8avSalWLBvLWchAHj 0T2M+doO8UVaCsyFo/3wF2TXdgFcOAr3 xDIdhHCCoanRVFZ+gFAwIw==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+ddnsa.csas.cz. IN NS
+SECTION AUTHORITY
+csas.cz. 120 IN RRSIG SOA 7 2 120 20190630054550 20190623054550 26663 csas.cz. c/sxvp5WLJOsDGgnhxPOk9oBwXRtsUXa enyWg5rd8yBcquHqfFKQu1v8wEPjJjAH B6joG1tJXq99nxtCN4jlDipPKLIzWxba aYIxE8Pab199qiHrR5vxO4KgPxRXbg5d gzIVrrhB+h23DZDacQ+l+kQWSAcycjPh xFvNjAZrH4obU/F+jHt4ix5XqEVuDrPQ YTGBGEUpl7YbcyaROzVP3dtCQZamkfaB CQYoNAJlNw6YFG1qulPm3pn3jJHhu88f dFgCisWfp7TjMYn7Id7aYJtliagE47xu ASnhOtaeXAVxDGUIkOI5u8uUCC/jAiHr MgARE5rcqh2AIZeSv0BiMQ==
+csas.cz. 120 IN SOA ddnsa.csas.cz. domainservices.csas.cz. 2019061320 28800 1800 2592000 120
+j0hp68elhot3j046r6mr0tnqlns1dbc7.csas.cz. 120 IN NSEC3 1 0 1 31245099125aedf7 j0hp68elhot3j046r6mr0tnqlns1dbc8 TXT
+j0hp68elhot3j046r6mr0tnqlns1dbc7.csas.cz. 120 IN RRSIG NSEC3 7 3 120 20190702130338 20190625130338 26663 csas.cz. gUyltGyzdD2L6M29xgqWXMO834aavtFc Si2oAbET0rEJZ5w9ewhEJdVT65MMUUlK wvVX239N7PtsyL+fQvxu5TZ8du0ML8Oi KBp3gao/stajg/lZFd6zVvDWliC3+psL 7PFmD5au5qcrYc6HLc8m8D4hHFPREyd6 1tLGA98RevbQGfrDYODXi6G28vwbxoYU POn4mo82MnVVTZhh58cu7nKRRvKAtay6 VZVWZBOuxy8u+LNsrj3vpDbaOIiWzHd0 pRACsv3LqGpxQNH8avSalWLBvLWchAHj 0T2M+doO8UVaCsyFo/3wF2TXdgFcOAr3 xDIdhHCCoanRVFZ+gFAwIw==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+ddnsc.csas.cz. IN AAAA
+SECTION AUTHORITY
+c1c03am0n36kncp4iqb4buoqo1ectql4.csas.cz. 120 IN NSEC3 1 0 1 31245099125aedf7 c1c03am0n36kncp4iqb4buoqo1ectql5 TXT
+c1c03am0n36kncp4iqb4buoqo1ectql4.csas.cz. 120 IN RRSIG NSEC3 7 3 120 20190702130338 20190625130338 26663 csas.cz. FKjWbcw5aP2HzHFy2t+M462dxM1ph0FW 02Tohh/aJQOp1iKQOi6u1V2tI3H9CMXW xeIAktZ+xiUDRYLX50fNuJZMaSsn7r5A LYjVAKGzwMPncIf6IlEDYkj1I1rdp6z8 LvWsWNO1wfIPq1Dw2geN60bcz3D7r/sY WfjU/7jO9f0nekZZXI2qFsMSYd9Dkaq7 mlpP0NrWnUbCjL+BfuLFNebh8g3D8f5w Tq3R9czwW5YTVXUquBIrjiZ0Ko9INgQ/ 4pvJqJ1bsTpmzdODfAssEtpu+es4wLwt ZTe8Ll9VeDB20RqEnAyHZwQRXXVF2t+F vdJU7Desbpu6rElA7IXwRw==
+csas.cz. 120 IN RRSIG SOA 7 2 120 20190630054550 20190623054550 26663 csas.cz. c/sxvp5WLJOsDGgnhxPOk9oBwXRtsUXa enyWg5rd8yBcquHqfFKQu1v8wEPjJjAH B6joG1tJXq99nxtCN4jlDipPKLIzWxba aYIxE8Pab199qiHrR5vxO4KgPxRXbg5d gzIVrrhB+h23DZDacQ+l+kQWSAcycjPh xFvNjAZrH4obU/F+jHt4ix5XqEVuDrPQ YTGBGEUpl7YbcyaROzVP3dtCQZamkfaB CQYoNAJlNw6YFG1qulPm3pn3jJHhu88f dFgCisWfp7TjMYn7Id7aYJtliagE47xu ASnhOtaeXAVxDGUIkOI5u8uUCC/jAiHr MgARE5rcqh2AIZeSv0BiMQ==
+csas.cz. 120 IN SOA ddnsa.csas.cz. domainservices.csas.cz. 2019061320 28800 1800 2592000 120
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH subdomain
+ADJUST copy_id copy_query
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+csas.cz. IN NS
+SECTION ANSWER
+csas.cz. 7200 IN NS ddnsa.csas.cz.
+csas.cz. 7200 IN NS ddnsb.csas.cz.
+csas.cz. 7200 IN NS ddnsc.csas.cz.
+csas.cz. 7200 IN NS ddnsd.csas.cz.
+csas.cz. 7200 IN RRSIG NS 7 2 7200 20190630180929 20190623180929 26663 csas.cz. PLqM9UHNFbb8GmE+SlzSCjAEKYsklbgt CnWf9G26HkwtacOyJkIHe+T0m94rJZTd 6Mnn32Sw/at6idSvVNGQfE6DIKr2rtK6 lJNe0HPMxYWC9Tr5zpzW1/SjLVooMw6n m8K+18RBI33PBI69UgXyuePnWefdTYOJ g4SK3rR2wUlFxnELEFGfYkytZ6tLi1Cd bTgch93lDnXNBRZ2t/mu5jPyv4NTdKCo WgIMJJcuFdPr/YRVRaemkVEup7qVYImk pa4n+7MMERTL/dw+GxtnZ2YKqyxcepYo rPib3FSTaOFZjEPqNPDNfXXYW+bPmWFP 9ESqUtgmvZ1rMDZbr8lbgQ==
+SECTION ADDITIONAL
+ddnsa.csas.cz. 7200 IN A 194.50.240.64
+ddnsa.csas.cz. 7200 IN RRSIG A 7 3 7200 20190630180929 20190623180929 26663 csas.cz. QJCNptf+bgoFFzW6vh6lMnevBqaHq1Qk p7UB7hJZfqewhVJsf4/aZlUJg9Ulq990 xe1K+Vw2H7zFKRmS+BhLL0NVS6F/uo3g VWU7UkiLCUdICMNmBlUfv6dTJmovHydF DeCtS8eunKTYKnvSklmr/aLKnFFEaeoi SUF8hkHM2fADZekxqTEMS2ATjlY0rbTb biDd4c1tZdSDeUV7z4B4pHVdgVFBOi6+ kL4MtMM2AY4o9h31jOUGFnfA0cJPmxNN Cx+qgBAl0zKL9+uFrBqB6nYgmd0a1pRa UEQCcVVKkSjDX3gWHtO/nqflFmyDNV4Y OlVLcHVCDNqRtwIRwucUOg==
+ddnsb.csas.cz. 7200 IN A 194.50.240.192
+ddnsb.csas.cz. 7200 IN RRSIG A 7 3 7200 20190630180929 20190623180929 26663 csas.cz. CXelkXBmt3nR60+gTwRcTXTVH1OBpfAE McYGfcEmxk8t+wFwLrCfM+6mJUWbV3a8 cIggoBHU8gJxarnIX4K5bXNel2QRzlTa +qTTPPTxH5LwHayDwoo5edk6c2HkCrY3 qChg5SyjuNxxsF4ybqvqIU0d/kM6wqG7 pKPmplD9BNJmzVIVQ8aTBMhdrvIcqK/f 81TGgNxMqJxfpTYKmnA8vVqpJ3C1kbfn no+ux39NY7Wj58NwI+UIcDlmBj414MSz Z4wEfYSgtVnEA8fO+ufZ3jaxjk6NClz+ XMP1gYj/y08bj0h5ACIKJqci2uqPujoi TNBYzQWn6LVPqNIM8O7eSg==
+ddnsc.csas.cz. 7200 IN A 194.50.240.66
+ddnsc.csas.cz. 7200 IN RRSIG A 7 3 7200 20190630180929 20190623180929 26663 csas.cz. AHQJp3i/UzKmjm/hhmEM1mhV7gPAq2rX 0z4ZOF+ZDyL57nXSHnzGqz4sdd3Q0E1H pmGENdgiOR1Grabo6X3QIp7mZbuAR14T 5TQYHSDoTZ+aTOkqvxCxfUCpEYLVHlbP whE+ntazt0gmkko3eGUBMefMv+JVmuwy tirS7pxlNL1VRnKtbfDsWJ2zmJuur/WK wGzHCMybt4fITB0Og/I9pnwMwykdxhpF bo/MQAa35oTefzvWsD3uFKOhrAc7CP2N MyqDFzv0QDN00s0yFXHHxNg3QFXLAg16 4khZaKT076k+F5N/ufsoIeU/AbByx82T PxpLg8NCh9nNvzgqoCEccw==
+ddnsd.csas.cz. 7200 IN A 194.50.240.194
+ddnsd.csas.cz. 7200 IN RRSIG A 7 3 7200 20190630180929 20190623180929 26663 csas.cz. nsWIVa/SusXOatYzHtX8IPkETOBo90yd Zz8ce1PQhUawbQamihm1di90qJSQJ/i4 QCdL5ulxKJdMv8jLBjIBGe1H08d43luD OmLwkiBNoROZ1apKKabSQAmJTuwIxZCD sqYti2+rEbmOaRC1n96fIH2HWL9pYAnn C0GrvoWEDeVkSHI70Ei9CUCpUNOrPzhS BZc3PrB0DhojkzlXj359e4OhO1gH2QDp 2Uj05suhlIEzQf3lsvvIRUOrMPG2i6Fh j3yThN21+kuVyasrsN5Pv6Dp52U1k60l Y7AuwQwMUXrsdrK3/15DyxSS+pHenpsq cBI3Rb8P4Z6uVxZv9sQ4rQ==
+ENTRY_END
+
+
+
+
+RANGE_END
+
+
+
+; Group's zones:
+; com.
+; net.
+; Server names:
+; a.gtld-servers.net.
+; j.gtld-servers.net.
+; e.gtld-servers.net.
+; i.gtld-servers.net.
+; d.gtld-servers.net.
+; m.gtld-servers.net.
+; h.gtld-servers.net.
+; c.gtld-servers.net.
+; l.gtld-servers.net.
+; g.gtld-servers.net.
+; b.gtld-servers.net.
+; k.gtld-servers.net.
+; f.gtld-servers.net.
+RANGE_BEGIN 0 1000
+ ADDRESS 2001:502:8cc::30
+ ADDRESS 2001:503:eea3::30
+ ADDRESS 192.5.6.30
+ ADDRESS 192.33.14.30
+ ADDRESS 192.43.172.30
+ ADDRESS 192.12.94.30
+ ADDRESS 192.48.79.30
+ ADDRESS 2001:502:1ca1::30
+ ADDRESS 192.54.112.30
+ ADDRESS 2001:500:856e::30
+ ADDRESS 2001:503:a83e::2:30
+ ADDRESS 192.52.178.30
+ ADDRESS 2001:503:d2d::30
+ ADDRESS 192.26.92.30
+ ADDRESS 192.41.162.30
+ ADDRESS 192.31.80.30
+ ADDRESS 2001:503:83eb::30
+ ADDRESS 192.42.93.30
+ ADDRESS 2001:503:39c1::30
+ ADDRESS 2001:503:231d::2:30
+ ADDRESS 192.35.51.30
+ ADDRESS 2001:500:d937::30
+ ADDRESS 2001:503:d414::30
+ ADDRESS 2001:502:7094::30
+ ADDRESS 2001:501:b1f9::30
+ ADDRESS 192.55.83.30
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+nstld.com. IN DS
+SECTION AUTHORITY
+5V12UURISSGGLPAS52GE1V3R0V7KR5BS.com. 86400 IN NSEC3 1 1 0 - 5v13q049b9ittui4fbdtm34dtev47bgj NS DS RRSIG
+5V12UURISSGGLPAS52GE1V3R0V7KR5BS.com. 86400 IN RRSIG NSEC3 8 2 86400 20190630044250 20190623033250 3800 com. NlBOkX84YgGooJJ2vp+Z/O16Vkz6z1gC Jy1Va3fJyEXfZr/GIm8J3KJ6Eq+xxp1A x3ZWxwUjNH3TGUEme7pDrmusqRpx/TZF Za3dVAYIvsaVgIWtDCn4BLBPrg0HXcon HE60KLgWGQmezzFKrNsy5Tzz9TajUSgQ uOTQHB7TFDg=
+CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN NSEC3 1 1 0 - ck0q1gin43n1arrc9osm6qpqr81h5m9a NS SOA RRSIG DNSKEY NSEC3PARAM
+CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN RRSIG NSEC3 8 2 86400 20190702044530 20190625033530 3800 com. BMWhk6USUrb7TNJ3dSObn8QEPWvpzedW kP9i4RRPz7V9c2yVPmHSPt29QKsHOYTg iF4uyHt+K8RK8DBIziB19nrOjbb8iRDY 7m5koEj/OrS2peMuF6rqRRmkI6SY/ACy XHb/hRGE4tZd2gThNb7evZkk02IVuhEo njO3NBjCrsw=
+com. 900 IN RRSIG SOA 8 1 900 20190702140912 20190625125912 3800 com. c6kEiaL24fAOXZf4AexmGfQejNxB+Na5 Omftkar0u1SFkd7I03ieGTsJt/aiFVND ucQklNtxUqTC4SQpGLmNYlzIDRvb2vYC GL7tSomPB/Tt4xYczPvNIOJKQOtFAjoL hJn5hj1jCo56iBD5OmbLwQcq8XI/W7xs yvTMfjKpeEQ=
+com. 900 IN SOA a.gtld-servers.net. nstld.verisign-grs.com. 1561471752 1800 900 604800 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+root-servers.net. IN DS
+SECTION AUTHORITY
+A1RT98BS5QGC9NFI51S9HCI47ULJG6JH.net. 86400 IN NSEC3 1 1 0 - a1ruuffjkct2q54p78f8ejgj8jbk7i8b NS SOA RRSIG DNSKEY NSEC3PARAM
+A1RT98BS5QGC9NFI51S9HCI47ULJG6JH.net. 86400 IN RRSIG NSEC3 8 2 86400 20190702055539 20190625044539 2129 net. KgEWjLXuYdPBhlNh2epfnKU879hg4GGf F4m4Fo7ZW+S3uhNqq8pF7sMJCvSs8ZZA Ctcm88XThCeIAxDxLZ5moOlMIWaweVX3 7B7s3mw+3K0cnkYF6J4FqBO8o7x6J3i2 c6kxI3q0DKub23GcXpWZu3x2yIkWuN0I ZgceikGAPpM=
+T2UF21DR03E0BNPB42UQMVUF38P2TA8D.net. 86400 IN NSEC3 1 1 0 - t2ukct9k5i0uhv7b3m3na6jaigdjm0gr NS DS RRSIG
+T2UF21DR03E0BNPB42UQMVUF38P2TA8D.net. 86400 IN RRSIG NSEC3 8 2 86400 20190630054523 20190623043523 2129 net. adpeQf+K6Hr5amhmF9DNK56LVWWnfGHK Dz9t9e7swG/P+4clc4yMKmUvK0OF9aTA kBzDwnzeB+FT+nsg1cWdibs4559AKQCL RtNErPhZRMojUFo6TLM9lQoXhv9i5rZB AJGmirHgSwiAvaUK7tgxX3nr1Atahyew iwHDQIVPhw4=
+net. 900 IN RRSIG SOA 8 1 900 20190702140916 20190625125916 2129 net. cMaAZOeBq2v9urE/L5RZEBRSTmY4/MMJ ADm+GUhaqP3FQ0RD3fO6IU7qdP3jCmlZ QmCl68ZVaMyZvVIcNcv7fokWbqTm9r4j 2NB0W9j/B/ZIOzCV4myDqaylU62tNTUA okGZMzclPCSd2n8ZDHZ3RysudhiZ/8WG FVdsHHtp67c=
+net. 900 IN SOA a.gtld-servers.net. nstld.verisign-grs.com. 1561471756 1800 900 604800 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+net. IN DS
+SECTION AUTHORITY
+A1RT98BS5QGC9NFI51S9HCI47ULJG6JH.net. 86400 IN NSEC3 1 1 0 - a1ruuffjkct2q54p78f8ejgj8jbk7i8b NS SOA RRSIG DNSKEY NSEC3PARAM
+A1RT98BS5QGC9NFI51S9HCI47ULJG6JH.net. 86400 IN RRSIG NSEC3 8 2 86400 20190702055539 20190625044539 2129 net. KgEWjLXuYdPBhlNh2epfnKU879hg4GGf F4m4Fo7ZW+S3uhNqq8pF7sMJCvSs8ZZA Ctcm88XThCeIAxDxLZ5moOlMIWaweVX3 7B7s3mw+3K0cnkYF6J4FqBO8o7x6J3i2 c6kxI3q0DKub23GcXpWZu3x2yIkWuN0I ZgceikGAPpM=
+net. 900 IN RRSIG SOA 8 1 900 20190702140916 20190625125916 2129 net. cMaAZOeBq2v9urE/L5RZEBRSTmY4/MMJ ADm+GUhaqP3FQ0RD3fO6IU7qdP3jCmlZ QmCl68ZVaMyZvVIcNcv7fokWbqTm9r4j 2NB0W9j/B/ZIOzCV4myDqaylU62tNTUA okGZMzclPCSd2n8ZDHZ3RysudhiZ/8WG FVdsHHtp67c=
+net. 900 IN SOA a.gtld-servers.net. nstld.verisign-grs.com. 1561471756 1800 900 604800 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+com. IN DS
+SECTION AUTHORITY
+CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN NSEC3 1 1 0 - ck0q1gin43n1arrc9osm6qpqr81h5m9a NS SOA RRSIG DNSKEY NSEC3PARAM
+CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN RRSIG NSEC3 8 2 86400 20190702044530 20190625033530 3800 com. BMWhk6USUrb7TNJ3dSObn8QEPWvpzedW kP9i4RRPz7V9c2yVPmHSPt29QKsHOYTg iF4uyHt+K8RK8DBIziB19nrOjbb8iRDY 7m5koEj/OrS2peMuF6rqRRmkI6SY/ACy XHb/hRGE4tZd2gThNb7evZkk02IVuhEo njO3NBjCrsw=
+com. 900 IN RRSIG SOA 8 1 900 20190702140912 20190625125912 3800 com. c6kEiaL24fAOXZf4AexmGfQejNxB+Na5 Omftkar0u1SFkd7I03ieGTsJt/aiFVND ucQklNtxUqTC4SQpGLmNYlzIDRvb2vYC GL7tSomPB/Tt4xYczPvNIOJKQOtFAjoL hJn5hj1jCo56iBD5OmbLwQcq8XI/W7xs yvTMfjKpeEQ=
+com. 900 IN SOA a.gtld-servers.net. nstld.verisign-grs.com. 1561471752 1800 900 604800 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+net. IN DNSKEY
+SECTION ANSWER
+net. 86400 IN DNSKEY 256 3 8 AQPB6mADOfWU6hTegl+pTl1wtjTll+Zn WIuRb8+cU9XNWNPpc3mX+rUqPeiw0RpK kD4QkTqTefWjMqjXMvYn2TxX4V4FMQXY MJr0bgiZXGosA9C9Aa7RgYyt4GJCToXq lM+mTqBjXDkh7yBa8I2X3p6Tt/PoKhiq CtmNl6sggTanJw==
+net. 86400 IN DNSKEY 257 3 8 AQOYBnzqWXIEj6mlgXg4LWC0HP2n8eK8 XqgHlmJ/69iuIHsa1TrHDG6TcOra/pye GKwH0nKZhTmXSuUFGh9BCNiwVDuyyb6O BGy2Nte9Kr8NwWg4q+zhSoOf4D+gC9dE zg0yFdwT0DKEvmNPt0K4jbQDS4Yimb+u PKuF6yieWWrPYYCrv8C9KC8JMze2uT6N uWBfsl2fDUoV4l65qMww06D7n+p7Rbdw WkAZ0fA63mXVXBZF6kpDtsYD7SUB9jhh fLQE/r85bvg3FaSs5Wi2BaqN06SzGWI1 DHu7axthIOeHwg00zxlhTpoYCH0ldoQz +S65zWYi/fRJiyLSBb6JZOvn
+net. 86400 IN RRSIG DNSKEY 8 1 86400 20190704153857 20190619153357 35886 net. T0Dcg9EVsoYzu+hywAW4mW11X/+oW/zt 0tQ8TdsKgY/5+/RL0tZCoU1EqbkBfM5h PxZgupQ0SQ//haveGagTgXOAOpa2nmUa o26dJC0xyZRTHuViy5708DONc88JZt+U pAgFcmJYjTXLu2QNywtyCXhcjnCuYAVG lTrarCn0rzW7PZp94xyGTCegkK9TysCt aqnIS0z/LVA2PjF+5etoEl7nWxCa1iUY 7as3zQ8CYlSDLwf7Sx4pUA/4hLZftwdO gNvb/pUdy7Zy/+6SGS3K4CPFkWG9kfs/ /76iMG6GkV2loGJApIFtYlui5iFaNfIM YBTD29dqC2I9ofe4WJnmpg==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+com. IN DNSKEY
+SECTION ANSWER
+com. 86400 IN DNSKEY 256 3 8 AQOcWJruwENIaapq3h3lKJlflLx6rWJz 2aKRBV6CBJRTxZu4ge2iDX164dQ7Hpc9 b8C9z2gqWyx1XyjvbQisgSid24voeUHQ gD0weedVDQjD6B9By7zMI6Yz+cM/w6H8 zB8ZRn6qZuWZAxFOjKvzoz+3vf32tyZE 7QmLFnXDgQpFxw==
+com. 86400 IN DNSKEY 257 3 8 AQPDzldNmMvZFX4NcNJ0uEnKDg7tmv/F 3MyQR0lpBmVcNcsIszxNFxsBfKNW9JYC Yqpik8366LE7VbIcNRzfp2h9OO8HRl+H +E08zauK8k7evWEmu/6od+2boggPoiEf GNyvNPaSI7FOIroDsnw/taggzHRX1Z7S OiOiPWPNIwSUyWOZ79VmcQ1GLkC6NlYv G3HwYmynQv6oFwGv/KELSw7ZSdrbTQ0H XvZbqMUI7BaMskmvgm1G7oKZ1YiF7O9i oVNc0+7ASbqmZN7Z98EGU/Qh2K/BgUe8 Hs0XVcdPKrtyYnoQHd2ynKPcMMlTEih2 /2HDHjRPJ2aywIpKNnv4oPo/
+com. 86400 IN RRSIG DNSKEY 8 1 86400 20190706182533 20190621182033 30909 com. v4xbl08Oyis8hHQ/7k9DuSLa75uMshqc V4783gXEEq1+dbgwBct8I2Td4+9mjIql fD1UO6Wu6VSYUtef39VQe4DuIWqtRrh/ WA/EOrrEY5Qieem9LTPL/zHWGQiILaHz CUHk1iUGFyZy4IRnZPkigTYKm1M7ZRXv qTTYSLemVZsna2/siDVYAdAhXWvJHQGl DkT3WDAvryFPpuEOrhUWkfhWAGy/ZsmD 87OiTX50TG/3ISEqFyzow/GZjViZnG5C tBmwdX/E8CIN6lVJV3LU3bMRYmuAHYEE lM+lVKAEyooxuRBNOdtZHD9tM8V6cfyd t89aE9LaiSn1DsFjUqFu/A==
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+gtld-servers.net. IN DS
+SECTION AUTHORITY
+5QDO29Q2PS5ARBKHB6R0BRN6NDSTSN90.net. 86400 IN NSEC3 1 1 0 - 5qdppotuk27kkp9ligtrb0k1cbvm9cim NS DS RRSIG
+5QDO29Q2PS5ARBKHB6R0BRN6NDSTSN90.net. 86400 IN RRSIG NSEC3 8 2 86400 20190629054715 20190622043715 2129 net. fvRKJkn9D2H3DFGE0zpk/tAkyjaoEZY4 4TkN6XtCAibjzQS8R0SCaXmZlQQujnjG wp0Rjhy0gMQaFUrJ8QuUbJSDZQaicAl7 pCESVKd95GZOSgi07BXSKwdUMAPROSjz gDkYGzHcUB5Kfe23gkL2eQ05YVigHYhI l0YCHui1wHE=
+A1RT98BS5QGC9NFI51S9HCI47ULJG6JH.net. 86400 IN NSEC3 1 1 0 - a1ruuffjkct2q54p78f8ejgj8jbk7i8b NS SOA RRSIG DNSKEY NSEC3PARAM
+A1RT98BS5QGC9NFI51S9HCI47ULJG6JH.net. 86400 IN RRSIG NSEC3 8 2 86400 20190702055539 20190625044539 2129 net. KgEWjLXuYdPBhlNh2epfnKU879hg4GGf F4m4Fo7ZW+S3uhNqq8pF7sMJCvSs8ZZA Ctcm88XThCeIAxDxLZ5moOlMIWaweVX3 7B7s3mw+3K0cnkYF6J4FqBO8o7x6J3i2 c6kxI3q0DKub23GcXpWZu3x2yIkWuN0I ZgceikGAPpM=
+net. 900 IN RRSIG SOA 8 1 900 20190702140916 20190625125916 2129 net. cMaAZOeBq2v9urE/L5RZEBRSTmY4/MMJ ADm+GUhaqP3FQ0RD3fO6IU7qdP3jCmlZ QmCl68ZVaMyZvVIcNcv7fokWbqTm9r4j 2NB0W9j/B/ZIOzCV4myDqaylU62tNTUA okGZMzclPCSd2n8ZDHZ3RysudhiZ/8WG FVdsHHtp67c=
+net. 900 IN SOA a.gtld-servers.net. nstld.verisign-grs.com. 1561471756 1800 900 604800 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH subdomain
+ADJUST copy_id copy_query
+REPLY QR RD NOERROR
+SECTION QUESTION
+gtld-servers.net. IN NS
+SECTION AUTHORITY
+5QDO29Q2PS5ARBKHB6R0BRN6NDSTSN90.net. 86400 IN NSEC3 1 1 0 - 5qdppotuk27kkp9ligtrb0k1cbvm9cim NS DS RRSIG
+5QDO29Q2PS5ARBKHB6R0BRN6NDSTSN90.net. 86400 IN RRSIG NSEC3 8 2 86400 20190629054715 20190622043715 2129 net. fvRKJkn9D2H3DFGE0zpk/tAkyjaoEZY4 4TkN6XtCAibjzQS8R0SCaXmZlQQujnjG wp0Rjhy0gMQaFUrJ8QuUbJSDZQaicAl7 pCESVKd95GZOSgi07BXSKwdUMAPROSjz gDkYGzHcUB5Kfe23gkL2eQ05YVigHYhI l0YCHui1wHE=
+A1RT98BS5QGC9NFI51S9HCI47ULJG6JH.net. 86400 IN NSEC3 1 1 0 - a1ruuffjkct2q54p78f8ejgj8jbk7i8b NS SOA RRSIG DNSKEY NSEC3PARAM
+A1RT98BS5QGC9NFI51S9HCI47ULJG6JH.net. 86400 IN RRSIG NSEC3 8 2 86400 20190702055539 20190625044539 2129 net. KgEWjLXuYdPBhlNh2epfnKU879hg4GGf F4m4Fo7ZW+S3uhNqq8pF7sMJCvSs8ZZA Ctcm88XThCeIAxDxLZ5moOlMIWaweVX3 7B7s3mw+3K0cnkYF6J4FqBO8o7x6J3i2 c6kxI3q0DKub23GcXpWZu3x2yIkWuN0I ZgceikGAPpM=
+gtld-servers.net. 172800 IN NS av1.nstld.com.
+gtld-servers.net. 172800 IN NS av2.nstld.com.
+gtld-servers.net. 172800 IN NS av3.nstld.com.
+gtld-servers.net. 172800 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH subdomain
+ADJUST copy_id copy_query
+REPLY QR RD NOERROR
+SECTION QUESTION
+root-servers.net. IN NS
+SECTION AUTHORITY
+A1RT98BS5QGC9NFI51S9HCI47ULJG6JH.net. 86400 IN NSEC3 1 1 0 - a1ruuffjkct2q54p78f8ejgj8jbk7i8b NS SOA RRSIG DNSKEY NSEC3PARAM
+A1RT98BS5QGC9NFI51S9HCI47ULJG6JH.net. 86400 IN RRSIG NSEC3 8 2 86400 20190702055539 20190625044539 2129 net. KgEWjLXuYdPBhlNh2epfnKU879hg4GGf F4m4Fo7ZW+S3uhNqq8pF7sMJCvSs8ZZA Ctcm88XThCeIAxDxLZ5moOlMIWaweVX3 7B7s3mw+3K0cnkYF6J4FqBO8o7x6J3i2 c6kxI3q0DKub23GcXpWZu3x2yIkWuN0I ZgceikGAPpM=
+T2UF21DR03E0BNPB42UQMVUF38P2TA8D.net. 86400 IN NSEC3 1 1 0 - t2ukct9k5i0uhv7b3m3na6jaigdjm0gr NS DS RRSIG
+T2UF21DR03E0BNPB42UQMVUF38P2TA8D.net. 86400 IN RRSIG NSEC3 8 2 86400 20190630054523 20190623043523 2129 net. adpeQf+K6Hr5amhmF9DNK56LVWWnfGHK Dz9t9e7swG/P+4clc4yMKmUvK0OF9aTA kBzDwnzeB+FT+nsg1cWdibs4559AKQCL RtNErPhZRMojUFo6TLM9lQoXhv9i5rZB AJGmirHgSwiAvaUK7tgxX3nr1Atahyew iwHDQIVPhw4=
+root-servers.net. 172800 IN NS a.root-servers.net.
+root-servers.net. 172800 IN NS b.root-servers.net.
+root-servers.net. 172800 IN NS c.root-servers.net.
+root-servers.net. 172800 IN NS d.root-servers.net.
+root-servers.net. 172800 IN NS e.root-servers.net.
+root-servers.net. 172800 IN NS f.root-servers.net.
+root-servers.net. 172800 IN NS g.root-servers.net.
+root-servers.net. 172800 IN NS h.root-servers.net.
+root-servers.net. 172800 IN NS i.root-servers.net.
+root-servers.net. 172800 IN NS j.root-servers.net.
+root-servers.net. 172800 IN NS k.root-servers.net.
+root-servers.net. 172800 IN NS l.root-servers.net.
+root-servers.net. 172800 IN NS m.root-servers.net.
+SECTION ADDITIONAL
+a.root-servers.net. 172800 IN A 198.41.0.4
+a.root-servers.net. 172800 IN AAAA 2001:503:ba3e::2:30
+b.root-servers.net. 172800 IN A 199.9.14.201
+b.root-servers.net. 172800 IN AAAA 2001:500:200::b
+c.root-servers.net. 172800 IN A 192.33.4.12
+c.root-servers.net. 172800 IN AAAA 2001:500:2::c
+d.root-servers.net. 172800 IN A 199.7.91.13
+d.root-servers.net. 172800 IN AAAA 2001:500:2d::d
+e.root-servers.net. 172800 IN A 192.203.230.10
+e.root-servers.net. 172800 IN AAAA 2001:500:a8::e
+f.root-servers.net. 172800 IN A 192.5.5.241
+f.root-servers.net. 172800 IN AAAA 2001:500:2f::f
+g.root-servers.net. 172800 IN A 192.112.36.4
+g.root-servers.net. 172800 IN AAAA 2001:500:12::d0d
+h.root-servers.net. 172800 IN A 198.97.190.53
+h.root-servers.net. 172800 IN AAAA 2001:500:1::53
+i.root-servers.net. 172800 IN A 192.36.148.17
+i.root-servers.net. 172800 IN AAAA 2001:7fe::53
+j.root-servers.net. 172800 IN A 192.58.128.30
+j.root-servers.net. 172800 IN AAAA 2001:503:c27::2:30
+k.root-servers.net. 172800 IN A 193.0.14.129
+k.root-servers.net. 172800 IN AAAA 2001:7fd::1
+l.root-servers.net. 172800 IN A 199.7.83.42
+l.root-servers.net. 172800 IN AAAA 2001:500:9f::42
+m.root-servers.net. 172800 IN A 202.12.27.33
+m.root-servers.net. 172800 IN AAAA 2001:dc3::35
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH subdomain
+ADJUST copy_id copy_query
+REPLY QR RD NOERROR
+SECTION QUESTION
+nstld.com. IN NS
+SECTION AUTHORITY
+5V12UURISSGGLPAS52GE1V3R0V7KR5BS.com. 86400 IN NSEC3 1 1 0 - 5v13q049b9ittui4fbdtm34dtev47bgj NS DS RRSIG
+5V12UURISSGGLPAS52GE1V3R0V7KR5BS.com. 86400 IN RRSIG NSEC3 8 2 86400 20190630044250 20190623033250 3800 com. NlBOkX84YgGooJJ2vp+Z/O16Vkz6z1gC Jy1Va3fJyEXfZr/GIm8J3KJ6Eq+xxp1A x3ZWxwUjNH3TGUEme7pDrmusqRpx/TZF Za3dVAYIvsaVgIWtDCn4BLBPrg0HXcon HE60KLgWGQmezzFKrNsy5Tzz9TajUSgQ uOTQHB7TFDg=
+CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN NSEC3 1 1 0 - ck0q1gin43n1arrc9osm6qpqr81h5m9a NS SOA RRSIG DNSKEY NSEC3PARAM
+CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN RRSIG NSEC3 8 2 86400 20190702044530 20190625033530 3800 com. BMWhk6USUrb7TNJ3dSObn8QEPWvpzedW kP9i4RRPz7V9c2yVPmHSPt29QKsHOYTg iF4uyHt+K8RK8DBIziB19nrOjbb8iRDY 7m5koEj/OrS2peMuF6rqRRmkI6SY/ACy XHb/hRGE4tZd2gThNb7evZkk02IVuhEo njO3NBjCrsw=
+nstld.com. 172800 IN NS av1.nstld.com.
+nstld.com. 172800 IN NS av2.nstld.com.
+nstld.com. 172800 IN NS av3.nstld.com.
+nstld.com. 172800 IN NS av4.nstld.com.
+SECTION ADDITIONAL
+av1.nstld.com. 172800 IN A 192.42.177.30
+av1.nstld.com. 172800 IN AAAA 2001:500:124::30
+av2.nstld.com. 172800 IN A 192.42.178.30
+av2.nstld.com. 172800 IN AAAA 2001:500:125::30
+av3.nstld.com. 172800 IN A 192.82.133.30
+av3.nstld.com. 172800 IN AAAA 2001:500:126::30
+av4.nstld.com. 172800 IN A 192.82.134.30
+av4.nstld.com. 172800 IN AAAA 2001:500:127::30
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH subdomain
+ADJUST copy_id copy_query
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+net. IN NS
+SECTION ANSWER
+net. 172800 IN NS a.gtld-servers.net.
+net. 172800 IN NS b.gtld-servers.net.
+net. 172800 IN NS c.gtld-servers.net.
+net. 172800 IN NS d.gtld-servers.net.
+net. 172800 IN NS e.gtld-servers.net.
+net. 172800 IN NS f.gtld-servers.net.
+net. 172800 IN NS g.gtld-servers.net.
+net. 172800 IN NS h.gtld-servers.net.
+net. 172800 IN NS i.gtld-servers.net.
+net. 172800 IN NS j.gtld-servers.net.
+net. 172800 IN NS k.gtld-servers.net.
+net. 172800 IN NS l.gtld-servers.net.
+net. 172800 IN NS m.gtld-servers.net.
+net. 172800 IN RRSIG NS 8 1 172800 20190630055417 20190623044417 2129 net. WUAzfzoslC7YpzfY7qJ+vPaYpL/TN1fq Ak97qaEsQbPEka9AfUyL/ZKgGucOrDmB e0GK55jGT1B1XXiQasdlB8/SThSPm+Oc V/aQ8zUopPJ6gzCCRfEZOWCRvRbXa3am f6apMdig+NSxXgYQpVjZmka8XX8xDJar 3c4G5gZS9rA=
+SECTION ADDITIONAL
+a.gtld-servers.net. 172800 IN A 192.5.6.30
+a.gtld-servers.net. 172800 IN AAAA 2001:503:a83e::2:30
+b.gtld-servers.net. 172800 IN A 192.33.14.30
+b.gtld-servers.net. 172800 IN AAAA 2001:503:231d::2:30
+c.gtld-servers.net. 172800 IN A 192.26.92.30
+c.gtld-servers.net. 172800 IN AAAA 2001:503:83eb::30
+d.gtld-servers.net. 172800 IN A 192.31.80.30
+d.gtld-servers.net. 172800 IN AAAA 2001:500:856e::30
+e.gtld-servers.net. 172800 IN A 192.12.94.30
+e.gtld-servers.net. 172800 IN AAAA 2001:502:1ca1::30
+f.gtld-servers.net. 172800 IN A 192.35.51.30
+f.gtld-servers.net. 172800 IN AAAA 2001:503:d414::30
+g.gtld-servers.net. 172800 IN A 192.42.93.30
+g.gtld-servers.net. 172800 IN AAAA 2001:503:eea3::30
+h.gtld-servers.net. 172800 IN A 192.54.112.30
+h.gtld-servers.net. 172800 IN AAAA 2001:502:8cc::30
+i.gtld-servers.net. 172800 IN A 192.43.172.30
+i.gtld-servers.net. 172800 IN AAAA 2001:503:39c1::30
+j.gtld-servers.net. 172800 IN A 192.48.79.30
+j.gtld-servers.net. 172800 IN AAAA 2001:502:7094::30
+k.gtld-servers.net. 172800 IN A 192.52.178.30
+k.gtld-servers.net. 172800 IN AAAA 2001:503:d2d::30
+l.gtld-servers.net. 172800 IN A 192.41.162.30
+l.gtld-servers.net. 172800 IN AAAA 2001:500:d937::30
+m.gtld-servers.net. 172800 IN A 192.55.83.30
+m.gtld-servers.net. 172800 IN AAAA 2001:501:b1f9::30
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH subdomain
+ADJUST copy_id copy_query
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+com. IN NS
+SECTION ANSWER
+com. 172800 IN NS a.gtld-servers.net.
+com. 172800 IN NS b.gtld-servers.net.
+com. 172800 IN NS c.gtld-servers.net.
+com. 172800 IN NS d.gtld-servers.net.
+com. 172800 IN NS e.gtld-servers.net.
+com. 172800 IN NS f.gtld-servers.net.
+com. 172800 IN NS g.gtld-servers.net.
+com. 172800 IN NS h.gtld-servers.net.
+com. 172800 IN NS i.gtld-servers.net.
+com. 172800 IN NS j.gtld-servers.net.
+com. 172800 IN NS k.gtld-servers.net.
+com. 172800 IN NS l.gtld-servers.net.
+com. 172800 IN NS m.gtld-servers.net.
+com. 172800 IN RRSIG NS 8 1 172800 20190702044530 20190625033530 3800 com. F4MEGl13z9h8iv22sko8S8/JjSskipqt COrmfpx4p5XeRutUOpr/6wAEdSXWJ7yu 5Z/PMTBDjTo37WxfEhyvvYyiOLTzYOf+ AvFeeGDAxdOAlfjQ+6etggDPz1bsqIhE 2FX5i7dhfk0WYshBIUqCJmmPMdnVgLNN Bh4zYoT5irQ=
+SECTION ADDITIONAL
+a.gtld-servers.net. 172800 IN A 192.5.6.30
+a.gtld-servers.net. 172800 IN AAAA 2001:503:a83e::2:30
+b.gtld-servers.net. 172800 IN A 192.33.14.30
+b.gtld-servers.net. 172800 IN AAAA 2001:503:231d::2:30
+c.gtld-servers.net. 172800 IN A 192.26.92.30
+c.gtld-servers.net. 172800 IN AAAA 2001:503:83eb::30
+d.gtld-servers.net. 172800 IN A 192.31.80.30
+d.gtld-servers.net. 172800 IN AAAA 2001:500:856e::30
+e.gtld-servers.net. 172800 IN A 192.12.94.30
+e.gtld-servers.net. 172800 IN AAAA 2001:502:1ca1::30
+f.gtld-servers.net. 172800 IN A 192.35.51.30
+f.gtld-servers.net. 172800 IN AAAA 2001:503:d414::30
+g.gtld-servers.net. 172800 IN A 192.42.93.30
+g.gtld-servers.net. 172800 IN AAAA 2001:503:eea3::30
+h.gtld-servers.net. 172800 IN A 192.54.112.30
+h.gtld-servers.net. 172800 IN AAAA 2001:502:8cc::30
+i.gtld-servers.net. 172800 IN A 192.43.172.30
+i.gtld-servers.net. 172800 IN AAAA 2001:503:39c1::30
+j.gtld-servers.net. 172800 IN A 192.48.79.30
+j.gtld-servers.net. 172800 IN AAAA 2001:502:7094::30
+k.gtld-servers.net. 172800 IN A 192.52.178.30
+k.gtld-servers.net. 172800 IN AAAA 2001:503:d2d::30
+l.gtld-servers.net. 172800 IN A 192.41.162.30
+l.gtld-servers.net. 172800 IN AAAA 2001:500:d937::30
+m.gtld-servers.net. 172800 IN A 192.55.83.30
+m.gtld-servers.net. 172800 IN AAAA 2001:501:b1f9::30
+ENTRY_END
+
+
+
+
+RANGE_END
+
+
+
+; Group's zones:
+; gtld-servers.net.
+; nstld.com.
+; Server names:
+; av1.nstld.com.
+; av2.nstld.com.
+; av3.nstld.com.
+; av4.nstld.com.
+RANGE_BEGIN 0 1000
+ ADDRESS 192.42.178.30
+ ADDRESS 2001:500:125::30
+ ADDRESS 192.82.133.30
+ ADDRESS 192.42.177.30
+ ADDRESS 2001:500:124::30
+ ADDRESS 192.82.134.30
+ ADDRESS 2001:500:126::30
+ ADDRESS 2001:500:127::30
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+h.gtld-servers.net. IN A
+SECTION ANSWER
+h.gtld-servers.net. 86400 IN A 192.54.112.30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+i.gtld-servers.net. IN AAAA
+SECTION ANSWER
+i.gtld-servers.net. 86400 IN AAAA 2001:503:39c1::30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+av3.nstld.com. IN A
+SECTION ANSWER
+av3.nstld.com. 300 IN A 192.82.133.30
+SECTION AUTHORITY
+nstld.com. 86400 IN NS av1.nstld.com.
+nstld.com. 86400 IN NS av2.nstld.com.
+nstld.com. 86400 IN NS av3.nstld.com.
+nstld.com. 86400 IN NS av4.nstld.com.
+SECTION ADDITIONAL
+av1.nstld.com. 300 IN A 192.42.177.30
+av1.nstld.com. 300 IN AAAA 2001:500:124::30
+av2.nstld.com. 300 IN A 192.42.178.30
+av2.nstld.com. 300 IN AAAA 2001:500:125::30
+av3.nstld.com. 300 IN AAAA 2001:500:126::30
+av4.nstld.com. 300 IN A 192.82.134.30
+av4.nstld.com. 300 IN AAAA 2001:500:127::30
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+av1.nstld.com. IN A
+SECTION ANSWER
+av1.nstld.com. 300 IN A 192.42.177.30
+SECTION AUTHORITY
+nstld.com. 86400 IN NS av1.nstld.com.
+nstld.com. 86400 IN NS av2.nstld.com.
+nstld.com. 86400 IN NS av3.nstld.com.
+nstld.com. 86400 IN NS av4.nstld.com.
+SECTION ADDITIONAL
+av1.nstld.com. 300 IN AAAA 2001:500:124::30
+av2.nstld.com. 300 IN A 192.42.178.30
+av2.nstld.com. 300 IN AAAA 2001:500:125::30
+av3.nstld.com. 300 IN A 192.82.133.30
+av3.nstld.com. 300 IN AAAA 2001:500:126::30
+av4.nstld.com. 300 IN A 192.82.134.30
+av4.nstld.com. 300 IN AAAA 2001:500:127::30
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+j.gtld-servers.net. IN AAAA
+SECTION ANSWER
+j.gtld-servers.net. 86400 IN AAAA 2001:502:7094::30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+av2.nstld.com. IN AAAA
+SECTION ANSWER
+av2.nstld.com. 300 IN AAAA 2001:500:125::30
+SECTION AUTHORITY
+nstld.com. 86400 IN NS av1.nstld.com.
+nstld.com. 86400 IN NS av2.nstld.com.
+nstld.com. 86400 IN NS av3.nstld.com.
+nstld.com. 86400 IN NS av4.nstld.com.
+SECTION ADDITIONAL
+av1.nstld.com. 300 IN A 192.42.177.30
+av1.nstld.com. 300 IN AAAA 2001:500:124::30
+av2.nstld.com. 300 IN A 192.42.178.30
+av3.nstld.com. 300 IN A 192.82.133.30
+av3.nstld.com. 300 IN AAAA 2001:500:126::30
+av4.nstld.com. 300 IN A 192.82.134.30
+av4.nstld.com. 300 IN AAAA 2001:500:127::30
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+k.gtld-servers.net. IN AAAA
+SECTION ANSWER
+k.gtld-servers.net. 86400 IN AAAA 2001:503:d2d::30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+av1.nstld.com. IN NS
+SECTION AUTHORITY
+nstld.com. 86400 IN SOA av4.nstld.com. nstld.verisign-grs.com. 2018073100 7200 900 1209600 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+f.gtld-servers.net. IN AAAA
+SECTION ANSWER
+f.gtld-servers.net. 86400 IN AAAA 2001:503:d414::30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+j.gtld-servers.net. IN NS
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN SOA av4.nstld.com. nstld.verisign-grs.com. 2017061500 3600 900 1209600 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+c.gtld-servers.net. IN NS
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN SOA av4.nstld.com. nstld.verisign-grs.com. 2017061500 3600 900 1209600 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+l.gtld-servers.net. IN AAAA
+SECTION ANSWER
+l.gtld-servers.net. 86400 IN AAAA 2001:500:d937::30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+b.gtld-servers.net. IN NS
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN SOA av4.nstld.com. nstld.verisign-grs.com. 2017061500 3600 900 1209600 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+f.gtld-servers.net. IN A
+SECTION ANSWER
+f.gtld-servers.net. 86400 IN A 192.35.51.30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+e.gtld-servers.net. IN NS
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN SOA av4.nstld.com. nstld.verisign-grs.com. 2017061500 3600 900 1209600 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+i.gtld-servers.net. IN A
+SECTION ANSWER
+i.gtld-servers.net. 86400 IN A 192.43.172.30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+d.gtld-servers.net. IN AAAA
+SECTION ANSWER
+d.gtld-servers.net. 86400 IN AAAA 2001:500:856e::30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+m.gtld-servers.net. IN NS
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN SOA av4.nstld.com. nstld.verisign-grs.com. 2017061500 3600 900 1209600 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+av3.nstld.com. IN NS
+SECTION AUTHORITY
+nstld.com. 86400 IN SOA av4.nstld.com. nstld.verisign-grs.com. 2018073100 7200 900 1209600 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+g.gtld-servers.net. IN A
+SECTION ANSWER
+g.gtld-servers.net. 86400 IN A 192.42.93.30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+j.gtld-servers.net. IN A
+SECTION ANSWER
+j.gtld-servers.net. 86400 IN A 192.48.79.30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+f.gtld-servers.net. IN NS
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN SOA av4.nstld.com. nstld.verisign-grs.com. 2017061500 3600 900 1209600 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+av2.nstld.com. IN NS
+SECTION AUTHORITY
+nstld.com. 86400 IN SOA av4.nstld.com. nstld.verisign-grs.com. 2018073100 7200 900 1209600 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+h.gtld-servers.net. IN NS
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN SOA av4.nstld.com. nstld.verisign-grs.com. 2017061500 3600 900 1209600 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+d.gtld-servers.net. IN NS
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN SOA av4.nstld.com. nstld.verisign-grs.com. 2017061500 3600 900 1209600 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+av1.nstld.com. IN AAAA
+SECTION ANSWER
+av1.nstld.com. 300 IN AAAA 2001:500:124::30
+SECTION AUTHORITY
+nstld.com. 86400 IN NS av1.nstld.com.
+nstld.com. 86400 IN NS av2.nstld.com.
+nstld.com. 86400 IN NS av3.nstld.com.
+nstld.com. 86400 IN NS av4.nstld.com.
+SECTION ADDITIONAL
+av1.nstld.com. 300 IN A 192.42.177.30
+av2.nstld.com. 300 IN A 192.42.178.30
+av2.nstld.com. 300 IN AAAA 2001:500:125::30
+av3.nstld.com. 300 IN A 192.82.133.30
+av3.nstld.com. 300 IN AAAA 2001:500:126::30
+av4.nstld.com. 300 IN A 192.82.134.30
+av4.nstld.com. 300 IN AAAA 2001:500:127::30
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+k.gtld-servers.net. IN A
+SECTION ANSWER
+k.gtld-servers.net. 86400 IN A 192.52.178.30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+h.gtld-servers.net. IN AAAA
+SECTION ANSWER
+h.gtld-servers.net. 86400 IN AAAA 2001:502:8cc::30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+a.gtld-servers.net. IN AAAA
+SECTION ANSWER
+a.gtld-servers.net. 86400 IN AAAA 2001:503:a83e::2:30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+l.gtld-servers.net. IN NS
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN SOA av4.nstld.com. nstld.verisign-grs.com. 2017061500 3600 900 1209600 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+b.gtld-servers.net. IN AAAA
+SECTION ANSWER
+b.gtld-servers.net. 86400 IN AAAA 2001:503:231d::2:30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+l.gtld-servers.net. IN A
+SECTION ANSWER
+l.gtld-servers.net. 86400 IN A 192.41.162.30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+d.gtld-servers.net. IN A
+SECTION ANSWER
+d.gtld-servers.net. 86400 IN A 192.31.80.30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+e.gtld-servers.net. IN AAAA
+SECTION ANSWER
+e.gtld-servers.net. 86400 IN AAAA 2001:502:1ca1::30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+k.gtld-servers.net. IN NS
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN SOA av4.nstld.com. nstld.verisign-grs.com. 2017061500 3600 900 1209600 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+av3.nstld.com. IN AAAA
+SECTION ANSWER
+av3.nstld.com. 300 IN AAAA 2001:500:126::30
+SECTION AUTHORITY
+nstld.com. 86400 IN NS av1.nstld.com.
+nstld.com. 86400 IN NS av2.nstld.com.
+nstld.com. 86400 IN NS av3.nstld.com.
+nstld.com. 86400 IN NS av4.nstld.com.
+SECTION ADDITIONAL
+av1.nstld.com. 300 IN A 192.42.177.30
+av1.nstld.com. 300 IN AAAA 2001:500:124::30
+av2.nstld.com. 300 IN A 192.42.178.30
+av2.nstld.com. 300 IN AAAA 2001:500:125::30
+av3.nstld.com. 300 IN A 192.82.133.30
+av4.nstld.com. 300 IN A 192.82.134.30
+av4.nstld.com. 300 IN AAAA 2001:500:127::30
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+a.gtld-servers.net. IN A
+SECTION ANSWER
+a.gtld-servers.net. 86400 IN A 192.5.6.30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+av4.nstld.com. IN AAAA
+SECTION ANSWER
+av4.nstld.com. 300 IN AAAA 2001:500:127::30
+SECTION AUTHORITY
+nstld.com. 86400 IN NS av1.nstld.com.
+nstld.com. 86400 IN NS av2.nstld.com.
+nstld.com. 86400 IN NS av3.nstld.com.
+nstld.com. 86400 IN NS av4.nstld.com.
+SECTION ADDITIONAL
+av1.nstld.com. 300 IN A 192.42.177.30
+av1.nstld.com. 300 IN AAAA 2001:500:124::30
+av2.nstld.com. 300 IN A 192.42.178.30
+av2.nstld.com. 300 IN AAAA 2001:500:125::30
+av3.nstld.com. 300 IN A 192.82.133.30
+av3.nstld.com. 300 IN AAAA 2001:500:126::30
+av4.nstld.com. 300 IN A 192.82.134.30
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+g.gtld-servers.net. IN AAAA
+SECTION ANSWER
+g.gtld-servers.net. 86400 IN AAAA 2001:503:eea3::30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+c.gtld-servers.net. IN A
+SECTION ANSWER
+c.gtld-servers.net. 86400 IN A 192.26.92.30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+av4.nstld.com. IN NS
+SECTION AUTHORITY
+nstld.com. 86400 IN SOA av4.nstld.com. nstld.verisign-grs.com. 2018073100 7200 900 1209600 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+a.gtld-servers.net. IN NS
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN SOA av4.nstld.com. nstld.verisign-grs.com. 2017061500 3600 900 1209600 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+m.gtld-servers.net. IN AAAA
+SECTION ANSWER
+m.gtld-servers.net. 86400 IN AAAA 2001:501:b1f9::30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+m.gtld-servers.net. IN A
+SECTION ANSWER
+m.gtld-servers.net. 86400 IN A 192.55.83.30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+i.gtld-servers.net. IN NS
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN SOA av4.nstld.com. nstld.verisign-grs.com. 2017061500 3600 900 1209600 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+g.gtld-servers.net. IN NS
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN SOA av4.nstld.com. nstld.verisign-grs.com. 2017061500 3600 900 1209600 86400
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+c.gtld-servers.net. IN AAAA
+SECTION ANSWER
+c.gtld-servers.net. 86400 IN AAAA 2001:503:83eb::30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+av2.nstld.com. IN A
+SECTION ANSWER
+av2.nstld.com. 300 IN A 192.42.178.30
+SECTION AUTHORITY
+nstld.com. 86400 IN NS av1.nstld.com.
+nstld.com. 86400 IN NS av2.nstld.com.
+nstld.com. 86400 IN NS av3.nstld.com.
+nstld.com. 86400 IN NS av4.nstld.com.
+SECTION ADDITIONAL
+av1.nstld.com. 300 IN A 192.42.177.30
+av1.nstld.com. 300 IN AAAA 2001:500:124::30
+av2.nstld.com. 300 IN AAAA 2001:500:125::30
+av3.nstld.com. 300 IN A 192.82.133.30
+av3.nstld.com. 300 IN AAAA 2001:500:126::30
+av4.nstld.com. 300 IN A 192.82.134.30
+av4.nstld.com. 300 IN AAAA 2001:500:127::30
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+av4.nstld.com. IN A
+SECTION ANSWER
+av4.nstld.com. 300 IN A 192.82.134.30
+SECTION AUTHORITY
+nstld.com. 86400 IN NS av1.nstld.com.
+nstld.com. 86400 IN NS av2.nstld.com.
+nstld.com. 86400 IN NS av3.nstld.com.
+nstld.com. 86400 IN NS av4.nstld.com.
+SECTION ADDITIONAL
+av1.nstld.com. 300 IN A 192.42.177.30
+av1.nstld.com. 300 IN AAAA 2001:500:124::30
+av2.nstld.com. 300 IN A 192.42.178.30
+av2.nstld.com. 300 IN AAAA 2001:500:125::30
+av3.nstld.com. 300 IN A 192.82.133.30
+av3.nstld.com. 300 IN AAAA 2001:500:126::30
+av4.nstld.com. 300 IN AAAA 2001:500:127::30
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+b.gtld-servers.net. IN A
+SECTION ANSWER
+b.gtld-servers.net. 86400 IN A 192.33.14.30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH qname qtype
+ADJUST copy_id
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+e.gtld-servers.net. IN A
+SECTION ANSWER
+e.gtld-servers.net. 86400 IN A 192.12.94.30
+SECTION AUTHORITY
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH subdomain
+ADJUST copy_id copy_query
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+gtld-servers.net. IN NS
+SECTION ANSWER
+gtld-servers.net. 86400 IN NS av1.nstld.com.
+gtld-servers.net. 86400 IN NS av2.nstld.com.
+gtld-servers.net. 86400 IN NS av3.nstld.com.
+gtld-servers.net. 86400 IN NS av4.nstld.com.
+ENTRY_END
+
+
+ENTRY_BEGIN
+MATCH subdomain
+ADJUST copy_id copy_query
+REPLY QR AA RD NOERROR
+SECTION QUESTION
+nstld.com. IN NS
+SECTION ANSWER
+nstld.com. 86400 IN NS av1.nstld.com.
+nstld.com. 86400 IN NS av2.nstld.com.
+nstld.com. 86400 IN NS av3.nstld.com.
+nstld.com. 86400 IN NS av4.nstld.com.
+SECTION ADDITIONAL
+av1.nstld.com. 300 IN A 192.42.177.30
+av1.nstld.com. 300 IN AAAA 2001:500:124::30
+av2.nstld.com. 300 IN A 192.42.178.30
+av2.nstld.com. 300 IN AAAA 2001:500:125::30
+av3.nstld.com. 300 IN A 192.82.133.30
+av3.nstld.com. 300 IN AAAA 2001:500:126::30
+av4.nstld.com. 300 IN A 192.82.134.30
+av4.nstld.com. 300 IN AAAA 2001:500:127::30
+ENTRY_END
+
+
+
+
+RANGE_END
+
+
+
+
+
+; Sequence of queries made by browser
+
+; 1st query for AAAA
+STEP 10 QUERY
+ENTRY_BEGIN
+REPLY RD AD
+SECTION QUESTION
+csas.cz. IN AAAA
+ENTRY_END
+
+; answer for AAAA contains minimally covering NSEC3 answer with incorrect bitmap
+; it claims that csas.cz A RR is not present
+STEP 11 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH opcode flags rcode question answer
+REPLY QR RD RA AD NOERROR
+SECTION QUESTION
+csas.cz. IN AAAA
+SECTION AUTHORITY
+csas.cz. 119 IN SOA ddnsa.csas.cz. domainservices.csas.cz. 2019061320 28800 1800 2592000 120
+ENTRY_END
+
+; 2nd query for A
+STEP 21 QUERY
+ENTRY_BEGIN
+REPLY RD AD
+SECTION QUESTION
+csas.cz. IN A
+ENTRY_END
+
+; check that A query gets an IP address
+; this answer would be empty
+; if minimally covering NSEC3 was not exempt from aggressive caching
+STEP 22 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH opcode flags rcode question answer
+REPLY QR RD RA AD NOERROR
+SECTION QUESTION
+csas.cz. IN A
+SECTION ANSWER
+csas.cz. 120 IN A 194.50.240.198
+csas.cz. 120 IN A 194.50.240.70
+ENTRY_END
+
+SCENARIO_END
diff --git a/lib/cache/test.integr/deckard.yaml b/lib/cache/test.integr/deckard.yaml
new file mode 100644
index 0000000..df88f83
--- /dev/null
+++ b/lib/cache/test.integr/deckard.yaml
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-3.0-or-later
+programs:
+- name: kresd
+ binary: kresd
+ additional:
+ - --noninteractive
+ templates:
+ - lib/cache/test.integr/kresd_config.j2
+ - tests/integration/hints_zone.j2
+ configs:
+ - config
+ - hints
+noclean: True
diff --git a/lib/cache/test.integr/kresd_config.j2 b/lib/cache/test.integr/kresd_config.j2
new file mode 100644
index 0000000..c4c286f
--- /dev/null
+++ b/lib/cache/test.integr/kresd_config.j2
@@ -0,0 +1,69 @@
+-- SPDX-License-Identifier: GPL-3.0-or-later
+{% for TAF in TRUST_ANCHOR_FILES %}
+-- trust_anchors.add_file('{{TAF}}')
+{% endfor %}
+
+{% raw %}
+-- Disable RFC5011 TA update
+if ta_update then
+ modules.unload('ta_update')
+end
+
+-- Disable RFC8145 signaling, scenario doesn't provide expected answers
+if ta_signal_query then
+ modules.unload('ta_signal_query')
+end
+
+-- Disable RFC8109 priming, scenario doesn't provide expected answers
+if priming then
+ modules.unload('priming')
+end
+
+-- Disable this module because it make one priming query
+if detect_time_skew then
+ modules.unload('detect_time_skew')
+end
+
+_hint_root_file('hints')
+cache.size = 2*MB
+log_level('debug')
+policy.add(policy.all(policy.DEBUG_ALWAYS))
+{% endraw %}
+
+net = { '{{SELF_ADDR}}' }
+
+{% if DO_IP6 == "true" %}
+net.ipv6 = true
+{% else %}
+net.ipv6 = false
+{% endif %}
+
+{% if DO_IP4 == "true" %}
+net.ipv4 = true
+{% else %}
+net.ipv4 = false
+{% endif %}
+
+{% if QMIN == "false" %}
+option('NO_MINIMIZE', true)
+{% else %}
+option('NO_MINIMIZE', false)
+{% endif %}
+
+
+-- Self-checks on globals
+assert(help() ~= nil)
+assert(worker.id ~= nil)
+-- Self-checks on facilities
+assert(cache.count() == 0)
+assert(cache.stats() ~= nil)
+assert(cache.backends() ~= nil)
+assert(worker.stats() ~= nil)
+assert(net.interfaces() ~= nil)
+-- Self-checks on loaded stuff
+assert(net.list()[1].transport.ip == '{{SELF_ADDR}}')
+assert(#modules.list() > 0)
+-- Self-check timers
+ev = event.recurrent(1 * sec, function (ev) return 1 end)
+event.cancel(ev)
+ev = event.after(0, function (ev) return 1 end)
diff --git a/lib/cache/util.h b/lib/cache/util.h
new file mode 100644
index 0000000..3f81830
--- /dev/null
+++ b/lib/cache/util.h
@@ -0,0 +1,4 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+#include <libknot/packet/pkt.h>
+
+uint32_t packet_ttl(const knot_pkt_t *pkt);