MEDIUM: checks: Add check-alpn.

Add a way to configure the ALPN used by check, with a new "check-alpn"
keyword. By default, the checks will use the server ALPN, but it may not
be convenient, for instance because the server may use HTTP/2, while checks
are unable to do HTTP/2 yet.
This commit is contained in:
Olivier Houchard 2018-12-21 19:47:01 +01:00 committed by Willy Tarreau
parent ab28a320aa
commit 921501443b
5 changed files with 30 additions and 9 deletions

View File

@ -11569,6 +11569,11 @@ check-send-proxy
"check-send-proxy" option needs to be used to force the use of the "check-send-proxy" option needs to be used to force the use of the
protocol. See also the "send-proxy" option for more information. protocol. See also the "send-proxy" option for more information.
check-alpn <protocols>
Defines which protocols to advertise with ALPN. The protocol list consists in
a comma-delimited list of protocol names, for instance: "http/1.1,http/1.0"
(without quotes). If it is not set, the server ALPN is used.
check-sni <sni> check-sni <sni>
This option allows you to specify the SNI to be used when doing health checks This option allows you to specify the SNI to be used when doing health checks
over SSL. It is only possible to use a string to set <sni>. If you want to over SSL. It is only possible to use a string to set <sni>. If you want to

View File

@ -186,6 +186,8 @@ struct check {
struct sockaddr_storage addr; /* the address to check */ struct sockaddr_storage addr; /* the address to check */
struct wait_event wait_list; /* Waiting for I/O events */ struct wait_event wait_list; /* Waiting for I/O events */
char *sni; /* Server name */ char *sni; /* Server name */
char *alpn_str; /* ALPN to use for checks */
int alpn_len; /* ALPN string length */
}; };
struct check_status { struct check_status {

View File

@ -1621,6 +1621,9 @@ static int connect_conn_chk(struct task *t)
#ifdef USE_OPENSSL #ifdef USE_OPENSSL
if (s->check.sni) if (s->check.sni)
ssl_sock_set_servername(conn, s->check.sni); ssl_sock_set_servername(conn, s->check.sni);
if (s->check.alpn_str)
ssl_sock_set_alpn(conn, (unsigned char *)s->check.alpn_str,
s->check.alpn_len);
#endif #endif
if (s->check.send_proxy && !(check->state & CHK_ST_AGENT)) { if (s->check.send_proxy && !(check->state & CHK_ST_AGENT)) {
conn->send_proxy_ofs = 1; conn->send_proxy_ofs = 1;

View File

@ -1613,6 +1613,8 @@ static void srv_settings_cpy(struct server *srv, struct server *src, int srv_tmp
srv->check.use_ssl = src->check.use_ssl; srv->check.use_ssl = src->check.use_ssl;
srv->check.port = src->check.port; srv->check.port = src->check.port;
srv->check.sni = src->check.sni; srv->check.sni = src->check.sni;
srv->check.alpn_str = src->check.alpn_str;
srv->check.alpn_len = srv->check.alpn_len;
/* Note: 'flags' field has potentially been already initialized. */ /* Note: 'flags' field has potentially been already initialized. */
srv->flags |= src->flags; srv->flags |= src->flags;
srv->do_check = src->do_check; srv->do_check = src->do_check;

View File

@ -7966,34 +7966,42 @@ static int srv_parse_npn(char **args, int *cur_arg, struct proxy *px, struct ser
#endif #endif
} }
/* parse the "alpn" bind keyword */ /* parse the "alpn" or the "check-alpn" server keyword */
static int srv_parse_alpn(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err) static int srv_parse_alpn(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
{ {
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation #ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
char *p1, *p2; char *p1, *p2;
char **alpn_str;
int *alpn_len;
if (*args[*cur_arg] == 'c') {
alpn_str = &newsrv->check.alpn_str;
alpn_len = &newsrv->check.alpn_len;
} else {
alpn_str = &newsrv->ssl_ctx.alpn_str;
alpn_len = &newsrv->ssl_ctx.alpn_len;
}
if (!*args[*cur_arg + 1]) { if (!*args[*cur_arg + 1]) {
memprintf(err, "'%s' : missing the comma-delimited ALPN protocol suite", args[*cur_arg]); memprintf(err, "'%s' : missing the comma-delimited ALPN protocol suite", args[*cur_arg]);
return ERR_ALERT | ERR_FATAL; return ERR_ALERT | ERR_FATAL;
} }
free(newsrv->ssl_ctx.alpn_str); free(*alpn_str);
/* the ALPN string is built as a suite of (<len> <name>)*, /* the ALPN string is built as a suite of (<len> <name>)*,
* so we reuse each comma to store the next <len> and need * so we reuse each comma to store the next <len> and need
* one more for the end of the string. * one more for the end of the string.
*/ */
newsrv->ssl_ctx.alpn_len = strlen(args[*cur_arg + 1]) + 1; *alpn_len = strlen(args[*cur_arg + 1]) + 1;
newsrv->ssl_ctx.alpn_str = calloc(1, newsrv->ssl_ctx.alpn_len + 1); *alpn_str = calloc(1, *alpn_len + 1);
memcpy(newsrv->ssl_ctx.alpn_str + 1, args[*cur_arg + 1], memcpy(*alpn_str + 1, args[*cur_arg + 1], *alpn_len);
newsrv->ssl_ctx.alpn_len);
/* replace commas with the name length */ /* replace commas with the name length */
p1 = newsrv->ssl_ctx.alpn_str; p1 = *alpn_str;
p2 = p1 + 1; p2 = p1 + 1;
while (1) { while (1) {
p2 = memchr(p1 + 1, ',', newsrv->ssl_ctx.alpn_str + p2 = memchr(p1 + 1, ',', *alpn_str + *alpn_len - (p1 + 1));
newsrv->ssl_ctx.alpn_len - (p1 + 1));
if (!p2) if (!p2)
p2 = p1 + 1 + strlen(p1 + 1); p2 = p1 + 1 + strlen(p1 + 1);
@ -9132,6 +9140,7 @@ static struct srv_kw_list srv_kws = { "SSL", { }, {
{ "allow-0rtt", srv_parse_allow_0rtt, 0, 1 }, /* Allow using early data on this server */ { "allow-0rtt", srv_parse_allow_0rtt, 0, 1 }, /* Allow using early data on this server */
{ "alpn", srv_parse_alpn, 1, 1 }, /* Set ALPN supported protocols */ { "alpn", srv_parse_alpn, 1, 1 }, /* Set ALPN supported protocols */
{ "ca-file", srv_parse_ca_file, 1, 1 }, /* set CAfile to process verify server cert */ { "ca-file", srv_parse_ca_file, 1, 1 }, /* set CAfile to process verify server cert */
{ "check-alpn", srv_parse_alpn, 1, 1 }, /* Set ALPN used for checks */
{ "check-sni", srv_parse_check_sni, 1, 1 }, /* set SNI */ { "check-sni", srv_parse_check_sni, 1, 1 }, /* set SNI */
{ "check-ssl", srv_parse_check_ssl, 0, 1 }, /* enable SSL for health checks */ { "check-ssl", srv_parse_check_ssl, 0, 1 }, /* enable SSL for health checks */
{ "ciphers", srv_parse_ciphers, 1, 1 }, /* select the cipher suite */ { "ciphers", srv_parse_ciphers, 1, 1 }, /* select the cipher suite */