Skip to content
Snippets Groups Projects
Commit 4c8ab94d authored by Marek Vavrusa's avatar Marek Vavrusa
Browse files

AXFR out processing, improved state handling.

parent 4bddc084
Branches
Tags
No related merge requests found
...@@ -2,9 +2,162 @@ ...@@ -2,9 +2,162 @@
#include "libknot/nameserver/axfr.h" #include "libknot/nameserver/axfr.h"
#include "libknot/nameserver/ns_proc_query.h" #include "libknot/nameserver/ns_proc_query.h"
#include "libknot/util/debug.h"
#include "common/descriptor.h"
#include "common/lists.h"
struct axfr_proc {
hattrie_iter_t *i;
unsigned cur_rrset;
list_t nodes;
};
static int axfr_put(knot_pkt_t *pkt, const knot_rrset_t *rrset)
{
const unsigned flags = KNOT_PF_NOTRUNC;
int ret = knot_pkt_put(pkt, 0, rrset, flags);
if (ret == KNOT_EOK && rrset->rrsigs) {
ret = knot_pkt_put(pkt, 0, rrset, flags);
}
return ret;
}
static int put_rrsets(knot_pkt_t *pkt, knot_node_t *node, struct axfr_proc *state)
{
int ret = KNOT_EOK;
/* Append all RRs. */
unsigned i = state->cur_rrset;
unsigned rrset_count = knot_node_rrset_count(node);
const knot_rrset_t **rrset = knot_node_rrsets_no_copy(node);
for (;i < rrset_count; ++i) {
/* Skip SOA and empty nodes. */
if (knot_rrset_type(rrset[i]) == KNOT_RRTYPE_SOA ||
knot_rrset_rdata_rr_count(rrset[i]) == 0) {
continue;
}
/* Put into packet. */
ret = axfr_put(pkt, rrset[i]);
if (ret != KNOT_EOK) { /* Keep for continuing. */
state->cur_rrset = i;
return ret;
}
}
state->cur_rrset = 0;
return ret;
}
static int answer_put_nodes(knot_pkt_t *pkt, struct axfr_proc *state)
{
/* Put responses. */
int ret = KNOT_EOK;
while(!hattrie_iter_finished(state->i)) {
knot_node_t *node = (knot_node_t *)*hattrie_iter_val(state->i);
ret = put_rrsets(pkt, node, state);
if (ret != KNOT_EOK) {
break;
}
hattrie_iter_next(state->i);
}
/* Finished all nodes. */
return ret;
}
static int answer_pkt(knot_pkt_t *pkt, struct query_data *qdata)
{
int ret = KNOT_EOK;
mm_ctx_t *mm = qdata->mm;
struct axfr_proc *state = qdata->ext;
knot_zone_contents_t *zone = pkt->zone->contents;
knot_rrset_t *soa_rr = knot_node_get_rrset(zone->apex, KNOT_RRTYPE_SOA);
/* Prepend SOA on first packet. */
if (state == NULL) {
ret = axfr_put(pkt, soa_rr);
if (ret != KNOT_EOK) {
return ret;
}
/* Begin zone iterator. */
state = mm->alloc(mm->ctx, sizeof(struct axfr_proc));
if (state == NULL) {
return KNOT_ENOMEM;
}
memset(state, 0, sizeof(struct axfr_proc));
init_list(&state->nodes);
ptrlist_add(&state->nodes, zone->nodes, mm);
ptrlist_add(&state->nodes, zone->nsec3_nodes, mm);
qdata->ext = state;
}
/* Put zone contents and then NSEC3-related contents. */
while (!EMPTY_LIST(state->nodes)) {
ptrnode_t *head = HEAD(state->nodes);
if (state->i == NULL) {
state->i = hattrie_iter_begin(head->d, true);
}
ret = answer_put_nodes(pkt, state);
if (ret == KNOT_EOK) { /* Finished. */
hattrie_iter_free(state->i);
state->i = NULL;
rem_node((node_t *)head);
mm->free(head);
} else { /* Packet full or error. */
break;
}
}
/* Append SOA on last packet. */
if (ret == KNOT_EOK) {
ret = axfr_put(pkt, soa_rr);
}
/* Check if finished or not. */
if (ret != KNOT_ESPACE) {
/* Finished successfuly or fatal error. */
ptrlist_free(&state->nodes, mm);
mm->free(state);
qdata->ext = NULL;
}
return ret;
}
int axfr_answer(knot_pkt_t *pkt, knot_nameserver_t *ns, struct query_data *qdata) int axfr_answer(knot_pkt_t *pkt, knot_nameserver_t *ns, struct query_data *qdata)
{ {
qdata->rcode = KNOT_RCODE_NOTIMPL; assert(pkt);
return NS_PROC_FAIL; assert(ns);
assert(qdata);
/* Check zone state. */
switch(knot_zone_state(pkt->zone)) {
case KNOT_EOK:
break;
case KNOT_ENOENT:
qdata->rcode = KNOT_RCODE_NOTAUTH;
return NS_PROC_FAIL;
default:
qdata->rcode = KNOT_RCODE_SERVFAIL;
return NS_PROC_FAIL;
}
/* Answer current packet (or continue). */
int ret = answer_pkt(pkt, qdata);
switch(ret) {
case KNOT_ESPACE: /* Couldn't write more, send packet and continue. */
return NS_PROC_FULL; /* Check for more. */
case KNOT_EOK: /* Last response. */
break;
default: /* Generic error. */
dbg_ns("%s: answered with ret = %s\n", __func__, knot_strerror(ret));
qdata->rcode = KNOT_RCODE_SERVFAIL;
return NS_PROC_FAIL;
}
return NS_PROC_FINISH;
} }
...@@ -4107,7 +4107,11 @@ void knot_ns_destroy(knot_nameserver_t **nameserver) ...@@ -4107,7 +4107,11 @@ void knot_ns_destroy(knot_nameserver_t **nameserver)
int ns_proc_begin(ns_proc_context_t *ctx, const ns_proc_module_t *module) int ns_proc_begin(ns_proc_context_t *ctx, const ns_proc_module_t *module)
{ {
/* #10 implement */ /* Only in inoperable state. */
if (ctx->state != NS_PROC_NOOP) {
return NS_PROC_NOOP;
}
ctx->module = module; ctx->module = module;
ctx->state = module->begin(ctx); ctx->state = module->begin(ctx);
...@@ -4117,6 +4121,11 @@ int ns_proc_begin(ns_proc_context_t *ctx, const ns_proc_module_t *module) ...@@ -4117,6 +4121,11 @@ int ns_proc_begin(ns_proc_context_t *ctx, const ns_proc_module_t *module)
int ns_proc_reset(ns_proc_context_t *ctx) int ns_proc_reset(ns_proc_context_t *ctx)
{ {
/* Only in operable state. */
if (ctx->state == NS_PROC_NOOP) {
return NS_PROC_NOOP;
}
/* #10 implement */ /* #10 implement */
ctx->state = ctx->module->reset(ctx); ctx->state = ctx->module->reset(ctx);
...@@ -4126,35 +4135,29 @@ int ns_proc_reset(ns_proc_context_t *ctx) ...@@ -4126,35 +4135,29 @@ int ns_proc_reset(ns_proc_context_t *ctx)
int ns_proc_finish(ns_proc_context_t *ctx) int ns_proc_finish(ns_proc_context_t *ctx)
{ {
/* Only in operable state. */
if (ctx->state == NS_PROC_NOOP) {
return NS_PROC_NOOP;
}
/* #10 implement */ /* #10 implement */
ctx->state = ctx->module->finish(ctx); ctx->state = ctx->module->finish(ctx);
/* Free packet buffers. */
knot_pkt_free(&ctx->in);
knot_pkt_free(&ctx->out);
dbg_ns("%s -> %d\n", __func__, ctx->state); dbg_ns("%s -> %d\n", __func__, ctx->state);
return ctx->state; return ctx->state;
} }
int ns_proc_in(const uint8_t *wire, uint16_t wire_len, ns_proc_context_t *ctx) int ns_proc_in(const uint8_t *wire, uint16_t wire_len, ns_proc_context_t *ctx)
{ {
/* #10 implement */ /* Only if expecting data. */
if (ctx->in == NULL) { if (ctx->state != NS_PROC_MORE) {
ctx->in = knot_pkt_new((uint8_t *)wire, wire_len, &ctx->mm); return NS_PROC_NOOP;
} else {
knot_pkt_reset(ctx->in, (uint8_t *)wire, wire_len);
} }
knot_pkt_t *pkt = ctx->in; knot_pkt_t *pkt = knot_pkt_new((uint8_t *)wire, wire_len, &ctx->mm);
knot_pkt_parse(pkt, 0); knot_pkt_parse(pkt, 0);
switch(ctx->state) { ctx->state = ctx->module->in(pkt, ctx);
case NS_PROC_MORE: ctx->state = ctx->module->in(pkt, ctx); break;
default:
assert(0); /* Improper use. */
return NS_PROC_NOOP;
}
dbg_ns("%s -> %d\n", __func__, ctx->state); dbg_ns("%s -> %d\n", __func__, ctx->state);
return ctx->state; return ctx->state;
...@@ -4162,24 +4165,20 @@ int ns_proc_in(const uint8_t *wire, uint16_t wire_len, ns_proc_context_t *ctx) ...@@ -4162,24 +4165,20 @@ int ns_proc_in(const uint8_t *wire, uint16_t wire_len, ns_proc_context_t *ctx)
int ns_proc_out(uint8_t *wire, uint16_t *wire_len, ns_proc_context_t *ctx) int ns_proc_out(uint8_t *wire, uint16_t *wire_len, ns_proc_context_t *ctx)
{ {
/* #10 implement */ knot_pkt_t *pkt = knot_pkt_new(wire, *wire_len, &ctx->mm);
if (ctx->out == NULL) { dbg_ns("%s: new TX packet %p\n", __func__, pkt);
ctx->out = knot_pkt_new(wire, *wire_len, &ctx->mm);
} else {
knot_pkt_reset(ctx->out, wire, *wire_len);
}
knot_pkt_t *pkt = ctx->out;
switch(ctx->state) { switch(ctx->state) {
case NS_PROC_FULL: ctx->state = ctx->module->out(pkt, ctx); break; case NS_PROC_FULL: ctx->state = ctx->module->out(pkt, ctx); break;
case NS_PROC_FAIL: ctx->state = ctx->module->err(pkt, ctx); break; case NS_PROC_FAIL: ctx->state = ctx->module->err(pkt, ctx); break;
default: default:
assert(0); /* Improper use. */ assert(0); /* Improper use. */
knot_pkt_free(&pkt);
return NS_PROC_NOOP; return NS_PROC_NOOP;
} }
*wire_len = pkt->size; *wire_len = pkt->size;
knot_pkt_free(&pkt);
dbg_ns("%s -> %d\n", __func__, ctx->state); dbg_ns("%s -> %d\n", __func__, ctx->state);
return ctx->state; return ctx->state;
......
...@@ -462,7 +462,6 @@ typedef struct ns_proc_context ...@@ -462,7 +462,6 @@ typedef struct ns_proc_context
uint16_t type; uint16_t type;
uint16_t flags; uint16_t flags;
void *data; void *data;
knot_pkt_t *in, *out;
int state; int state;
knot_nameserver_t *ns; knot_nameserver_t *ns;
......
...@@ -17,8 +17,8 @@ ...@@ -17,8 +17,8 @@
/* Forward decls. */ /* Forward decls. */
static int tsig_check(knot_pkt_t *pkt); static int tsig_check(knot_pkt_t *pkt);
static const knot_zone_t *answer_zone_find(knot_pkt_t *pkt, knot_zonedb_t *zonedb); static const knot_zone_t *answer_zone_find(const knot_pkt_t *pkt, knot_zonedb_t *zonedb);
static int prepare_answer(knot_pkt_t *query, knot_pkt_t *resp, ns_proc_context_t *ctx); static int prepare_answer(const knot_pkt_t *query, knot_pkt_t *resp, ns_proc_context_t *ctx);
int query_internet(knot_pkt_t *pkt, ns_proc_context_t *ctx); int query_internet(knot_pkt_t *pkt, ns_proc_context_t *ctx);
int query_chaos(knot_pkt_t *pkt, ns_proc_context_t *ctx); int query_chaos(knot_pkt_t *pkt, ns_proc_context_t *ctx);
...@@ -57,7 +57,7 @@ int ns_proc_query_reset(ns_proc_context_t *ctx) ...@@ -57,7 +57,7 @@ int ns_proc_query_reset(ns_proc_context_t *ctx)
/* Clear */ /* Clear */
assert(ctx); assert(ctx);
struct query_data *data = QUERY_DATA(ctx); struct query_data *data = QUERY_DATA(ctx);
data->pkt = NULL; knot_pkt_free(&data->pkt);
data->rcode = KNOT_RCODE_NOERROR; data->rcode = KNOT_RCODE_NOERROR;
data->rcode_tsig = 0; data->rcode_tsig = 0;
data->node = data->encloser = data->previous = NULL; data->node = data->encloser = data->previous = NULL;
...@@ -74,7 +74,7 @@ int ns_proc_query_finish(ns_proc_context_t *ctx) ...@@ -74,7 +74,7 @@ int ns_proc_query_finish(ns_proc_context_t *ctx)
ctx->mm.free(ctx->data); ctx->mm.free(ctx->data);
ctx->data = NULL; ctx->data = NULL;
return NS_PROC_FINISH; return NS_PROC_NOOP;
} }
int ns_proc_query_in(knot_pkt_t *pkt, ns_proc_context_t *ctx) int ns_proc_query_in(knot_pkt_t *pkt, ns_proc_context_t *ctx)
{ {
...@@ -92,6 +92,7 @@ int ns_proc_query_in(knot_pkt_t *pkt, ns_proc_context_t *ctx) ...@@ -92,6 +92,7 @@ int ns_proc_query_in(knot_pkt_t *pkt, ns_proc_context_t *ctx)
break; /* Supported. */ break; /* Supported. */
default: default:
dbg_ns("%s: query_type(%hu) NOT SUPPORTED\n", __func__, query_type); dbg_ns("%s: query_type(%hu) NOT SUPPORTED\n", __func__, query_type);
knot_pkt_free(&pkt);
return NS_PROC_NOOP; /* Refuse to process. */ return NS_PROC_NOOP; /* Refuse to process. */
} }
...@@ -252,7 +253,7 @@ static int tsig_check(knot_pkt_t *pkt) ...@@ -252,7 +253,7 @@ static int tsig_check(knot_pkt_t *pkt)
return KNOT_EOK; return KNOT_EOK;
} }
static const knot_zone_t *answer_zone_find(knot_pkt_t *pkt, knot_zonedb_t *zonedb) static const knot_zone_t *answer_zone_find(const knot_pkt_t *pkt, knot_zonedb_t *zonedb)
{ {
uint16_t qtype = knot_pkt_qtype(pkt); uint16_t qtype = knot_pkt_qtype(pkt);
uint16_t qclass = knot_pkt_qclass(pkt); uint16_t qclass = knot_pkt_qclass(pkt);
...@@ -267,7 +268,7 @@ static const knot_zone_t *answer_zone_find(knot_pkt_t *pkt, knot_zonedb_t *zoned ...@@ -267,7 +268,7 @@ static const knot_zone_t *answer_zone_find(knot_pkt_t *pkt, knot_zonedb_t *zoned
return ns_get_zone_for_qname(zonedb, qname, qtype); return ns_get_zone_for_qname(zonedb, qname, qtype);
} }
static int prepare_answer(knot_pkt_t *query, knot_pkt_t *resp, ns_proc_context_t *ctx) static int prepare_answer(const knot_pkt_t *query, knot_pkt_t *resp, ns_proc_context_t *ctx)
{ {
dbg_ns("%s(%p, %p, %p)\n", __func__, query, resp, ctx); dbg_ns("%s(%p, %p, %p)\n", __func__, query, resp, ctx);
......
...@@ -47,6 +47,7 @@ struct query_data { ...@@ -47,6 +47,7 @@ struct query_data {
const knot_node_t *node, *encloser, *previous; const knot_node_t *node, *encloser, *previous;
list_t wildcards; list_t wildcards;
mm_ctx_t *mm; mm_ctx_t *mm;
void *ext;
}; };
int ns_proc_query_begin(ns_proc_context_t *ctx); int ns_proc_query_begin(ns_proc_context_t *ctx);
......
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