Commit c382a077 authored by Marek Vavruša's avatar Marek Vavruša

Merge branch 'ns_reputation_groundwork'

parents 16b2cc5f 64b4fb0d
......@@ -32,7 +32,7 @@
*
* // Prefix search
* int i = 0;
* int count(const char *s, void *n) { (*(int *)n)++; return 0; }
* int count(const char *k, void *v, void *ext) { (*(int *)ext)++; return 0; }
* if (map_walk_prefixed(map, "princ", count, &i) == 0) {
* printf("%d matches\n", i);
* }
......@@ -57,37 +57,47 @@
extern "C" {
#endif
/*! Main data structure */
typedef void *(*map_alloc_f)(void *, size_t);
typedef void (*map_free_f)(void *baton, void *ptr);
/** Main data structure */
typedef struct {
void *root;
void *(*malloc)(void *baton, size_t size);
void (*free)(void *baton, void *ptr);
void *baton; /*! Passed to malloc() and free() */
map_alloc_f malloc;
map_free_f free;
void *baton; /** Passed to malloc() and free() */
} map_t;
/*! Creates an new, empty critbit map */
/** Creates an new, empty critbit map */
map_t map_make(void);
/*! Returns non-zero if map contains str */
/** Returns non-zero if map contains str */
int map_contains(map_t *map, const char *str);
/*! Returns value if map contains str */
/** Returns value if map contains str */
void *map_get(map_t *map, const char *str);
/*! Inserts str into map, returns 0 on suceess */
/** Inserts str into map, returns 0 on suceess */
int map_set(map_t *map, const char *str, void *val);
/*! Deletes str from the map, returns 0 on suceess */
/** Deletes str from the map, returns 0 on suceess */
int map_del(map_t *map, const char *str);
/*! Clears the given map */
/** Clears the given map */
void map_clear(map_t *map);
/*! Calls callback for all strings in map */
/**
* Calls callback for all strings in map
* See @fn map_walk_prefixed() for documentation on parameters.
*/
#define map_walk(map, callback, baton) \
map_walk_prefixed((map), "", (callback), (baton))
/*! Calls callback for all strings in map with the given prefix */
/**
* Calls callback for all strings in map with the given prefix
* @param callback callback parameters are (key, value, baton)
* @param baton passed uservalue
*/
int map_walk_prefixed(map_t *map, const char *prefix,
int (*callback)(const char *, void *, void *), void *baton);
......
......@@ -43,6 +43,9 @@
* it = pack_obj_next(it);
* }
*
* // Remove object
* pack_obj_del(pack, U8("jedi"), 4);
*
* pack_clear(pack);
*
* \addtogroup generics
......@@ -80,7 +83,7 @@ typedef array_t(uint8_t) pack_t;
array_reserve_mm((pack), (pack).len + (sizeof(pack_objlen_t)*(objs_count) + (objs_len)), (reserve), (baton))
/** Return pointer to first packed object. */
#define pack_head(pack) \
&((pack).at[0])
((pack).len > 0 ? &((pack).at[0]) : NULL)
/** Return pack end pointer. */
#define pack_tail(pack) \
&((pack).at[(pack).len])
......@@ -122,6 +125,26 @@ static inline int pack_obj_push(pack_t *pack, const uint8_t *obj, pack_objlen_t
return 0;
}
/** Delete object from the pack
* @return 0 on success, negative number on failure
*/
static inline int pack_obj_del(pack_t *pack, const uint8_t *obj, pack_objlen_t len)
{
uint8_t *endp = pack_tail(*pack);
uint8_t *it = pack_head(*pack);
while (it != endp) {
uint8_t *val = pack_obj_val(it);
if (pack_obj_len(it) == len && memcmp(obj, val, len) == 0) {
size_t packed_len = len + sizeof(len);
memmove(it, it + packed_len, endp - it - packed_len);
pack->len -= packed_len;
return 0;
}
it = pack_obj_next(it);
}
return -1;
}
#ifdef __cplusplus
}
#endif
......
......@@ -23,8 +23,10 @@
#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.
......
......@@ -127,14 +127,10 @@ static void follow_cname_chain(const knot_dname_t **cname, const knot_rrset_t *r
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;
}
}
......@@ -169,99 +165,83 @@ int rr_update_answer(const knot_rrset_t *rr, unsigned hint, struct kr_layer_para
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)
......@@ -329,7 +309,7 @@ static int process_answer(knot_pkt_t *pkt, struct kr_layer_param *param)
}
/* Either way it resolves current query. */
query->resolved = true;
query->flags |= QUERY_RESOLVED;
return KNOT_STATE_DONE;
}
......@@ -388,9 +368,10 @@ static int prepare_query(knot_layer_t *ctx, knot_pkt_t *pkt)
}
#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
......@@ -408,7 +389,7 @@ static int resolve(knot_layer_t *ctx, knot_pkt_t *pkt)
assert(pkt && ctx);
struct kr_layer_param *param = ctx->data;
struct kr_query *query = kr_rplan_current(param->rplan);
if (query == NULL || query->resolved) {
if (query == NULL || (query->flags & QUERY_RESOLVED)) {
return ctx->state;
}
......@@ -454,9 +435,8 @@ static int resolve(knot_layer_t *ctx, knot_pkt_t *pkt)
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;
......
......@@ -17,6 +17,7 @@
#pragma once
#include "lib/layer.h"
#include "lib/rplan.h"
/* Processing module implementation. */
extern const knot_layer_api_t *iterate_layer(void);
......
......@@ -21,6 +21,7 @@
#include <libknot/rrtype/rdname.h>
#include "lib/layer/iterate.h"
#include "lib/cache.h"
#include "lib/module.h"
#define DEBUG_MSG(fmt...) QRDEBUG(kr_rplan_current(param->rplan), " cc ", fmt)
......@@ -95,7 +96,7 @@ static int read_cache(knot_layer_t *ctx, knot_pkt_t *pkt)
int state = read_cache_rr(txn, &cache_rr, timestamp, callback, param);
if (state == KNOT_STATE_DONE) {
DEBUG_MSG("=> satisfied from cache\n");
cur->resolved = true;
cur->flags |= QUERY_RESOLVED;
return state;
}
......@@ -110,7 +111,7 @@ static int read_cache(knot_layer_t *ctx, knot_pkt_t *pkt)
}
}
cur->resolved = true;
cur->flags |= QUERY_RESOLVED;
return KNOT_STATE_DONE;
}
......
......@@ -15,9 +15,61 @@
*/
#include "lib/nsrep.h"
#include "lib/generic/pack.h"
int kr_nsrep_score(const knot_dname_t *ns, struct kr_layer_param *param)
/** @internal Macro to set address structure. */
#define ADDR_SET(sa, family, addr, len) do {\
memcpy(&sa ## _addr, (addr), (len)); \
sa ## _family = (family); \
sa ## _port = htons(KR_DNS_PORT); \
} while (0)
/** Update nameserver representation with current name/address pair. */
static void update_nsrep(struct kr_nsrep *ns, const knot_dname_t *name, uint8_t *addr, unsigned score)
{
ns->name = name;
ns->score = score;
if (addr == NULL) {
return;
}
size_t len = pack_obj_len(addr);
void *addr_val = pack_obj_val(addr);
switch(len) {
case sizeof(struct in_addr):
ADDR_SET(ns->addr.ip4.sin, AF_INET, addr_val, len); break;
case sizeof(struct in6_addr):
ADDR_SET(ns->addr.ip6.sin6, AF_INET6, addr_val, len); break;
default: assert(0); break;
}
}
#undef ADDR_SET
static int eval_nsrep(const char *k, void *v, void *baton)
{
unsigned score = KR_NS_VALID;
struct kr_nsrep *ns = baton;
pack_t *addr_set = v;
uint8_t *addr = NULL;
/* Name server is better candidate if it has address record. */
if (addr_set->len > 0) {
addr = pack_head(*addr_set);
score += 1;
}
/* Update best scoring nameserver. */
if (ns->score < score) {
update_nsrep(ns, (const knot_dname_t *)k, addr, score);
}
return kr_ok();
}
int kr_nsrep_elect(struct kr_nsrep *ns, map_t *nsset)
{
/* TODO: stub, always returns valid */
return KR_NS_VALID;
ns->addr.ip.sa_family = AF_UNSPEC;
ns->score = KR_NS_INVALID;
return map_walk(nsset, eval_nsrep, ns);
}
......@@ -20,18 +20,40 @@
#pragma once
#include <netinet/in.h>
#include "lib/generic/map.h"
#include "lib/layer.h"
enum kr_ns_score {
KR_NS_INVALID = -1,
KR_NS_VALID = 0
KR_NS_INVALID = 0,
KR_NS_VALID = 1
};
struct kr_nsrep
{
unsigned score;
const knot_dname_t *name;
union {
struct sockaddr ip;
struct sockaddr_in ip4;
struct sockaddr_in6 ip6;
} addr;
};
/** Return name server score (KR_NS_VALID is baseline, the higher the better).
* @param ns evaluated NS name
* @param param layer parameters
* @return enum kr_ns_score or higher positive value
/** @internal Address bytes for given family. */
#define kr_nsrep_inaddr(addr) \
((addr).ip.sa_family == AF_INET ? (void *)&((addr).ip4.sin_addr) : (void *)&((addr).ip6.sin6_addr))
/** @internal Address length for given family. */
#define kr_nsrep_inaddr_len(addr) \
((addr).ip.sa_family == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr))
/**
* Elect best nameserver/address pair from the nsset.
* @param ns updated NS representation
* @param nsset NS set to choose from
* @return 0 if success (ns is updated), error otherwise
*/
int kr_nsrep_score(const knot_dname_t *ns, struct kr_layer_param *param);
int kr_nsrep_elect(struct kr_nsrep *ns, map_t *nsset);
/** @} */
......@@ -22,8 +22,8 @@
#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"
......@@ -32,61 +32,29 @@
/* 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) ||
cur->flags & QUERY_AWAIT_ADDR) {
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);
cur->flags |= QUERY_AWAIT_ADDR;
return KNOT_EOK;
}
......@@ -104,17 +72,23 @@ static int iterate(struct knot_requestor *requestor, struct kr_layer_param *para
DEBUG_MSG("query '%s %s'\n", name_str, type_str);
#endif
/* Invalid address for current zone cut. */
if (sockaddr_len((struct sockaddr *)&cur->zone_cut.addr) < 1) {
DEBUG_MSG("=> ns missing A/AAAA, fetching\n");
return ns_resolve_addr(cur, param);
/* Elect best nameserver candidate. */
kr_nsrep_elect(&cur->ns, &cur->zone_cut.nsset);
if (cur->ns.score < KR_NS_VALID) {
DEBUG_MSG("=> no valid NS left\n");
kr_rplan_pop(param->rplan, cur);
return KNOT_EOK;
} else {
if (cur->ns.addr.ip.sa_family == AF_UNSPEC) {
DEBUG_MSG("=> ns missing A/AAAA, fetching\n");
return ns_resolve_addr(cur, param);
}
}
/* 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. */
......@@ -128,17 +102,14 @@ static int iterate(struct knot_requestor *requestor, struct kr_layer_param *para
}
/* 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);
}
......@@ -158,7 +129,7 @@ static void prepare_layers(struct knot_requestor *req, struct kr_layer_param *pa
static int resolve_iterative(struct kr_layer_param *param, mm_ctx_t *pool)
{
/* Initialize requestor. */
/* Initialize requestor. */
struct knot_requestor requestor;
knot_requestor_init(&requestor, pool);
prepare_layers(&requestor, param);
......@@ -181,6 +152,7 @@ static int resolve_iterative(struct kr_layer_param *param, mm_ctx_t *pool)
}
}
DEBUG_MSG("finished: %s, mempool: %llu B\n", knot_strerror(ret), mp_total_size(pool->ctx));
knot_requestor_clear(&requestor);
return ret;
}
......
......@@ -19,6 +19,7 @@
#include <libknot/errcode.h>
#include "lib/rplan.h"
#include "lib/resolve.h"
#include "lib/cache.h"
#include "lib/defines.h"
#include "lib/layer.h"
......@@ -50,6 +51,7 @@ static struct kr_query *query_create(mm_ctx_t *pool, const knot_dname_t *name)
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);
}
......@@ -118,7 +120,8 @@ struct kr_query *kr_rplan_push(struct kr_rplan *rplan, struct kr_query *parent,
/* 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];
......
......@@ -29,11 +29,14 @@
#include "lib/cache.h"
#include "lib/zonecut.h"
#include "lib/nsrep.h"
/** Query flags */
enum kr_query_flag {
QUERY_NO_MINIMIZE = 1 << 0, /**< Don't minimize QNAME. */
QUERY_TCP = 1 << 1 /**< Use TCP for this query. */
QUERY_TCP = 1 << 1, /**< Use TCP for this query. */
QUERY_RESOLVED = 1 << 2, /**< Query is resolved. */
QUERY_AWAIT_ADDR = 1 << 3 /**< Query is waiting for NS address. */
};
/**
......@@ -42,10 +45,10 @@ 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;
bool resolved;
uint16_t stype;
uint16_t sclass;
uint16_t id;
......
......@@ -25,106 +25,177 @@
#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)) {