From 4ab2679689c02882d9ea743ab0c458cd0c3b5388 Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Wed, 1 Dec 2021 09:50:41 +0100 Subject: [PATCH] BUG/MINOR: server: Don't rely on last default-server to init server SSL context During post-parsing stage, the SSL context of a server is initialized if SSL is configured on the server or its default-server. It is required to be able to enable SSL at runtime. However a regression was introduced, because the last parsed default-server is used. But it is not necessarily the default-server line used to configure the server. This may lead to erroneously initialize the SSL context for a server without SSL parameter or the skip it while it should be done. The problem is the default-server used to configure a server is not saved during configuration parsing. So, the information is lost during the post-parsing. To fix the bug, the SRV_F_DEFSRV_USE_SSL flag is introduced. It is used to know when a server was initialized with a default-server using SSL. For the record, the commit f63704488e ("MEDIUM: cli/ssl: configure ssl on server at runtime") has introduced the bug. This patch must be backported as far as 2.4. --- include/haproxy/server-t.h | 1 + reg-tests/server/cli_set_ssl.vtc | 24 +++++++++++++++--------- src/cfgparse.c | 4 ++-- src/server.c | 4 ++++ 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/include/haproxy/server-t.h b/include/haproxy/server-t.h index b17f0de46f..71b8e4a873 100644 --- a/include/haproxy/server-t.h +++ b/include/haproxy/server-t.h @@ -148,6 +148,7 @@ enum srv_initaddr { #define SRV_F_NO_RESOLUTION 0x0800 /* disable runtime DNS resolution on this server */ #define SRV_F_DYNAMIC 0x1000 /* dynamic server instantiated at runtime */ #define SRV_F_NON_PURGEABLE 0x2000 /* this server cannot be removed at runtime */ +#define SRV_F_DEFSRV_USE_SSL 0x4000 /* default-server uses SSL */ /* configured server options for send-proxy (server->pp_opts) */ #define SRV_PP_V1 0x0001 /* proxy protocol version 1 */ diff --git a/reg-tests/server/cli_set_ssl.vtc b/reg-tests/server/cli_set_ssl.vtc index 093943b00b..fa6fe68c5d 100644 --- a/reg-tests/server/cli_set_ssl.vtc +++ b/reg-tests/server/cli_set_ssl.vtc @@ -26,8 +26,9 @@ haproxy h1 -conf { default_backend test0 backend test0 - default-server ssl server www0 ${s1_addr}:${s1_port} no-ssl + default-server ssl + server www1 ${s1_addr}:${s1_port} no-ssl backend test1 server www0 ${s1_addr}:${s1_port} no-ssl @@ -36,17 +37,22 @@ haproxy h1 -conf { haproxy h1 -cli { # supported case send "show servers state test0" + expect ~ "test0 2 www1 ${s1_addr} .* - ${s1_port} - -1" + send "set server test0/www1 ssl on" + expect ~ "server ssl setting updated" + send "show servers state test0" + expect ~ "test0 2 www1 ${s1_addr} .* - ${s1_port} - 1" + send "set server test0/www1 ssl off" + expect ~ "server ssl setting updated" + send "show servers state test0" + expect ~ "test0 2 www1 ${s1_addr} .* - ${s1_port} - 0" + + # unsupported cases + send "show servers state test0" expect ~ "test0 1 www0 ${s1_addr} .* - ${s1_port} - -1" send "set server test0/www0 ssl on" - expect ~ "server ssl setting updated" - send "show servers state test0" - expect ~ "test0 1 www0 ${s1_addr} .* - ${s1_port} - 1" - send "set server test0/www0 ssl off" - expect ~ "server ssl setting updated" - send "show servers state test0" - expect ~ "test0 1 www0 ${s1_addr} .* - ${s1_port} - 0" + expect ~ "'set server ssl' cannot be set" - # unsupported case send "show servers state test1" expect ~ "test1 1 www0 ${s1_addr} .* - ${s1_port} - -1" send "set server test1/www0 ssl on" diff --git a/src/cfgparse.c b/src/cfgparse.c index 58067c8edf..06352e294f 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -3399,8 +3399,8 @@ int check_config_validity() * if default-server have use_ssl, prerare ssl init * without activating it */ if (newsrv->use_ssl == 1 || newsrv->check.use_ssl == 1 || - (newsrv->proxy->options & PR_O_TCPCHK_SSL) || - (newsrv->use_ssl != 1 && curproxy->defsrv.use_ssl == 1)) { + (newsrv->proxy->options & PR_O_TCPCHK_SSL) || + ((newsrv->flags & SRV_F_DEFSRV_USE_SSL) && newsrv->use_ssl != 1)) { if (xprt_get(XPRT_SSL) && xprt_get(XPRT_SSL)->prepare_srv) cfgerr += xprt_get(XPRT_SSL)->prepare_srv(newsrv); } diff --git a/src/server.c b/src/server.c index a8e85a982e..47bd38bc06 100644 --- a/src/server.c +++ b/src/server.c @@ -2049,6 +2049,10 @@ static void srv_conn_src_cpy(struct server *srv, struct server *src) #if defined(USE_OPENSSL) static void srv_ssl_settings_cpy(struct server *srv, struct server *src) { + /* is the current proxy's default server and SSL is enabled */ + if (src == &srv->proxy->defsrv && src->use_ssl == 1) + srv->flags |= SRV_F_DEFSRV_USE_SSL; + if (src->ssl_ctx.ca_file != NULL) srv->ssl_ctx.ca_file = strdup(src->ssl_ctx.ca_file); if (src->ssl_ctx.crl_file != NULL)