From: Olivier Houchard Date: Tue, 19 May 2026 13:52:21 +0000 (+0200) Subject: MEDIUM: connections: Use both mux_proto and alpn to pick a mux X-Git-Tag: v3.4-dev13~35 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=6aab6d4e980ef0a11f0536f72a39b6a6b8e3fa17;p=thirdparty%2Fhaproxy.git MEDIUM: connections: Use both mux_proto and alpn to pick a mux 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. --- diff --git a/include/haproxy/connection.h b/include/haproxy/connection.h index f73bb334c..dfd816344 100644 --- a/include/haproxy/connection.h +++ b/include/haproxy/connection.h @@ -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; } diff --git a/src/connection.c b/src/connection.c index 7112ef1cd..50fc6c457 100644 --- a/src/connection.c +++ b/src/connection.c @@ -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; } diff --git a/src/proxy.c b/src/proxy.c index c12ffdf55..f0667228c 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -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", diff --git a/src/server.c b/src/server.c index 4d52556e0..94105518c 100644 --- a/src/server.c +++ b/src/server.c @@ -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"); diff --git a/src/stream.c b/src/stream.c index fd27b9cf6..73feb7ebf 100644 --- a/src/stream.c +++ b/src/stream.c @@ -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; diff --git a/src/tcpcheck.c b/src/tcpcheck.c index d354291f1..b7203d1fa 100644 --- a/src/tcpcheck.c +++ b/src/tcpcheck.c @@ -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);