mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-22 14:21:25 +02:00
MEDIUM: ssl: add sni support on the server lines
The new "sni" server directive takes a sample fetch expression and uses its return value as a hostname sent as the TLS SNI extension. A typical use case consists in forwarding the front connection's SNI value to the server in a bridged HTTPS forwarder : sni ssl_fc_sni
This commit is contained in:
parent
630764188b
commit
732eac41f4
@ -10183,6 +10183,15 @@ slowstart <start_time_in_ms>
|
|||||||
|
|
||||||
Supported in default-server: Yes
|
Supported in default-server: Yes
|
||||||
|
|
||||||
|
sni <expression>
|
||||||
|
The "sni" parameter evaluates the sample fetch expression, converts it to a
|
||||||
|
string and uses the result as the host name sent in the SNI TLS extension to
|
||||||
|
the server. A typical use case is to send the SNI received from the client in
|
||||||
|
a bridged HTTPS scenario, using the "ssl_fc_sni" sample fetch for the
|
||||||
|
expression, though alternatives such as req.hdr(host) can also make sense.
|
||||||
|
|
||||||
|
Supported in default-server: no
|
||||||
|
|
||||||
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>] ...
|
||||||
|
@ -222,6 +222,7 @@ struct server {
|
|||||||
char *ca_file; /* CAfile to use on verify */
|
char *ca_file; /* CAfile to use on verify */
|
||||||
char *crl_file; /* CRLfile to use on verify */
|
char *crl_file; /* CRLfile to use on verify */
|
||||||
char *client_crt; /* client certificate to send */
|
char *client_crt; /* client certificate to send */
|
||||||
|
struct sample_expr *sni; /* sample expression for SNI */
|
||||||
} ssl_ctx;
|
} ssl_ctx;
|
||||||
#endif
|
#endif
|
||||||
struct {
|
struct {
|
||||||
|
@ -55,6 +55,10 @@
|
|||||||
#include <proto/stream_interface.h>
|
#include <proto/stream_interface.h>
|
||||||
#include <proto/task.h>
|
#include <proto/task.h>
|
||||||
|
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
|
#include <proto/ssl_sock.h>
|
||||||
|
#endif /* USE_OPENSSL */
|
||||||
|
|
||||||
int be_lastsession(const struct proxy *be)
|
int be_lastsession(const struct proxy *be)
|
||||||
{
|
{
|
||||||
if (be->be_counters.last_sess)
|
if (be->be_counters.last_sess)
|
||||||
@ -1116,6 +1120,36 @@ int connect_server(struct stream *s)
|
|||||||
srv->counters.cur_sess_max = srv->cur_sess;
|
srv->counters.cur_sess_max = srv->cur_sess;
|
||||||
if (s->be->lbprm.server_take_conn)
|
if (s->be->lbprm.server_take_conn)
|
||||||
s->be->lbprm.server_take_conn(srv);
|
s->be->lbprm.server_take_conn(srv);
|
||||||
|
|
||||||
|
#ifdef USE_OPENSSL
|
||||||
|
if (srv->ssl_ctx.sni) {
|
||||||
|
struct sample *smp;
|
||||||
|
int rewind;
|
||||||
|
|
||||||
|
/* Tricky case : we have already scheduled the pending
|
||||||
|
* HTTP request or TCP data for leaving. So in HTTP we
|
||||||
|
* rewind exactly the headers, otherwise we rewind the
|
||||||
|
* output data.
|
||||||
|
*/
|
||||||
|
rewind = s->txn ? http_hdr_rewind(&s->txn->req) : s->req.buf->o;
|
||||||
|
b_rew(s->req.buf, rewind);
|
||||||
|
|
||||||
|
smp = sample_fetch_as_type(s->be, s->sess, s, SMP_OPT_DIR_REQ | SMP_OPT_FINAL, srv->ssl_ctx.sni, SMP_T_STR);
|
||||||
|
|
||||||
|
/* restore the pointers */
|
||||||
|
b_adv(s->req.buf, rewind);
|
||||||
|
|
||||||
|
if (smp) {
|
||||||
|
/* get write access to terminate with a zero */
|
||||||
|
smp_dup(smp);
|
||||||
|
if (smp->data.str.len >= smp->data.str.size)
|
||||||
|
smp->data.str.len = smp->data.str.size - 1;
|
||||||
|
smp->data.str.str[smp->data.str.len] = 0;
|
||||||
|
ssl_sock_set_servername(srv_conn, smp->data.str.str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* USE_OPENSSL */
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return SF_ERR_NONE; /* connection is OK */
|
return SF_ERR_NONE; /* connection is OK */
|
||||||
|
@ -4952,6 +4952,42 @@ static int srv_parse_send_proxy_cn(char **args, int *cur_arg, struct proxy *px,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* parse the "sni" server keyword */
|
||||||
|
static int srv_parse_sni(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
|
||||||
|
{
|
||||||
|
#ifndef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||||
|
memprintf(err, "'%s' : the current SSL library doesn't support the SNI TLS extension", args[*cur_arg]);
|
||||||
|
return ERR_ALERT | ERR_FATAL;
|
||||||
|
#else
|
||||||
|
struct sample_expr *expr;
|
||||||
|
|
||||||
|
if (!*args[*cur_arg + 1]) {
|
||||||
|
memprintf(err, "'%s' : missing sni expression", args[*cur_arg]);
|
||||||
|
return ERR_ALERT | ERR_FATAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
(*cur_arg)++;
|
||||||
|
proxy->conf.args.ctx = ARGC_SRV;
|
||||||
|
|
||||||
|
expr = sample_parse_expr((char **)args, cur_arg, 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[*cur_arg-1], sample_src_names(expr->fetch->use));
|
||||||
|
return ERR_ALERT | ERR_FATAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
px->http_needed |= !!(expr->fetch->use & SMP_USE_HTTP_ANY);
|
||||||
|
newsrv->ssl_ctx.sni = expr;
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* parse the "ssl" server keyword */
|
/* parse the "ssl" server keyword */
|
||||||
static int srv_parse_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
|
static int srv_parse_ssl(char **args, int *cur_arg, struct proxy *px, struct server *newsrv, char **err)
|
||||||
{
|
{
|
||||||
@ -5225,6 +5261,7 @@ static struct srv_kw_list srv_kws = { "SSL", { }, {
|
|||||||
{ "no-tls-tickets", srv_parse_no_tls_tickets, 0, 0 }, /* disable session resumption tickets */
|
{ "no-tls-tickets", srv_parse_no_tls_tickets, 0, 0 }, /* disable session resumption tickets */
|
||||||
{ "send-proxy-v2-ssl", srv_parse_send_proxy_ssl, 0, 0 }, /* send PROXY protocol header v2 with SSL info */
|
{ "send-proxy-v2-ssl", srv_parse_send_proxy_ssl, 0, 0 }, /* send PROXY protocol header v2 with SSL info */
|
||||||
{ "send-proxy-v2-ssl-cn", srv_parse_send_proxy_cn, 0, 0 }, /* send PROXY protocol header v2 with CN */
|
{ "send-proxy-v2-ssl-cn", srv_parse_send_proxy_cn, 0, 0 }, /* send PROXY protocol header v2 with CN */
|
||||||
|
{ "sni", srv_parse_sni, 1, 0 }, /* send SNI extension */
|
||||||
{ "ssl", srv_parse_ssl, 0, 0 }, /* enable SSL processing */
|
{ "ssl", srv_parse_ssl, 0, 0 }, /* enable SSL processing */
|
||||||
{ "verify", srv_parse_verify, 1, 0 }, /* set SSL verify method */
|
{ "verify", srv_parse_verify, 1, 0 }, /* set SSL verify method */
|
||||||
{ "verifyhost", srv_parse_verifyhost, 1, 0 }, /* require that SSL cert verifies for hostname */
|
{ "verifyhost", srv_parse_verifyhost, 1, 0 }, /* require that SSL cert verifies for hostname */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user