From de5fc2f515be1bb0d5b3d1b5961ed0744c2c9d9a Mon Sep 17 00:00:00 2001 From: Amaury Denoyelle Date: Thu, 19 Feb 2026 16:31:25 +0100 Subject: [PATCH] BUG/MINOR: server: set auto SNI for dynamic servers Auto SNI configuration is configured during check config validity. However, nothing was implemented for dynamic servers. Fix this by implementing auto SNI configuration during "add server" CLI handler. Auto SNI configuration code is moved in a dedicated function srv_configure_auto_sni() called both for static and dynamic servers. Along with this, allows the keyword "no-sni-auto" on dynamic servers, so that this process can be deactivated if wanted. Note that "sni-auto" remains unavailable as it only makes sense with default-servers which are never used for dynamic server creation. This must be backported up to 3.3. --- include/haproxy/server.h | 1 + src/cfgparse-ssl.c | 2 +- src/proxy.c | 35 +++++++++++++---------------------- src/server.c | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 23 deletions(-) diff --git a/include/haproxy/server.h b/include/haproxy/server.h index 05446e98f..ba4e6c104 100644 --- a/include/haproxy/server.h +++ b/include/haproxy/server.h @@ -55,6 +55,7 @@ int srv_update_addr(struct server *s, void *ip, int ip_sin_family, struct server struct sample_expr *_parse_srv_expr(char *expr, struct arg_list *args_px, const char *file, int linenum, char **err); int server_parse_exprs(struct server *srv, struct proxy *px, char **err); +int srv_configure_auto_sni(struct server *srv, int *err_code, char **err); int server_set_inetaddr(struct server *s, const struct server_inetaddr *inetaddr, struct server_inetaddr_updater updater, struct buffer *msg); int server_set_inetaddr_warn(struct server *s, const struct server_inetaddr *inetaddr, struct server_inetaddr_updater updater); void server_get_inetaddr(struct server *s, struct server_inetaddr *inetaddr); diff --git a/src/cfgparse-ssl.c b/src/cfgparse-ssl.c index 5053cf336..508113668 100644 --- a/src/cfgparse-ssl.c +++ b/src/cfgparse-ssl.c @@ -2743,7 +2743,7 @@ static struct srv_kw_list srv_kws = { "SSL", { }, { { "no-renegotiate", srv_parse_renegotiate, 0, 1, 1 }, /* Disable renegotiation */ { "no-send-proxy-v2-ssl", srv_parse_no_send_proxy_ssl, 0, 1, 0 }, /* do not send PROXY protocol header v2 with SSL info */ { "no-send-proxy-v2-ssl-cn", srv_parse_no_send_proxy_cn, 0, 1, 0 }, /* do not send PROXY protocol header v2 with CN */ - { "no-sni-auto", srv_parse_no_sni_auto, 0, 1, 0 }, /* disable automatic SNI selection */ + { "no-sni-auto", srv_parse_no_sni_auto, 0, 1, 1 }, /* disable automatic SNI selection */ { "no-ssl", srv_parse_no_ssl, 0, 1, 0 }, /* disable SSL processing */ { "no-ssl-reuse", srv_parse_no_ssl_reuse, 0, 1, 1 }, /* disable session reuse */ { "no-sslv3", srv_parse_tls_method_options, 0, 0, 1 }, /* disable SSLv3 */ diff --git a/src/proxy.c b/src/proxy.c index 92550dcd1..dadcff0c6 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -2536,29 +2536,20 @@ int proxy_finalize(struct proxy *px, int *err_code) cfgerr += xprt_get(XPRT_QUIC)->prepare_srv(newsrv); } - if (newsrv->use_ssl == 1 || ((newsrv->flags & SRV_F_DEFSRV_USE_SSL) && newsrv->use_ssl != 1)) { - /* In HTTP only, if the SNI is not set and we can rely on the host - * header value, fill the sni expression accordingly - */ - if (!newsrv->sni_expr && newsrv->proxy->mode == PR_MODE_HTTP && - !(newsrv->ssl_ctx.options & SRV_SSL_O_NO_AUTO_SNI)) { - newsrv->sni_expr = strdup("req.hdr(host),field(1,:)"); - if (!newsrv->sni_expr) { - ha_alert("parsing [%s:%d]: out of memory while generating server auto SNI expression.\n", - newsrv->conf.file, newsrv->conf.line); - cfgerr++; - *err_code |= ERR_ALERT | ERR_ABORT; + /* In HTTP only, if the SNI is not set and we can rely on the + * host header value, fill the sni expression accordingly + */ + if (newsrv->proxy->mode == PR_MODE_HTTP && + (newsrv->use_ssl == 1 || (newsrv->flags & SRV_F_DEFSRV_USE_SSL)) && + !newsrv->sni_expr && !(newsrv->ssl_ctx.options & SRV_SSL_O_NO_AUTO_SNI)) { + if (srv_configure_auto_sni(newsrv, err_code, &err)) { + ha_alert("parsing [%s:%d]: %s.\n", + newsrv->conf.file, newsrv->conf.line, err); + ha_free(&err); + ++cfgerr; + if (*err_code & ERR_ABORT) goto out; - } - - err = NULL; - if (server_parse_exprs(newsrv, px, &err)) { - ha_alert("parsing [%s:%d]: failed to parse auto SNI expression: %s\n", - newsrv->conf.file, newsrv->conf.line, err); - free(err); - ++cfgerr; - goto next_srv; - } + goto next_srv; } } diff --git a/src/server.c b/src/server.c index 925b0c4af..66e1513d3 100644 --- a/src/server.c +++ b/src/server.c @@ -3377,6 +3377,29 @@ int server_parse_exprs(struct server *srv, struct proxy *px, char **errmsg) return ret; } +/* Fill SNI expression to reuse the host header on outgoing requests. + * + * Returns 0 on success else non-zero. On error, and message + * are both set. + */ +int srv_configure_auto_sni(struct server *srv, int *err_code, char **err) +{ + srv->sni_expr = strdup("req.hdr(host),field(1,:)"); + if (!srv->sni_expr) { + memprintf(err, "out of memory while generating server auto SNI expression"); + *err_code |= ERR_ALERT | ERR_ABORT; + return 1; + } + + if (server_parse_exprs(srv, srv->proxy, err)) { + memprintf(err, "failed to parse auto SNI expression: %s", *err); + *err_code |= ERR_ALERT | ERR_FATAL; + return 1; + } + + return 0; +} + /* Initialize as much as possible servers from server template. * Note that a server template is a special server with * a few different parameters than a server which has @@ -6231,6 +6254,15 @@ static int cli_parse_add_server(char **args, char *payload, struct appctx *appct } } + /* Define default SNI from host header if needed. */ + if (srv->proxy->mode == PR_MODE_HTTP && srv->use_ssl == 1 && + !srv->sni_expr && !(srv->ssl_ctx.options & SRV_SSL_O_NO_AUTO_SNI)) { + if (srv_configure_auto_sni(srv, &errcode, &errmsg)) { + ha_alert("%s.\n", errmsg); + goto out; + } + } + if (srv->trackit) { if (srv_apply_track(srv, be)) goto out; -- 2.47.3