mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-20 21:31:28 +02:00
MEDIUM: httpcheck/ssl: Base the SNI value on the HTTP host header by default
Similarly to the automic SNI selection for regulat SSL traffic, the SNI of health-checks HTTPS connection is now automatically set by default by using the host header value. "check-sni-auto" and "no-check-sni-auto" server settings were added to change this behavior. Only implicit HTTPS health-checks can take advantage of this feature. In this case, the host header value from the "option httpchk" directive is used to extract the SNI. It is disabled if http-check rules are used. So, the SNI must still be explicitly specified via a "http-check connect" rule. This patch with should paritally fix the issue #3081.
This commit is contained in:
parent
668916c1a2
commit
ffc1f096e0
@ -17635,6 +17635,28 @@ check-proto <name>
|
|||||||
protocol for health-check connections established to this server.
|
protocol for health-check connections established to this server.
|
||||||
If not defined, the server one will be used, if set.
|
If not defined, the server one will be used, if set.
|
||||||
|
|
||||||
|
check-sni-auto
|
||||||
|
May be used in the following contexts: tcp, http, log
|
||||||
|
|
||||||
|
This option enables the automatic SNI selection when doing health checks over
|
||||||
|
SSL, if no value was already set. It is enabled by default but this parameter
|
||||||
|
may be used as "server" setting to reset any "no-check-sni-auto" setting
|
||||||
|
which would have been inherited from "default-server" directive as default
|
||||||
|
value. It may also be used as "default-server" setting to reset any previous
|
||||||
|
"default-server" "no-check-sni-auto" setting.
|
||||||
|
|
||||||
|
For HTTPS connections, the SNI is automatically selected but only if there is
|
||||||
|
no "http-check connect" rule. In that case, the selected SNI is based on the
|
||||||
|
host header value, specified via the "option httpchk" directive or a
|
||||||
|
"http-check send" rule. There is no automatic selection for "http-check
|
||||||
|
connect" rules. For other protocols, the option is ignored.
|
||||||
|
|
||||||
|
If the automatic selection of the SNI is used for health-checks, the value is
|
||||||
|
assigned to the connection name if "check-reuse-pool" setting is set, unless
|
||||||
|
overridden by the "check-pool-conn-name" server keyword.
|
||||||
|
|
||||||
|
See "sni-auto" option to enable automatic SNI selection for proxied traffic.
|
||||||
|
|
||||||
check-sni <sni>
|
check-sni <sni>
|
||||||
May be used in the following contexts: tcp, http, log
|
May be used in the following contexts: tcp, http, log
|
||||||
|
|
||||||
@ -18129,6 +18151,15 @@ no-check-reuse-pool
|
|||||||
This option reverts any previous "check-reuse-pool" possibly inherited from a
|
This option reverts any previous "check-reuse-pool" possibly inherited from a
|
||||||
"default-server". Any checks will be conducted on its dedicated connection.
|
"default-server". Any checks will be conducted on its dedicated connection.
|
||||||
|
|
||||||
|
no-check-sni-auto
|
||||||
|
May be used in the following contexts: tcp, http, log
|
||||||
|
|
||||||
|
This option may be used as "server" setting to disable the automatic SNI
|
||||||
|
selection for SSL health checks which is enabled by default.
|
||||||
|
|
||||||
|
See "no-sni-auto" option to disable automatic SNI selection for proxied
|
||||||
|
traffic.
|
||||||
|
|
||||||
no-check-ssl
|
no-check-ssl
|
||||||
May be used in the following contexts: tcp, http, log
|
May be used in the following contexts: tcp, http, log
|
||||||
|
|
||||||
@ -18195,6 +18226,9 @@ no-sni-auto
|
|||||||
This option may be used as "server" setting to disable the automatic SNI
|
This option may be used as "server" setting to disable the automatic SNI
|
||||||
selection which is enabled by default.
|
selection which is enabled by default.
|
||||||
|
|
||||||
|
See "no-check-sni-auto" option to disable automatic SNI selection for SSL
|
||||||
|
health checks.
|
||||||
|
|
||||||
no-ssl
|
no-ssl
|
||||||
May be used in the following contexts: tcp, http, log, peers, ring
|
May be used in the following contexts: tcp, http, log, peers, ring
|
||||||
|
|
||||||
@ -18780,6 +18814,9 @@ sni-auto
|
|||||||
connection name for "http-reuse", unless overridden by the "pool-conn-name"
|
connection name for "http-reuse", unless overridden by the "pool-conn-name"
|
||||||
server keyword.
|
server keyword.
|
||||||
|
|
||||||
|
See "check-sni-auto" option to enable automatic SNI selection for SSL health
|
||||||
|
checks.
|
||||||
|
|
||||||
source <addr>[:<pl>[-<ph>]] [usesrc { <addr2>[:<port2>] | client | clientip } ]
|
source <addr>[:<pl>[-<ph>]] [usesrc { <addr2>[:<port2>] | client | clientip } ]
|
||||||
source <addr>[:<port>] [usesrc { <addr2>[:<port2>] | hdr_ip(<hdr>[,<occ>]) } ]
|
source <addr>[:<port>] [usesrc { <addr2>[:<port2>] | hdr_ip(<hdr>[,<occ>]) } ]
|
||||||
source <addr>[:<pl>[-<ph>]] [interface <name>] ...
|
source <addr>[:<pl>[-<ph>]] [interface <name>] ...
|
||||||
|
@ -171,7 +171,7 @@ enum srv_init_state {
|
|||||||
#define SRV_F_DEFSRV_USE_SSL 0x4000 /* default-server uses SSL */
|
#define SRV_F_DEFSRV_USE_SSL 0x4000 /* default-server uses SSL */
|
||||||
#define SRV_F_DELETED 0x8000 /* srv is deleted but not yet purged */
|
#define SRV_F_DELETED 0x8000 /* srv is deleted but not yet purged */
|
||||||
#define SRV_F_STRICT_MAXCONN 0x10000 /* maxconn is to be strictly enforced, as a limit of outbound connections */
|
#define SRV_F_STRICT_MAXCONN 0x10000 /* maxconn is to be strictly enforced, as a limit of outbound connections */
|
||||||
/* unused: 0x20000 */
|
#define SRV_F_CHK_NO_AUTO_SNI 0x20000 /* disable automatic SNI selection for healthcheck */
|
||||||
|
|
||||||
/* configured server options for send-proxy (server->pp_opts) */
|
/* configured server options for send-proxy (server->pp_opts) */
|
||||||
#define SRV_PP_V1 0x0001 /* proxy protocol version 1 */
|
#define SRV_PP_V1 0x0001 /* proxy protocol version 1 */
|
||||||
|
@ -125,6 +125,7 @@ enum tcpcheck_rule_type {
|
|||||||
struct check;
|
struct check;
|
||||||
struct tcpcheck_connect {
|
struct tcpcheck_connect {
|
||||||
char *sni; /* server name to use for SSL connections */
|
char *sni; /* server name to use for SSL connections */
|
||||||
|
struct lf_expr *sni_fmt; /* log-format string used for SNI. if defined, point on the following HTTP host header value */
|
||||||
char *alpn; /* ALPN to use for the SSL connection */
|
char *alpn; /* ALPN to use for the SSL connection */
|
||||||
int alpn_len; /* ALPN string length */
|
int alpn_len; /* ALPN string length */
|
||||||
const struct mux_proto_list *mux_proto; /* the mux to use for all outgoing connections (specified by the "proto" keyword) */
|
const struct mux_proto_list *mux_proto; /* the mux to use for all outgoing connections (specified by the "proto" keyword) */
|
||||||
|
@ -1878,6 +1878,20 @@ static int srv_parse_crt(char **args, int *cur_arg, struct proxy *px, struct ser
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* parse the "check-sni-auto" server keyword */
|
||||||
|
static int srv_parse_check_sni_auto(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
|
||||||
|
{
|
||||||
|
newsrv->flags &= ~SRV_F_CHK_NO_AUTO_SNI;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parse the "no-check-sni-auto" server keyword */
|
||||||
|
static int srv_parse_no_check_sni_auto(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
|
||||||
|
{
|
||||||
|
newsrv->flags |= SRV_F_CHK_NO_AUTO_SNI;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* parse the "no-check-ssl" server keyword */
|
/* parse the "no-check-ssl" server keyword */
|
||||||
static int srv_parse_no_check_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
|
static int srv_parse_no_check_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
|
||||||
{
|
{
|
||||||
@ -2594,6 +2608,7 @@ static struct srv_kw_list srv_kws = { "SSL", { }, {
|
|||||||
{ "ca-file", srv_parse_ca_file, 1, 1, 1 }, /* set CAfile to process verify server cert */
|
{ "ca-file", srv_parse_ca_file, 1, 1, 1 }, /* set CAfile to process verify server cert */
|
||||||
{ "check-alpn", srv_parse_check_alpn, 1, 1, 1 }, /* Set ALPN used for checks */
|
{ "check-alpn", srv_parse_check_alpn, 1, 1, 1 }, /* Set ALPN used for checks */
|
||||||
{ "check-sni", srv_parse_check_sni, 1, 1, 1 }, /* set SNI */
|
{ "check-sni", srv_parse_check_sni, 1, 1, 1 }, /* set SNI */
|
||||||
|
{ "check-sni-auto", srv_parse_check_sni_auto, 0, 1, 0 }, /* enable automatic SNI selection for health checks */
|
||||||
{ "check-ssl", srv_parse_check_ssl, 0, 1, 1 }, /* enable SSL for health checks */
|
{ "check-ssl", srv_parse_check_ssl, 0, 1, 1 }, /* enable SSL for health checks */
|
||||||
{ "ciphers", srv_parse_ciphers, 1, 1, 1 }, /* select the cipher suite */
|
{ "ciphers", srv_parse_ciphers, 1, 1, 1 }, /* select the cipher suite */
|
||||||
{ "ciphersuites", srv_parse_ciphersuites, 1, 1, 1 }, /* select the cipher suite */
|
{ "ciphersuites", srv_parse_ciphersuites, 1, 1, 1 }, /* select the cipher suite */
|
||||||
@ -2607,6 +2622,7 @@ static struct srv_kw_list srv_kws = { "SSL", { }, {
|
|||||||
{ "force-tlsv12", srv_parse_tls_method_options, 0, 1, 1 }, /* force TLSv12 */
|
{ "force-tlsv12", srv_parse_tls_method_options, 0, 1, 1 }, /* force TLSv12 */
|
||||||
{ "force-tlsv13", srv_parse_tls_method_options, 0, 1, 1 }, /* force TLSv13 */
|
{ "force-tlsv13", srv_parse_tls_method_options, 0, 1, 1 }, /* force TLSv13 */
|
||||||
{ "ktls", srv_parse_ktls, 1, 1, 1 }, /* enable or disable kTLS */
|
{ "ktls", srv_parse_ktls, 1, 1, 1 }, /* enable or disable kTLS */
|
||||||
|
{ "no-check-sni-auto", srv_parse_no_check_sni_auto, 0, 1, 0 }, /* disable automatic SNI selection for health checks */
|
||||||
{ "no-check-ssl", srv_parse_no_check_ssl, 0, 1, 0 }, /* disable SSL for health checks */
|
{ "no-check-ssl", srv_parse_no_check_ssl, 0, 1, 0 }, /* disable SSL for health checks */
|
||||||
{ "no-renegotiate", srv_parse_renegotiate, 0, 1, 1 }, /* Disable renegotiation */
|
{ "no-renegotiate", srv_parse_renegotiate, 0, 1, 1 }, /* Disable renegotiation */
|
||||||
{ "no-send-proxy-v2-ssl", srv_parse_no_send_proxy_ssl, 0, 1, 0 }, /* do not send PROXY protocol header v2 with SSL info */
|
{ "no-send-proxy-v2-ssl", srv_parse_no_send_proxy_ssl, 0, 1, 0 }, /* do not send PROXY protocol header v2 with SSL info */
|
||||||
|
@ -1232,6 +1232,27 @@ static inline int tcpcheck_connect_use_ssl(const struct check *check,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void tcpcheck_connect_auto_sni(const struct check *check,
|
||||||
|
const struct tcpcheck_connect *connect,
|
||||||
|
struct buffer *chk)
|
||||||
|
{
|
||||||
|
chunk_reset(chk);
|
||||||
|
chk->data = sess_build_logline(check->sess, NULL, b_orig(chk), b_size(chk), connect->sni_fmt);
|
||||||
|
if (b_data(chk)) {
|
||||||
|
char *beg = b_orig(chk);
|
||||||
|
char *end = b_tail(chk) - 1;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
for (p = end; p >= beg; p--) {
|
||||||
|
if (*p == ':' || *p == ']')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (p >= beg && *p == ':')
|
||||||
|
b_set_data(chk, p - beg);
|
||||||
|
*b_tail(chk) = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Evaluates a TCPCHK_ACT_CONNECT rule. Returns TCPCHK_EVAL_WAIT to wait the
|
/* Evaluates a TCPCHK_ACT_CONNECT rule. Returns TCPCHK_EVAL_WAIT to wait the
|
||||||
* connection establishment, TCPCHK_EVAL_CONTINUE to evaluate the next rule or
|
* connection establishment, TCPCHK_EVAL_CONTINUE to evaluate the next rule or
|
||||||
* TCPCHK_EVAL_STOP if an error occurred.
|
* TCPCHK_EVAL_STOP if an error occurred.
|
||||||
@ -1247,6 +1268,7 @@ enum tcpcheck_eval_ret tcpcheck_eval_connect(struct check *check, struct tcpchec
|
|||||||
struct protocol *proto;
|
struct protocol *proto;
|
||||||
struct xprt_ops *xprt;
|
struct xprt_ops *xprt;
|
||||||
struct tcpcheck_rule *next;
|
struct tcpcheck_rule *next;
|
||||||
|
struct buffer *auto_sni = NULL;
|
||||||
int status, port;
|
int status, port;
|
||||||
|
|
||||||
TRACE_ENTER(CHK_EV_TCPCHK_CONN, check);
|
TRACE_ENTER(CHK_EV_TCPCHK_CONN, check);
|
||||||
@ -1275,6 +1297,19 @@ enum tcpcheck_eval_ret tcpcheck_eval_connect(struct check *check, struct tcpchec
|
|||||||
check_release_buf(check, &check->bi);
|
check_release_buf(check, &check->bi);
|
||||||
check_release_buf(check, &check->bo);
|
check_release_buf(check, &check->bo);
|
||||||
|
|
||||||
|
/* Deal with automatic SNI selection now because it can be used as connection name */
|
||||||
|
if (tcpcheck_connect_use_ssl(check, connect) && s && !(s->flags & SRV_F_CHK_NO_AUTO_SNI) && connect->sni_fmt) {
|
||||||
|
auto_sni = alloc_trash_chunk();
|
||||||
|
if (auto_sni) {
|
||||||
|
tcpcheck_connect_auto_sni(check, connect, auto_sni);
|
||||||
|
if (!b_data(auto_sni)) {
|
||||||
|
free_trash_chunk(auto_sni);
|
||||||
|
auto_sni = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!(check->state & CHK_ST_AGENT) && check->reuse_pool &&
|
if (!(check->state & CHK_ST_AGENT) && check->reuse_pool &&
|
||||||
!tcpcheck_use_nondefault_connect(check, connect) &&
|
!tcpcheck_use_nondefault_connect(check, connect) &&
|
||||||
!srv_is_transparent(s)) {
|
!srv_is_transparent(s)) {
|
||||||
@ -1292,6 +1327,8 @@ enum tcpcheck_eval_ret tcpcheck_eval_connect(struct check *check, struct tcpchec
|
|||||||
pool_conn_name = ist(connect->sni);
|
pool_conn_name = ist(connect->sni);
|
||||||
else if ((connect->options & TCPCHK_OPT_DEFAULT_CONNECT) && check->sni)
|
else if ((connect->options & TCPCHK_OPT_DEFAULT_CONNECT) && check->sni)
|
||||||
pool_conn_name = ist(check->sni);
|
pool_conn_name = ist(check->sni);
|
||||||
|
else if (auto_sni)
|
||||||
|
pool_conn_name = ist2(b_orig(auto_sni), b_data(auto_sni));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(s->flags & SRV_F_RHTTP)) {
|
if (!(s->flags & SRV_F_RHTTP)) {
|
||||||
@ -1444,6 +1481,8 @@ enum tcpcheck_eval_ret tcpcheck_eval_connect(struct check *check, struct tcpchec
|
|||||||
ssl_sock_set_servername(conn, connect->sni);
|
ssl_sock_set_servername(conn, connect->sni);
|
||||||
else if ((connect->options & TCPCHK_OPT_DEFAULT_CONNECT) && s && s->check.sni)
|
else if ((connect->options & TCPCHK_OPT_DEFAULT_CONNECT) && s && s->check.sni)
|
||||||
ssl_sock_set_servername(conn, s->check.sni);
|
ssl_sock_set_servername(conn, s->check.sni);
|
||||||
|
else if (auto_sni)
|
||||||
|
ssl_sock_set_servername(conn, b_orig(auto_sni));
|
||||||
|
|
||||||
if (connect->alpn)
|
if (connect->alpn)
|
||||||
ssl_sock_set_alpn(conn, (unsigned char *)connect->alpn, connect->alpn_len);
|
ssl_sock_set_alpn(conn, (unsigned char *)connect->alpn, connect->alpn_len);
|
||||||
@ -1551,6 +1590,9 @@ enum tcpcheck_eval_ret tcpcheck_eval_connect(struct check *check, struct tcpchec
|
|||||||
if (ret == TCPCHK_EVAL_CONTINUE && check->proxy->timeout.check)
|
if (ret == TCPCHK_EVAL_CONTINUE && check->proxy->timeout.check)
|
||||||
check->task->expire = tick_add_ifset(now_ms, check->proxy->timeout.check);
|
check->task->expire = tick_add_ifset(now_ms, check->proxy->timeout.check);
|
||||||
|
|
||||||
|
if (auto_sni)
|
||||||
|
free_trash_chunk(auto_sni);
|
||||||
|
|
||||||
TRACE_LEAVE(CHK_EV_TCPCHK_CONN, check, 0, 0, (size_t[]){ret});
|
TRACE_LEAVE(CHK_EV_TCPCHK_CONN, check, 0, 0, (size_t[]){ret});
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -3959,6 +4001,32 @@ static int check_proxy_tcpcheck(struct proxy *px)
|
|||||||
LIST_INSERT(px->tcpcheck_rules.list, &chk->list);
|
LIST_INSERT(px->tcpcheck_rules.list, &chk->list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Now, back again on HTTP ruleset. Try to resolve the sni log-format
|
||||||
|
* string if necessary, but onlu for implicit connect rules, by getting
|
||||||
|
* it from the following send rule.
|
||||||
|
*/
|
||||||
|
if ((px->tcpcheck_rules.flags & TCPCHK_RULES_PROTO_CHK) == TCPCHK_RULES_HTTP_CHK) {
|
||||||
|
struct tcpcheck_connect *connect = NULL;
|
||||||
|
|
||||||
|
list_for_each_entry(chk, px->tcpcheck_rules.list, list) {
|
||||||
|
if (chk->action == TCPCHK_ACT_CONNECT && !chk->connect.sni &&
|
||||||
|
(chk->connect.options & TCPCHK_OPT_IMPLICIT)) {
|
||||||
|
/* Only eval connect rule with no explici SNI */
|
||||||
|
connect = &chk->connect;
|
||||||
|
}
|
||||||
|
else if (connect && chk->action == TCPCHK_ACT_SEND) {
|
||||||
|
struct tcpcheck_http_hdr *hdr;
|
||||||
|
|
||||||
|
list_for_each_entry(hdr, &chk->send.http.hdrs, list) {
|
||||||
|
if (isteqi(hdr->name, ist("host")))
|
||||||
|
connect->sni_fmt = &hdr->value;
|
||||||
|
}
|
||||||
|
connect = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Remove all comment rules. To do so, when a such rule is found, the
|
/* Remove all comment rules. To do so, when a such rule is found, the
|
||||||
* comment is assigned to the following rule(s).
|
* comment is assigned to the following rule(s).
|
||||||
*/
|
*/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user