#include <libknot/processing/layer.h>
#include <libknot/packet/pkt.h>
-#include "lib/resolve.h"
-#include "lib/rplan.h"
+#include "lib/defines.h"
+
+struct kr_context;
+struct kr_rplan;
/**
* Processing module parameters.
static int update_nsaddr(const knot_rrset_t *rr, struct kr_query *query, uint16_t index)
{
if (rr->type == KNOT_RRTYPE_A || rr->type == KNOT_RRTYPE_AAAA) {
- if (knot_dname_is_equal(query->zone_cut.ns, rr->owner)) {
- /* Set zone cut address. */
- int ret = kr_set_zone_cut_addr(&query->zone_cut, rr, index);
- if (ret == KNOT_EOK) {
- return KNOT_STATE_DONE;
- } else {
- return KNOT_STATE_FAIL;
- }
+ const knot_rdata_t *rdata = knot_rdataset_at(&rr->rrs, index);
+ int ret = kr_zonecut_add(&query->zone_cut, rr->owner, rdata);
+ if (ret != 0) {
+ return KNOT_STATE_FAIL;
}
}
return KNOT_STATE_DONE;
}
-static bool has_glue(const knot_dname_t *ns_name, knot_pkt_t *pkt)
+/** Attempt to find glue for given nameserver name (best effort). */
+static int fetch_glue(knot_pkt_t *pkt, const knot_dname_t *ns, struct kr_layer_param *param)
{
+ int result = 0;
const knot_pktsection_t *ar = knot_pkt_section(pkt, KNOT_ADDITIONAL);
for (unsigned i = 0; i < ar->count; ++i) {
const knot_rrset_t *rr = knot_pkt_rr(ar, i);
- if ((rr->type == KNOT_RRTYPE_A || rr->type == KNOT_RRTYPE_AAAA) &&
- (knot_dname_is_equal(ns_name, rr->owner))) {
- return true;
+ if (knot_dname_is_equal(ns, rr->owner)) {
+ (void) update_glue(rr, 0, param);
+ result += 1;
}
}
- return false;
+ return result;
}
-static int nameserver_score(const knot_rrset_t *rr, unsigned hint, knot_pkt_t *pkt, struct kr_layer_param *param)
+static int update_cut(knot_pkt_t *pkt, const knot_rrset_t *rr, struct kr_layer_param *param)
{
struct kr_query *query = kr_rplan_current(param->rplan);
- const knot_dname_t *ns_name = knot_ns_name(&rr->rrs, hint);
- int score = kr_nsrep_score(rr->owner, param);
- if (score < KR_NS_VALID) {
- return score;
- }
+ struct kr_zonecut *cut = &query->zone_cut;
+ int state = KNOT_STATE_CONSUME;
/* Authority MUST be at/below the authority of the nameserver, otherwise
* possible cache injection attempt. */
- if (!knot_dname_in(query->zone_cut.name, rr->owner)) {
+ if (!knot_dname_in(cut->name, rr->owner)) {
DEBUG_MSG("<= authority: ns outside bailiwick, rejecting\n");
- return KR_NS_INVALID;
+ return KNOT_STATE_FAIL;
}
- /* Ignore already resolved zone cut. */
- if (knot_dname_is_equal(rr->owner, query->zone_cut.name)) {
- return KR_NS_VALID;
- } else {
- score += 1;
+ /* Update zone cut name */
+ if (!knot_dname_is_equal(rr->owner, cut->name)) {
+ kr_zonecut_set(cut, rr->owner);
+ state = KNOT_STATE_DONE;
}
- /* Check if contains glue. */
- if (has_glue(ns_name, pkt)) {
- score += 1;
+ /* Fetch glue for each NS */
+ kr_zonecut_add(cut, knot_ns_name(&rr->rrs, 0), NULL);
+ for (unsigned i = 0; i < rr->rrs.rr_count; ++i) {
+ const knot_dname_t *ns_name = knot_ns_name(&rr->rrs, i);
+ int glue_records = fetch_glue(pkt, ns_name, param);
+ /* Glue is mandatory for NS below zone */
+ if (knot_dname_in(ns_name, rr->owner) ) {
+ if (glue_records == 0) {
+ DEBUG_MSG("<= authority: missing mandatory glue, rejecting\n");
+ return KNOT_STATE_FAIL;
+ }
+ }
}
- return score;
+ return state;
}
static int process_authority(knot_pkt_t *pkt, struct kr_layer_param *param)
{
- struct kr_query *query = kr_rplan_current(param->rplan);
- const knot_rrset_t *best_ns = NULL;
- int best_score = 0;
+ int result = KNOT_STATE_CONSUME;
+ const knot_pktsection_t *ns = knot_pkt_section(pkt, KNOT_AUTHORITY);
/* AA, terminate resolution chain. */
if (knot_wire_get_aa(pkt->wire)) {
return KNOT_STATE_CONSUME;
}
- /* Elect best name server candidate. */
- const knot_pktsection_t *ns = knot_pkt_section(pkt, KNOT_AUTHORITY);
+ /* Update zone cut information. */
for (unsigned i = 0; i < ns->count; ++i) {
const knot_rrset_t *rr = knot_pkt_rr(ns, i);
if (rr->type == KNOT_RRTYPE_NS) {
- int score = nameserver_score(rr, 0, pkt, param);
- if (score < KR_NS_VALID) {
- return KNOT_STATE_FAIL;
+ int state = update_cut(pkt, rr, param);
+ switch(state) {
+ case KNOT_STATE_DONE: result = state; break;
+ case KNOT_STATE_FAIL: return state; break;
+ default: /* continue */ break;
}
- if (score > best_score) {
- best_ns = rr;
- best_score = score;
- }
- }
- }
-
- /* Update name server candidate. */
- if (best_ns != NULL) {
- kr_set_zone_cut(&query->zone_cut, best_ns->owner, knot_ns_name(&best_ns->rrs, 0));
- return KNOT_STATE_DONE;
- }
-
- return KNOT_STATE_CONSUME;
-}
-
-static int process_additional(knot_pkt_t *pkt, struct kr_layer_param *param)
-{
- /* Attempt to find glue for current nameserver. */
- const knot_pktsection_t *ar = knot_pkt_section(pkt, KNOT_ADDITIONAL);
- for (unsigned i = 0; i < ar->count; ++i) {
- const knot_rrset_t *rr = knot_pkt_rr(ar, i);
- int state = update_glue(rr, 0, param);
- if (state != KNOT_STATE_CONSUME) {
- return state;
}
}
- return KNOT_STATE_DONE;
+ /* CONSUME => Unhelpful referral.
+ * DONE => Zone cut updated. */
+ return result;
}
static void finalize_answer(knot_pkt_t *pkt, struct kr_layer_param *param)
}
#ifndef NDEBUG
- char qname_str[KNOT_DNAME_MAXLEN], zonecut_str[KNOT_DNAME_MAXLEN], ns_str[KNOT_DNAME_MAXLEN];
+ char qname_str[KNOT_DNAME_MAXLEN], zonecut_str[KNOT_DNAME_MAXLEN], ns_str[SOCKADDR_STRLEN];
knot_dname_to_str(qname_str, qname, sizeof(qname_str));
- knot_dname_to_str(ns_str, query->zone_cut.ns, sizeof(ns_str));
+ struct sockaddr *addr = &query->ns.addr.ip;
+ inet_ntop(addr->sa_family, kr_nsrep_inaddr(query->ns.addr), ns_str, sizeof(ns_str));
knot_dname_to_str(zonecut_str, query->zone_cut.name, sizeof(zonecut_str));
DEBUG_MSG("=> querying: '%s' zone cut: '%s' m12n: '%s'\n", ns_str, zonecut_str, qname_str);
#endif
DEBUG_MSG("<= rcode: %s\n", rcode ? rcode->name : "??");
state = process_answer(pkt, param);
break;
- case KNOT_STATE_DONE: /* Referral, try to find glue. */
+ case KNOT_STATE_DONE: /* Referral */
DEBUG_MSG("<= referral response, follow\n");
- state = process_additional(pkt, param);
break;
default:
break;
#pragma once
#include "lib/layer.h"
+#include "lib/rplan.h"
/* Processing module implementation. */
extern const knot_layer_api_t *iterate_layer(void);
#include <libknot/descriptor.h>
#include <dnssec/random.h>
+#include "lib/rplan.h"
#include "lib/resolve.h"
-#include "lib/defines.h"
#include "lib/layer/itercache.h"
#include "lib/layer/iterate.h"
/* Defines */
#define ITER_LIMIT 50
-/** Invalidate current NS in cache. */
+/** Invalidate current NS/addr pair. */
static int invalidate_ns(struct kr_rplan *rplan, struct kr_query *qry)
{
- namedb_txn_t *txn = kr_rplan_txn_acquire(rplan, 0);
- if (txn == NULL) {
- return KNOT_EOK;
- }
-
- /* Fetch current nameserver cache. */
- uint32_t drift = qry->timestamp.tv_sec;
- knot_rrset_t cached;
- knot_rrset_init(&cached, qry->zone_cut.name, KNOT_RRTYPE_NS, KNOT_CLASS_IN);
- if (kr_cache_peek(txn, &cached, &drift) != KNOT_EOK) {
- kr_init_zone_cut(&qry->zone_cut);
- return KNOT_EOK;
- }
- cached = kr_cache_materialize(&cached, drift, rplan->pool);
-
- /* Find a matching RD. */
- knot_rdataset_t to_remove;
- knot_rdataset_init(&to_remove);
- for (unsigned i = 0; i < cached.rrs.rr_count; ++i) {
- knot_rdata_t *rd = knot_rdataset_at(&cached.rrs, i);
- if (knot_dname_is_equal(knot_rdata_data(rd), qry->zone_cut.ns)) {
- knot_rdataset_add(&to_remove, rd, rplan->pool);
- }
- }
- knot_rdataset_subtract(&cached.rrs, &to_remove, rplan->pool);
- knot_rdataset_clear(&to_remove, rplan->pool);
-
- /* Remove record(s) */
- int ret = KNOT_EOK;
- if (cached.rrs.rr_count == 0) {
- (void) kr_cache_remove(txn, &cached);
- ret = KNOT_ENOENT;
- } else {
- (void) kr_cache_insert(txn, &cached, qry->timestamp.tv_sec);
- kr_set_zone_cut(&qry->zone_cut, cached.owner, knot_ns_name(&cached.rrs, 0));
- }
-
- knot_rrset_clear(&cached, rplan->pool);
- return ret;
+ uint8_t *addr = kr_nsrep_inaddr(qry->ns.addr);
+ size_t addr_len = kr_nsrep_inaddr_len(qry->ns.addr);
+ knot_rdata_t rdata[knot_rdata_array_size(addr_len)];
+ knot_rdata_init(rdata, addr_len, addr, 0);
+ return kr_zonecut_del(&qry->zone_cut, qry->ns.name, rdata);
}
static int ns_resolve_addr(struct kr_query *cur, struct kr_layer_param *param)
{
- if (kr_rplan_satisfies(cur, cur->zone_cut.ns, KNOT_CLASS_IN, KNOT_RRTYPE_A) ||
- kr_rplan_satisfies(cur, cur->zone_cut.ns, KNOT_CLASS_IN, KNOT_RRTYPE_AAAA)) {
+ if (kr_rplan_satisfies(cur, cur->ns.name, KNOT_CLASS_IN, KNOT_RRTYPE_A) ||
+ kr_rplan_satisfies(cur, cur->ns.name, KNOT_CLASS_IN, KNOT_RRTYPE_AAAA) ||
DEBUG_MSG("=> dependency loop, bailing out\n");
kr_rplan_pop(param->rplan, cur);
return KNOT_EOK;
}
- (void) kr_rplan_push(param->rplan, cur, cur->zone_cut.ns, KNOT_CLASS_IN, KNOT_RRTYPE_AAAA);
- (void) kr_rplan_push(param->rplan, cur, cur->zone_cut.ns, KNOT_CLASS_IN, KNOT_RRTYPE_A);
+ (void) kr_rplan_push(param->rplan, cur, cur->ns.name, KNOT_CLASS_IN, KNOT_RRTYPE_AAAA);
+ (void) kr_rplan_push(param->rplan, cur, cur->ns.name, KNOT_CLASS_IN, KNOT_RRTYPE_A);
return KNOT_EOK;
}
/* Prepare query resolution. */
int mode = (cur->flags & QUERY_TCP) ? 0 : KNOT_RQ_UDP;
- struct sockaddr *ns_addr = (struct sockaddr *)&cur->zone_cut.addr;
knot_pkt_t *query = knot_pkt_new(NULL, KNOT_WIRE_MIN_PKTSIZE, requestor->mm);
- struct knot_request *tx = knot_request_make(requestor->mm, ns_addr, NULL, query, mode);
+ struct knot_request *tx = knot_request_make(requestor->mm, &cur->ns.addr.ip, NULL, query, mode);
knot_requestor_enqueue(requestor, tx);
/* Resolve and check status. */
}
/* Resolution failed, invalidate current NS and reset to UDP. */
DEBUG_MSG("=> resolution failed: '%s', invalidating\n", knot_strerror(ret));
- if (invalidate_ns(rplan, cur) == KNOT_EOK) {
+ if (invalidate_ns(rplan, cur) == 0) {
cur->flags &= ~QUERY_TCP;
- } else {
- DEBUG_MSG("=> no ns left to ask\n");
- kr_rplan_pop(rplan, cur);
}
return KNOT_EOK;
}
/* Pop query if resolved. */
- if (cur->resolved) {
+ if (cur->flags & QUERY_RESOLVED) {
kr_rplan_pop(rplan, cur);
}
#include <libknot/errcode.h>
#include "lib/rplan.h"
+#include "lib/resolve.h"
#include "lib/cache.h"
#include "lib/defines.h"
#include "lib/layer.h"
static void query_free(mm_ctx_t *pool, struct kr_query *qry)
{
+ kr_zonecut_deinit(&qry->zone_cut);
mm_free(pool, qry->sname);
mm_free(pool, qry);
}
/* Find closest zone cut for this query. */
namedb_txn_t *txn = kr_rplan_txn_acquire(rplan, NAMEDB_RDONLY);
- kr_find_zone_cut(&qry->zone_cut, name, txn, qry->timestamp.tv_sec);
+ kr_zonecut_init(&qry->zone_cut, name, rplan->pool);
+ kr_zonecut_find_cached(&qry->zone_cut, txn, qry->timestamp.tv_sec);
#ifndef NDEBUG
char name_str[KNOT_DNAME_MAXLEN], type_str[16];
#include "lib/cache.h"
#include "lib/zonecut.h"
+#include "lib/nsrep.h"
/** Query flags */
enum kr_query_flag {
struct kr_query {
node_t node;
struct kr_query *parent;
+ struct kr_nsrep ns;
struct kr_zonecut zone_cut;
struct timeval timestamp;
knot_dname_t *sname;
#include "lib/rplan.h"
#include "lib/defines.h"
#include "lib/layer.h"
+#include "lib/generic/pack.h"
/* Root hint descriptor. */
struct hint_info {
const knot_dname_t *name;
- const char *addr;
+ const uint8_t *addr;
};
/* Initialize with SBELT name servers. */
#define U8(x) (const uint8_t *)(x)
#define HINT_COUNT 13
+#define HINT_ADDRLEN sizeof(struct in_addr)
static const struct hint_info SBELT[HINT_COUNT] = {
- { U8("\x01""a""\x0c""root-servers""\x03""net"), "198.41.0.4" },
- { U8("\x01""b""\x0c""root-servers""\x03""net"), "192.228.79.201" },
- { U8("\x01""c""\x0c""root-servers""\x03""net"), "192.33.4.12" },
- { U8("\x01""d""\x0c""root-servers""\x03""net"), "199.7.91.13" },
- { U8("\x01""e""\x0c""root-servers""\x03""net"), "192.203.230.10" },
- { U8("\x01""f""\x0c""root-servers""\x03""net"), "192.5.5.241" },
- { U8("\x01""g""\x0c""root-servers""\x03""net"), "192.112.36.4" },
- { U8("\x01""h""\x0c""root-servers""\x03""net"), "128.63.2.53" },
- { U8("\x01""i""\x0c""root-servers""\x03""net"), "192.36.148.17" },
- { U8("\x01""j""\x0c""root-servers""\x03""net"), "192.58.128.30" },
- { U8("\x01""k""\x0c""root-servers""\x03""net"), "193.0.14.129" },
- { U8("\x01""l""\x0c""root-servers""\x03""net"), "199.7.83.42" },
- { U8("\x01""m""\x0c""root-servers""\x03""net"), "202.12.27.33" }
+ { U8("\x01""a""\x0c""root-servers""\x03""net"), U8("\xc6)\x00\x04") }, /* 198.41.0.4 */
+ { U8("\x01""b""\x0c""root-servers""\x03""net"), U8("\xc0\xe4O\xc9") }, /* 192.228.79.201 */
+ { U8("\x01""c""\x0c""root-servers""\x03""net"), U8("\xc6)\x00\x04") }, /* 192.33.4.12 */
+ { U8("\x01""d""\x0c""root-servers""\x03""net"), U8("\xc7\x07[\r") }, /* 199.7.91.13 */
+ { U8("\x01""e""\x0c""root-servers""\x03""net"), U8("\xc0\xcb\xe6\n") }, /* 192.203.230.10 */
+ { U8("\x01""f""\x0c""root-servers""\x03""net"), U8("\xc0\x05\x05\xf1") }, /* 192.5.5.241 */
+ { U8("\x01""g""\x0c""root-servers""\x03""net"), U8("\xc0p$\x04") }, /* 192.112.36.4 */
+ { U8("\x01""h""\x0c""root-servers""\x03""net"), U8("\x80?\x025") }, /* 128.63.2.53 */
+ { U8("\x01""i""\x0c""root-servers""\x03""net"), U8("\xc0$\x94\x11") }, /* 192.36.148.17 */
+ { U8("\x01""j""\x0c""root-servers""\x03""net"), U8("\xc0:\x80\x1e") }, /* 192.58.128.30 */
+ { U8("\x01""k""\x0c""root-servers""\x03""net"), U8("\xc1\x00\x0e\x81") }, /* 193.0.14.129 */
+ { U8("\x01""l""\x0c""root-servers""\x03""net"), U8("\xc7\x07S*") }, /* 199.7.83.42 */
+ { U8("\x01""m""\x0c""root-servers""\x03""net"), U8("\xca\x0c\x1b!") }, /* 202.12.27.33 */
};
-int kr_init_zone_cut(struct kr_zonecut *cut)
+static void update_cut_name(struct kr_zonecut *cut, const knot_dname_t *name)
+{
+ if (knot_dname_is_equal(name, cut->name)) {
+ return;
+ }
+ knot_dname_t *next_name = knot_dname_copy(name, cut->pool);
+ mm_free(cut->pool, cut->name);
+ cut->name = next_name;
+}
+
+int kr_zonecut_init(struct kr_zonecut *cut, const knot_dname_t *name, mm_ctx_t *pool)
{
if (cut == NULL) {
- return KNOT_EINVAL;
+ return kr_error(EINVAL);
}
- const unsigned hint_id = dnssec_random_uint16_t() % HINT_COUNT;
- const struct hint_info *hint = &SBELT[hint_id];
+ cut->name = knot_dname_copy(name, pool);
+ cut->pool = pool;
+ cut->nsset = map_make();
+ cut->nsset.malloc = (map_alloc_f) mm_alloc;
+ cut->nsset.free = (map_free_f) mm_free;
+ cut->nsset.baton = pool;
+ return kr_ok();
+}
+
+static int free_addr_set(const char *k, void *v, void *baton)
+{
+ pack_t *pack = v;
+ pack_clear_mm(*pack, mm_free, baton);
+ mm_free(baton, pack);
+ return kr_ok();
+}
- kr_set_zone_cut(cut, U8(""), hint->name);
+void kr_zonecut_deinit(struct kr_zonecut *cut)
+{
+ if (cut == NULL) {
+ return;
+ }
+ mm_free(cut->pool, cut->name);
+ map_walk(&cut->nsset, free_addr_set, cut->pool);
+ map_clear(&cut->nsset);
+}
- /* Prefetch address. */
- return sockaddr_set(&cut->addr, AF_INET, hint->addr, 53);
+void kr_zonecut_set(struct kr_zonecut *cut, const knot_dname_t *name)
+{
+ if (cut == NULL) {
+ return;
+ }
+ kr_zonecut_deinit(cut);
+ kr_zonecut_init(cut, name, cut->pool);
}
-int kr_set_zone_cut(struct kr_zonecut *cut, const knot_dname_t *name, const knot_dname_t *ns)
+int kr_zonecut_add(struct kr_zonecut *cut, const knot_dname_t *ns, const knot_rdata_t *rdata)
{
- if (cut == NULL || name == NULL) {
- return KNOT_EINVAL;
+ if (cut == NULL || ns == NULL) {
+ return kr_error(EINVAL);
}
- /* Set current NS and zone cut. */
- knot_dname_to_wire(cut->name, name, KNOT_DNAME_MAXLEN);
- knot_dname_to_wire(cut->ns, ns, KNOT_DNAME_MAXLEN);
+ /* Fetch/insert nameserver. */
+ const char *key = (const char *)ns;
+ pack_t *pack = map_get(&cut->nsset, key);
+ if (pack == NULL) {
+ pack = mm_alloc(cut->pool, sizeof(*pack));
+ if (!pack || (map_set(&cut->nsset, key, pack) != 0)) {
+ mm_free(cut->pool, pack);
+ return kr_error(ENOMEM);
+ }
+ pack_init(*pack);
+ }
- /* Invalidate address. */
- cut->addr.ss_family = AF_UNSPEC;
+ /* Insert data (if has any) */
+ if (rdata == NULL) {
+ return kr_ok();
+ }
+ uint16_t rdlen = knot_rdata_rdlen(rdata);
+ int ret = pack_reserve(*pack, 1, rdlen);
+ if (ret != 0) {
+ return kr_error(ENOMEM);
+ }
- return KNOT_EOK;
+ return pack_obj_push(pack, knot_rdata_data(rdata), rdlen);
}
-int kr_set_zone_cut_addr(struct kr_zonecut *cut, const knot_rrset_t *rr, uint16_t i)
+int kr_zonecut_del(struct kr_zonecut *cut, const knot_dname_t *ns, const knot_rdata_t *rdata)
{
- int ret = KNOT_EOK;
+ if (cut == NULL || ns == NULL) {
+ return kr_error(EINVAL);
+ }
- switch(rr->type) {
- case KNOT_RRTYPE_A:
- ret = knot_a_addr(&rr->rrs, i, (struct sockaddr_in *)&cut->addr);
- break;
- case KNOT_RRTYPE_AAAA:
- ret = knot_aaaa_addr(&rr->rrs, i, (struct sockaddr_in6 *)&cut->addr);
- break;
- default:
- return KNOT_EINVAL;
+ /* Find the address list. */
+ const char *key = (const char *)ns;
+ map_t *nsset = &cut->nsset;
+ pack_t *pack = map_get(nsset, key);
+ if (pack == NULL) {
+ return kr_error(ENOENT);
}
- sockaddr_port_set(&cut->addr, KR_DNS_PORT);
+ /* Remove address from the pack. */
+ int ret = pack_obj_del(pack, knot_rdata_data(rdata), knot_rdata_rdlen(rdata));
+ if (pack->len == 0) {
+ /* No servers left, remove NS from the set. */
+ free_addr_set(key, pack, cut->pool);
+ return map_del(nsset, key);
+ }
return ret;
}
+int kr_zonecut_set_sbelt(struct kr_zonecut *cut)
+{
+ if (cut == NULL) {
+ return kr_error(EINVAL);
+ }
+
+ update_cut_name(cut, U8(""));
+ for (unsigned i = 0; i < HINT_COUNT; ++i) {
+ const struct hint_info *hint = &SBELT[i];
+ knot_rdata_t rdata[knot_rdata_array_size(HINT_ADDRLEN)];
+ knot_rdata_init(rdata, HINT_ADDRLEN, hint->addr, 0);
+ int ret = kr_zonecut_add(cut, hint->name, rdata);
+ if (ret != 0) {
+ return ret;
+ }
+ }
+
+ return kr_ok();
+}
+
/** Fetch address for zone cut. */
-static int fetch_addr(struct kr_zonecut *cut, namedb_txn_t *txn, uint32_t timestamp)
+static void fetch_addr(struct kr_zonecut *cut, const knot_dname_t *ns, uint16_t rrtype, namedb_txn_t *txn, uint32_t timestamp)
{
- /* Fetch nameserver address from cache. */
knot_rrset_t cached_rr;
- knot_rrset_init(&cached_rr, cut->ns, 0, KNOT_CLASS_IN);
- cached_rr.type = KNOT_RRTYPE_A;
- if (kr_cache_peek(txn, &cached_rr, ×tamp) != KNOT_EOK) {
- cached_rr.type = KNOT_RRTYPE_AAAA;
- if (kr_cache_peek(txn, &cached_rr, ×tamp) != KNOT_EOK) {
- return KNOT_ENOENT;
- }
+ knot_rrset_init(&cached_rr, (knot_dname_t *)ns, rrtype, KNOT_CLASS_IN);
+ if (kr_cache_peek(txn, &cached_rr, ×tamp) != 0) {
+ return;
}
- /* Find first valid record. */
- uint16_t i = 0;
- for (; i < cached_rr.rrs.rr_count; ++i) {
+
+ for (uint16_t i = 0; i < cached_rr.rrs.rr_count; ++i) {
knot_rdata_t *rd = knot_rdataset_at(&cached_rr.rrs, i);
if (knot_rdata_ttl(rd) > timestamp) {
- break;
+ (void) kr_zonecut_add(cut, ns, rd);
}
}
-
- return kr_set_zone_cut_addr(cut, &cached_rr, i);
}
/** Fetch best NS for zone cut. */
knot_rrset_t cached_rr;
knot_rrset_init(&cached_rr, (knot_dname_t *)name, KNOT_RRTYPE_NS, KNOT_CLASS_IN);
int ret = kr_cache_peek(txn, &cached_rr, &drift);
- if (ret != KNOT_EOK) {
+ if (ret != 0) {
return ret;
}
- /* Accept only if has address records cached. */
+ /* Fetch address records for this nameserver */
for (unsigned i = 0; i < cached_rr.rrs.rr_count; ++i) {
- kr_set_zone_cut(cut, name, knot_ns_name(&cached_rr.rrs, i));
- ret = fetch_addr(cut, txn, timestamp);
- if (ret == KNOT_EOK) {
- break;
- }
+ const knot_dname_t *ns_name = knot_ns_name(&cached_rr.rrs, i);
+ kr_zonecut_add(cut, ns_name, NULL);
+ fetch_addr(cut, ns_name, KNOT_RRTYPE_A, txn, timestamp);
+ fetch_addr(cut, ns_name, KNOT_RRTYPE_AAAA, txn, timestamp);
}
- return ret;
+ return kr_ok();
}
-int kr_find_zone_cut(struct kr_zonecut *cut, const knot_dname_t *name, namedb_txn_t *txn, uint32_t timestamp)
+int kr_zonecut_find_cached(struct kr_zonecut *cut, namedb_txn_t *txn, uint32_t timestamp)
{
- if (cut == NULL || name == NULL) {
- return KNOT_EINVAL;
- }
-
- /* No cache, start with SBELT. */
- if (txn == NULL) {
- return kr_init_zone_cut(cut);
+ if (cut == NULL) {
+ return kr_error(EINVAL);
}
/* Start at QNAME. */
- while (true) {
- if (fetch_ns(cut, name, txn, timestamp) == KNOT_EOK) {
- return KNOT_EOK;
+ const knot_dname_t *name = cut->name;
+ while (txn) {
+ if (fetch_ns(cut, name, txn, timestamp) == 0) {
+ update_cut_name(cut, name);
+ return kr_ok();
}
/* Subtract label from QNAME. */
if (name[0] == '\0') {
}
/* Name server not found, start with SBELT. */
- return kr_init_zone_cut(cut);
+ return kr_zonecut_set_sbelt(cut);
}
#pragma once
-#include <libknot/dname.h>
-#include <libknot/rrset.h>
-#include <libknot/internal/sockaddr.h>
-#include <libknot/internal/namedb/namedb.h>
+#include "lib/cache.h"
+#include "lib/generic/map.h"
struct kr_rplan;
* Current zone cut representation.
*/
struct kr_zonecut {
- knot_dname_t name[KNOT_DNAME_MAXLEN]; /**< Current zone cut */
- knot_dname_t ns[KNOT_DNAME_MAXLEN]; /**< Authoritative NS */
- struct sockaddr_storage addr; /**< Authoritative NS address. */
+ knot_dname_t *name; /**< Zone cut name. */
+ mm_ctx_t *pool; /**< Memory pool. */
+ map_t nsset; /**< Map of nameserver => address_set. */
};
/**
- * Initialize zone cut with SBELT.
- * @param cut zone cut to be set
- * @return KNOT_E*
+ * Populate root zone cut with SBELT.
+ * @param cut zone cut
+ * @param name
+ * @param pool
+ * @return 0 or error code
*/
-int kr_init_zone_cut(struct kr_zonecut *cut);
+int kr_zonecut_init(struct kr_zonecut *cut, const knot_dname_t *name, mm_ctx_t *pool);
/**
- * Set zone cut to given name and name server.
- * @note Name server address is blanked.
- * @param cut zone cut to be set
- * @param name zone cut name
- * @param ns zone cut nameserver
- * @return KNOT_E*
+ * Clear the structure and free the address set.
+ * @param cut zone cut
*/
-int kr_set_zone_cut(struct kr_zonecut *cut, const knot_dname_t *name, const knot_dname_t *ns);
+void kr_zonecut_deinit(struct kr_zonecut *cut);
/**
- * Convert A/AAAA RRs to address with DNS port.
- * @param cut zone cut to be set
- * @param rr resource record
- * @param i index of the set address in the rr
- * @return KNOT_E*
+ * Reset zone cut to given name and clear address list.
+ * @note This preserves already-allocated memory.
+ * @note This clears the address list even if the name doesn't change.
+ * @param cut zone cut to be set
+ * @param name new zone cut name
*/
-int kr_set_zone_cut_addr(struct kr_zonecut *cut, const knot_rrset_t *rr, uint16_t i);
+void kr_zonecut_set(struct kr_zonecut *cut, const knot_dname_t *name);
/**
- * Find the closest enclosing zone cut/nameserver from the cache.
- * @param cut zone cut to be set
- * @param name zone cut name
- * @param txn cache transaction
+ * Add address record to the zone cut.
+ *
+ * The record will be merged with existing data,
+ * it may be either A/AAAA type.
+ *
+ * @param cut zone cut to be populated
+ * @param ns nameserver name
+ * @param rdata nameserver address (as rdata)
+ * @return 0 or error code
+ */
+int kr_zonecut_add(struct kr_zonecut *cut, const knot_dname_t *ns, const knot_rdata_t *rdata);
+
+/**
+ * Delete nameserver/address pair from the zone cut.
+ * @param cut
+ * @param ns name server name
+ * @param rdata name server address
+ * @return 0 or error code
+ */
+int kr_zonecut_del(struct kr_zonecut *cut, const knot_dname_t *ns, const knot_rdata_t *rdata);
+
+/**
+ * Populate zone cut with a root zone using SBELT :rfc:`1034`
+ *
+ * @param cut zone cut to be populated
+ * @return 0 or error code
+ */
+int kr_zonecut_set_sbelt(struct kr_zonecut *cut);
+
+/**
+ * Populate zone cut address set from cache.
+ *
+ * @param cut zone cut to be populated
+ * @param txn cache transaction (read)
* @param timestamp transaction timestamp
- * @return KNOT_E*
+ * @return 0 or error code
*/
-int kr_find_zone_cut(struct kr_zonecut *cut, const knot_dname_t *name, namedb_txn_t *txn, uint32_t timestamp);
+int kr_zonecut_find_cached(struct kr_zonecut *cut, namedb_txn_t *txn, uint32_t timestamp);
/** @} */