>From 78c8279eb296b4a70eecb7eff599e2851749b3c3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20L=C3=A9caille?= <flecai...@haproxy.com>
Date: Mon, 20 Mar 2017 14:54:41 +0100
Subject: [PATCH 27/31] MINOR: server: Make 'default-server' support 'sni'
 keyword.
X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4

This patch makes 'default-server' directives support 'sni' settings.
A field 'sni_expr' has been added to 'struct server' to temporary
stores SNI expressions as strings during both 'default-server' and 'server'
lines parsing. So, to duplicate SNI expressions from 'default-server' 'sni' setting
for new 'server' instances we only have to "strdup" these strings as this is
often done for most of the 'server' settings.
Then, sample expressions are computed calling sample_parse_expr() (only for 'server'
instances).
A new function has been added to produce the same error output as before in case
of any error during 'sni' settings parsing (display_parser_err()).
Should not break anything.
---
 include/types/server.h |  1 +
 src/server.c           | 75 +++++++++++++++++++++++++++++++++++++++++++++-----
 src/ssl_sock.c         | 27 ++++--------------
 3 files changed, 75 insertions(+), 28 deletions(-)

diff --git a/include/types/server.h b/include/types/server.h
index c973d69..781a889 100644
--- a/include/types/server.h
+++ b/include/types/server.h
@@ -254,6 +254,7 @@ struct server {
 
 	int use_ssl;				/* ssl enabled  */
 #ifdef USE_OPENSSL
+	char *sni_expr;             /* Temporary variable to store a sample expression for SNI */
 	struct {
 		SSL_CTX *ctx;
 		SSL_SESSION *reused_sess;
diff --git a/src/server.c b/src/server.c
index 51c5ee6..404c0b1 100644
--- a/src/server.c
+++ b/src/server.c
@@ -36,6 +36,7 @@
 #include <proto/port_range.h>
 #include <proto/protocol.h>
 #include <proto/queue.h>
+#include <proto/sample.h>
 #include <proto/server.h>
 #include <proto/stream.h>
 #include <proto/stream_interface.h>
@@ -1438,6 +1439,53 @@ const char *server_parse_maxconn_change_request(struct server *sv,
 	return NULL;
 }
 
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+static int server_parse_sni_expr(struct server *newsrv, struct proxy *px, char **err)
+{
+	int idx;
+	struct sample_expr *expr;
+	const char *args[] = {
+		newsrv->sni_expr,
+		NULL,
+	};
+
+	idx = 0;
+	proxy->conf.args.ctx = ARGC_SRV;
+
+	expr = sample_parse_expr((char **)args, &idx, px->conf.file, px->conf.line,
+	                         err, &proxy->conf.args);
+	if (!expr) {
+		memprintf(err, "error detected while parsing sni expression : %s", *err);
+		return ERR_ALERT | ERR_FATAL;
+	}
+
+	if (!(expr->fetch->val & SMP_VAL_BE_SRV_CON)) {
+		memprintf(err, "error detected while parsing sni expression : "
+		          " fetch method '%s' extracts information from '%s', "
+		          "none of which is available here.\n",
+		          args[0], sample_src_names(expr->fetch->use));
+		return ERR_ALERT | ERR_FATAL;
+	}
+
+	px->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
+	release_sample_expr(newsrv->ssl_ctx.sni);
+	newsrv->ssl_ctx.sni = expr;
+
+	return 0;
+}
+#endif
+
+static void display_parser_err(const char *file, int linenum, char **args, int cur_arg, char **err)
+{
+	if (err && *err) {
+		indent_msg(err, 2);
+		Alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], *err);
+	}
+	else
+		Alert("parsing [%s:%d] : '%s %s' : error encountered while processing '%s'.\n",
+		      file, linenum, args[0], args[1], args[cur_arg]);
+}
+
 int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, struct proxy *defproxy)
 {
 	struct server *newsrv = NULL;
@@ -1688,6 +1736,8 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
 				newsrv->ssl_ctx.verify_host = strdup(curproxy->defsrv.ssl_ctx.verify_host);
 			if (curproxy->defsrv.ssl_ctx.ciphers != NULL)
 				newsrv->ssl_ctx.ciphers = strdup(curproxy->defsrv.ssl_ctx.ciphers);
+			if (curproxy->defsrv.sni_expr != NULL)
+				newsrv->sni_expr = strdup(curproxy->defsrv.sni_expr);
 #endif
 
 #ifdef TCP_USER_TIMEOUT
@@ -2135,13 +2185,7 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
 					err_code |= code;
 
 					if (code) {
-						if (err && *err) {
-							indent_msg(&err, 2);
-							Alert("parsing [%s:%d] : '%s %s' : %s\n", file, linenum, args[0], args[1], err);
-						}
-						else
-							Alert("parsing [%s:%d] : '%s %s' : error encountered while processing '%s'.\n",
-							      file, linenum, args[0], args[1], args[cur_arg]);
+						display_parser_err(file, linenum, args, cur_arg, &err);
 						if (code & ERR_FATAL) {
 							free(err);
 							cur_arg += 1 + kw->skip;
@@ -2270,6 +2314,23 @@ int parse_server(const char *file, int linenum, char **args, struct proxy *curpr
 
 			srv_lb_commit_status(newsrv);
 		}
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+		if (!defsrv && newsrv->sni_expr) {
+			int code;
+			char *err;
+
+			err = NULL;
+
+			code = server_parse_sni_expr(newsrv, curproxy, &err);
+			err_code |= code;
+			if (code) {
+				display_parser_err(file, linenum, args, cur_arg, &err);
+				free(err);
+				if (code & ERR_FATAL)
+					goto out;
+			}
+		}
+#endif
 	}
 	free(fqdn);
 	return 0;
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 9d85eac..4c1be5a 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -6679,32 +6679,17 @@ static int srv_parse_sni(char **args, int *cur_arg, struct proxy *px, struct ser
 	memprintf(err, "'%s' : the current SSL library doesn't support the SNI TLS extension", args[*cur_arg]);
 	return ERR_ALERT | ERR_FATAL;
 #else
-	int idx;
-	struct sample_expr *expr;
+	char *arg;
 
-	if (!*args[*cur_arg + 1]) {
+	arg = args[*cur_arg + 1];
+	if (!*arg) {
 		memprintf(err, "'%s' : missing sni expression", args[*cur_arg]);
 		return ERR_ALERT | ERR_FATAL;
 	}
 
-	idx = (*cur_arg) + 1;
-	proxy->conf.args.ctx = ARGC_SRV;
-
-	expr = sample_parse_expr((char **)args, &idx, px->conf.file, px->conf.line, err, &proxy->conf.args);
-	if (!expr) {
-		memprintf(err, "error detected while parsing sni expression : %s", *err);
-		return ERR_ALERT | ERR_FATAL;
-	}
-
-	if (!(expr->fetch->val & SMP_VAL_BE_SRV_CON)) {
-		memprintf(err, "error detected while parsing sni expression : "
-		          " fetch method '%s' extracts information from '%s', none of which is available here.\n",
-		          args[idx-1], sample_src_names(expr->fetch->use));
-		return ERR_ALERT | ERR_FATAL;
-	}
+	free(newsrv->sni_expr);
+	newsrv->sni_expr = strdup(arg);
 
-	px->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
-	newsrv->ssl_ctx.sni = expr;
 	return 0;
 #endif
 }
@@ -7510,7 +7495,7 @@ static struct srv_kw_list srv_kws = { "SSL", { }, {
 	{ "no-tls-tickets",          srv_parse_no_tls_tickets,    0, 1 }, /* disable session resumption tickets */
 	{ "send-proxy-v2-ssl",       srv_parse_send_proxy_ssl,    0, 1 }, /* send PROXY protocol header v2 with SSL info */
 	{ "send-proxy-v2-ssl-cn",    srv_parse_send_proxy_cn,     0, 1 }, /* send PROXY protocol header v2 with CN */
-	{ "sni",                     srv_parse_sni,               1, 0 }, /* send SNI extension */
+	{ "sni",                     srv_parse_sni,               1, 1 }, /* send SNI extension */
 	{ "ssl",                     srv_parse_ssl,               0, 1 }, /* enable SSL processing */
 	{ "ssl-reuse",               srv_parse_ssl_reuse,         0, 1 }, /* enable session reuse */
 	{ "sslv3",                   srv_parse_sslv3,             0, 1 }, /* enable SSLv3 */
-- 
2.1.4

Reply via email to