MINOR: ssl: add 'ssl_npn' sample/acl to extract TLS/NPN information
This may be used to distinguish between SPDY versions for example.
diff --git a/doc/configuration.txt b/doc/configuration.txt
index 208c432..119f440 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -8339,6 +8339,12 @@
that the SSL library is build with support for TLS extensions enabled (check
haproxy -vv).
+ssl_npn <string>
+ Returns true when the incoming connection was made over an SSL/TLS transport
+ layer which deciphered it and found a Next Protocol Negociation TLS extension
+ sent by the client, matching the specified string. This requires that the SSL
+ library is build with support for TLS extensions enabled (check haproxy -vv).
+
ssl_sni <string>
Returns true when the incoming connection was made over an SSL/TLS transport
layer which deciphered it and found a Server Name Indication TLS extension
@@ -8996,6 +9002,13 @@
otherwise zero. This requires that the SSL library is build with
support for TLS extensions enabled (check haproxy -vv).
+ ssl_npn This extracts the Next Protocol Negociation field from an
+ incoming connection made via an SSL/TLS transport layer and
+ locally deciphered by haproxy. The result is a string containing
+ the protocol name advertised by the client. The SSL library must
+ have been built with support for TLS extensions enabled (check
+ haproxy -vv).
+
ssl_sni This extracts the Server Name Indication field from an incoming
connection made via an SSL/TLS transport layer and locally
deciphered by haproxy. The result typically is a string matching
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 9aed915..6121b12 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -1119,6 +1119,30 @@
}
static int
+smp_fetch_ssl_npn(struct proxy *px, struct session *l4, void *l7, unsigned int opt,
+ const struct arg *args, struct sample *smp)
+{
+#ifdef OPENSSL_NPN_NEGOTIATED
+ smp->flags = 0;
+ smp->type = SMP_T_CSTR;
+
+ if (!l4 || !l4->si[0].conn.xprt_ctx || l4->si[0].conn.xprt != &ssl_sock)
+ return 0;
+
+ smp->data.str.str = NULL;
+ SSL_get0_next_proto_negotiated(l4->si[0].conn.xprt_ctx,
+ (const unsigned char **)&smp->data.str.str, (unsigned *)&smp->data.str.len);
+
+ if (!smp->data.str.str)
+ return 0;
+
+ 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)
{
@@ -1662,6 +1686,9 @@
{ "client_crt", smp_fetch_client_crt, 0, NULL, SMP_T_BOOL, SMP_CAP_REQ|SMP_CAP_RES },
{ "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 },
+#ifdef OPENSSL_NPN_NEGOTIATED
+ { "ssl_npn", smp_fetch_ssl_npn, 0, NULL, SMP_T_CSTR, SMP_CAP_REQ|SMP_CAP_RES },
+#endif
{ "ssl_sni", smp_fetch_ssl_sni, 0, NULL, SMP_T_CSTR, SMP_CAP_REQ|SMP_CAP_RES },
{ "ssl_verify_caerr", smp_fetch_verify_caerr, 0, NULL, SMP_T_UINT, SMP_CAP_REQ|SMP_CAP_RES },
{ "ssl_verify_caerr_depth", smp_fetch_verify_caerr_depth, 0, NULL, SMP_T_UINT, SMP_CAP_REQ|SMP_CAP_RES },
@@ -1677,6 +1704,9 @@
{ "client_crt", acl_parse_int, smp_fetch_client_crt, acl_match_nothing, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },
{ "is_ssl", acl_parse_int, smp_fetch_is_ssl, acl_match_nothing, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },
{ "ssl_has_sni", acl_parse_int, smp_fetch_has_sni, acl_match_nothing, ACL_USE_L6REQ_PERMANENT, 0 },
+#ifdef OPENSSL_NPN_NEGOTIATED
+ { "ssl_npn", acl_parse_str, smp_fetch_ssl_npn, acl_match_str, ACL_USE_L6REQ_PERMANENT|ACL_MAY_LOOKUP, 0 },
+#endif
{ "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 },