From 1b0dfff552713274b95c81594b153104e215ec81 Mon Sep 17 00:00:00 2001 From: Olivier Houchard Date: Thu, 19 Mar 2026 15:00:41 +0100 Subject: [PATCH] MEDIUM: connections: Enforce mux protocol requirements When picking a mux, pay attention to its MX_FL_FRAMED. If it is set, then it means we explicitely want QUIC, so don't use that mux for any protocol that is not QUIC. --- include/haproxy/connection.h | 7 ++++--- src/proxy.c | 10 ++++++++-- src/server.c | 2 +- src/stream.c | 4 ++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/include/haproxy/connection.h b/include/haproxy/connection.h index e311c8d12..03c3306ae 100644 --- a/include/haproxy/connection.h +++ b/include/haproxy/connection.h @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -609,13 +610,13 @@ void list_mux_proto(FILE *out); */ static inline const struct mux_proto_list *conn_get_best_mux_entry( const struct ist mux_proto, - int proto_side, int proto_mode) + int proto_side, int proto_is_quic, int proto_mode) { struct mux_proto_list *item; struct mux_proto_list *fallback = NULL; list_for_each_entry(item, &mux_proto_list.list, list) { - if (!(item->side & proto_side) || !(item->mode & proto_mode)) + if (!(item->side & proto_side) || !(item->mode & proto_mode) || (proto_is_quic && !(item->mux->flags & MX_FL_FRAMED))) continue; if (istlen(mux_proto) && isteq(mux_proto, item->token)) return item; @@ -640,7 +641,7 @@ static inline const struct mux_ops *conn_get_best_mux(struct connection *conn, { const struct mux_proto_list *item; - item = conn_get_best_mux_entry(mux_proto, proto_side, proto_mode); + item = conn_get_best_mux_entry(mux_proto, proto_side, proto_is_quic(conn->ctrl), proto_mode); return item ? item->mux : NULL; } diff --git a/src/proxy.c b/src/proxy.c index 2efef1090..203f2ac09 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -1676,11 +1676,17 @@ int proxy_finalize(struct proxy *px, int *err_code) } if (bind_conf->mux_proto) { + int is_quic; + + if ((bind_conf->options & (BC_O_USE_SOCK_DGRAM | BC_O_USE_XPRT_STREAM)) == (BC_O_USE_SOCK_DGRAM | BC_O_USE_XPRT_STREAM)) + is_quic = 1; + else + is_quic = 0; /* it is possible that an incorrect mux was referenced * 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->token, PROTO_SIDE_FE, mode); + mux_ent = conn_get_best_mux_entry(bind_conf->mux_proto->token, PROTO_SIDE_FE, is_quic, mode); if (!mux_ent || !isteq(mux_ent->token, bind_conf->mux_proto->token)) { ha_alert("%s '%s' : MUX protocol '%.*s' is not usable for 'bind %s' at [%s:%d].\n", @@ -2879,7 +2885,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->token, PROTO_SIDE_BE, mode); + mux_ent = conn_get_best_mux_entry(newsrv->mux_proto->token, PROTO_SIDE_BE, srv_is_quic(newsrv), mode); if (!mux_ent || !isteq(mux_ent->token, newsrv->mux_proto->token)) { ha_alert("%s '%s' : MUX protocol '%.*s' is not usable for server '%s' at [%s:%d].\n", diff --git a/src/server.c b/src/server.c index 2a6f01817..4368d7067 100644 --- a/src/server.c +++ b/src/server.c @@ -6242,7 +6242,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->token, PROTO_SIDE_BE, proto_mode); + mux_ent = conn_get_best_mux_entry(srv->mux_proto->token, PROTO_SIDE_BE, srv_is_quic(srv), proto_mode); if (!mux_ent || !isteq(mux_ent->token, srv->mux_proto->token)) { ha_alert("MUX protocol is not usable for server.\n"); diff --git a/src/stream.c b/src/stream.c index a83a4f68e..123f70961 100644 --- a/src/stream.c +++ b/src/stream.c @@ -3289,7 +3289,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->token, PROTO_SIDE_FE, mode); + mux_ent = conn_get_best_mux_entry(mux_proto->token, PROTO_SIDE_FE, 0, mode); if (!mux_ent || !isteq(mux_ent->token, mux_proto->token)) { memprintf(err, "MUX protocol '%.*s' is not compatible with the selected mode", (int)mux_proto->token.len, mux_proto->token.ptr); @@ -3297,7 +3297,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, mode); + mux_ent = conn_get_best_mux_entry(IST_NULL, PROTO_SIDE_FE, 0, mode); if (!mux_ent) { memprintf(err, "Unable to find compatible MUX protocol with the selected mode"); return 0; -- 2.47.3