trafficserver-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bc...@apache.org
Subject [trafficserver] 02/03: SNI based IP_ALLOW
Date Thu, 05 Jul 2018 17:18:47 GMT
This is an automated email from the ASF dual-hosted git repository.

bcall pushed a commit to branch 8.0.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git

commit a9c9081684a7ea982e35975057b469d893396dde
Author: Persia Aziz <persia@yahoo-inc.com>
AuthorDate: Thu Apr 5 17:43:42 2018 -0500

    SNI based IP_ALLOW
    
    (cherry picked from commit b61b82cdfb1ad1cd9c8e03bc3363396aea034123)
---
 configs/ssl_server_name.yaml.default |  4 ++-
 iocore/net/P_SNIActionPerformer.h    | 61 +++++++++++++++++++++++++++++++++---
 iocore/net/SNIActionPerformer.cc     |  8 +++--
 iocore/net/SSLSNIConfig.cc           |  2 ++
 iocore/net/SSLUtils.cc               |  6 +++-
 iocore/net/YamlSNIConfig.cc          | 10 ++++--
 iocore/net/YamlSNIConfig.h           |  2 ++
 7 files changed, 83 insertions(+), 10 deletions(-)

diff --git a/configs/ssl_server_name.yaml.default b/configs/ssl_server_name.yaml.default
index ed2c956..60bb6ea 100644
--- a/configs/ssl_server_name.yaml.default
+++ b/configs/ssl_server_name.yaml.default
@@ -13,6 +13,8 @@
 #    client_cert - sets the client certificate to present to the server specified in dest_host;
parameters = certificate file .
 #                      The location of the certificate file is relative to proxy.config.ssl.server.cert.path
directory.
 #    tunnel_route  - sets the e2e tunnel route
+#    ip_allow - lists or range of client IP addresses, subnets that are allowed for this
connection. This accepts CIDR format
+#              for subnet specification.
 #
 #  Example:
 #
@@ -23,4 +25,4 @@
 #   verify_client: MODERATE
 # - fqdn: two.com
 #   tunnel_route: two.com
-#
+#   ip_allow = '10.0.0.1-10.0.0.255'
diff --git a/iocore/net/P_SNIActionPerformer.h b/iocore/net/P_SNIActionPerformer.h
index f876a70..c40091e 100644
--- a/iocore/net/P_SNIActionPerformer.h
+++ b/iocore/net/P_SNIActionPerformer.h
@@ -35,6 +35,7 @@
 //#include"P_UnixNetProcessor.h"
 #include <vector>
 #include "P_SSLNextProtocolAccept.h"
+#include "ts/ink_inet.h"
 
 extern Map<int, SSLNextProtocolSet *> snpsMap;
 // enum of all the actions
@@ -50,7 +51,7 @@ enum PropertyActions { TS_VERIFY_SERVER = 200, TS_CLIENT_CERT };
 class ActionItem
 {
 public:
-  virtual void SNIAction(Continuation *cont) = 0;
+  virtual int SNIAction(Continuation *cont) = 0;
   virtual ~ActionItem(){};
 };
 
@@ -60,7 +61,7 @@ public:
   DisableH2() {}
   ~DisableH2() override {}
 
-  void
+  int
   SNIAction(Continuation *cont) override
   {
     auto ssl_vc     = reinterpret_cast<SSLNetVConnection *>(cont);
@@ -69,6 +70,7 @@ public:
       auto nps = snpsMap.get(accept_obj->id);
       ssl_vc->registerNextProtocolSet(reinterpret_cast<SSLNextProtocolSet *>(nps));
     }
+    return SSL_TLSEXT_ERR_OK;
   }
 };
 
@@ -80,12 +82,63 @@ public:
   VerifyClient(const char *param) : mode(atoi(param)) {}
   VerifyClient(uint8_t param) : mode(param) {}
   ~VerifyClient() override {}
-  void
+  int
   SNIAction(Continuation *cont) override
   {
     auto ssl_vc = reinterpret_cast<SSLNetVConnection *>(cont);
     Debug("ssl_sni", "action verify param %d", this->mode);
     setClientCertLevel(ssl_vc->ssl, this->mode);
+    return SSL_TLSEXT_ERR_OK;
+  }
+};
+
+class SNI_IpAllow : public ActionItem
+{
+  IpMap ip_map;
+
+public:
+  SNI_IpAllow(std::string const &ip_allow_list, cchar *servername)
+  {
+    // the server identified by item.fqdn requires ATS to do IP filtering
+    if (ip_allow_list.length()) {
+      IpAddr addr1;
+      IpAddr addr2;
+      // check format first
+      // check if the input is a comma separated list of IPs
+      ts::TextView content(ip_allow_list);
+      while (!content.empty()) {
+        ts::TextView list{content.take_prefix_at(',')};
+        if (0 != ats_ip_range_parse(list, addr1, addr2)) {
+          Debug("ssl_sni", "%.*s is not a valid format", static_cast<int>(list.size()),
list.data());
+          break;
+        } else {
+          Debug("ssl_sni", "%.*s added to the ip_allow list %s", static_cast<int>(list.size()),
list.data(), servername);
+          ip_map.fill(IpEndpoint().assign(addr1), IpEndpoint().assign(addr2), reinterpret_cast<void
*>(1));
+        }
+      }
+    }
+  } // end function SNI_IpAllow
+
+  int
+  SNIAction(Continuation *cont) override
+  {
+    // i.e, ip filtering is not required
+    if (ip_map.getCount() == 0) {
+      return SSL_TLSEXT_ERR_OK;
+    }
+
+    auto ssl_vc = reinterpret_cast<SSLNetVConnection *>(cont);
+    auto ip     = ssl_vc->get_remote_endpoint();
+
+    // check the allowed ips
+    if (ip_map.contains(ip)) {
+      return SSL_TLSEXT_ERR_OK;
+    } else {
+      char buff[256];
+      ats_ip_ntop(&ip.sa, buff, sizeof(buff));
+      Debug("ssl_sni", "%s is not allowed. Denying connection", buff);
+      return SSL_TLSEXT_ERR_ALERT_FATAL;
+    }
   }
 };
 
@@ -93,5 +146,5 @@ class SNIActionPerformer
 {
 public:
   SNIActionPerformer() = default;
-  static void PerformAction(Continuation *cont, cchar *servername);
+  static int PerformAction(Continuation *cont, cchar *servername);
 };
diff --git a/iocore/net/SNIActionPerformer.cc b/iocore/net/SNIActionPerformer.cc
index 710a7b5..0561096 100644
--- a/iocore/net/SNIActionPerformer.cc
+++ b/iocore/net/SNIActionPerformer.cc
@@ -37,7 +37,7 @@
 
 extern Map<int, SSLNextProtocolSet *> snpsMap;
 
-void
+int
 SNIActionPerformer::PerformAction(Continuation *cont, cchar *servername)
 {
   SNIConfig::scoped_config params;
@@ -47,8 +47,12 @@ SNIActionPerformer::PerformAction(Continuation *cont, cchar *servername)
   } else {
     for (auto it : *actionvec) {
       if (it) {
-        it->SNIAction(cont);
+        auto ret = it->SNIAction(cont);
+        if (ret != SSL_TLSEXT_ERR_OK) {
+          return ret;
+        }
       }
     }
   }
+  return SSL_TLSEXT_ERR_OK;
 }
diff --git a/iocore/net/SSLSNIConfig.cc b/iocore/net/SSLSNIConfig.cc
index a735444..71ff860 100644
--- a/iocore/net/SSLSNIConfig.cc
+++ b/iocore/net/SSLSNIConfig.cc
@@ -82,6 +82,8 @@ SNIConfigParams::loadSNIConfig()
       TunnelMap.emplace(item.fqdn.data(), item.tunnel_destination);
     }
 
+    auto ai3 = new SNI_IpAllow(item.ip_allow, servername);
+    aiVec->push_back(ai3);
     // set the next hop properties
     SSLConfig::scoped_config params;
     auto clientCTX  = params->getCTX(servername);
diff --git a/iocore/net/SSLUtils.cc b/iocore/net/SSLUtils.cc
index acc8d57..93d7fb3 100644
--- a/iocore/net/SSLUtils.cc
+++ b/iocore/net/SSLUtils.cc
@@ -448,12 +448,16 @@ extern SNIActionPerformer sni_action_performer;
 static int
 ssl_servername_only_callback(SSL *ssl, int * /* ad */, void * /*arg*/)
 {
+  int ret                  = SSL_TLSEXT_ERR_OK;
   SSLNetVConnection *netvc = SSLNetVCAccess(ssl);
   const char *servername   = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
   Debug("ssl", "Requested servername is %s", servername);
   if (servername != nullptr) {
-    sni_action_performer.PerformAction(netvc, servername);
+    ret = sni_action_performer.PerformAction(netvc, servername);
   }
+  if (ret != SSL_TLSEXT_ERR_OK)
+    return SSL_TLSEXT_ERR_ALERT_FATAL;
+
   netvc->callHooks(TS_EVENT_SSL_SERVERNAME);
   return SSL_TLSEXT_ERR_OK;
 }
diff --git a/iocore/net/YamlSNIConfig.cc b/iocore/net/YamlSNIConfig.cc
index 5ab7ad2..5d20ccd 100644
--- a/iocore/net/YamlSNIConfig.cc
+++ b/iocore/net/YamlSNIConfig.cc
@@ -52,8 +52,8 @@ YamlSNIConfig::loader(const char *cfgFilename)
 
 TsEnumDescriptor LEVEL_DESCRIPTOR = {{{"NONE", 0}, {"MODERATE", 1}, {"STRICT", 2}}};
 
-std::set<std::string> valid_sni_config_keys = {TS_fqdn,         TS_disable_H2,    
      TS_verify_client,
-                                               TS_tunnel_route, TS_verify_origin_server,
TS_client_cert};
+std::set<std::string> valid_sni_config_keys = {
+  TS_fqdn, TS_disable_H2, TS_verify_client, TS_tunnel_route, TS_verify_origin_server, TS_client_cert,
TS_ip_allow};
 
 namespace YAML
 {
@@ -70,6 +70,8 @@ template <> struct convert<YamlSNIConfig::Item> {
 
     if (node[TS_fqdn]) {
       item.fqdn = node[TS_fqdn].as<std::string>();
+    } else {
+      return false; // servername must be present
     }
     if (node[TS_disable_H2]) {
       item.fqdn = node[TS_disable_H2].as<bool>();
@@ -101,6 +103,10 @@ template <> struct convert<YamlSNIConfig::Item> {
     if (node[TS_client_cert]) {
       item.client_cert = node[TS_client_cert].as<std::string>();
     }
+
+    if (node[TS_ip_allow]) {
+      item.ip_allow = node[TS_ip_allow].as<std::string>();
+    }
     return true;
   }
 };
diff --git a/iocore/net/YamlSNIConfig.h b/iocore/net/YamlSNIConfig.h
index e3fcd11..cb57d5b 100644
--- a/iocore/net/YamlSNIConfig.h
+++ b/iocore/net/YamlSNIConfig.h
@@ -32,6 +32,7 @@ constexpr char TS_verify_client[]        = "verify_client";
 constexpr char TS_tunnel_route[]         = "tunnel_route";
 constexpr char TS_verify_origin_server[] = "verify_origin_server";
 constexpr char TS_client_cert[]          = "client_cert";
+constexpr char TS_ip_allow[]             = "ip_allow";
 
 const int start = 0;
 struct YamlSNIConfig {
@@ -54,6 +55,7 @@ struct YamlSNIConfig {
     std::string tunnel_destination;
     uint8_t verify_origin_server = 0;
     std::string client_cert;
+    std::string ip_allow;
   };
 
   ts::Errata loader(const char *cfgFilename);


Mime
View raw message