From 312e874d75ae07054078dfc809044727675456eb Mon Sep 17 00:00:00 2001 From: =?utf8?q?Marek=20Vavru=C5=A1a?= Date: Sun, 3 May 2015 20:12:26 +0200 Subject: [PATCH] lib/resolve: correct edns0 handling for clients the server responds with edns0 if the client requests it, it also uses DNSSEC for queries if DO=1 the obtained records are not however validated --- lib/layer/iterate.c | 32 +--------------- lib/resolve.c | 91 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 85 insertions(+), 38 deletions(-) diff --git a/lib/layer/iterate.c b/lib/layer/iterate.c index b3f722aa1..9e0fbc720 100644 --- a/lib/layer/iterate.c +++ b/lib/layer/iterate.c @@ -345,31 +345,12 @@ static int begin(knot_layer_t *ctx, void *module_param) return reset(ctx); } -static int prepare_additionals(knot_pkt_t *pkt) -{ - knot_rrset_t opt_rr; - int ret = knot_edns_init(&opt_rr, KR_EDNS_PAYLOAD, 0, KR_EDNS_VERSION, &pkt->mm); - if (ret != KNOT_EOK) { - return ret; - } - - knot_pkt_begin(pkt, KNOT_ADDITIONAL); - ret = knot_pkt_put(pkt, KNOT_COMPR_HINT_NONE, &opt_rr, KNOT_PF_FREE); - if (ret != KNOT_EOK) { - knot_rrset_clear(&opt_rr, &pkt->mm); - return ret; - } - - return kr_ok(); -} - static int prepare_query(knot_layer_t *ctx, knot_pkt_t *pkt) { assert(pkt && ctx); struct kr_request *req = ctx->data; struct kr_query *query = kr_rplan_current(&req->rplan); - if (query == NULL || ctx->state == KNOT_STATE_DONE) { - assert(0); + if (!query || ctx->state & (KNOT_STATE_DONE|KNOT_STATE_FAIL)) { return ctx->state; } @@ -384,18 +365,9 @@ static int prepare_query(knot_layer_t *ctx, knot_pkt_t *pkt) return KNOT_STATE_FAIL; } + /* Query built, expect answer. */ query->id = isaac_next_uint(&ISAAC, UINT16_MAX); knot_wire_set_id(pkt->wire, query->id); - - /* Declare EDNS0 support. */ - if (!(query->flags & QUERY_SAFEMODE)) { - ret = prepare_additionals(pkt); - if (ret != 0) { - return KNOT_STATE_FAIL; - } - } - - /* Query built, expect answer. */ return KNOT_STATE_CONSUME; } diff --git a/lib/resolve.c b/lib/resolve.c index a9580266a..285e50817 100644 --- a/lib/resolve.c +++ b/lib/resolve.c @@ -131,6 +131,78 @@ static int sendrecv(struct sockaddr *addr, int proto, const knot_pkt_t *query, k return knot_pkt_parse(resp, 0); } +static int edns_put(knot_pkt_t *pkt) +{ + /* 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_put(pkt, KNOT_COMPR_HINT_NONE, pkt->opt_rr, KNOT_PF_FREE); +} + +static int edns_create(knot_pkt_t *pkt, knot_pkt_t *template) +{ + /* Create empty OPT RR */ + pkt->opt_rr = mm_alloc(&pkt->mm, sizeof(*pkt->opt_rr)); + if (!pkt->opt_rr) { + return kr_error(ENOMEM); + } + int ret = knot_edns_init(pkt->opt_rr, KR_EDNS_PAYLOAD, 0, KR_EDNS_VERSION, &pkt->mm); + if (ret != 0) { + return ret; + } + /* Set DO bit if set (DNSSEC requested). */ + if (knot_pkt_has_dnssec(template)) { + knot_edns_set_do(pkt->opt_rr); + } + return knot_pkt_reserve(pkt, knot_edns_wire_size(pkt->opt_rr)); +} + +static int answer_prepare(knot_pkt_t *answer, knot_pkt_t *query) +{ + if (!knot_wire_get_rd(query->wire)) { + return kr_error(ENOSYS); /* Only recursive service */ + } + 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); + if (ret != 0){ + return ret; + } + } + return kr_ok(); +} + +static int answer_finalize(knot_pkt_t *answer) +{ + knot_pkt_begin(answer, KNOT_ADDITIONAL); + if (answer->opt_rr) { + return edns_put(answer); + + } + return kr_ok(); +} + +static int query_finalize(struct kr_request *request, knot_pkt_t *pkt) +{ + int ret = 0; + struct kr_query *qry = kr_rplan_current(&request->rplan); + knot_pkt_begin(pkt, KNOT_ADDITIONAL); + if (!(qry->flags & QUERY_SAFEMODE)) { + ret = edns_create(pkt, request->answer); + if (ret == 0) { + ret = edns_put(pkt); + } + } + return ret; +} + int kr_resolve(struct kr_context* ctx, knot_pkt_t *answer, const knot_dname_t *qname, uint16_t qclass, uint16_t qtype) { @@ -155,7 +227,6 @@ int kr_resolve(struct kr_context* ctx, knot_pkt_t *answer, #ifndef NDEBUG struct kr_rplan *rplan = &request.rplan; /* for DEBUG_MSG */ #endif - /* Resolve query, iteratively */ int proto = 0; struct sockaddr *addr = NULL; @@ -188,7 +259,6 @@ int kr_resolve(struct kr_context* ctx, knot_pkt_t *answer, return state == KNOT_STATE_DONE ? 0 : kr_error(EIO); } - int kr_resolve_begin(struct kr_request *request, struct kr_context *ctx, knot_pkt_t *answer) { /* Initialize request */ @@ -228,12 +298,10 @@ int kr_resolve_consume(struct kr_request *request, knot_pkt_t *packet) /* Empty resolution plan, push packet as the new query */ if (packet && kr_rplan_empty(rplan)) { - if (!knot_wire_get_rd(packet->wire)) { - return KNOT_STATE_FAIL; - } - if (knot_pkt_init_response(request->answer, packet) != 0) { + if (answer_prepare(request->answer, packet) != 0) { return KNOT_STATE_FAIL; } + /* Start query resolution */ const knot_dname_t *qname = knot_pkt_qname(packet); uint16_t qclass = knot_pkt_qclass(packet); uint16_t qtype = knot_pkt_qtype(packet); @@ -324,7 +392,11 @@ int kr_resolve_produce(struct kr_request *request, struct sockaddr **dst, int *t DEBUG_MSG("=> querying: '%s' zone cut: '%s' m12n: '%s'\n", ns_str, zonecut_str, qname_str); #endif - /* Issue dependent query to this address */ + /* Prepare additional query */ + int ret = query_finalize(request, packet); + if (ret != 0) { + return KNOT_STATE_FAIL; + } *dst = &qry->ns.addr.ip; *type = (qry->flags & QUERY_TCP) ? SOCK_STREAM : SOCK_DGRAM; return state; @@ -336,6 +408,10 @@ int kr_resolve_finish(struct kr_request *request, int state) struct kr_rplan *rplan = &request->rplan; DEBUG_MSG("finished: %d, mempool: %zu B\n", state, (size_t) mp_total_size(request->pool.ctx)); #endif + /* Finalize answer */ + if (answer_finalize(request->answer) != 0) { + state = KNOT_STATE_FAIL; + } /* Error during procesing, internal failure */ if (state != KNOT_STATE_DONE) { knot_pkt_t *answer = request->answer; @@ -343,7 +419,6 @@ int kr_resolve_finish(struct kr_request *request, int state) knot_wire_set_rcode(answer->wire, KNOT_RCODE_SERVFAIL); } } - /* Clean up. */ knot_overlay_deinit(&request->overlay); request->overlay.state = KNOT_STATE_NOOP; -- 2.47.2