]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: use server cache for ALPN on BE side
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 3 Mar 2026 09:02:39 +0000 (10:02 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 3 Mar 2026 15:23:03 +0000 (16:23 +0100)
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
src/xprt_quic.c

index 5b672b174a788fef3d79b084109be3bd13b2e9e2..1ba2d65a86dd76296a817393deefce39a2aba1fa 100644 (file)
@@ -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)
index 4670f6a865408814678eeaf8df77800ac36d4074..27cce68e5fd1d818f099e6dee5e09cc5ca389572 100644 (file)
@@ -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);