From 4176413ea7ed505db42de134758c4c44b84cb2dc Mon Sep 17 00:00:00 2001
From: Emmanuel Hocdet <manu@gandi.net>
Date: Thu, 1 Feb 2018 18:29:59 +0100
Subject: [PATCH 5/5] MINOR: add proxy-v2-options authority

This patch add option PP2_TYPE_AUTHORITY to proxy protocol v2 when a TLS
connection was negotiated. In this case, authority corresponds to the sni.
---
 doc/configuration.txt    |  4 +++-
 include/proto/ssl_sock.h |  1 +
 include/types/server.h   |  1 +
 src/connection.c         |  9 +++++++++
 src/server.c             |  2 ++
 src/ssl_sock.c           | 12 ++++++++++++
 6 files changed, 28 insertions(+), 1 deletion(-)

diff --git a/doc/configuration.txt b/doc/configuration.txt
index 3743ceba2..8929142d4 100644
--- a/doc/configuration.txt
+++ b/doc/configuration.txt
@@ -11723,7 +11723,9 @@ proxy-v2-options <option>[,<option>]*
   2 when "send-proxy-v2" is used. Options available are "ssl" (see also
   send-proxy-v2-ssl), "cert-cn" (see also "send-proxy-v2-ssl-cn"), "ssl-cipher":
   name of the used cipher, "cert-sig": signature algorithm of the used
-  certificate, "cert-key": key algorithm of the used certificate).
+  certificate, "cert-key": key algorithm of the used certificate), "authority":
+  host name value passed by the client (only sni from a tls connection is
+  supported).
 
 send-proxy-v2-ssl
   The "send-proxy-v2-ssl" parameter enforces use of the PROXY protocol version
diff --git a/include/proto/ssl_sock.h b/include/proto/ssl_sock.h
index e1d76a6a0..e36cbddc1 100644
--- a/include/proto/ssl_sock.h
+++ b/include/proto/ssl_sock.h
@@ -50,6 +50,7 @@ void ssl_sock_free_srv_ctx(struct server *srv);
 void ssl_sock_free_all_ctx(struct bind_conf *bind_conf);
 int ssl_sock_load_ca(struct bind_conf *bind_conf);
 void ssl_sock_free_ca(struct bind_conf *bind_conf);
+const char *ssl_sock_get_sni(struct connection *conn);
 const char *ssl_sock_get_cert_sig(struct connection *conn);
 const char *ssl_sock_get_cipher_name(struct connection *conn);
 const char *ssl_sock_get_proto_version(struct connection *conn);
diff --git a/include/types/server.h b/include/types/server.h
index 91f8a9d4f..6d0566be2 100644
--- a/include/types/server.h
+++ b/include/types/server.h
@@ -151,6 +151,7 @@ enum srv_initaddr {
 #define SRV_PP_V2_SSL_KEY_ALG   0x0010   /* proxy protocol version 2 with cert key algorithm */
 #define SRV_PP_V2_SSL_SIG_ALG   0x0020   /* proxy protocol version 2 with cert signature algorithm */
 #define SRV_PP_V2_SSL_CIPHER    0x0040   /* proxy protocol version 2 with cipher used */
+#define SRV_PP_V2_AUTHORITY     0x0080   /* proxy protocol version 2 with authority */
 
 /* function which act on servers need to return various errors */
 #define SRV_STATUS_OK       0   /* everything is OK. */
diff --git a/src/connection.c b/src/connection.c
index e8a02ea40..206b22b72 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -1044,6 +1044,15 @@ int make_proxy_line_v2(char *buf, int buf_len, struct server *srv, struct connec
 	}
 
 #ifdef USE_OPENSSL
+	if (srv->pp_opts & SRV_PP_V2_AUTHORITY) {
+		value = ssl_sock_get_sni(remote);
+		if (value) {
+			if ((buf_len - ret) < sizeof(struct tlv))
+				return 0;
+			ret += make_tlv(&buf[ret], (buf_len - ret), PP2_TYPE_AUTHORITY, strlen(value), value);
+		}
+	}
+
 	if (srv->pp_opts & SRV_PP_V2_SSL) {
 		struct tlv_ssl *tlv;
 		int ssl_tlv_len = 0;
diff --git a/src/server.c b/src/server.c
index 77fc0c6ad..f4cf45cd3 100644
--- a/src/server.c
+++ b/src/server.c
@@ -526,6 +526,8 @@ static int srv_parse_proxy_v2_options(char **args, int *cur_arg,
 		} else if (!strcmp(p, "ssl-cipher")) {
 			newsrv->pp_opts |= SRV_PP_V2_SSL;
 			newsrv->pp_opts |= SRV_PP_V2_SSL_CIPHER;
+		} else if (!strcmp(p, "authority")) {
+			newsrv->pp_opts |= SRV_PP_V2_AUTHORITY;
 		} else
 			goto fail;
 	}
diff --git a/src/ssl_sock.c b/src/ssl_sock.c
index 2fc3482ab..54482c543 100644
--- a/src/ssl_sock.c
+++ b/src/ssl_sock.c
@@ -5762,6 +5762,18 @@ const char *ssl_sock_get_cert_sig(struct connection *conn)
 	return OBJ_nid2sn(OBJ_obj2nid(algorithm));
 }
 
+/* used for ppv2 authority */
+const char *ssl_sock_get_sni(struct connection *conn)
+{
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+	if (!ssl_sock_is_ssl(conn))
+		return NULL;
+	return SSL_get_servername(conn->xprt_ctx, TLSEXT_NAMETYPE_host_name);
+#else
+	return 0;
+#endif
+}
+
 /* used for logging/ppv2, may be changed for a sample fetch later */
 const char *ssl_sock_get_cipher_name(struct connection *conn)
 {
-- 
2.11.0

