diff --git a/include/haproxy/server.h b/include/haproxy/server.h index 8d58e74c4..b8f8c7131 100644 --- a/include/haproxy/server.h +++ b/include/haproxy/server.h @@ -26,9 +26,11 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -48,7 +50,8 @@ void srv_settings_init(struct server *srv); void srv_settings_cpy(struct server *srv, const struct server *src, int srv_tmpl); int parse_server(const char *file, int linenum, char **args, struct proxy *curproxy, const struct proxy *defproxy, int parse_flags); int srv_update_addr(struct server *s, void *ip, int ip_sin_family, struct server_inetaddr_updater updater); -int server_parse_sni_expr(struct server *newsrv, struct proxy *px, char **err); +struct sample_expr *_parse_srv_expr(char *expr, struct arg_list *args_px, + const char *file, int linenum, 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); diff --git a/src/http_client.c b/src/http_client.c index 7a8d7fdf6..848e6cec0 100644 --- a/src/http_client.c +++ b/src/http_client.c @@ -1389,9 +1389,12 @@ static int httpclient_postcheck_proxy(struct proxy *curproxy) /* init the SNI expression */ /* always use the host header as SNI, without the port */ srv_ssl->sni_expr = strdup("req.hdr(host),field(1,:)"); - err_code |= server_parse_sni_expr(srv_ssl, curproxy, &errmsg); - if (err_code & ERR_CODE) { - memprintf(&errmsg, "failed to configure sni: %s.", errmsg); + srv_ssl->ssl_ctx.sni = _parse_srv_expr(srv_ssl->sni_expr, + &curproxy->conf.args, + NULL, 0, NULL); + if (!srv_ssl->ssl_ctx.sni) { + memprintf(&errmsg, "failed to configure sni."); + err_code |= ERR_ALERT | ERR_FATAL; goto err; } } diff --git a/src/server.c b/src/server.c index 48984fe5c..f0362a09b 100644 --- a/src/server.c +++ b/src/server.c @@ -2429,42 +2429,56 @@ const char *server_parse_maxconn_change_request(struct server *sv, return NULL; } -static struct sample_expr *srv_sni_sample_parse_expr(struct server *srv, struct proxy *px, - const char *file, int linenum, char **err) +/* Interpret as sample expression. This function is reserved for + * internal server allocation. On parsing use parse_srv_expr() for extra sample + * check validity. + * + * Returns the allocated sample on success or NULL on error. + */ +struct sample_expr *_parse_srv_expr(char *expr, struct arg_list *args_px, + const char *file, int linenum, char **err) { int idx; const char *args[] = { - srv->sni_expr, + expr, NULL, }; idx = 0; - px->conf.args.ctx = ARGC_SRV; + args_px->ctx = ARGC_SRV; - return sample_parse_expr((char **)args, &idx, file, linenum, err, &px->conf.args, NULL); + return sample_parse_expr((char **)args, &idx, file, linenum, err, args_px, NULL); } -int server_parse_sni_expr(struct server *newsrv, struct proxy *px, char **err) +/* Interpret if not empty as a sample expression and store it into . + * Contrary to _parse_srv_expr(), fetch scope validity is checked to ensure it + * is valid on a server line context. It also updates HTTP mode + * requirement depending on fetch method used. + * + * Returns 0 on success else non zero. + */ +static int parse_srv_expr(char *str, struct sample_expr **out, struct proxy *px, + char **err) { struct sample_expr *expr; - expr = srv_sni_sample_parse_expr(newsrv, px, px->conf.file, px->conf.line, err); - if (!expr) { - memprintf(err, "error detected while parsing sni expression : %s", *err); + if (!str) + return 0; + + expr = _parse_srv_expr(str, &px->conf.args, px->conf.file, px->conf.line, err); + if (!expr) 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', " + memprintf(err, "fetch method '%s' extracts information from '%s', " "none of which is available here.", - newsrv->sni_expr, sample_src_names(expr->fetch->use)); + str, 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; + release_sample_expr(*out); + *out = expr; return 0; } @@ -3106,7 +3120,7 @@ static int _srv_parse_tmpl_init(struct server *srv, struct proxy *px) srv_prepare_for_resolution(newsrv, srv->hostname); if (newsrv->sni_expr) { - newsrv->ssl_ctx.sni = srv_sni_sample_parse_expr(newsrv, px, NULL, 0, NULL); + newsrv->ssl_ctx.sni = _parse_srv_expr(srv->sni_expr, &px->conf.args, NULL, 0, NULL); if (!newsrv->ssl_ctx.sni) goto err; } @@ -3495,25 +3509,6 @@ static int _srv_parse_kw(struct server *srv, char **args, int *cur_arg, return err_code; } -/* This function is first intended to be used through parse_server to - * initialize a new server on startup. - */ -static int _srv_parse_sni_expr_init(char **args, int cur_arg, - struct server *srv, struct proxy *proxy, - char **errmsg) -{ - int ret; - - if (!srv->sni_expr) - return 0; - - ret = server_parse_sni_expr(srv, proxy, errmsg); - if (!ret) - return 0; - - return ret; -} - /* Server initializations finalization. * Initialize health check, agent check, SNI expression and outgoing TLVs if enabled. * Must not be called for a default server instance. @@ -3540,9 +3535,9 @@ static int _srv_parse_finalize(char **args, int cur_arg, return ERR_ALERT | ERR_FATAL; } - if ((ret = _srv_parse_sni_expr_init(args, cur_arg, srv, px, &errmsg)) != 0) { + if ((ret = parse_srv_expr(srv->sni_expr, &srv->ssl_ctx.sni, px, &errmsg))) { if (errmsg) { - ha_alert("%s\n", errmsg); + ha_alert("error detected while parsing sni expression : %s.\n", errmsg); free(errmsg); } return ret;