From: Amaury Denoyelle Date: Wed, 8 Apr 2026 12:13:05 +0000 (+0200) Subject: MEDIUM: xprt_qstrm: implement QMux record parsing X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=792e055c7c6e089d1cac01faf701d6dabdbb1a4f;p=thirdparty%2Fhaproxy.git MEDIUM: xprt_qstrm: implement QMux record parsing This patch implements the new QMux record layer parsing for xprt_qstrm. This is mostly similar to the MUX code from the previous patch. Along with this change, a new xprt_qstrm layer accessor exposes the possible remaining record length after Transport parameters parsing. This can only occur when xprt_qstrm Rx buffer is not completely emptied due to other following frames. If stored in the same record, MUX layer has to know the remaining record length. Thus, xprt_qstrm_rxrlen() is now used in qmux_init() to preinitialize QCC field. --- diff --git a/include/haproxy/xprt_qstrm.h b/include/haproxy/xprt_qstrm.h index 536ba1abd..5a992f21f 100644 --- a/include/haproxy/xprt_qstrm.h +++ b/include/haproxy/xprt_qstrm.h @@ -5,5 +5,6 @@ const struct quic_transport_params *xprt_qstrm_lparams(const void *context); const struct quic_transport_params *xprt_qstrm_rparams(const void *context); struct buffer *xprt_qstrm_rxbuf(const void *context); +size_t xprt_qstrm_rxrlen(const void *context); #endif /* _HAPROXY_XPRT_QSTRM_H */ diff --git a/src/mux_quic.c b/src/mux_quic.c index 15302f5fa..0ea65fefc 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -3802,8 +3802,13 @@ static int qmux_init(struct connection *conn, struct proxy *prx, /* Retrieve data if xprt read too much */ xprt_buf = xprt_qstrm_rxbuf(conn->xprt_ctx); - if (unlikely(b_data(xprt_buf))) + if (unlikely(b_data(xprt_buf))) { b_xfer(&qcc->rx.qstrm_buf, xprt_buf, b_data(xprt_buf)); + qcc->rx.rlen = xprt_qstrm_rxrlen(conn->xprt_ctx); + } + else { + qcc->rx.rlen = 0; + } } if (conn_is_back(conn)) { diff --git a/src/xprt_qstrm.c b/src/xprt_qstrm.c index 01a9265fc..5d6ac9adc 100644 --- a/src/xprt_qstrm.c +++ b/src/xprt_qstrm.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -22,6 +23,7 @@ struct xprt_qstrm_ctx { struct buffer txbuf; struct buffer rxbuf; + size_t rxrlen; }; DECLARE_STATIC_TYPED_POOL(xprt_qstrm_ctx_pool, "xprt_qstrm_ctx", struct xprt_qstrm_ctx); @@ -45,11 +47,17 @@ struct buffer *xprt_qstrm_rxbuf(void *context) return &ctx->rxbuf; } +size_t xprt_qstrm_rxrlen(const void *context) +{ + const struct xprt_qstrm_ctx *ctx = context; + return ctx->rxrlen; +} + int conn_recv_qstrm(struct connection *conn, struct xprt_qstrm_ctx *ctx, int flag) { struct quic_frame frm; struct buffer *buf = &ctx->rxbuf; - const unsigned char *pos, *end; + const unsigned char *pos, *old, *end; size_t ret; if (!conn_ctrl_ready(conn)) @@ -72,18 +80,32 @@ int conn_recv_qstrm(struct connection *conn, struct xprt_qstrm_ctx *ctx, int fla if (!b_data(buf)) goto not_ready; - pos = (unsigned char *)b_orig(buf); - end = (unsigned char *)(b_orig(buf) + b_data(buf)); - if (!qc_parse_frm_type(&frm, &pos, end, NULL)) + /* Read record length. */ + if (!b_quic_dec_int(&ctx->rxrlen, buf, NULL)) goto not_ready; + /* Reject too small or too big records. */ + if (!ctx->rxrlen || ctx->rxrlen > b_size(buf)) + goto fail; + if (ctx->rxrlen > b_data(buf)) + goto not_ready; + + old = pos = (unsigned char *)b_head(buf); + end = pos + ctx->rxrlen; + if (!qc_parse_frm_type(&frm, &pos, end, NULL)) + goto fail; + /* TODO close connection with TRANSPORT_PARAMETER_ERROR if frame not present. */ BUG_ON(frm.type != QUIC_FT_QX_TRANSPORT_PARAMETERS); if (!qc_parse_frm_payload(&frm, &pos, end, NULL)) - goto not_ready; + goto fail; ctx->rparams = frm.qmux_transport_params.params; + b_del(buf, pos - old); + /* delimiter should guarantee than frame length does not go beyong the record end */ + BUG_ON(ctx->rxrlen < pos - old); + ctx->rxrlen -= (pos - old); conn->flags &= ~flag; return 1; @@ -235,6 +257,7 @@ static int xprt_qstrm_init(struct connection *conn, void **xprt_ctx) ctx->ops_lower = NULL; ctx->rxbuf = BUF_NULL; + ctx->rxrlen = 0; ctx->txbuf = BUF_NULL; memset(&ctx->rparams, 0, sizeof(struct quic_transport_params));