]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: server: set auto SNI for dynamic servers
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Thu, 19 Feb 2026 15:31:25 +0000 (16:31 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 20 Feb 2026 08:02:47 +0000 (09:02 +0100)
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
src/cfgparse-ssl.c
src/proxy.c
src/server.c

index 05446e98f5e61aa37d8cce152c854c0c99a16ad1..ba4e6c10430001be0e24eaee7a69590d30b0e358 100644 (file)
@@ -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);
index 5053cf336e86a6ae6276a13046a65be6155a7e49..508113668c6fa34bdb34cf9f726b20b5e9b30283 100644 (file)
@@ -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 */
index 92550dcd13f83dbe615ff72346d7883d57e88aeb..dadcff0c6949b8e0f448635a49fe6c03af1ed1b6 100644 (file)
@@ -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;
                        }
                }
 
index 925b0c4afd41826f17e8a458b839b8f97dd891b2..66e1513d3ccdce883ef881c0fb92718e348aa1f2 100644 (file)
@@ -3377,6 +3377,29 @@ int server_parse_exprs(struct server *srv, struct proxy *px, char **errmsg)
        return ret;
 }
 
+/* Fill <srv> SNI expression to reuse the host header on outgoing requests.
+ *
+ * Returns 0 on success else non-zero. On error, <err_code> and <err> 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 <srv> 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;