]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/resolve answer_finalize: separate a special case
authorVladimír Čunát <vladimir.cunat@nic.cz>
Wed, 10 Jul 2019 08:17:05 +0000 (10:17 +0200)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Tue, 23 Jul 2019 09:00:26 +0000 (11:00 +0200)
We currently allow modules to produce a packet beforehand,
but the possibility was rather implicit in this part of code.
In particular, we might possible trigger a false alarm in
assert(answer->current <= KNOT_ANSWER)

lib/resolve.c

index fe357453d97bf7f73756446256da9e45f059b863..888a0a1013d8562dc9d805b4778a5dd60ca7ea63 100644 (file)
@@ -573,11 +573,49 @@ static void answer_fail(struct kr_request *request)
        }
 }
 
+/* Append EDNS records into the answer. */
+static int answer_append_edns(struct kr_request *request)
+{
+       knot_pkt_t *answer = request->answer;
+       if (!answer->opt_rr)
+               return kr_ok();
+       int ret = 0;
+       if (request->qsource.flags.tls) {
+               ret = answer_padding(request);
+       }
+       if (!ret) ret = knot_pkt_begin(answer, KNOT_ADDITIONAL);
+       if (!ret) ret = knot_pkt_put(answer, KNOT_COMPR_HINT_NONE,
+                                    answer->opt_rr, KNOT_PF_FREE);
+       return ret;
+}
+
 static void answer_finalize(struct kr_request *request)
 {
        struct kr_rplan *rplan = &request->rplan;
        knot_pkt_t *answer = request->answer;
 
+       if (answer->rrset_count != 0) {
+               /* Non-standard: we assume the answer had been constructed.
+                * Let's check we don't have a "collision". */
+               const ranked_rr_array_t *selected[] = kr_request_selected(request);
+               for (int psec = KNOT_ANSWER; psec <= KNOT_ADDITIONAL; ++psec) {
+                       const ranked_rr_array_t *arr = selected[psec];
+                       for (ssize_t i = 0; i < arr->len; ++i) {
+                               if (unlikely(arr->at[i]->to_wire)) {
+                                       assert(false);
+                                       answer_fail(request);
+                                       return;
+                               }
+                       }
+               }
+               /* We only add EDNS, and we even assume AD bit was correct. */
+               if (answer_append_edns(request)) {
+                       answer_fail(request);
+                       return;
+               }
+               return;
+       }
+
        struct kr_query *const last =
                rplan->resolved.len > 0 ? array_tail(rplan->resolved) : NULL;
                /* TODO  ^^^^ this is slightly fragile */
@@ -641,21 +679,10 @@ static void answer_finalize(struct kr_request *request)
                answer_fail(request);
                return;
        }
-       /* Write EDNS information */
-       if (answer->opt_rr) {
-               if (request->qsource.flags.tls) {
-                       if (answer_padding(request) != kr_ok()) {
-                               answer_fail(request);
-                               return;
-                       }
-               }
-               knot_pkt_begin(answer, KNOT_ADDITIONAL);
-               int ret = knot_pkt_put(answer, KNOT_COMPR_HINT_NONE,
-                                      answer->opt_rr, KNOT_PF_FREE);
-               if (ret != KNOT_EOK) {
-                       answer_fail(request);
-                       return;
-               }
+
+       if (answer_append_edns(request)) {
+               answer_fail(request);
+               return;
        }
 
        if (!last) secure = false; /*< should be no-op, mostly documentation */