]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: server: Make 'default-server' support 'sni' keyword.
authorFrédéric Lécaille <flecaille@haproxy.com>
Mon, 20 Mar 2017 13:54:41 +0000 (14:54 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 27 Mar 2017 12:37:01 +0000 (14:37 +0200)
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
src/server.c
src/ssl_sock.c

index c973d6934cc1d30c2da363c057cc66f7b14d77a3..781a889ef5745ec537f8378bf3e53ffe93595781 100644 (file)
@@ -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;
index 6b0c49637c5f18eeb817282a87c63ede9a3fdc49..602a7c9ba542aff7323a863942dffeee5bc1e164 100644 (file)
@@ -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;
index 9d85eac94fe3c5cf28d31333ff9c01b720231d66..4c1be5a4ba914988c92ad012f143c56c34e0281f 100644 (file)
@@ -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 */