Commit 93c5faf2 authored by Marek Vavruša's avatar Marek Vavruša

process_answer: support for SOA, notify + unittests

parent e913a5f7
......@@ -298,11 +298,13 @@ tests/dnssec_nsec3.c
tests/dnssec_sign.c
tests/dnssec_zone_nsec.c
tests/dthreads.c
tests/fake_server.h
tests/fdset.c
tests/hattrie.c
tests/hhash.c
tests/journal.c
tests/pkt.c
tests/process_answer.c
tests/process_query.c
tests/query_module.c
tests/rrl.c
......
......@@ -23,6 +23,7 @@
#include "knot/nameserver/internet.h"
#include "knot/nameserver/nsec_proofs.h"
#include "knot/nameserver/process_query.h"
#include "knot/nameserver/process_answer.h"
#include "knot/zone/zonedb.h"
/*! \brief Check if given node was already visited. */
......@@ -743,7 +744,7 @@ int ns_put_rr(knot_pkt_t *pkt, const knot_rrset_t *rr,
return ret;
}
/*! \brief Helper for internet_answer repetitive code. */
/*! \brief Helper for internet_query repetitive code. */
#define SOLVE_STEP(solver, state, context) \
state = (solver)(state, response, qdata, context); \
if (state == TRUNC) { \
......@@ -811,7 +812,7 @@ static int planned_answer(struct query_plan *plan, knot_pkt_t *response, struct
#undef SOLVE_STEP
int internet_answer(knot_pkt_t *response, struct query_data *qdata)
int internet_query(knot_pkt_t *response, struct query_data *qdata)
{
dbg_ns("%s(%p, %p)\n", __func__, response, qdata);
if (response == NULL || qdata == NULL) {
......@@ -855,3 +856,43 @@ int internet_query_plan(struct query_plan *plan)
return KNOT_EOK;
}
/*! \brief Process answer to SOA query. */
static int internet_answer_soa(knot_pkt_t *pkt, struct answer_data *data)
{
zone_t *zone = data->param->zone;
/* Expect SOA in answer section. */
const knot_pktsection_t *answer = knot_pkt_section(pkt, KNOT_ANSWER);
if (answer->count < 1 || answer->rr[0].type != KNOT_RRTYPE_SOA) {
return NS_PROC_FAIL;
}
/* Check if master has newer zone and schedule transfer. */
knot_rdataset_t *soa = node_rdataset(zone->contents->apex, KNOT_RRTYPE_SOA);
uint32_t our_serial = knot_soa_serial(soa);
uint32_t their_serial = knot_soa_serial(&answer->rr[0].rrs);
if (knot_serial_compare(our_serial, their_serial) >= 0) {
zone_events_schedule(zone, ZONE_EVENT_REFRESH, knot_soa_refresh(soa));
return NS_PROC_DONE; /* Our zone is up to date. */
}
/* Our zone is outdated, schedule zone transfer. */
zone_events_schedule(zone, ZONE_EVENT_XFER, ZONE_EVENT_NOW);
return NS_PROC_DONE;
}
int internet_answer(knot_pkt_t *pkt, struct answer_data *data)
{
if (pkt == NULL || data == NULL) {
return NS_PROC_FAIL;
}
/* As of now, server can only issue SOA queries. */
switch(knot_pkt_qtype(pkt)) {
case KNOT_RRTYPE_SOA:
return internet_answer_soa(pkt, data);
default:
return NS_PROC_NOOP;
}
}
......@@ -33,6 +33,7 @@
struct query_data;
struct query_plan;
struct query_module;
struct answer_data;
/*! \brief Internet query processing states. */
enum {
......@@ -47,12 +48,12 @@ enum {
};
/*!
* \brief Answer query from IN class zone.
* \brief Answer query from an IN class zone.
*
* \retval FAIL if it encountered an error.
* \retval DONE if finished.
*/
int internet_answer(knot_pkt_t *resp, struct query_data *qdata);
int internet_query(knot_pkt_t *resp, struct query_data *qdata);
/*!
* \brief Initialize query plan for IN class zone.
......@@ -61,6 +62,15 @@ int internet_answer(knot_pkt_t *resp, struct query_data *qdata);
*/
int internet_query_plan(struct query_plan *plan);
/*!
* \brief Process answer in an IN class zone.
*
* \retval FAIL if it encountered an error.
* \retval DONE if finished.
* \retval NOOP if not supported.
*/
int internet_answer(knot_pkt_t *pkt, struct answer_data *data);
/*!
* \brief Puts RRSet to packet, will store its RRSIG for later use.
*
......
......@@ -15,6 +15,10 @@
*/
#include "knot/nameserver/process_answer.h"
#include "knot/nameserver/internet.h"
#include "knot/nameserver/notify.h"
#include "knot/nameserver/ixfr.h"
#include "knot/nameserver/axfr.h"
static int noop(knot_pkt_t *pkt, knot_process_t *ctx)
{
......@@ -28,7 +32,7 @@ const knot_process_module_t _process_answer = {
&process_answer_finish,
&process_answer,
&noop,
&process_answer_cleanup
&noop
};
/*! \brief Accessor to query-specific data. */
......@@ -43,6 +47,15 @@ static void answer_data_init(knot_process_t *ctx, void *module_param)
data->param = module_param;
}
/*! \brief Answer is paired to query if MsgId and QUESTION matches. */
static bool is_answer_to_query(const knot_pkt_t *query, knot_pkt_t *answer)
{
return knot_wire_get_id(query->wire) == knot_wire_get_id(answer->wire) &&
knot_pkt_qtype(query) == knot_pkt_qtype(answer) &&
knot_pkt_qclass(query) == knot_pkt_qclass(answer) &&
knot_dname_is_equal(knot_pkt_qname(query), knot_pkt_qname(answer));
}
int process_answer_begin(knot_process_t *ctx, void *module_param)
{
/* Initialize context. */
......@@ -67,6 +80,7 @@ int process_answer_reset(knot_process_t *ctx)
/* Await packet. */
return NS_PROC_MORE;
}
int process_answer_finish(knot_process_t *ctx)
{
#warning TODO: finalize multi-packet
......@@ -76,32 +90,70 @@ int process_answer_finish(knot_process_t *ctx)
return NS_PROC_NOOP;
}
/*! \brief Process response in IN class zone. */
static int answer_internet(knot_pkt_t *pkt, knot_process_t *ctx)
{
struct answer_data *data = ANSWER_DATA(ctx);
int next_state = NS_PROC_FAIL;
switch(knot_pkt_type(pkt)) {
case KNOT_RESPONSE_NORMAL:
next_state = internet_answer(pkt, data);
break;
case KNOT_RESPONSE_AXFR:
break;
case KNOT_RESPONSE_IXFR:
break;
case KNOT_RESPONSE_NOTIFY:
next_state = NS_PROC_DONE; /* No processing. */
break;
default:
next_state = NS_PROC_NOOP;
break;
}
return next_state;
}
int process_answer(knot_pkt_t *pkt, knot_process_t *ctx)
{
assert(pkt && ctx);
struct answer_data *data = ANSWER_DATA(ctx);
/* Check if at least header is parsed. */
if (pkt->parsed < KNOT_WIRE_HEADER_SIZE || !knot_wire_get_qr(pkt->wire)) {
knot_pkt_free(&pkt);
return NS_PROC_NOOP; /* Ignore. */
}
/* Check parse state. */
int next_state = NS_PROC_DONE;
if (pkt->parsed < pkt->size) {
knot_pkt_clear(pkt);
if (pkt->parsed < KNOT_WIRE_HEADER_SIZE || pkt->parsed < pkt->size) {
next_state = NS_PROC_FAIL;
goto finish;
}
#warning TODO: process the actual packet
/* Accept only responses. */
if (!knot_wire_get_qr(pkt->wire)) {
next_state = NS_PROC_NOOP;
goto finish;
}
/* Check if we want answer paired to query. */
const knot_pkt_t *query = data->param->query;
if (query && !is_answer_to_query(query, pkt)) {
next_state = NS_PROC_NOOP; /* Ignore */
goto finish;
}
#warning TODO: check TSIG here?
/* Class specific answer processing. */
switch (knot_pkt_qclass(pkt)) {
case KNOT_CLASS_IN:
next_state = answer_internet(pkt, ctx);
break;
default: /* No known processor. */
next_state = NS_PROC_NOOP;
break;
}
finish:
knot_pkt_free(&pkt);
return next_state;
}
int process_answer_cleanup(knot_pkt_t *pkt, knot_process_t *ctx)
{
#warning TODO: cleanup multi-packet
return NS_PROC_DONE;
}
\ No newline at end of file
......@@ -26,9 +26,8 @@ extern const knot_process_module_t _process_answer;
/* Module load parameters. */
struct process_answer_param {
zone_t *zone;
int socket;
const knot_pkt_t *query;
struct sockaddr_storage *remote;
const struct sockaddr_storage *remote;
};
struct answer_data
......@@ -79,12 +78,3 @@ int process_answer_finish(knot_process_t *ctx);
* \retval FAIL (processing failed)
*/
int process_answer(knot_pkt_t *pkt, knot_process_t *ctx);
/*!
* \brief Cleanup after failed answer processing.
*
* \param pkt
* \param ctx
* \retval DONE (finished)
*/
int process_answer_cleanup(knot_pkt_t *pkt, knot_process_t *ctx);
......@@ -363,7 +363,7 @@ static int query_internet(knot_pkt_t *pkt, knot_process_t *ctx)
switch(data->packet_type) {
case KNOT_QUERY_NORMAL:
next_state = internet_answer(pkt, data);
next_state = internet_query(pkt, data);
break;
case KNOT_QUERY_NOTIFY:
next_state = internet_notify(pkt, data);
......
......@@ -8,30 +8,31 @@ LDADD = \
$(top_builddir)/src/libknots.la
check_PROGRAMS = \
journal \
slab \
hattrie \
hhash \
dthreads \
acl \
fdset \
base64 \
base32hex \
descriptor \
server \
conf \
rrl \
wire \
dname \
ztree \
zonedb \
dnssec_keys \
journal \
slab \
hattrie \
hhash \
dthreads \
acl \
fdset \
base64 \
base32hex \
descriptor \
server \
conf \
rrl \
wire \
dname \
ztree \
zonedb \
dnssec_keys \
dnssec_nsec3 \
dnssec_sign \
dnssec_sign \
dnssec_zone_nsec \
rrset \
pkt \
process_query \
rrset \
pkt \
process_query \
process_answer \
query_module
check-compile-only: $(check_PROGRAMS)
......@@ -46,6 +47,8 @@ EXTRA_DIST = data
dist_check_SCRIPTS = resource.sh
conf_SOURCES = conf.c sample_conf.h
process_query_SOURCES = process_query.c fake_server.h
process_answer_SOURCES = process_answer.c fake_server.h
nodist_conf_SOURCES = sample_conf.c
CLEANFILES = sample_conf.c runtests.log
sample_conf.c: data/sample_conf
......
#pragma once
#include "knot/server/server.h"
#include "common/mempattern.h"
/* Some domain names. */
#define ROOT_DNAME ((const uint8_t *)"")
#define EXAMPLE_DNAME ((const uint8_t *)"\x7""example")
#define IDSERVER_DNAME ((const uint8_t *)"\2""id""\6""server")
/* Create fake root zone. */
static inline void create_root_zone(server_t *server, mm_ctx_t *mm)
{
/* SOA RDATA. */
#define SOA_RDLEN 30
static const uint8_t SOA_RDATA[SOA_RDLEN] = {
0x02, 0x6e, 0x73, 0x00, /* ns. */
0x04, 'm', 'a', 'i', 'l', 0x00,/* mail. */
0x77, 0xdf, 0x1e, 0x63, /* serial */
0x00, 0x01, 0x51, 0x80, /* refresh */
0x00, 0x00, 0x1c, 0x20, /* retry */
0x00, 0x0a, 0x8c, 0x00, /* expire */
0x00, 0x00, 0x0e, 0x10 /* min ttl */
};
/* Insert root zone. */
conf_zone_t *conf = malloc(sizeof(conf_zone_t));
conf_init_zone(conf);
conf->name = strdup(".");
zone_t *root = zone_new(conf);
root->contents = zone_contents_new(root->name);
knot_rrset_t *soa = knot_rrset_new(root->name, KNOT_RRTYPE_SOA, KNOT_CLASS_IN, mm);
knot_rrset_add_rdata(soa, SOA_RDATA, SOA_RDLEN, 7200, mm);
node_add_rrset(root->contents->apex, soa, NULL);
knot_rrset_free(&soa, mm);
/* Bake the zone. */
zone_node_t *first_nsec3 = NULL, *last_nsec3 = NULL;
zone_contents_adjust_full(root->contents, &first_nsec3, &last_nsec3);
/* Switch zone db. */
knot_zonedb_free(&server->zone_db);
server->zone_db = knot_zonedb_new(1);
knot_zonedb_insert(server->zone_db, root);
knot_zonedb_build_index(server->zone_db);
}
/* Create fake server. */
static inline void create_fake_server(server_t *server, mm_ctx_t *mm)
{
/* Create name server. */
server_init(server);
server->opt_rr = knot_edns_new();
knot_edns_set_version(server->opt_rr, EDNS_VERSION);
knot_edns_set_payload(server->opt_rr, 4096);
/* Create configuration. */
s_config = conf_new(strdup("rc:/noconf"));
conf()->identity = strdup("bogus.ns");
conf()->version = strdup("0.11");
/* Insert root zone. */
create_root_zone(server, mm);
}
/* Copyright (C) 2013 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <tap/basic.h>
#include <string.h>
#include <stdlib.h>
#include "common/mempool.h"
#include "common/descriptor.h"
#include "libknot/packet/wire.h"
#include "knot/nameserver/process_answer.h"
#include "fake_server.h"
/* @note Test helpers. */
#define TEST_RESET() \
knot_process_reset(proc); \
knot_pkt_clear(pkt)
#define TEST_EXEC(expect, info) {\
int state = knot_process_in(pkt->wire, pkt->size, proc); \
is_int((expect), state, "proc_answer: " info); \
}
#define INVALID_COUNT 2
#define SPECIFIC_COUNT 4
#define INCLASS_COUNT 2
#define TEST_COUNT INVALID_COUNT + SPECIFIC_COUNT + INCLASS_COUNT
static void test_invalid(knot_pkt_t *pkt, knot_process_t *proc)
{
/* Invalid packet - query. */
TEST_RESET();
knot_pkt_put_question(pkt, ROOT_DNAME, KNOT_CLASS_IN, KNOT_RRTYPE_A);
TEST_EXEC(NS_PROC_NOOP, "ignored query");
/* Invalid packet - mangled. */
TEST_RESET();
knot_pkt_put_question(pkt, ROOT_DNAME, KNOT_CLASS_IN, KNOT_RRTYPE_A);
pkt->size += 1; /* Mangle size. */
TEST_EXEC(NS_PROC_FAIL, "malformed query");
}
/* Test if context accepts only answer to specific query. */
static void test_specific(knot_pkt_t *pkt, knot_process_t *proc, struct process_answer_param *param)
{
/* Set specific SOA query. */
uint16_t query_id = 0xBEEF;
knot_pkt_t *query = knot_pkt_new(NULL, KNOT_WIRE_MIN_PKTSIZE, &proc->mm);
assert(query);
knot_pkt_put_question(query, ROOT_DNAME, KNOT_CLASS_IN, KNOT_RRTYPE_SOA);
knot_wire_set_id(query->wire, query_id);
param->query = query;
/* MSGID mismatch */
TEST_RESET();
knot_pkt_init_response(pkt, param->query);
knot_wire_set_id(pkt->wire, 0xDEAD);
TEST_EXEC(NS_PROC_NOOP, "ignored mismatching MSGID");
/* QCLASS mismatch */
TEST_RESET();
knot_pkt_put_question(pkt, ROOT_DNAME, KNOT_CLASS_CH, KNOT_RRTYPE_SOA);
knot_wire_set_id(pkt->wire, query_id);
knot_wire_set_qr(pkt->wire);
TEST_EXEC(NS_PROC_NOOP, "ignored mismatching QCLASS");
/* QTYPE mismatch. */
TEST_RESET();
knot_pkt_put_question(pkt, ROOT_DNAME, KNOT_CLASS_IN, KNOT_RRTYPE_TXT);
knot_wire_set_id(pkt->wire, query_id);
knot_wire_set_qr(pkt->wire);
TEST_EXEC(NS_PROC_NOOP, "ignored mismatching QTYPE");
/* QNAME mismatch. */
TEST_RESET();
knot_pkt_put_question(pkt, EXAMPLE_DNAME, KNOT_CLASS_IN, KNOT_RRTYPE_SOA);
knot_wire_set_id(pkt->wire, query_id);
knot_wire_set_qr(pkt->wire);
TEST_EXEC(NS_PROC_NOOP, "ignored mismatching QNAME");
/* Clear the specific query. */
knot_pkt_free(&query);
param->query = NULL;
}
static void test_inclass(knot_pkt_t *pkt, knot_process_t *proc, struct process_answer_param *param)
{
/* SOA query answer. */
TEST_RESET();
zone_node_t *apex = param->zone->contents->apex;
knot_rrset_t soa = node_rrset(apex, KNOT_RRTYPE_SOA);
knot_pkt_put_question(pkt, ROOT_DNAME, KNOT_CLASS_IN, KNOT_RRTYPE_SOA);
knot_wire_set_qr(pkt->wire);
knot_pkt_begin(pkt, KNOT_ANSWER);
knot_pkt_put(pkt, COMPR_HINT_OWNER, &soa, 0);
TEST_EXEC(NS_PROC_DONE, "IN/SOA answer");
/* Unsupported anwer. */
TEST_RESET();
knot_pkt_put_question(pkt, ROOT_DNAME, KNOT_CLASS_IN, KNOT_RRTYPE_TXT);
knot_wire_set_qr(pkt->wire);
TEST_EXEC(NS_PROC_NOOP, "IN/unsupported answer");
}
int main(int argc, char *argv[])
{
plan(2 + TEST_COUNT);
/* Create processing context. */
knot_process_t proc;
memset(&proc, 0, sizeof(knot_process_t));
mm_ctx_mempool(&proc.mm, sizeof(knot_pkt_t));
/* Create fake server environment. */
server_t server;
create_fake_server(&server, &proc.mm);
/* Prepare. */
struct sockaddr_storage remote;
memset(&remote, 0, sizeof(struct sockaddr_storage));
sockaddr_set(&remote, AF_INET, "127.0.0.1", 53);
struct process_answer_param param = {0};
param.remote = &remote;
param.zone = knot_zonedb_find(server.zone_db, ROOT_DNAME);
knot_pkt_t *pkt = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, &proc.mm);
/* Begin processing. */
int state = knot_process_begin(&proc, &param, NS_PROC_ANSWER);
ok(state == NS_PROC_MORE, "proc_answer: expects packet after init");
/* Invalid generic input tests. */
test_invalid(pkt, &proc);
/* Specific input tests (response to given query). */
test_specific(pkt, &proc, &param);
/* IN_CLASS input tests. */
test_inclass(pkt, &proc, &param);
/* IXFR input tests. */
/* AXFR input tests. */
/* NOTIFY input tests. */
/* TSIG check tests. */
/* Finish. */
state = knot_process_finish(&proc);
ok(state == NS_PROC_NOOP, "proc_answer: processing end" );
/* Cleanup. */
mp_delete((struct mempool *)proc.mm.ctx);
server_deinit(&server);
return 0;
}
#undef TEST_RESET
#undef TEST_EXEC
......@@ -23,46 +23,7 @@
#include "common/descriptor.h"
#include "libknot/packet/wire.h"
#include "knot/nameserver/process_query.h"
/* SOA RDATA. */
#define SOA_RDLEN 30
static const uint8_t SOA_RDATA[SOA_RDLEN] = {
0x02, 0x6e, 0x73, 0x00, /* ns. */
0x04, 'm', 'a', 'i', 'l', 0x00,/* mail. */
0x77, 0xdf, 0x1e, 0x63, /* serial */
0x00, 0x01, 0x51, 0x80, /* refresh */
0x00, 0x00, 0x1c, 0x20, /* retry */
0x00, 0x0a, 0x8c, 0x00, /* expire */
0x00, 0x00, 0x0e, 0x10 /* min ttl */
};
/* Create fake root zone. */
void create_root_zone(server_t *server, mm_ctx_t *mm)
{
/* Insert root zone. */
conf_zone_t *conf = malloc(sizeof(conf_zone_t));
conf_init_zone(conf);
conf->name = strdup(".");
zone_t *root = zone_new(conf);
root->contents = zone_contents_new(root->name);
knot_rrset_t *soa_rrset = knot_rrset_new(root->name,
KNOT_RRTYPE_SOA, KNOT_CLASS_IN,
NULL);
knot_rrset_add_rdata(soa_rrset, SOA_RDATA, SOA_RDLEN, 7200, NULL);
node_add_rrset(root->contents->apex, soa_rrset, NULL);
/* Bake the zone. */
zone_node_t *first_nsec3 = NULL, *last_nsec3 = NULL;
zone_contents_adjust_full(root->contents, &first_nsec3, &last_nsec3);
/* Switch zone db. */
knot_zonedb_free(&server->zone_db);
server->zone_db = knot_zonedb_new(1);
knot_zonedb_insert(server->zone_db, root);
knot_zonedb_build_index(server->zone_db);
}
#include "fake_server.h"
/* Basic response check (4 TAP tests). */
static void answer_sanity_check(const uint8_t *query,
......@@ -112,38 +73,22 @@ static void exec_query(knot_process_t *query_ctx, const char *name,
memcpy(dst, src, src_len); \
dst_len = src_len;
#define ROOT_DNAME ((const uint8_t *)"")
int main(int argc, char *argv[])
{
plan(8*6 + 3); /* exec_query = 6 TAP tests */
/* Create processing context. */
knot_process_t query_ctx;
memset(&query_ctx, 0, sizeof(knot_process_t));
mm_ctx_mempool(&query_ctx.mm, sizeof(knot_pkt_t));
knot_process_t proc;
memset(&proc, 0, sizeof(knot_process_t));
mm_ctx_mempool(&proc.mm, sizeof(knot_pkt_t));
/* Create name server. */
/* Create fake server environment. */
server_t server;
server_init(&server);
server.opt_rr = knot_edns_new();
knot_edns_set_version(server.opt_rr, EDNS_VERSION);
knot_edns_set_payload(server.opt_rr, 4096);
/* Create configuration. */
s_config = conf_new(strdup("rc:/noconf"));
conf()->identity = strdup("bogus.ns");
conf()->version = strdup("0.11");
/* Insert root zone. */
create_root_zone(&server, &query_ctx.mm);
create_fake_server(&server, &proc.mm);
zone_t *zone = knot_zonedb_find(server.zone_db, ROOT_DNAME);
/* Prepare. */
int state = NS_PROC_FAIL;
uint8_t query_wire[KNOT_WIRE_MAX_PKTSIZE];
uint16_t query_len = KNOT_WIRE_MAX_PKTSIZE;
knot_pkt_t *query = knot_pkt_new(query_wire, query_len, &query_ctx.mm);
knot_pkt_t *query = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, &proc.mm);
/* Create query processing parameter. */
struct sockaddr_storage ss;
......@@ -154,51 +99,50 @@ int main(int argc, char *argv[])
param.server = &server;
/* Query processor (CH zone) */
state = knot_process_begin(&query_ctx, &param, NS_PROC_QUERY);
const uint8_t chaos_dname[] = "\2""id""\6""server"; /* id.server */
int state = knot_process_begin(&proc, &param, NS_PROC_QUERY);
knot_pkt_clear(query);
knot_pkt_put_question(query, chaos_dname, KNOT_CLASS_CH, KNOT_RRTYPE_TXT);
exec_query(&query_ctx, "CH TXT", query->wire, query->size, KNOT_RCODE_NOERROR);
knot_pkt_put_question(query, IDSERVER_DNAME, KNOT_CLASS_CH, KNOT_RRTYPE_TXT);
exec_query(&proc, "CH TXT", query->wire, query->size, KNOT_RCODE_NOERROR);
/* Query processor (valid input). */
state = knot_process_reset(&query_ctx);
state = knot_process_reset(&proc);
knot_pkt_clear(query);
knot_pkt_put_question(query, ROOT_DNAME, KNOT_CLASS_IN, KNOT_RRTYPE_SOA);
exec_query(&query_ctx, "IN/root", query->wire, query->size, KNOT_RCODE_NOERROR);
exec_query(&proc, "IN/root", query->wire, query->size, KNOT_RCODE_NOERROR);
/* Query processor (-1 bytes, not enough data). */
state = knot_process_reset(&query_ctx);
exec_query(&query_ctx, "IN/few-data", query->wire, query->size - 1, KNOT_RCODE_FORMERR);
state = knot_process_reset(&proc);
exec_query(&proc, "IN/few-data", query->wire, query->size - 1, KNOT_RCODE_FORMERR);
/* Query processor (+1 bytes trailing). */
state = knot_process_reset(&query_ctx);
state = knot_process_reset(&proc);
query->wire[query->size] = '\1'; /* Initialize the "garbage" value. */
exec_query(&query_ctx, "IN/trail-garbage", query->wire, query->size + 1, KNOT_RCODE_FORMERR);
exec_query(&proc, "IN/trail-garbage", query->wire, query->size + 1, KNOT_RCODE_FORMERR);
/* Forge NOTIFY query from SOA query. */
state = knot_process_reset(&query_ctx);
state = knot_process_reset(&proc);
knot_wire_set_opcode(query->wire, KNOT_OPCODE_NOTIFY);
exec_query(&query_ctx, "IN/notify", query->wire, query->size, KNOT_RCODE_NOTAUTH);
exec_query(&proc, "IN/notify", query->wire, query->size, KNOT_RCODE_NOTAUTH);
/* Forge AXFR query. */
knot_process_reset(&query_ctx);
knot_process_reset(&proc);
knot_pkt_clear(query);
knot_pkt_put_question(query, ROOT_DNAME, KNOT_CLASS_IN, KNOT_RRTYPE_AXFR);
exec_query(&query_ctx, "IN/axfr", query->wire, query->size, KNOT_RCODE_NOTAUTH);
exec_query(&proc, "IN/axfr", query->wire, query->size, KNOT_RCODE_NOTAUTH);
/* Forge IXFR query (badly formed, no SOA in AUTHORITY section). */
knot_process_reset(&query_ctx);
knot_process_reset(&proc);
knot_pkt_clear(query);
knot_pkt_put_question(query, ROOT_DNAME, KNOT_CLASS_IN, KNOT_RRTYPE_IXFR);
exec_query(&query_ctx, "IN/ixfr-formerr", query->wire, query->size, KNOT_RCODE_FORMERR);
exec_query(&proc, "IN/ixfr-formerr", query->wire, query->size, KNOT_RCODE_FORMERR);
/* Forge IXFR query (well formed). */
knot_process_reset(&query_ctx);
knot_process_reset(&proc);
/* Append SOA RR. */
knot_rrset_t soa_rr = node_rrset(zone->contents->apex, KNOT_RRTYPE_SOA);
knot_pkt_begin(query, KNOT_AUTHORITY);
knot_pkt_put(query</