mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-07 23:56:57 +02:00
MEDIUM: ssl: add sample fetches for is_ssl, ssl_has_sni, ssl_sni_*
This allows SNI presence and value to be checked on incoming SSL connections. It is usable both for ACLs and stick tables.
This commit is contained in:
parent
1ee0e302a1
commit
7875d0967f
@ -7901,11 +7901,18 @@ during analysis. This requires that some data has been buffered, for instance
|
|||||||
through TCP request content inspection. Please see the "tcp-request content"
|
through TCP request content inspection. Please see the "tcp-request content"
|
||||||
keyword for more detailed information on the subject.
|
keyword for more detailed information on the subject.
|
||||||
|
|
||||||
|
is_ssl
|
||||||
|
Returns true when the incoming connection was made via an SSL/TLS data layer
|
||||||
|
and is locally deciphered. This means it has matched a socket declared with
|
||||||
|
a "bind" line having the "ssl" option.
|
||||||
|
|
||||||
rep_ssl_hello_type <integer>
|
rep_ssl_hello_type <integer>
|
||||||
Returns true when data in the response buffer looks like a complete SSL (v3
|
Returns true when data in the response buffer looks like a complete SSL (v3
|
||||||
or superior) hello message and handshake type is equal to <integer>.
|
or superior) hello message and handshake type is equal to <integer>.
|
||||||
This test was designed to be used with TCP response content inspection: a
|
This test was designed to be used with TCP response content inspection: a
|
||||||
SSL session ID may be fetched.
|
SSL session ID may be fetched. Note that this only applies to raw contents
|
||||||
|
found in the request buffer and not to contents deciphered via an SSL data
|
||||||
|
layer, so this will not work with "bind" lines having the "ssl" option.
|
||||||
|
|
||||||
req_len <integer>
|
req_len <integer>
|
||||||
Returns true when the length of the data in the request buffer matches the
|
Returns true when the length of the data in the request buffer matches the
|
||||||
@ -7946,7 +7953,9 @@ req_ssl_hello_type <integer>
|
|||||||
Returns true when data in the request buffer looks like a complete SSL (v3
|
Returns true when data in the request buffer looks like a complete SSL (v3
|
||||||
or superior) hello message and handshake type is equal to <integer>.
|
or superior) hello message and handshake type is equal to <integer>.
|
||||||
This test was designed to be used with TCP request content inspection: an
|
This test was designed to be used with TCP request content inspection: an
|
||||||
SSL session ID may be fetched.
|
SSL session ID may be fetched. Note that this only applies to raw contents
|
||||||
|
found in the request buffer and not to contents deciphered via an SSL data
|
||||||
|
layer, so this will not work with "bind" lines having the "ssl" option.
|
||||||
|
|
||||||
req_ssl_sni <string>
|
req_ssl_sni <string>
|
||||||
Returns true when data in the request buffer looks like a complete SSL (v3
|
Returns true when data in the request buffer looks like a complete SSL (v3
|
||||||
@ -7956,7 +7965,10 @@ req_ssl_sni <string>
|
|||||||
or denying access to certain hosts when SSL/TLS is used by the client. This
|
or denying access to certain hosts when SSL/TLS is used by the client. This
|
||||||
test was designed to be used with TCP request content inspection. If content
|
test was designed to be used with TCP request content inspection. If content
|
||||||
switching is needed, it is recommended to first wait for a complete client
|
switching is needed, it is recommended to first wait for a complete client
|
||||||
hello (type 1), like in the example below.
|
hello (type 1), like in the example below. Note that this only applies to raw
|
||||||
|
contents found in the request buffer and not to contents deciphered via an
|
||||||
|
SSL data layer, so this will not work with "bind" lines having the "ssl"
|
||||||
|
option. See also "ssl_sni" below.
|
||||||
|
|
||||||
Examples :
|
Examples :
|
||||||
# Wait for a client hello for at most 5 seconds
|
# Wait for a client hello for at most 5 seconds
|
||||||
@ -7972,7 +7984,53 @@ req_ssl_ver <decimal>
|
|||||||
easily fooled. In particular, it waits for as many bytes as announced in the
|
easily fooled. In particular, it waits for as many bytes as announced in the
|
||||||
message header if this header looks valid (bound to the buffer size). Note
|
message header if this header looks valid (bound to the buffer size). Note
|
||||||
that TLSv1 is announced as SSL version 3.1. This test was designed to be used
|
that TLSv1 is announced as SSL version 3.1. This test was designed to be used
|
||||||
with TCP request content inspection.
|
with TCP request content inspection. Note that this only applies to raw
|
||||||
|
contents found in the request buffer and not to contents deciphered via an
|
||||||
|
SSL data layer, so this will not work with "bind" lines having the "ssl"
|
||||||
|
option.
|
||||||
|
|
||||||
|
ssl_sni <string>
|
||||||
|
Returns true when the incoming connection was made over an SSL/TLS data layer
|
||||||
|
which deciphered it and found a Server Name Indication TLS extension sent by
|
||||||
|
the client, matching the specified string. In HTTPS, the SNI field (when
|
||||||
|
present) is equal to the requested host name. This match is different from
|
||||||
|
req_ssl_sni above in that it applies to the connection being deciphered by
|
||||||
|
haproxy and not to SSL contents being blindly forwarded. This requires that
|
||||||
|
the SSL library is build with support for TLS extensions (check haproxy -vv).
|
||||||
|
|
||||||
|
ssl_has_sni
|
||||||
|
This is used to check for presence of a Server Name Indication TLS extension
|
||||||
|
in an incoming connection was made over an SSL/TLS data layer. Returns true
|
||||||
|
when the incoming connection presents a TLS SNI field. This requires that
|
||||||
|
the SSL library is build with support for TLS extensions (check haproxy -vv).
|
||||||
|
|
||||||
|
ssl_sni <string>
|
||||||
|
Returns true when the incoming connection was made over an SSL/TLS data layer
|
||||||
|
which deciphered it and found a Server Name Indication TLS extension sent by
|
||||||
|
the client, matching the specified string. In HTTPS, the SNI field (when
|
||||||
|
present) is equal to the requested host name. This match is different from
|
||||||
|
req_ssl_sni above in that it applies to the connection being deciphered by
|
||||||
|
haproxy and not to SSL contents being blindly forwarded. See also ssl_sni_end
|
||||||
|
and ssl_sni_req below. This requires that the SSL library is build with
|
||||||
|
support for TLS extensions (check haproxy -vv).
|
||||||
|
|
||||||
|
ssl_sni_end <string>
|
||||||
|
Returns true when the incoming connection was made over an SSL/TLS data layer
|
||||||
|
which deciphered it and found a Server Name Indication TLS extension sent by
|
||||||
|
the client, ending like the specified string. In HTTPS, the SNI field (when
|
||||||
|
present) is equal to the requested host name. This match is different from
|
||||||
|
req_ssl_sni above in that it applies to the connection being deciphered by
|
||||||
|
haproxy and not to SSL contents being blindly forwarded. This requires that
|
||||||
|
the SSL library is build with support for TLS extensions (check haproxy -vv).
|
||||||
|
|
||||||
|
ssl_sni_req <regex>
|
||||||
|
Returns true when the incoming connection was made over an SSL/TLS data layer
|
||||||
|
which deciphered it and found a Server Name Indication TLS extension sent by
|
||||||
|
the client, matching the specified regex. In HTTPS, the SNI field (when
|
||||||
|
present) is equal to the requested host name. This match is different from
|
||||||
|
req_ssl_sni above in that it applies to the connection being deciphered by
|
||||||
|
haproxy and not to SSL contents being blindly forwarded. This requires that
|
||||||
|
the SSL library is build with support for TLS extensions (check haproxy -vv).
|
||||||
|
|
||||||
wait_end
|
wait_end
|
||||||
Waits for the end of the analysis period to return true. This may be used in
|
Waits for the end of the analysis period to return true. This may be used in
|
||||||
@ -8542,6 +8600,10 @@ The list of currently supported pattern fetch functions is the following :
|
|||||||
last one. A typical use is with the X-Forwarded-For header once
|
last one. A typical use is with the X-Forwarded-For header once
|
||||||
converted to IP, associated with an IP stick-table.
|
converted to IP, associated with an IP stick-table.
|
||||||
|
|
||||||
|
is_ssl This checks the data layer used by incoming connection, and
|
||||||
|
returns 1 if the connection was made via an SSL/TLS data layer,
|
||||||
|
otherwise zero.
|
||||||
|
|
||||||
path This extracts the request's URL path (without the host part). A
|
path This extracts the request's URL path (without the host part). A
|
||||||
typical use is with prefetch-capable caches, and with portals
|
typical use is with prefetch-capable caches, and with portals
|
||||||
which need to aggregate multiple information from databases and
|
which need to aggregate multiple information from databases and
|
||||||
@ -8569,6 +8631,18 @@ The list of currently supported pattern fetch functions is the following :
|
|||||||
that this function will be useful but it's available at no cost.
|
that this function will be useful but it's available at no cost.
|
||||||
It is of type integer and only works with such tables.
|
It is of type integer and only works with such tables.
|
||||||
|
|
||||||
|
ssl_has_sni This checks the data layer used by incoming connection, and
|
||||||
|
returns 1 if the connection was made via an SSL/TLS data layer
|
||||||
|
and the client sent a Server Name Indication TLS extension,
|
||||||
|
otherwise zero. This requires that the SSL library is build with
|
||||||
|
support for TLS extensions (check haproxy -vv).
|
||||||
|
|
||||||
|
ssl_sni This extracts the Server Name Indication field from an incoming
|
||||||
|
connection made via an SSL/TLS data layer and locally deciphered
|
||||||
|
by haproxy. The result typically is a string matching the HTTPS
|
||||||
|
host name (253 chars or less). The SSL library must have been
|
||||||
|
built with support for TLS extensions (check haproxy -vv).
|
||||||
|
|
||||||
url This extracts the request's URL as presented in the request. A
|
url This extracts the request's URL as presented in the request. A
|
||||||
typical use is with prefetch-capable caches, and with portals
|
typical use is with prefetch-capable caches, and with portals
|
||||||
which need to aggregate multiple information from databases and
|
which need to aggregate multiple information from databases and
|
||||||
|
@ -45,6 +45,8 @@
|
|||||||
#include <types/global.h>
|
#include <types/global.h>
|
||||||
#include <types/ssl_sock.h>
|
#include <types/ssl_sock.h>
|
||||||
|
|
||||||
|
#include <proto/acl.h>
|
||||||
|
#include <proto/arg.h>
|
||||||
#include <proto/connection.h>
|
#include <proto/connection.h>
|
||||||
#include <proto/fd.h>
|
#include <proto/fd.h>
|
||||||
#include <proto/freq_ctr.h>
|
#include <proto/freq_ctr.h>
|
||||||
@ -748,6 +750,75 @@ static void ssl_sock_shutw(struct connection *conn, int clean)
|
|||||||
SSL_set_shutdown(conn->data_ctx, SSL_SENT_SHUTDOWN);
|
SSL_set_shutdown(conn->data_ctx, SSL_SENT_SHUTDOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***** Below are some sample fetching functions for ACL/patterns *****/
|
||||||
|
|
||||||
|
/* boolean, returns true if data layer is SSL */
|
||||||
|
static int
|
||||||
|
smp_fetch_is_ssl(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
|
||||||
|
const struct arg *args, struct sample *smp)
|
||||||
|
{
|
||||||
|
smp->type = SMP_T_BOOL;
|
||||||
|
smp->data.uint = (l4->si[0].conn.data == &ssl_sock);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* boolean, returns true if data layer is SSL */
|
||||||
|
static int
|
||||||
|
smp_fetch_has_sni(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
|
||||||
|
const struct arg *args, struct sample *smp)
|
||||||
|
{
|
||||||
|
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||||
|
smp->type = SMP_T_BOOL;
|
||||||
|
smp->data.uint = (l4->si[0].conn.data == &ssl_sock) &&
|
||||||
|
SSL_get_servername(l4->si[0].conn.data_ctx, TLSEXT_NAMETYPE_host_name) != NULL;
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
smp_fetch_ssl_sni(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
|
||||||
|
const struct arg *args, struct sample *smp)
|
||||||
|
{
|
||||||
|
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
|
||||||
|
smp->flags = 0;
|
||||||
|
smp->type = SMP_T_CSTR;
|
||||||
|
|
||||||
|
if (!l4 || l4->si[0].conn.data != &ssl_sock)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* data points to cookie value */
|
||||||
|
smp->data.str.str = (char *)SSL_get_servername(l4->si[0].conn.data_ctx, TLSEXT_NAMETYPE_host_name);
|
||||||
|
smp->data.str.len = strlen(smp->data.str.str);
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note: must not be declared <const> as its list will be overwritten.
|
||||||
|
* Please take care of keeping this list alphabetically sorted.
|
||||||
|
*/
|
||||||
|
static struct sample_fetch_kw_list sample_fetch_keywords = {{ },{
|
||||||
|
{ "is_ssl", smp_fetch_is_ssl, 0, NULL, SMP_T_BOOL, SMP_CAP_REQ|SMP_CAP_RES },
|
||||||
|
{ "ssl_has_sni", smp_fetch_has_sni, 0, NULL, SMP_T_BOOL, SMP_CAP_REQ|SMP_CAP_RES },
|
||||||
|
{ "ssl_sni", smp_fetch_ssl_sni, 0, NULL, SMP_T_CSTR, SMP_CAP_REQ|SMP_CAP_RES },
|
||||||
|
{ NULL, NULL, 0, 0, 0 },
|
||||||
|
}};
|
||||||
|
|
||||||
|
/* Note: must not be declared <const> as its list will be overwritten.
|
||||||
|
* Please take care of keeping this list alphabetically sorted.
|
||||||
|
*/
|
||||||
|
static struct acl_kw_list acl_kws = {{ },{
|
||||||
|
{ "is_ssl", acl_parse_int, smp_fetch_is_ssl, acl_match_nothing, ACL_USE_L6REQ_PERMANENT, 0 },
|
||||||
|
{ "ssl_has_sni", acl_parse_int, smp_fetch_has_sni, acl_match_nothing, ACL_USE_L6REQ_PERMANENT, 0 },
|
||||||
|
{ "ssl_sni", acl_parse_str, smp_fetch_ssl_sni, acl_match_str, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },
|
||||||
|
{ "ssl_sni_end", acl_parse_str, smp_fetch_ssl_sni, acl_match_end, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },
|
||||||
|
{ "ssl_sni_reg", acl_parse_str, smp_fetch_ssl_sni, acl_match_reg, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },
|
||||||
|
{ NULL, NULL, NULL, NULL },
|
||||||
|
}};
|
||||||
|
|
||||||
|
|
||||||
/* data-layer operations for SSL sockets */
|
/* data-layer operations for SSL sockets */
|
||||||
struct data_ops ssl_sock = {
|
struct data_ops ssl_sock = {
|
||||||
@ -768,6 +839,8 @@ static void __ssl_sock_init(void) {
|
|||||||
SSL_library_init();
|
SSL_library_init();
|
||||||
cm = SSL_COMP_get_compression_methods();
|
cm = SSL_COMP_get_compression_methods();
|
||||||
sk_SSL_COMP_zero(cm);
|
sk_SSL_COMP_zero(cm);
|
||||||
|
sample_register_fetches(&sample_fetch_keywords);
|
||||||
|
acl_register_keywords(&acl_kws);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user