]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/resolve: correct edns0 handling for clients
authorMarek Vavruša <marek.vavrusa@nic.cz>
Sun, 3 May 2015 18:12:26 +0000 (20:12 +0200)
committerMarek Vavruša <marek.vavrusa@nic.cz>
Sun, 3 May 2015 18:12:26 +0000 (20:12 +0200)
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
lib/resolve.c

index b3f722aa1775fc8fc67eee846370bc1d988c586c..9e0fbc72024a91a97d35ba17ee54afae2a3af5d3 100644 (file)
@@ -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;
 }
 
index a9580266ae606560f95bf72753e77252d5f07e69..285e50817efaadcec1451042a0c338d8f1a3b2f4 100644 (file)
@@ -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;