BUG/MEDIUM: ssl: Always check the ALPN after handshake

Move the code that is responsible for checking the ALPN, and updating
the one stored in the server's path_param, from after we created the
mux, to after we did an handshake. Once we did it once, the mux will not
be created by the ssl code anymore, as when we know which mux to use
thanks to the ALPN, it will be done earlier in connect_server(), so in
the unlikely event it changes, we would not detect it anymore, and we'd
keep on creating the wrong mux.
This can be reproduced by doing a first request, and then changing the
ALPN of the server without haproxy noticing (ie without haproxy noticing
that the server went down).

This should be backported to 3.3.
This commit is contained in:
Olivier Houchard 2025-12-09 16:02:00 +01:00 committed by Olivier Houchard
parent 594408cd61
commit 260d64d787

View File

@ -6860,6 +6860,32 @@ struct task *ssl_sock_io_cb(struct task *t, void *context, unsigned int state)
ssl_sock_setup_ktls(ctx);
#endif
#endif
/*
* For backend connections, attempt to
* retrieve the ALPN, and store it into
* the server's path_params, so that for
* next connections, we'll know the ALPN
* already, and immediately know which mux
* to use, in case we want to use 0RTT.
*/
if (!(conn->flags & CO_FL_ERROR) && conn_is_back(conn)) {
struct server *srv;
const char *alpn;
int len;
srv = objt_server(conn->target);
if (srv && ssl_sock_get_alpn(conn, ctx, &alpn, &len)) {
if (len < sizeof(srv->path_params.nego_alpn) &&
(len != strlen(srv->path_params.nego_alpn) ||
memcmp(&srv->path_params.nego_alpn, alpn, len) != 0)) {
HA_RWLOCK_WRLOCK(SERVER_LOCK, &srv->path_params.param_lock);
memcpy(&srv->path_params.nego_alpn, alpn, len);
srv->path_params.nego_alpn[len] = 0;
HA_RWLOCK_WRUNLOCK(SERVER_LOCK, &srv->path_params.param_lock);
}
}
}
}
}
/* If we had an error, or the handshake is done and I/O is available,
@ -6893,35 +6919,8 @@ struct task *ssl_sock_io_cb(struct task *t, void *context, unsigned int state)
if (ctx->conn->xprt_ctx == ctx) {
int closed_connection = 0;
if (!ctx->conn->mux) {
if (!ctx->conn->mux)
ret = conn_create_mux(ctx->conn, &closed_connection);
/*
* For backend connections, attempt to
* retrieve the ALPN, and store it into
* the server's path_params, so that for
* next connections, we'll know the ALPN
* already, and immediately know which mux
* to use, in case we want to use 0RTT.
*/
if (ret >= 0 && conn_is_back(conn)) {
struct server *srv;
const char *alpn;
int len;
srv = objt_server(conn->target);
if (srv && ssl_sock_get_alpn(conn, ctx, &alpn, &len)) {
if (len < sizeof(srv->path_params.nego_alpn) &&
(len != strlen(srv->path_params.nego_alpn) ||
memcmp(&srv->path_params.nego_alpn, alpn, len) != 0)) {
HA_RWLOCK_WRLOCK(SERVER_LOCK, &srv->path_params.param_lock);
memcpy(&srv->path_params.nego_alpn, alpn, len);
srv->path_params.nego_alpn[len] = 0;
HA_RWLOCK_WRUNLOCK(SERVER_LOCK, &srv->path_params.param_lock);
}
}
}
}
if (ret >= 0 && !woke && ctx->conn->mux && ctx->conn->mux->wake) {
ret = ctx->conn->mux->wake(ctx->conn);
if (ret < 0)