>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