req->pool = pool;
req->vars_ref = LUA_NOREF;
req->uid = uid;
+ req->daemon_context = worker;
/* Remember query source addr */
if (!addr || (addr->sa_family != AF_INET && addr->sa_family != AF_INET6)) {
KNOT_WIRE_MIN_PKTSIZE);
}
req->qsource.size = query->size;
+ if (knot_pkt_has_tsig(query)) {
+ req->qsource.size += query->tsig_wire.len;
+ }
- req->answer = knot_pkt_new(NULL, answer_max, &req->pool);
- if (!req->answer) {
+ knot_pkt_t *answer = knot_pkt_new(NULL, answer_max, &req->pool);
+ if (!answer) { /* Failed to allocate answer */
return kr_error(ENOMEM);
}
- /* Remember query source TSIG key */
- if (query->tsig_rr) {
- req->qsource.key = knot_rrset_copy(query->tsig_rr, &req->pool);
+ knot_pkt_t *pkt = knot_pkt_new(NULL, req->qsource.size, &req->pool);
+ if (!pkt) {
+ return kr_error(ENOMEM);
}
-
- /* Remember query source EDNS data */
- if (query->opt_rr) {
- req->qsource.opt = knot_rrset_copy(query->opt_rr, &req->pool);
+ if (knot_pkt_copy(pkt, query) != 0) {
+ return kr_error(ENOMEM);
}
+ req->qsource.packet = pkt;
+
/* Start resolution */
struct worker_ctx *worker = ctx->worker;
struct engine *engine = worker->engine;
- kr_resolve_begin(req, &engine->resolver, req->answer);
+ kr_resolve_begin(req, &engine->resolver, answer);
worker->stats.queries += 1;
/* Throttle outbound queries only when high pressure */
if (worker->stats.concurrent < QUERY_RATE_THRESHOLD) {
return 0;
}
struct request_ctx *ctx = task->ctx;
+ struct session *source_session = ctx->source.session;
kr_resolve_finish(&ctx->req, state);
task->finished = true;
- if (ctx->source.session == NULL) {
+ if (source_session == NULL) {
(void) qr_task_on_send(task, NULL, kr_error(EIO));
return state == KR_STATE_DONE ? 0 : kr_error(EIO);
}
qr_task_ref(task);
/* Send back answer */
- struct session *source_session = ctx->source.session;
assert(!session_flags(source_session)->closing);
assert(ctx->source.addr.ip.sa_family != AF_UNSPEC);
int res = qr_task_send(task, source_session,
static int consume_yield(kr_layer_t *ctx, knot_pkt_t *pkt)
{
struct kr_request *req = ctx->req;
- knot_pkt_t *pkt_copy = knot_pkt_new(NULL, pkt->size, &req->pool);
+ size_t pkt_size = pkt->size;
+ if (knot_pkt_has_tsig(pkt)) {
+ pkt_size += pkt->tsig_wire.len;
+ }
+ knot_pkt_t *pkt_copy = knot_pkt_new(NULL, pkt_size, &req->pool);
struct kr_layer_pickle *pickle = mm_alloc(&req->pool, sizeof(*pickle));
if (pickle && pkt_copy && knot_pkt_copy(pkt_copy, pkt) == 0) {
struct kr_query *qry = req->current_query;
static int finish_yield(kr_layer_t *ctx) { return kr_ok(); }
static int produce_yield(kr_layer_t *ctx, knot_pkt_t *pkt) { return kr_ok(); }
static int checkout_yield(kr_layer_t *ctx, knot_pkt_t *packet, struct sockaddr *dst, int type) { return kr_ok(); }
+static int answer_finalize_yield(kr_layer_t *ctx) { return kr_ok(); }
/** @internal Macro for iterating module layers. */
#define RESUME_LAYERS(from, r, qry, func, ...) \
return ret;
}
-static int edns_put(knot_pkt_t *pkt)
+static int edns_put(knot_pkt_t *pkt, bool reclaim)
{
if (!pkt->opt_rr) {
return kr_ok();
}
- /* Reclaim reserved size. */
- int ret = knot_pkt_reclaim(pkt, knot_edns_wire_size(pkt->opt_rr));
- if (ret != 0) {
- return ret;
+ if (reclaim) {
+ /* Reclaim reserved size. */
+ int ret = knot_pkt_reclaim(pkt, knot_edns_wire_size(pkt->opt_rr));
+ if (ret != 0) {
+ return ret;
+ }
}
/* Write to packet. */
assert(pkt->current == KNOT_ADDITIONAL);
return knot_pkt_reserve(pkt, wire_size);
}
-static int answer_prepare(knot_pkt_t *answer, knot_pkt_t *query, struct kr_request *req)
+static int answer_prepare(struct kr_request *req, knot_pkt_t *query)
{
+ knot_pkt_t *answer = req->answer;
if (knot_pkt_init_response(answer, query) != 0) {
return kr_error(ENOMEM); /* Failed to initialize answer */
}
/* Handle EDNS in the query */
if (knot_pkt_has_edns(query)) {
- int ret = edns_create(answer, query, req);
- if (ret != 0){
- return ret;
+ answer->opt_rr = knot_rrset_copy(req->ctx->opt_rr, &answer->mm);
+ if (answer->opt_rr == NULL){
+ return kr_error(ENOMEM);
}
/* Set DO bit if set (DNSSEC requested). */
if (knot_pkt_has_dnssec(query)) {
/* OPT in SERVFAIL response is still useful for cookies/additional info. */
knot_pkt_begin(answer, KNOT_ADDITIONAL);
answer_padding(request); /* Ignore failed padding in SERVFAIL answer. */
- ret = edns_put(answer);
+ ret = edns_put(answer, false);
}
return ret;
}
return answer_fail(request);
}
/* Write EDNS information */
- int ret = 0;
if (answer->opt_rr) {
if (request->has_tls) {
if (answer_padding(request) != kr_ok()) {
}
}
knot_pkt_begin(answer, KNOT_ADDITIONAL);
- ret = edns_put(answer);
+ int ret = knot_pkt_put(answer, KNOT_COMPR_HINT_NONE,
+ answer->opt_rr, KNOT_PF_FREE);
+ if (ret != KNOT_EOK) {
+ return answer_fail(request);
+ }
}
if (!last) secure = false; /*< should be no-op, mostly documentation */
knot_wire_clear_ad(answer->wire);
}
- return ret;
+ return kr_ok();
}
static int query_finalize(struct kr_request *request, struct kr_query *qry, knot_pkt_t *pkt)
/* Stub resolution (ask for +rd and +do) */
if (qry->flags.STUB) {
knot_wire_set_rd(pkt->wire);
- if (knot_pkt_has_dnssec(request->answer)) {
+ if (knot_pkt_has_dnssec(request->qsource.packet)) {
knot_edns_set_do(pkt->opt_rr);
}
- if (knot_wire_get_cd(request->answer->wire)) {
+ if (knot_wire_get_cd(request->qsource.packet->wire)) {
knot_wire_set_cd(pkt->wire);
}
/* Full resolution (ask for +cd and +do) */
knot_edns_set_do(pkt->opt_rr);
knot_wire_set_cd(pkt->wire);
}
- ret = edns_put(pkt);
+ ret = edns_put(pkt, true);
}
}
return ret;
const knot_dname_t *qname = knot_pkt_qname(packet);
uint16_t qclass = knot_pkt_qclass(packet);
uint16_t qtype = knot_pkt_qtype(packet);
- bool cd_is_set = knot_wire_get_cd(packet->wire);
struct kr_query *qry = NULL;
struct kr_context *ctx = request->ctx;
struct kr_cookie_ctx *cookie_ctx = ctx ? &ctx->cookie_ctx : NULL;
knot_wire_set_ra(answer->wire);
knot_wire_set_rcode(answer->wire, KNOT_RCODE_NOERROR);
- if (cd_is_set) {
+ assert(request->qsource.packet);
+ if (knot_wire_get_cd(request->qsource.packet->wire)) {
knot_wire_set_cd(answer->wire);
} else if (qry->flags.DNSSEC_WANT) {
knot_wire_set_ad(answer->wire);
}
/* Expect answer, pop if satisfied immediately */
- request->qsource.packet = packet;
ITERATE_LAYERS(request, qry, begin);
- request->qsource.packet = NULL;
if ((request->state & KR_STATE_DONE) != 0) {
kr_rplan_pop(rplan, qry);
} else if (qname == NULL) {
/* Empty resolution plan, push packet as the new query */
if (packet && kr_rplan_empty(rplan)) {
- if (answer_prepare(request->answer, packet, request) != 0) {
+ if (answer_prepare(request, packet) != 0) {
return KR_STATE_FAIL;
}
return resolve_query(request, packet);
/* Enable DNSSEC if enters a new island of trust. */
bool want_secured = (qry->flags.DNSSEC_WANT) &&
- !knot_wire_get_cd(request->answer->wire);
+ !knot_wire_get_cd(request->qsource.packet->wire);
if (!(qry->flags.DNSSEC_WANT) &&
- !knot_wire_get_cd(request->answer->wire) &&
+ !knot_wire_get_cd(request->qsource.packet->wire) &&
kr_ta_get(trust_anchors, wanted_name)) {
qry->flags.DNSSEC_WANT = true;
want_secured = true;
/* Enable DNSSEC if entering a new (or different) island of trust,
* and update the TA RRset if required. */
bool want_secured = (qry->flags.DNSSEC_WANT) &&
- !knot_wire_get_cd(request->answer->wire);
+ !knot_wire_get_cd(request->qsource.packet->wire);
knot_rrset_t *ta_rr = kr_ta_get(trust_anchors, qry->zone_cut.name);
- if (!knot_wire_get_cd(request->answer->wire) && ta_rr) {
+ if (!knot_wire_get_cd(request->qsource.packet->wire) && ta_rr) {
qry->flags.DNSSEC_WANT = true;
want_secured = true;
/* This query has RD=0 or is ANY, stop here. */
- if (qry->stype == KNOT_RRTYPE_ANY || !knot_wire_get_rd(request->answer->wire)) {
+ if (qry->stype == KNOT_RRTYPE_ANY ||
+ !knot_wire_get_rd(request->qsource.packet->wire)) {
VERBOSE_MSG(qry, "=> qtype is ANY or RD=0, bail out\n");
return KR_STATE_FAIL;
}
#ifndef NOVERBOSELOG
struct kr_rplan *rplan = &request->rplan;
#endif
- /* Finalize answer */
- if (answer_finalize(request, state) != 0) {
+
+ /* Finalize answer and construct wire-buffer. */
+ ITERATE_LAYERS(request, NULL, answer_finalize);
+ if (request->state == KR_STATE_FAIL) {
+ state = KR_STATE_FAIL;
+ } else if (answer_finalize(request, state) != 0) {
state = KR_STATE_FAIL;
}
- /* Error during procesing, internal failure */
+
+ /* Error during processing, internal failure */
if (state != KR_STATE_DONE) {
knot_pkt_t *answer = request->answer;
if (knot_wire_get_rcode(answer->wire) == KNOT_RCODE_NOERROR) {
+ knot_wire_clear_ad(answer->wire);
+ knot_wire_clear_aa(answer->wire);
knot_wire_set_rcode(answer->wire, KNOT_RCODE_SERVFAIL);
}
}