]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: ssl: add sample fetches for is_ssl, ssl_has_sni, ssl_sni_*
authorWilly Tarreau <w@1wt.eu>
Mon, 10 Sep 2012 06:20:03 +0000 (08:20 +0200)
committerWilly Tarreau <w@1wt.eu>
Mon, 10 Sep 2012 07:27:02 +0000 (09:27 +0200)
This allows SNI presence and value to be checked on incoming SSL connections.
It is usable both for ACLs and stick tables.

doc/configuration.txt
src/ssl_sock.c

index 5501444668d9a69e84f6f8ca06e89891ac22ccc1..33cb53032095f42b777722832a096a65b1425288 100644 (file)
@@ -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"
 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>
   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>.
   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>
   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
   or superior) hello message and handshake type is equal to <integer>.
   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>
   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
   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
-  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 :
      # 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
   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
-  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
   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
                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
                typical use is with prefetch-capable caches, and with portals
                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.
                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
                typical use is with prefetch-capable caches, and with portals
                which need to aggregate multiple information from databases and
index 531d56b499f71151ef11184bab10d033a4ece0f8..8410ab0eef227b213d563da302bb1b3aac0702ab 100644 (file)
@@ -45,6 +45,8 @@
 #include <types/global.h>
 #include <types/ssl_sock.h>
 
+#include <proto/acl.h>
+#include <proto/arg.h>
 #include <proto/connection.h>
 #include <proto/fd.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);
 }
 
+/***** 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 */
 struct data_ops ssl_sock = {
@@ -768,6 +839,8 @@ static void __ssl_sock_init(void) {
        SSL_library_init();
        cm = SSL_COMP_get_compression_methods();
        sk_SSL_COMP_zero(cm);
+       sample_register_fetches(&sample_fetch_keywords);
+       acl_register_keywords(&acl_kws);
 }
 
 /*