]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: connections: Use both mux_proto and alpn to pick a mux
authorOlivier Houchard <ohouchard@haproxy.com>
Tue, 19 May 2026 13:52:21 +0000 (15:52 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Tue, 19 May 2026 16:33:54 +0000 (18:33 +0200)
In conn_get_best_mux() and conn_get_best_mux_entry(), the mux name was
provided sometimes based on the "proto" directive, sometimes based on
the ALPN, but in any case, it was compared again the mux_proto_list
mux_proto field. This is not correct, as ALPN can be different from the
internal mux_proto. So enhance those functions so that they wll accept
an ALPN as well. If a mux_proto is provided, that will be used, if not,
and if an ALPN is provided, then that will be used, and compared against
the ALPN provided by the mux, if any.

include/haproxy/connection.h
src/connection.c
src/proxy.c
src/server.c
src/stream.c
src/tcpcheck.c

index f73bb334cd791282cf3e330394a2c28a5bcdf485..dfd816344c0f1b7396933383976e2f8bc1229a69 100644 (file)
@@ -668,6 +668,7 @@ void list_mux_proto(FILE *out);
  */
 static inline const struct mux_proto_list *conn_get_best_mux_entry(
         const struct ist mux_proto,
+        const struct ist alpn,
         int proto_side, int proto_is_quic, int proto_mode)
 {
        struct mux_proto_list *item;
@@ -679,6 +680,10 @@ static inline const struct mux_proto_list *conn_get_best_mux_entry(
                if (istlen(mux_proto) && isteq(mux_proto, item->mux_proto)) {
                        return item;
                }
+               else if (istlen(alpn) && item->alpn &&
+                   strlen(item->alpn) == istlen(alpn) + 1 &&
+                   !memcmp(alpn.ptr, item->alpn + 1, istlen(alpn)))
+                       return item;
                else if (!istlen(item->mux_proto)) {
                        if (!fallback || (item->mode == proto_mode && fallback->mode != proto_mode))
                                fallback = item;
@@ -696,11 +701,12 @@ static inline const struct mux_proto_list *conn_get_best_mux_entry(
  */
 static inline const struct mux_ops *conn_get_best_mux(struct connection *conn,
                                                      const struct ist mux_proto,
+                                                     const struct ist alpn,
                                                      int proto_side, int proto_mode)
 {
        const struct mux_proto_list *item;
 
-       item = conn_get_best_mux_entry(mux_proto, proto_side, proto_is_quic(conn->ctrl), proto_mode);
+       item = conn_get_best_mux_entry(mux_proto, alpn, proto_side, proto_is_quic(conn->ctrl), proto_mode);
 
        return item ? item->mux : NULL;
 }
index 7112ef1cd0710a00644f8eab7cf639c82cb4e3dd..50fc6c45750d5335a682968b43322a43e3b971f7 100644 (file)
@@ -282,6 +282,7 @@ int conn_upgrade_mux_fe(struct connection *conn, void *ctx, struct buffer *buf,
                         struct ist mux_proto, int mode)
 {
        struct bind_conf *bind_conf = __objt_listener(conn->target)->bind_conf;
+       struct ist alpn = IST_NULL;
        const struct mux_ops *old_mux, *new_mux;
        void *old_mux_ctx;
        const char *alpn_str = NULL;
@@ -289,9 +290,9 @@ int conn_upgrade_mux_fe(struct connection *conn, void *ctx, struct buffer *buf,
 
        if (!mux_proto.len) {
                conn_get_alpn(conn, &alpn_str, &alpn_len);
-               mux_proto = ist2(alpn_str, alpn_len);
+               alpn = ist2(alpn_str, alpn_len);
        }
-       new_mux = conn_get_best_mux(conn, mux_proto, PROTO_SIDE_FE, mode);
+       new_mux = conn_get_best_mux(conn, mux_proto, alpn, PROTO_SIDE_FE, mode);
        old_mux = conn->mux;
 
        /* No mux found */
@@ -330,14 +331,14 @@ int conn_install_mux_fe(struct connection *conn, void *ctx)
        if (bind_conf->mux_proto)
                mux_ops = bind_conf->mux_proto->mux;
        else {
-               struct ist mux_proto;
+               struct ist alpn;
                const char *alpn_str = NULL;
                int alpn_len = 0;
                int mode = conn_pr_mode_to_proto_mode(bind_conf->frontend->mode);
 
                conn_get_alpn(conn, &alpn_str, &alpn_len);
-               mux_proto = ist2(alpn_str, alpn_len);
-               mux_ops = conn_get_best_mux(conn, mux_proto, PROTO_SIDE_FE, mode);
+               alpn = ist2(alpn_str, alpn_len);
+               mux_ops = conn_get_best_mux(conn, IST_NULL, alpn, PROTO_SIDE_FE, mode);
                if (!mux_ops)
                        return -1;
        }
@@ -380,7 +381,7 @@ int conn_install_mux_be(struct connection *conn, void *ctx, struct session *sess
                mux_ops = force_mux_ops;
        }
        else {
-               struct ist mux_proto;
+               struct ist alpn;
                const char *alpn_str = NULL;
                int alpn_len = 0;
                int mode = conn_pr_mode_to_proto_mode(prx->mode);
@@ -391,9 +392,9 @@ int conn_install_mux_be(struct connection *conn, void *ctx, struct session *sess
                                alpn_len = strlen(alpn_str);
                        }
                }
-               mux_proto = ist2(alpn_str, alpn_len);
+               alpn = ist2(alpn_str, alpn_len);
 
-               mux_ops = conn_get_best_mux(conn, mux_proto, PROTO_SIDE_BE, mode);
+               mux_ops = conn_get_best_mux(conn, IST_NULL, alpn, PROTO_SIDE_BE, mode);
                if (!mux_ops)
                        return -1;
        }
@@ -434,15 +435,15 @@ int conn_install_mux_chk(struct connection *conn, void *ctx, struct session *ses
        if (check->mux_proto)
                mux_ops = check->mux_proto->mux;
        else {
-               struct ist mux_proto;
+               struct ist alpn;
                const char *alpn_str = NULL;
                int alpn_len = 0;
                int mode = tcpchk_rules_type_to_proto_mode(check->tcpcheck->rs->flags);
 
                conn_get_alpn(conn, &alpn_str, &alpn_len);
-               mux_proto = ist2(alpn_str, alpn_len);
+               alpn = ist2(alpn_str, alpn_len);
 
-               mux_ops = conn_get_best_mux(conn, mux_proto, PROTO_SIDE_BE, mode);
+               mux_ops = conn_get_best_mux(conn, IST_NULL, alpn, PROTO_SIDE_BE, mode);
                if (!mux_ops)
                        return -1;
        }
index c12ffdf554e37c710cc5e44855197e72097cc985..f0667228c573a437006d54a58bf946bf36ff1e62 100644 (file)
@@ -1689,7 +1689,7 @@ int proxy_finalize(struct proxy *px, int *err_code)
                         * due to the proxy's mode not being taken into account
                         * on first pass. Let's adjust it now.
                         */
-                       mux_ent = conn_get_best_mux_entry(bind_conf->mux_proto->mux_proto, PROTO_SIDE_FE, is_quic, mode);
+                       mux_ent = conn_get_best_mux_entry(bind_conf->mux_proto->mux_proto, IST_NULL, PROTO_SIDE_FE, is_quic, mode);
 
                        if (!mux_ent || !isteq(mux_ent->mux_proto, bind_conf->mux_proto->mux_proto)) {
                                ha_alert("%s '%s' : MUX protocol '%.*s' is not usable for 'bind %s' at [%s:%d].\n",
@@ -2849,7 +2849,7 @@ int proxy_finalize(struct proxy *px, int *err_code)
                 * due to the proxy's mode not being taken into account
                 * on first pass. Let's adjust it now.
                 */
-               mux_ent = conn_get_best_mux_entry(newsrv->mux_proto->mux_proto, PROTO_SIDE_BE, srv_is_quic(newsrv), mode);
+               mux_ent = conn_get_best_mux_entry(newsrv->mux_proto->mux_proto, IST_NULL, PROTO_SIDE_BE, srv_is_quic(newsrv), mode);
 
                if (!mux_ent || !isteq(mux_ent->mux_proto, newsrv->mux_proto->mux_proto)) {
                        ha_alert("%s '%s' : MUX protocol '%.*s' is not usable for server '%s' at [%s:%d].\n",
index 4d52556e0e3aa015373bf3fb4621a700fd2861da..94105518c3756699bfe86d568914a9850e73097e 100644 (file)
@@ -6278,7 +6278,7 @@ static int cli_parse_add_server(char **args, char *payload, struct appctx *appct
                int proto_mode = conn_pr_mode_to_proto_mode(be->mode);
                const struct mux_proto_list *mux_ent;
 
-               mux_ent = conn_get_best_mux_entry(srv->mux_proto->mux_proto, PROTO_SIDE_BE, srv_is_quic(srv), proto_mode);
+               mux_ent = conn_get_best_mux_entry(srv->mux_proto->mux_proto, IST_NULL, PROTO_SIDE_BE, srv_is_quic(srv), proto_mode);
 
                if (!mux_ent || !isteq(mux_ent->mux_proto, srv->mux_proto->mux_proto)) {
                        ha_alert("MUX protocol is not usable for server.\n");
index fd27b9cf6824da71036fe7a7a302d80900cb64de..73feb7ebfd2ddc49f73445bc6abf1457083e647c 100644 (file)
@@ -3268,7 +3268,7 @@ static int check_tcp_switch_stream_mode(struct act_rule *rule, struct proxy *px,
                px->options |= PR_O_HTTP_UPG;
 
        if (mux_proto) {
-               mux_ent = conn_get_best_mux_entry(mux_proto->mux_proto, PROTO_SIDE_FE, 0, mode);
+               mux_ent = conn_get_best_mux_entry(mux_proto->mux_proto, IST_NULL, PROTO_SIDE_FE, 0, mode);
                if (!mux_ent || !isteq(mux_ent->mux_proto, mux_proto->mux_proto)) {
                        memprintf(err, "MUX protocol '%.*s' is not compatible with the selected mode",
                                  (int)mux_proto->mux_proto.len, mux_proto->mux_proto.ptr);
@@ -3276,7 +3276,7 @@ static int check_tcp_switch_stream_mode(struct act_rule *rule, struct proxy *px,
                }
        }
        else {
-               mux_ent = conn_get_best_mux_entry(IST_NULL, PROTO_SIDE_FE, 0, mode);
+               mux_ent = conn_get_best_mux_entry(IST_NULL, IST_NULL, PROTO_SIDE_FE, 0, mode);
                if (!mux_ent) {
                        memprintf(err, "Unable to find compatible MUX protocol with the selected mode");
                        return 0;
index d354291f1986178aeb810e3288cc7ffc3636efeb..b7203d1faa0325ae3a07455595978c83bf101489 100644 (file)
@@ -1570,7 +1570,7 @@ enum tcpcheck_eval_ret tcpcheck_eval_connect(struct check *check, struct tcpchec
                else {
                        int mode = tcpchk_rules_type_to_proto_mode(check->tcpcheck->rs->flags);
 
-                       mux_ops = conn_get_best_mux(conn, IST_NULL, PROTO_SIDE_BE, mode);
+                       mux_ops = conn_get_best_mux(conn, IST_NULL, IST_NULL, PROTO_SIDE_BE, mode);
                }
                if (mux_ops && conn_install_mux(conn, mux_ops, check->sc, proxy, check->sess) < 0) {
                        TRACE_ERROR("failed to install mux", CHK_EV_TCPCHK_CONN|CHK_EV_TCPCHK_ERR, check);