From 54674324e24d2c40385c78f7473427965fc18848 Mon Sep 17 00:00:00 2001 From: Masaori Koshiba Date: Thu, 18 Feb 2021 16:22:43 +0900 Subject: [PATCH] Override proxy.config.ssl.client.sni_policy from sni.yaml --- doc/admin-guide/files/sni.yaml.en.rst | 4 ++++ iocore/net/I_NetVConnection.h | 4 ++++ iocore/net/P_SNIActionPerformer.h | 24 ++++++++++++++++++++++++ iocore/net/P_UnixNetVConnection.h | 1 + iocore/net/SSLSNIConfig.cc | 3 +++ iocore/net/YamlSNIConfig.cc | 4 ++++ iocore/net/YamlSNIConfig.h | 2 ++ proxy/http/HttpSM.cc | 7 +++++++ 8 files changed, 49 insertions(+) diff --git a/doc/admin-guide/files/sni.yaml.en.rst b/doc/admin-guide/files/sni.yaml.en.rst index 94b88c8cdeb..8478c5099ab 100644 --- a/doc/admin-guide/files/sni.yaml.en.rst +++ b/doc/admin-guide/files/sni.yaml.en.rst @@ -114,6 +114,10 @@ client_key The file containing the client private key that corres |TS| tries to use a private key in client_cert. Otherwise, :ts:cv:`proxy.config.ssl.client.private_key.filename` is used. +client_sni_policy Policy of SNI on outbound connection. + + If not specified, the value of :ts:cv:`proxy.config.ssl.client.sni_policy` is used. + http2 Indicates whether the H2 protocol should be added to or removed from the protocol negotiation list. The valid values are :code:`on` or :code:`off`. diff --git a/iocore/net/I_NetVConnection.h b/iocore/net/I_NetVConnection.h index 9f42e5b566b..ea290174645 100644 --- a/iocore/net/I_NetVConnection.h +++ b/iocore/net/I_NetVConnection.h @@ -202,6 +202,10 @@ struct NetVCOptions { */ ats_scoped_str sni_hostname; + /** Outbound sni policy which overrides proxy.ssl.client.sni_policy + */ + ats_scoped_str outbound_sni_policy; + /** * Client certificate to use in response to OS's certificate request */ diff --git a/iocore/net/P_SNIActionPerformer.h b/iocore/net/P_SNIActionPerformer.h index 636a07a3302..bcaec2b9917 100644 --- a/iocore/net/P_SNIActionPerformer.h +++ b/iocore/net/P_SNIActionPerformer.h @@ -344,3 +344,27 @@ class SNI_IpAllow : public ActionItem return retval; } }; + +/** + Override proxy.config.ssl.client.sni_policy by client_sni_policy in sni.yaml + */ +class OutboundSNIPolicy : public ActionItem +{ +public: + OutboundSNIPolicy(const std::string_view &p) : policy(p) {} + ~OutboundSNIPolicy() override {} + + int + SNIAction(TLSSNISupport *snis, const Context &ctx) const override + { + // TODO: change design to avoid this dynamic_cast + auto ssl_vc = dynamic_cast(snis); + if (ssl_vc && !policy.empty()) { + ssl_vc->options.outbound_sni_policy = policy; + } + return SSL_TLSEXT_ERR_OK; + } + +private: + std::string_view policy{}; +}; diff --git a/iocore/net/P_UnixNetVConnection.h b/iocore/net/P_UnixNetVConnection.h index 8d34bf8a6e6..399e1d9690b 100644 --- a/iocore/net/P_UnixNetVConnection.h +++ b/iocore/net/P_UnixNetVConnection.h @@ -72,6 +72,7 @@ NetVCOptions::reset() sni_hostname = nullptr; ssl_client_cert_name = nullptr; ssl_client_private_key_name = nullptr; + outbound_sni_policy = nullptr; } inline void diff --git a/iocore/net/SSLSNIConfig.cc b/iocore/net/SSLSNIConfig.cc index 647b687181f..ee92eb04635 100644 --- a/iocore/net/SSLSNIConfig.cc +++ b/iocore/net/SSLSNIConfig.cc @@ -79,6 +79,9 @@ SNIConfigParams::loadSNIConfig() if (item.tunnel_destination.length() > 0) { ai->actions.push_back(std::make_unique(item.tunnel_destination, item.tunnel_type, item.tunnel_alpn)); } + if (!item.client_sni_policy.empty()) { + ai->actions.push_back(std::make_unique(item.client_sni_policy)); + } ai->actions.push_back(std::make_unique(item.ip_allow, item.fqdn)); diff --git a/iocore/net/YamlSNIConfig.cc b/iocore/net/YamlSNIConfig.cc index 6744bd3f36e..0b66917fe43 100644 --- a/iocore/net/YamlSNIConfig.cc +++ b/iocore/net/YamlSNIConfig.cc @@ -133,6 +133,7 @@ std::set valid_sni_config_keys = {TS_fqdn, TS_verify_server_properties, TS_client_cert, TS_client_key, + TS_client_sni_policy, TS_http2, TS_ip_allow, #if TS_USE_HELLO_CB @@ -266,6 +267,9 @@ template <> struct convert { if (node[TS_client_key]) { item.client_key = node[TS_client_key].as(); } + if (node[TS_client_sni_policy]) { + item.client_sni_policy = node[TS_client_sni_policy].as(); + } if (node[TS_ip_allow]) { item.ip_allow = node[TS_ip_allow].as(); diff --git a/iocore/net/YamlSNIConfig.h b/iocore/net/YamlSNIConfig.h index 47c2fa6eef0..f1c4b6111ca 100644 --- a/iocore/net/YamlSNIConfig.h +++ b/iocore/net/YamlSNIConfig.h @@ -43,6 +43,7 @@ TSDECL(verify_server_properties); TSDECL(verify_origin_server); TSDECL(client_cert); TSDECL(client_key); +TSDECL(client_sni_policy); TSDECL(ip_allow); TSDECL(valid_tls_versions_in); TSDECL(http2); @@ -69,6 +70,7 @@ struct YamlSNIConfig { Property verify_server_properties = Property::UNSET; std::string client_cert; std::string client_key; + std::string client_sni_policy; std::string ip_allow; bool protocol_unset = true; unsigned long protocol_mask; diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc index 3b5deb15062..39357004b61 100644 --- a/proxy/http/HttpSM.cc +++ b/proxy/http/HttpSM.cc @@ -4854,6 +4854,13 @@ HttpSM::get_outbound_sni() const using namespace ts::literals; ts::TextView zret; ts::TextView policy{t_state.txn_conf->ssl_client_sni_policy, ts::TextView::npos}; + + if (ua_txn) { + if (const NetVConnection *netvc = ua_txn->get_netvc(); netvc->options.outbound_sni_policy) { + policy.assign(netvc->options.outbound_sni_policy.get(), ts::TextView::npos); + } + } + if (policy.empty() || !strcmp(policy, "host"_tv)) { // By default the host header field value is used for the SNI. int len;