]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
lib/resolve: EDNS padding for outgoing TLS queries
authorOto Šťáva <oto.stava@nic.cz>
Wed, 2 Feb 2022 14:43:11 +0000 (15:43 +0100)
committerOto Šťáva <oto.stava@nic.cz>
Mon, 7 Feb 2022 14:52:55 +0000 (15:52 +0100)
NEWS
lib/resolve.c

diff --git a/NEWS b/NEWS
index 3cefde1b6fdb24a22b70e57c86419b704dae57ba..8a4801ae6d4b48128f5348a808a2694dbf78a8cb 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,7 @@ Improvements
 - policy: new action policy.IPTRACE for logging request origin (!1239)
 - prefill module: prepare for ZONEMD, improve performance (!1225)
 - validator: conditionally ignore SHA1 DS, as SHOULD by RFC4509 (!1251)
+- lib/resolve: use EDNS padding for outgoing TLS queries (!1254)
 
 Incompatible changes
 --------------------
index 0e06fb7201c1c4e447d3469e400b19cd883ebe46..2a4e672ecc6d84a0be54d7a3335bb833ff28b983 100644 (file)
@@ -346,6 +346,19 @@ static int edns_erase_and_reserve(knot_pkt_t *pkt)
        return knot_pkt_reserve(pkt, len);
 }
 
+static inline size_t edns_padding_option_size(int32_t tls_padding)
+{
+       if (tls_padding == -1)
+               /* FIXME: we do not know how to reserve space for the
+                * default padding policy, since we can't predict what
+                * it will select. So i'm just guessing :/ */
+               return KNOT_EDNS_OPTION_HDRLEN + 512;
+       if (tls_padding >= 2)
+               return KNOT_EDNS_OPTION_HDRLEN + tls_padding;
+
+       return 0;
+}
+
 static int edns_create(knot_pkt_t *pkt, const struct kr_request *req)
 {
        pkt->opt_rr = knot_rrset_copy(req->ctx->upstream_opt_rr, &pkt->mm);
@@ -357,13 +370,7 @@ static int edns_create(knot_pkt_t *pkt, const struct kr_request *req)
        }
 #endif /* ENABLE_COOKIES */
        if (req->qsource.flags.tls) {
-               if (req->ctx->tls_padding == -1)
-                       /* FIXME: we do not know how to reserve space for the
-                        * default padding policy, since we can't predict what
-                        * it will select. So i'm just guessing :/ */
-                       wire_size += KNOT_EDNS_OPTION_HDRLEN + 512;
-               if (req->ctx->tls_padding >= 2)
-                       wire_size += KNOT_EDNS_OPTION_HDRLEN + req->ctx->tls_padding;
+               wire_size += edns_padding_option_size(req->ctx->tls_padding);
        }
        return knot_pkt_reserve(pkt, wire_size);
 }
@@ -417,26 +424,17 @@ static int write_extra_ranked_records(const ranked_rr_array_t *arr, uint16_t reo
        return err;
 }
 
-/** @internal Add an EDNS padding RR into the answer if requested and required. */
-static int answer_padding(struct kr_request *request)
+static int pkt_padding(knot_pkt_t *packet, int32_t padding)
 {
-       if (kr_fails_assert(request && request->answer && request->ctx))
-               return kr_error(EINVAL);
-       if (!request->qsource.flags.tls) {
-               /* Not meaningful to pad without encryption. */
-               return kr_ok();
-       }
-       int32_t padding = request->ctx->tls_padding;
-       knot_pkt_t *answer = request->answer;
-       knot_rrset_t *opt_rr = answer->opt_rr;
+       knot_rrset_t *opt_rr = packet->opt_rr;
        int32_t pad_bytes = -1;
 
        if (padding == -1) { /* use the default padding policy from libknot */
-               pad_bytes =  knot_pkt_default_padding_size(answer, opt_rr);
+               pad_bytes =  knot_pkt_default_padding_size(packet, opt_rr);
        }
        if (padding >= 2) {
-               int32_t max_pad_bytes = knot_edns_get_payload(opt_rr) - (answer->size + knot_rrset_size(opt_rr));
-               pad_bytes = MIN(knot_edns_alignment_size(answer->size, knot_rrset_size(opt_rr), padding),
+               int32_t max_pad_bytes = knot_edns_get_payload(opt_rr) - (packet->size + knot_rrset_size(opt_rr));
+               pad_bytes = MIN(knot_edns_alignment_size(packet->size, knot_rrset_size(opt_rr), padding),
                                max_pad_bytes);
        }
 
@@ -444,15 +442,27 @@ static int answer_padding(struct kr_request *request)
                uint8_t zeros[MAX(1, pad_bytes)];
                memset(zeros, 0, sizeof(zeros));
                int r = knot_edns_add_option(opt_rr, KNOT_EDNS_OPTION_PADDING,
-                                            pad_bytes, zeros, &answer->mm);
+                                            pad_bytes, zeros, &packet->mm);
                if (r != KNOT_EOK) {
-                       knot_rrset_clear(opt_rr, &answer->mm);
+                       knot_rrset_clear(opt_rr, &packet->mm);
                        return kr_error(r);
                }
        }
        return kr_ok();
 }
 
+/** @internal Add an EDNS padding RR into the answer if requested and required. */
+static int answer_padding(struct kr_request *request)
+{
+       if (kr_fails_assert(request && request->answer && request->ctx))
+               return kr_error(EINVAL);
+       if (!request->qsource.flags.tls) {
+               /* Not meaningful to pad without encryption. */
+               return kr_ok();
+       }
+       return pkt_padding(request->answer, request->ctx->tls_padding);
+}
+
 /* Make a clean SERVFAIL answer. */
 static void answer_fail(struct kr_request *request)
 {
@@ -1525,6 +1535,17 @@ int kr_resolve_checkout(struct kr_request *request, const struct sockaddr *src,
 
        /* Write down OPT unless in safemode */
        if (!(qry->flags.NO_EDNS)) {
+               /* TLS padding */
+               if (transport->protocol == KR_TRANSPORT_TLS) {
+                       size_t padding_size = edns_padding_option_size(request->ctx->tls_padding);
+                       ret = knot_pkt_reserve(packet, padding_size);
+                       if (ret)
+                               return kr_error(EINVAL);
+                       ret = pkt_padding(packet, request->ctx->tls_padding);
+                       if (ret)
+                               return kr_error(EINVAL);
+               }
+
                ret = edns_put(packet, true);
                if (ret != 0) {
                        return kr_error(EINVAL);