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

resolve: accept zone cut only if it has address records

parent b146a135
......@@ -73,7 +73,7 @@ static int query_cache_zonecut(struct kr_zonecut *cut, namedb_txn_t *txn, knot_r
switch(cache_rr->type) {
case KNOT_RRTYPE_NS:
return kr_set_zone_cut(cut, cache_rr->owner, knot_ns_name(&cache_rr->rrs, 0));
return kr_find_zone_cut(cut, cache_rr->owner, txn, timestamp);
case KNOT_RRTYPE_A:
case KNOT_RRTYPE_AAAA:
return kr_rrset_to_addr(&cut->addr, cache_rr);
......@@ -112,14 +112,13 @@ static int query_cache(knot_layer_t *ctx, knot_pkt_t *pkt)
cache_rr.type = KNOT_RRTYPE_CNAME;
ret = query_cache_append(param->answer, txn, &cache_rr, timestamp);
if (ret == KNOT_EOK) {
/* Terminate if the STYPE was CNAME as well, otherwise follow. */
kr_rplan_pop(param->rplan, cur);
if (cur->stype != KNOT_RRTYPE_CNAME) {
const knot_dname_t *cname = knot_cname_name(&cache_rr.rrs);
if (kr_rplan_push(param->rplan, cname, cur->sclass, cur->stype) == NULL) {
return KNOT_NS_PROC_FAIL;
}
}
kr_rplan_pop(param->rplan, cur);
return KNOT_NS_PROC_DONE;
}
......@@ -163,22 +162,38 @@ static int merge_in_section(knot_rrset_t *cache_rr, const knot_pktsection_t *sec
/*! \brief Cache direct answer. */
static int update_cache_answer(knot_pkt_t *pkt, namedb_txn_t *txn, mm_ctx_t *pool, uint32_t timestamp)
{
/* Cache only positive answers. */
if (knot_wire_get_rcode(pkt->wire) != KNOT_RCODE_NOERROR) {
return KNOT_EOK;
}
const knot_pktsection_t *an = knot_pkt_section(pkt, KNOT_ANSWER);
knot_dname_t name_buf[KNOT_DNAME_MAXLEN];
knot_dname_to_wire(name_buf, knot_pkt_qname(pkt), sizeof(name_buf));
/* Cache only direct answer. */
knot_rrset_t cache_rr;
knot_rrset_init(&cache_rr, (knot_dname_t *)knot_pkt_qname(pkt), knot_pkt_qtype(pkt), knot_pkt_qclass(pkt));
int ret = merge_in_section(&cache_rr, knot_pkt_section(pkt, KNOT_ANSWER), 0, pool);
knot_rrset_init(&cache_rr, name_buf, KNOT_RRTYPE_CNAME, knot_pkt_qclass(pkt));
int ret = merge_in_section(&cache_rr, an, 0, pool);
if (ret != KNOT_EOK) {
return ret;
}
/* Cache the merged RRSet (may fail) */
(void) kr_cache_insert(txn, &cache_rr, timestamp);
/* Cache CNAME chain. */
while(cache_rr.rrs.rr_count > 0) {
/* Cache the merged RRSet (may fail) */
(void) kr_cache_insert(txn, &cache_rr, timestamp);
/* Follow the chain */
knot_dname_to_wire(name_buf, knot_ns_name(&cache_rr.rrs, 0), sizeof(name_buf));
knot_rdataset_clear(&cache_rr.rrs, pool);
ret = merge_in_section(&cache_rr, an, 0, pool);
if (ret != KNOT_EOK) {
return ret;
}
}
/* Now there may be a terminal record. */
cache_rr.type = knot_pkt_qtype(pkt);
knot_rdataset_clear(&cache_rr.rrs, pool);
ret = merge_in_section(&cache_rr, an, 0, pool);
if (ret == KNOT_EOK) {
kr_cache_insert(txn, &cache_rr, timestamp);
}
return ret;
}
......@@ -218,6 +233,11 @@ static int update_cache_authority(knot_pkt_t *pkt, namedb_txn_t *txn, mm_ctx_t *
static void update_cache_pkt(knot_pkt_t *pkt, namedb_txn_t *txn, mm_ctx_t *pool, uint32_t timestamp)
{
/* Cache only positive answers. */
if (knot_wire_get_rcode(pkt->wire) != KNOT_RCODE_NOERROR) {
return;
}
/* If authoritative, cache answer for current query. */
if (knot_wire_get_aa(pkt->wire)) {
update_cache_answer(pkt, txn, pool, timestamp);
......
......@@ -18,41 +18,6 @@
/* Defines */
#define ITER_LIMIT 50
/*! \brief Fetch address record for nameserver. */
static int prefetch_ns_addr(struct kr_rplan *rplan, const struct timeval *now)
{
namedb_txn_t *txn = kr_rplan_txn_acquire(rplan, NAMEDB_RDONLY);
struct kr_zonecut *cut = &rplan->zone_cut;
knot_rrset_t cached_rr;
knot_rrset_init(&cached_rr, (knot_dname_t *)cut->name, KNOT_RRTYPE_A, KNOT_CLASS_IN);
/* Fetch nameserver address from cache. */
uint32_t timestamp = now->tv_sec;
if (kr_cache_query(txn, &cached_rr, &timestamp) != KNOT_EOK) {
cached_rr.type = KNOT_RRTYPE_AAAA;
if (kr_cache_query(txn, &cached_rr, &timestamp) != KNOT_EOK) {
return KNOT_ENOENT;
}
}
/* Update nameserver address if found. */
return kr_rrset_to_addr(&cut->addr, &cached_rr);
}
/*! \brief Plan NS address resolution. */
static int plan_ns_addr_fetch(struct kr_rplan *rplan)
{
/* TODO: implement rplan states to iteratively scan for A and then AAAA */
(void) kr_rplan_push(rplan, rplan->zone_cut.ns, KNOT_CLASS_IN, KNOT_RRTYPE_A);
(void) kr_rplan_push(rplan, rplan->zone_cut.ns, KNOT_CLASS_IN, KNOT_RRTYPE_AAAA);
/* Reset zone cut for current query. */
struct kr_query *last = kr_rplan_last(rplan);
namedb_txn_t *txn = kr_rplan_txn_acquire(rplan, NAMEDB_RDONLY);
return kr_find_zone_cut(&rplan->zone_cut, KR_DNAME_ROOT, txn, last->timestamp.tv_sec);
}
/*! \brief Invalidate current NS in cache. */
static int invalidate_ns(struct kr_rplan *rplan, const struct kr_query *qry)
{
......@@ -80,13 +45,9 @@ static int iterate(struct knot_requestor *requestor, struct kr_layer_param *para
struct kr_rplan *rplan = param->rplan;
const struct kr_query *cur = kr_rplan_current(rplan);
/* Retrieve address for current zone cut. */
/* Invalid address for current zone cut. */
if (rplan->zone_cut.addr.ss_family == AF_UNSPEC) {
ret = prefetch_ns_addr(rplan, &cur->timestamp);
if (ret != KNOT_EOK) {
plan_ns_addr_fetch(rplan);
return KNOT_EOK;
}
return invalidate_ns(rplan, cur);
}
char name_str[KNOT_DNAME_MAXLEN], zonecut_str[KNOT_DNAME_MAXLEN], ns_str[KNOT_DNAME_MAXLEN], type_str[16];
......
......@@ -4,7 +4,7 @@
#include <libknot/packet/wire.h>
#include "lib/zonecut.h"
#include "lib/defines.h"
#include "lib/utils.h"
#include "lib/rplan.h"
#define DEBUG_MSG(fmt, ...) fprintf(stderr, "[z-cut] " fmt, ## __VA_ARGS__)
......@@ -34,17 +34,35 @@ static const struct hint_info SBELT[HINT_COUNT] = {
{ U8("\x01""m""\x0c""root-servers""\x03""net"), "202.12.27.33" }
};
/*! \brief Fetch address record for nameserver. */
static int prefetch_ns_addr(struct kr_zonecut *cut, knot_rrset_t *cached_rr, namedb_txn_t *txn, uint32_t timestamp)
{
/* Fetch nameserver address from cache. */
cached_rr->type = KNOT_RRTYPE_A;
if (kr_cache_query(txn, cached_rr, &timestamp) != KNOT_EOK) {
cached_rr->type = KNOT_RRTYPE_AAAA;
if (kr_cache_query(txn, cached_rr, &timestamp) != KNOT_EOK) {
return KNOT_ENOENT;
}
}
return kr_rrset_to_addr(&cut->addr, cached_rr);
}
/*! \brief Fetch best NS for zone cut. */
static const knot_dname_t *fetch_ns(const knot_dname_t *name, namedb_txn_t *txn, uint32_t timestamp)
static int fetch_ns(struct kr_zonecut *cut, const knot_dname_t *name, namedb_txn_t *txn, uint32_t timestamp)
{
knot_rrset_t cached_rr;
knot_rrset_init(&cached_rr, (knot_dname_t *)name, KNOT_RRTYPE_NS, KNOT_CLASS_IN);
if (kr_cache_query(txn, &cached_rr, &timestamp) == KNOT_EOK) {
return knot_ns_name(&cached_rr.rrs, 0);
int ret = kr_cache_query(txn, &cached_rr, &timestamp);
if (ret == KNOT_EOK) {
/* Accept only if has address records cached. */
kr_set_zone_cut(cut, name, knot_ns_name(&cached_rr.rrs, 0));
knot_rrset_init(&cached_rr, cut->ns, 0, KNOT_CLASS_IN);
ret = prefetch_ns_addr(cut, &cached_rr, txn, timestamp);
}
return NULL;
return ret;
}
/*! \brief Set zone cut to '.' and choose a random root nameserver from the SBELT. */
......@@ -86,26 +104,24 @@ int kr_find_zone_cut(struct kr_zonecut *cut, const knot_dname_t *name, namedb_tx
return KNOT_EINVAL;
}
/* No cache, start with SBELT. */
if (txn == NULL) {
return set_sbelt_zone_cut(cut);
}
/* Start at QNAME. */
const knot_dname_t *ns_name = NULL;
while (name[0] != '\0') {
ns_name = fetch_ns(name, txn, timestamp);
if (ns_name != NULL) {
break;
while (true) {
if (fetch_ns(cut, name, txn, timestamp) == KNOT_EOK) {
return KNOT_EOK;
}
/* Subtract label from QNAME. */
if (name[0] == '\0') {
break;
}
name = knot_wire_next_label(name, NULL);
}
/* Name server not found, start with SBELT. */
if (ns_name == NULL) {
return set_sbelt_zone_cut(cut);
}
return kr_set_zone_cut(cut, name, ns_name);
return set_sbelt_zone_cut(cut);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment