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

lib: resolver query plan, support chasing NSs

parent d89147a0
......@@ -16,10 +16,15 @@ limitations under the License.
#include "daemon/layer/query.h"
#include "lib/resolve.h"
static int reset(knot_layer_t *ctx)
{
return NS_PROC_MORE;
}
static int begin(knot_layer_t *ctx, void *module_param)
{
ctx->data = module_param;
return NS_PROC_MORE;
return reset(ctx);
}
static int input_query(knot_layer_t *ctx, knot_pkt_t *pkt)
......@@ -58,7 +63,7 @@ static int input_query(knot_layer_t *ctx, knot_pkt_t *pkt)
static const knot_layer_api_t LAYER_QUERY_MODULE = {
&begin,
NULL,
NULL,
&reset,
&input_query,
NULL,
NULL
......
......@@ -12,7 +12,7 @@ libknotresolve_la_SOURCES = \
context.c \
resolve.h \
resolve.c \
delegpt.h \
delegpt.c \
delegpt.h
rplan.h \
rplan.c
......@@ -3,12 +3,15 @@
#include <common/sockaddr.h>
#include "lib/context.h"
#include "lib/rplan.h"
int kr_context_init(struct kr_context *ctx, mm_ctx_t *mm)
{
memset(ctx, 0, sizeof(struct kr_context));
ctx->pool = mm;
kr_rplan_init(&ctx->rplan, mm);
kr_delegmap_init(&ctx->dp_map, mm);
return 0;
......@@ -16,6 +19,12 @@ int kr_context_init(struct kr_context *ctx, mm_ctx_t *mm)
int kr_context_reset(struct kr_context *ctx)
{
ctx->state = 0;
ctx->resolved_qry = NULL;
ctx->current_ns = NULL;
ctx->query = NULL;
kr_rplan_clear(&ctx->rplan);
return 0;
}
......@@ -35,7 +44,12 @@ int kr_result_init(struct kr_context *ctx, struct kr_result *result)
return -1;
}
knot_pkt_put_question(ans, ctx->sname, ctx->sclass, ctx->stype);
struct kr_query *qry = kr_rplan_next(&ctx->rplan);
if (qry == NULL) {
return -1;
}
knot_pkt_put_question(ans, qry->sname, qry->sclass, qry->stype);
knot_wire_set_rcode(ans->wire, KNOT_RCODE_SERVFAIL);
knot_wire_set_qr(ans->wire);
......
......@@ -17,15 +17,13 @@ limitations under the License.
#include <stdint.h>
#include <libknot/mempattern.h>
#warning TODO: this is private define
#include <common/sockaddr.h>
#include "lib/delegpt.h"
#include "lib/rplan.h"
/*! \brief Name resolution result. */
struct kr_result {
const knot_dname_t *cname;
knot_pkt_t *ans;
unsigned flags;
struct timeval t_start, t_end;
......@@ -35,10 +33,10 @@ struct kr_result {
/*! \brief Name resolution context. */
struct kr_context
{
struct kr_ns *current_ns;
struct kr_query *resolved_qry;
const knot_pkt_t *query;
const knot_dname_t *sname;
uint16_t stype;
uint16_t sclass;
struct kr_rplan rplan;
struct kr_delegmap dp_map;
mm_ctx_t *pool;
unsigned state;
......
......@@ -70,27 +70,42 @@ list_t *kr_delegmap_find(struct kr_delegmap *map, const knot_dname_t *name)
return *val;
}
struct kr_ns *kr_ns_create(const knot_dname_t *name, mm_ctx_t *mm)
struct kr_ns *kr_ns_get(list_t *list, const knot_dname_t *name, mm_ctx_t *mm)
{
struct kr_ns *ns = mm_alloc(mm, sizeof(struct kr_ns));
/* Check for duplicates. */
struct kr_ns *ns = kr_ns_find(list, name);
if (ns != NULL) {
return ns;
}
ns = mm_alloc(mm, sizeof(struct kr_ns));
if (ns == NULL) {
return NULL;
}
memset(ns, 0, sizeof(struct kr_ns));
ns->name = knot_dname_copy(name, mm);
ns->flags = DP_LAME;
add_tail(list, (node_t *)ns);
return ns;
}
void kr_ns_append(list_t *list, struct kr_ns *ns)
struct kr_ns *kr_ns_find(list_t *list, const knot_dname_t *name)
{
add_tail(list, (node_t *)ns);
struct kr_ns *ns = NULL;
WALK_LIST(ns, *list) {
if (knot_dname_is_equal(ns->name, name)) {
return ns;
}
}
return NULL;
}
void kr_ns_remove(struct kr_ns *ns, mm_ctx_t *mm)
{
rem_node((node_t *)ns);
delegpt_free(ns, mm);
}
int kr_ns_resolve(struct kr_ns *ns)
{
return -1;
}
}
\ No newline at end of file
......@@ -16,16 +16,15 @@ limitations under the License.
#pragma once
#include <libknot/packet/pkt.h>
#warning TODO: this is private define
#include <common/lists.h>
#include <common/sockaddr.h>
#include <common/trie/hat-trie.h>
/*! \brief Name server flag. */
enum kr_ns_flag {
DP_LAME = 0,
DP_RESOLVED
DP_LAME = 0,
DP_PENDING = 1 << 0,
DP_RESOLVED = 1 << 1
};
struct kr_context;
......@@ -55,7 +54,6 @@ list_t *kr_delegmap_find(struct kr_delegmap *map, const knot_dname_t *name);
* choose next and move DPs from the other half for next sweep.
*/
struct kr_ns *kr_ns_create(const knot_dname_t *name, mm_ctx_t *mm);
void kr_ns_append(list_t *list, struct kr_ns *ns);
struct kr_ns *kr_ns_get(list_t *list, const knot_dname_t *name, mm_ctx_t *mm);
struct kr_ns *kr_ns_find(list_t *list, const knot_dname_t *name);
void kr_ns_remove(struct kr_ns *ns, mm_ctx_t *mm);
int kr_ns_resolve(struct kr_ns *ns);
......@@ -22,6 +22,7 @@ limitations under the License.
#include <libknot/dnssec/random.h>
#include "lib/layer/iterate.h"
#include "lib/rplan.h"
static int glue_record(knot_pkt_t *pkt, const knot_dname_t *dp, struct sockaddr *sa)
{
......@@ -56,32 +57,32 @@ static int glue_record(knot_pkt_t *pkt, const knot_dname_t *dp, struct sockaddr
return 0;
}
static int evaluate_dp(const knot_rrset_t *dp, knot_pkt_t *pkt, struct kr_layer_param *param)
static int inspect_dp(const knot_rrset_t *ns_rr, knot_pkt_t *pkt, struct kr_layer_param *param)
{
struct kr_context *resolve = param->ctx;
/* Fetch delegation point. */
list_t *dplist = kr_delegmap_get(&resolve->dp_map, dp->owner);
if (dplist == NULL) {
list_t *dp = kr_delegmap_get(&resolve->dp_map, ns_rr->owner);
if (dp == NULL) {
return -1;
}
const knot_dname_t *dp_name = knot_ns_name(&dp->rrs, 0);
struct kr_ns *ns_new = kr_ns_create(dp_name, resolve->dp_map.pool);
const knot_dname_t *ns_name = knot_ns_name(&ns_rr->rrs, 0);
struct kr_ns *ns = kr_ns_get(dp, ns_name, resolve->dp_map.pool);
/* Check if there's a glue for the record. */
int ret = glue_record(pkt, dp_name, (struct sockaddr *)&ns_new->addr);
if (ret != 0) {
/* TODO: API for duplicates? */
ns_new->flags |= DP_LAME;
/* TODO: resolve. */
kr_ns_append(dplist, ns_new);
return -1;
/* Update only unresolved NSs. */
/* TODO: cache expiration */
if (ns->flags & DP_RESOLVED) {
return 0;
}
/* Add name server. */
ns_new->flags |= DP_RESOLVED;
kr_ns_append(dplist, ns_new);
/* Check if there's a glue for the record. */
int ret = glue_record(pkt, ns_name, (struct sockaddr *)&ns->addr);
if (ret == 0) {
ns->flags = DP_RESOLVED;
} else {
ns->flags = DP_LAME;
}
return 0;
}
......@@ -91,76 +92,130 @@ static int resolve_nonauth(knot_pkt_t *pkt, struct kr_layer_param *param)
const knot_pktsection_t *ns = knot_pkt_section(pkt, KNOT_AUTHORITY);
for (unsigned i = 0; i < ns->count; ++i) {
if (ns->rr[i].type == KNOT_RRTYPE_NS) {
evaluate_dp(&ns->rr[i], pkt, param);
inspect_dp(&ns->rr[i], pkt, param);
}
}
return NS_PROC_DONE;
}
static void follow_cname_chain(const knot_rrset_t *rr, struct kr_layer_param *param)
static void follow_cname_chain(const knot_dname_t **cname, const knot_rrset_t *rr,
struct kr_layer_param *param)
{
struct kr_context *resolve = param->ctx;
struct kr_result *result = param->result;
struct kr_query *cur = kr_rplan_next(&resolve->rplan);
assert(cur);
/* Follow chain from SNAME. */
if (knot_dname_is_equal(rr->owner, result->cname)) {
if (knot_dname_is_equal(rr->owner, *cname)) {
if (rr->type == KNOT_RRTYPE_CNAME) {
result->cname = knot_cname_name(&rr->rrs);
*cname = knot_cname_name(&rr->rrs);
} else {
/* Terminate CNAME chain. */
result->cname = resolve->sname;
*cname = cur->sname;
}
}
}
/*! \brief Result updates the original query. */
static int update_query(struct kr_query *qry, struct kr_result *result, const knot_rrset_t *rr)
{
knot_pkt_t *ans = result->ans;
knot_rrset_t *rr_copy = knot_rrset_copy(rr, &ans->mm);
if (rr_copy == NULL) {
return -1;
}
/* Write copied RR to the result packet. */
int ret = knot_pkt_put(ans, COMPR_HINT_NONE, rr_copy, KNOT_PF_FREE);
if (ret != 0) {
knot_rrset_free(&rr_copy, &ans->mm);
knot_wire_set_tc(ans->wire);
}
/* Free just the allocated container. */
mm_free(&ans->mm, rr_copy);
return ret;
}
/*! \brief Result updates a delegation point. */
static int update_deleg(struct kr_query *qry, struct kr_result *result, const knot_rrset_t *rr)
{
struct kr_ns *ns = qry->ext;
if (ns->flags & DP_RESOLVED) {
return 0;
}
if (!knot_dname_is_equal(ns->name, rr->owner)) {
return 0;
}
/* Fetch address. */
switch(rr->type) {
case KNOT_RRTYPE_A:
knot_a_addr(&rr->rrs, 0, (struct sockaddr_in *)&ns->addr);
break;
case KNOT_RRTYPE_AAAA:
knot_aaaa_addr(&rr->rrs, 0, (struct sockaddr_in6 *)&ns->addr);
break;
default:
return 0; /* Ignore unsupported RR type. */
}
/* Mark NS as resolved. */
sockaddr_port_set(&ns->addr, 53);
ns->flags = DP_RESOLVED;
return 0;
}
static int resolve_auth(knot_pkt_t *pkt, struct kr_layer_param *param)
{
struct kr_context *resolve = param->ctx;
struct kr_result *result = param->result;
knot_pkt_t *ans = result->ans;
struct kr_query *cur = kr_rplan_next(&resolve->rplan);
if (cur == NULL) {
return NS_PROC_FAIL;
}
/* Store flags. */
knot_wire_set_rcode(ans->wire, knot_wire_get_rcode(pkt->wire));
/* Add results to the final packet. */
/* TODO: API call */
result->cname = resolve->sname;
knot_pkt_begin(ans, KNOT_ANSWER);
const knot_dname_t *cname = cur->sname;
const knot_pktsection_t *an = knot_pkt_section(pkt, KNOT_ANSWER);
for (unsigned i = 0; i < an->count; ++i) {
knot_rrset_t *rr = knot_rrset_copy(&an->rr[i], &ans->mm);
if (rr == NULL) {
return NS_PROC_FAIL;
/* RR callbacks per query type. */
int ret = -1;
switch(cur->flags) {
case RESOLVE_QUERY: ret = update_query(cur, result, &an->rr[i]); break;
case RESOLVE_DELEG: ret = update_deleg(cur, result, &an->rr[i]); break;
default: assert(0); break;
}
int ret = knot_pkt_put(ans, COMPR_HINT_NONE, rr, KNOT_PF_FREE);
/* Check output. */
if (ret != 0) {
knot_rrset_free(&rr, &ans->mm);
knot_wire_set_tc(ans->wire);
return NS_PROC_FAIL;
}
/* Check canonical name. */
/* TODO: these may not come in order, queueing is needed. */
follow_cname_chain(rr, param);
/* Free just the allocated container. */
mm_free(&ans->mm, rr);
follow_cname_chain(&cname, &an->rr[i], param);
}
/* Follow canonical name as next SNAME. */
if (result->cname != resolve->sname) {
/* Reset name server scoring for new SNAME. */
resolve->sname = result->cname;
resolve->state = NS_PROC_MORE;
return NS_PROC_DONE;
if (cname != cur->sname) {
struct kr_query *next = kr_rplan_push(&resolve->rplan, cname,
cur->stype, cur->sclass);
if (next == NULL) {
return NS_PROC_FAIL;
}
}
/* Finished for the original SNAME. */
resolve->state = NS_PROC_DONE;
/* Store stats. */
gettimeofday(&result->t_end, NULL);
/* Resolved current SNAME. */
resolve->resolved_qry = cur;
return NS_PROC_DONE;
}
......@@ -174,10 +229,15 @@ static int resolve_error(knot_pkt_t *pkt, struct kr_layer_param *param)
/*! \brief Answer is paired to query. */
static bool is_answer_to_query(const knot_pkt_t *answer, struct kr_context *resolve)
{
struct kr_query *expect = kr_rplan_next(&resolve->rplan);
if (expect == NULL) {
return -1;
}
return knot_wire_get_id(resolve->query->wire) == knot_wire_get_id(answer->wire) &&
resolve->sclass == knot_pkt_qclass(answer) &&
resolve->stype == knot_pkt_qtype(answer) &&
knot_dname_is_equal(resolve->sname, knot_pkt_qname(answer));
expect->sclass == knot_pkt_qclass(answer) &&
expect->stype == knot_pkt_qtype(answer) &&
knot_dname_is_equal(expect->sname, knot_pkt_qname(answer));
}
/* State-less single resolution iteration step, not needed. */
......@@ -196,13 +256,15 @@ static int prepare_query(knot_layer_t *ctx, knot_pkt_t *pkt)
assert(pkt && ctx);
struct kr_layer_param *param = ctx->data;
struct kr_context* resolve = param->ctx;
struct kr_query *next = kr_rplan_next(&resolve->rplan);
if (next == NULL) {
return -1;
}
resolve->query = pkt;
knot_pkt_clear(pkt);
int ret = knot_pkt_put_question(pkt, resolve->sname, resolve->sclass, resolve->stype);
int ret = knot_pkt_put_question(pkt, next->sname, next->sclass, next->stype);
if (ret != KNOT_EOK) {
assert(0);
return NS_PROC_FAIL;
}
......@@ -210,7 +272,6 @@ static int prepare_query(knot_layer_t *ctx, knot_pkt_t *pkt)
/* Query complete, expect answer. */
return NS_PROC_MORE;
}
/*! \brief Resolve input query or continue resolution with followups.
......
......@@ -43,8 +43,7 @@ static const struct hint_info SBELT[HINT_COUNT] = {
static int reset(knot_layer_t *ctx)
{
/* TODO: sync cache, cleanup */
/* TODO: sync, cleanup after resolution */
return ctx->state;
}
......@@ -62,11 +61,10 @@ static int begin(knot_layer_t *ctx, void *param)
/* Initialize static root hints. */
for (unsigned i = 0; i < HINT_COUNT; ++i) {
struct kr_ns *ns = kr_ns_create(SBELT[i].name, resolve->dp_map.pool);
struct kr_ns *ns = kr_ns_get(dp, SBELT[i].name, resolve->dp_map.pool);
if (ns != NULL) {
sockaddr_set(&ns->addr, AF_INET, SBELT[i].addr, 53);
ns->flags |= DP_RESOLVED;
kr_ns_append(dp, ns);
ns->flags = DP_RESOLVED;
}
}
......
......@@ -2,60 +2,62 @@
#include <uv.h>
#include <libknot/processing/requestor.h>
#include <libknot/descriptor.h>
#include "lib/resolve.h"
#include "lib/layer/iterate.h"
#include "lib/layer/static.h"
#include "lib/layer/stats.h"
/* TODO: temporary */
#include <libknot/rrset-dump.h>
#include <common/print.h>
static void print_result(struct kr_result *result)
static int resolve_ns(struct kr_context *resolve, struct kr_ns *ns)
{
#ifndef NDEBUG
char *qnamestr = knot_dname_to_str(knot_pkt_qname(result->ans));
char *cnamestr = knot_dname_to_str(result->cname);
printf("resolution of %s -> %s\n", qnamestr, cnamestr);
free(qnamestr); free(cnamestr);
printf("rcode = %d (%u RR)\n", knot_wire_get_rcode(result->ans->wire), result->ans->rrset_count);
char strbuf[4096] = {0};
int buflen = sizeof(strbuf);
knot_dump_style_t style = {0};
for (unsigned i = 0; i < result->ans->rrset_count; ++i) {
int r = knot_rrset_txt_dump(&result->ans->rr[i], strbuf, buflen, &style);
if (r > 0) buflen -= r;
/* Create an address query. */
struct kr_query *qry = kr_rplan_push(&resolve->rplan, ns->name,
KNOT_CLASS_IN, KNOT_RRTYPE_A);
if (qry == NULL) {
return -1;
}
printf("%s", strbuf);
printf("queries: %u\n", result->nr_queries);
printf("rtt %.02f msecs\n", time_diff(&result->t_start, &result->t_end));
#endif
/* Resolve as delegation. */
qry->flags = RESOLVE_DELEG;
qry->ext = ns;
/* Mark as resolving. */
ns->flags |= DP_PENDING;
return 0;
}
static void iterate(struct knot_requestor *requestor, struct kr_context* ctx)
{
struct timeval timeout = { 5, 0 };
const struct kr_query *next = kr_rplan_next(&ctx->rplan);
assert(next);
/* Find closest delegation point. */
list_t *dp = kr_delegmap_find(&ctx->dp_map, ctx->sname);
list_t *dp = kr_delegmap_find(&ctx->dp_map, next->sname);
if (dp == NULL) {
ctx->state = NS_PROC_FAIL;
return;
}
struct kr_ns *ns = NULL;
WALK_LIST(ns, *dp) {
if (ns->flags & DP_RESOLVED) {
break;
struct kr_ns *ns = HEAD(*dp);
if (!(ns->flags & DP_RESOLVED)) {
/* Dependency loop or inaccessible resolvers, give up. */
if (ns->flags & DP_PENDING) {
ctx->state = NS_PROC_FAIL;
return;
}
/* TODO: validity */
}
assert(ns->flags & DP_RESOLVED);
resolve_ns(ctx, ns);
return;
}
/* Build query. */
/* Update context. */
knot_pkt_t *query = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, requestor->mm);
ctx->current_ns = ns;
ctx->query = query;
ctx->resolved_qry = NULL;
/* Resolve. */
struct knot_request *tx = knot_request_make(requestor->mm,
......@@ -64,10 +66,20 @@ static void iterate(struct knot_requestor *requestor, struct kr_context* ctx)
knot_requestor_enqueue(requestor, tx);
int ret = knot_requestor_exec(requestor, &timeout);
if (ret != 0) {
/* Move to the tail, and disable. */
rem_node((node_t *)ns);
add_tail(dp, (node_t *)ns);
ns->flags = DP_LAME;
kr_ns_remove(ns, ctx->dp_map.pool);
}
/* Pop resolved query. */
if (ctx->resolved_qry) {
kr_rplan_pop(&ctx->rplan, ctx->resolved_qry);
ctx->resolved_qry = NULL;
}
/* Continue resolution if has more queries planned. */
if (kr_rplan_next(&ctx->rplan) == NULL) {
ctx->state = NS_PROC_DONE;
} else {
ctx->state = NS_PROC_MORE;
}
}
......@@ -79,11 +91,8 @@ int kr_resolve(struct kr_context* ctx, struct kr_result* result,
}
/* Initialize context. */
ctx->sname = qname;
ctx->sclass = qclass;
ctx->stype = qtype;
ctx->state = NS_PROC_MORE;
ctx->query = NULL;
kr_rplan_push(&ctx->rplan, qname, qclass, qtype);
kr_result_init(ctx, result);
struct kr_layer_param param;
......@@ -102,7 +111,5 @@ int kr_resolve(struct kr_context* ctx, struct kr_result* result,
/* Clean up. */
knot_requestor_clear(&requestor);
print_result(result);
return 0;
}
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