From b1441c64404351366edc255c635ec378d5d2e78e Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Tue, 3 Mar 2026 10:02:39 +0100 Subject: [PATCH] MINOR: quic: use server cache for ALPN on BE side On the backend side, QUIC MUX may be started preemptively before the ALPN negotiation. This is useful notably for 0-RTT implementation. However, this was a source of crashes. ALPN was expected to be retrieved from the server cache, however QUIC MUX still used the ALPN from the transport layer. This could cause a crash, especially when several connections runs in parallel as the server cache is shared among threads. Thanks to the previous patch which reworks QUIC MUX init, this solution can now be fixed. Indeed, if conn_get_alpn() is not successful, MUX can look at the server cache again to use the expected value. Note that this could still prevent the MUX to work as expected if the server cache is resetted between connect_server() and MUX init. Thus, the ultimate solution would be to copy the cached ALPN into the connection. This problem is not specific to QUIC though, and must be fixed in a separate patch. --- src/mux_quic.c | 16 ++++++++++++++-- src/xprt_quic.c | 1 + 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/mux_quic.c b/src/mux_quic.c index 5b672b174..1ba2d65a8 100644 --- a/src/mux_quic.c +++ b/src/mux_quic.c @@ -1695,13 +1695,25 @@ int qcc_install_app_ops(struct qcc *qcc) { struct connection *conn = qcc->conn; const struct qcc_app_ops *app_ops; + struct server *srv; const char *alpn; int alpn_len; TRACE_ENTER(QMUX_EV_QCC_NEW, conn); - if (!conn_get_alpn(conn, &alpn, &alpn_len)) - goto err; + if (!conn_get_alpn(conn, &alpn, &alpn_len)) { + if (!conn_is_back(conn)) + goto err; + + srv = __objt_server(conn->target); + HA_RWLOCK_RDLOCK(SERVER_LOCK, &srv->path_params.param_lock); + alpn = srv->path_params.nego_alpn; + HA_RWLOCK_RDUNLOCK(SERVER_LOCK, &srv->path_params.param_lock); + + if (!alpn) + goto err; + alpn_len = strlen(srv->path_params.nego_alpn); + } app_ops = quic_alpn_to_app_ops(alpn, alpn_len); if (!app_ops) diff --git a/src/xprt_quic.c b/src/xprt_quic.c index 4670f6a86..27cce68e5 100644 --- a/src/xprt_quic.c +++ b/src/xprt_quic.c @@ -245,6 +245,7 @@ static int qc_get_alpn(const struct connection *conn, void *xprt_ctx, const char int ret = 0; TRACE_ENTER(QUIC_EV_CONN_NEW, qc); + if (qc->alpn) { *str = qc->alpn; *len = strlen(qc->alpn);