]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: RX buffer full due to wrong CRYPTO data handling
authorFrédéric Lécaille <flecaille@haproxy.com>
Thu, 2 Dec 2021 10:25:58 +0000 (11:25 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 7 Dec 2021 14:53:56 +0000 (15:53 +0100)
Do not leave in the RX buffer packets with CRYPTO data which were
already received. We do this when parsing CRYPTO frame. If already
received we must not consider such frames as if they were not received
in order! This had as side effect to interrupt the transfer of long streams
(ACK frames not parsed).

src/xprt_quic.c

index d70be2cc51261223a7e2f54326fd005de73006e5..2809de92d523f73084ba13f4f4b64e1c7ec9a9fc 100644 (file)
@@ -2230,35 +2230,66 @@ static int qc_parse_pkt_frms(struct quic_rx_packet *pkt, struct ssl_sock_ctx *ct
                        break;
                }
                case QUIC_FT_CRYPTO:
-                       if (frm.crypto.offset != qel->rx.crypto.offset) {
-                               struct quic_rx_crypto_frm *cf;
-
-                               cf = pool_alloc(pool_head_quic_rx_crypto_frm);
-                               if (!cf) {
-                                       TRACE_DEVEL("CRYPTO frame allocation failed",
-                                                   QUIC_EV_CONN_PRSHPKT, ctx->conn);
-                                       goto err;
+               {
+                       struct quic_rx_crypto_frm *cf;
+
+                       if (unlikely(frm.crypto.offset < qel->rx.crypto.offset)) {
+                               if (frm.crypto.offset + frm.crypto.len <= qel->rx.crypto.offset) {
+                                       /* XXX TO DO: <cfdebug> is used only for the traces. */
+                                       struct quic_rx_crypto_frm cfdebug = { };
+
+                                       cfdebug.offset_node.key = frm.crypto.offset;
+                                       cfdebug.len = frm.crypto.len;
+                                       /* Nothing to do */
+                                       TRACE_PROTO("Already received CRYPTO data",
+                                                   QUIC_EV_CONN_ELRXPKTS, ctx->conn, pkt, &cfdebug);
+                                       break;
+                               }
+                               else {
+                                       size_t diff = qel->rx.crypto.offset - frm.crypto.offset;
+                                       /* XXX TO DO: <cfdebug> is used only for the traces. */
+                                       struct quic_rx_crypto_frm cfdebug = { };
+
+                                       cfdebug.offset_node.key = frm.crypto.offset;
+                                       cfdebug.len = frm.crypto.len;
+                                       TRACE_PROTO("Partially already received CRYPTO data",
+                                                   QUIC_EV_CONN_ELRXPKTS, ctx->conn, pkt, &cfdebug);
+                                       frm.crypto.len -= diff;
+                                       frm.crypto.data += diff;
+                                       frm.crypto.offset = qel->rx.crypto.offset;
                                }
-
-                               cf->offset_node.key = frm.crypto.offset;
-                               cf->len = frm.crypto.len;
-                               cf->data = frm.crypto.data;
-                               cf->pkt = pkt;
-                               eb64_insert(&qel->rx.crypto.frms, &cf->offset_node);
-                               quic_rx_packet_refinc(pkt);
                        }
-                       else {
+
+                       if (frm.crypto.offset == qel->rx.crypto.offset) {
                                /* XXX TO DO: <cf> is used only for the traces. */
-                               struct quic_rx_crypto_frm cf = { };
+                               struct quic_rx_crypto_frm cfdebug = { };
 
-                               cf.offset_node.key = frm.crypto.offset;
-                               cf.len = frm.crypto.len;
+                               cfdebug.offset_node.key = frm.crypto.offset;
+                               cfdebug.len = frm.crypto.len;
                                if (!qc_provide_cdata(qel, ctx,
                                                      frm.crypto.data, frm.crypto.len,
-                                                     pkt, &cf))
+                                                     pkt, &cfdebug))
                                        goto err;
+
+                               break;
                        }
+
+                       /* frm.crypto.offset > qel->rx.crypto.offset */
+                       cf = pool_alloc(pool_head_quic_rx_crypto_frm);
+                       if (!cf) {
+                               TRACE_DEVEL("CRYPTO frame allocation failed",
+                                                       QUIC_EV_CONN_PRSHPKT, ctx->conn);
+                               goto err;
+                       }
+
+                       cf->offset_node.key = frm.crypto.offset;
+                       cf->len = frm.crypto.len;
+                       cf->data = frm.crypto.data;
+                       cf->pkt = pkt;
+                       eb64_insert(&qel->rx.crypto.frms, &cf->offset_node);
+                       quic_rx_packet_refinc(pkt);
                        break;
+               }
                case QUIC_FT_STREAM_8:
                case QUIC_FT_STREAM_9:
                case QUIC_FT_STREAM_A: