]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: quic: pad Initial pkt with CONNECTION_CLOSE on client
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 2 Sep 2025 07:16:02 +0000 (09:16 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 2 Sep 2025 08:34:12 +0000 (10:34 +0200)
Currently, when connection is closing, only CONNECTION_CLOSE frame is
emitted via qc_prep_pkts()/qc_do_build_pkt(). Also, only the first
registered encryption level is considered while the others are
dismissed. This results in a single packet datagram.

This can cause issues for QUIC client support, as padding is required
for every Initial packet, contrary to server side where only
ack-eliciting packets are eligible. Thus a client must add padding to a
CONNECTION_CLOSE frame on Initial level.

This patch adjusts qc_prep_pkts() to ensure such packet will be
correctly padded on client side. It sets <final_packet> variable which
instructs that if padding is necessary it must be apply immediately on
the current encryption level instead of the last one.

It could appear as unnecessary to pad a CONNECTION_CLOSE packet, as the
peer will enter in draining state when processing it. However, RFC
mandates that a client Initial packet too small must be dropped by the
server, so there is a risk that the CONNECTION_CLOSE is simply discarded
prior to its processing if stored in a too small datagram.

No need to backport as this is a QUIC backend issue only.

src/quic_tx.c

index 2fd149065c9eca8d12baaf760bb34aca4ef05ff3..ee354470d533bfcbae8f3f35509433994e7b0b31 100644 (file)
@@ -715,6 +715,12 @@ static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
                         */
                        if (probe && (must_ack || (qel->pktns->flags & QUIC_FL_PKTNS_ACK_REQUIRED)))
                                final_packet = 1;
+                       /* If CONNECTION_CLOSE is emitted only a single QEL is considered while the others are dismissed. This
+                        * must be taken into account if padding is required on QUIC client side. Note that this is irrelevant
+                        * for server side as CONNECTION_CLOSE is not ack-eliciting.
+                        */
+                       else if (qc_is_back(qc) && cc)
+                               final_packet = 1;
 
                        pkt_type = quic_enc_level_pkt_type(qc, qel);
                        cur_pkt = qc_build_pkt(&pos, end, qel, tls_ctx, frms,