trafficserver-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From a..@apache.org
Subject [1/2] TS-3006: Add SSL extensions and examples.
Date Mon, 22 Sep 2014 19:13:11 GMT
Repository: trafficserver
Updated Branches:
  refs/heads/master 2f6d6e0d0 -> 044da6999


http://git-wip-us.apache.org/repos/asf/trafficserver/blob/044da699/plugins/experimental/ssl_cert_loader/domain-tree.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/ssl_cert_loader/domain-tree.cc b/plugins/experimental/ssl_cert_loader/domain-tree.cc
new file mode 100644
index 0000000..b659193
--- /dev/null
+++ b/plugins/experimental/ssl_cert_loader/domain-tree.cc
@@ -0,0 +1,168 @@
+/** @file 
+    SSL dynamic certificate loader
+    Loads certificates into a hash table as they are requested
+*/
+
+# include <stdio.h>
+# include <memory.h>
+# include <inttypes.h>
+# include <alloca.h>
+# include "domain-tree.h"
+
+// return true if comparable.  Return type of compare in relative parameter
+// 0 if eq.  < 0 if node key is broader.  > 0 if parameter key is broader
+bool 
+DomainNameTree::DomainNameNode::compare(std::string key, int &relative) {
+  size_t star_loc = key.find("*");
+  bool is_wild = false;
+  if (star_loc != std::string::npos) {
+    star_loc++;
+    is_wild = true;
+    key = key.substr(star_loc);
+  }
+  return this->prunedCompare(key, relative, is_wild);
+}
+
+bool 
+DomainNameTree::DomainNameNode::prunedCompare(std::string key, int &relative, bool is_wild)
{
+  if (key == this->key) {
+    relative = 0;
+    return true;
+  }
+  else {
+    if (this->is_wild) { 
+      size_t loc = key.find(this->key);
+      if (this->key == "") { // Match all
+        relative =  -1;
+        return true;
+      }
+      else if (loc != std::string::npos) {
+        // node key is in search key
+        if ((key.length() - this->key.length()) == loc) {
+          // And node key is at the end of search key
+          relative =  -1;
+          return true;
+        }
+      }
+    }
+    if (is_wild) {
+      if (key == "") { // Match all
+        relative =  1;
+        return true;
+      }
+      else {
+        size_t loc = this->key.find(key);
+        if (loc != std::string::npos) {
+          if ((this->key.length() - key.length()) == loc) {
+            relative = 1;
+            return true;
+          } 
+        }
+      }
+    }
+  }
+  return false;
+}
+
+DomainNameTree::DomainNameNode *DomainNameTree::find(std::string key, bool best_match) {
+  DomainNameNode *retval = NULL;
+  DomainNameNode *first = NULL;
+  size_t star_loc = key.find("*");
+  bool is_wild = false;
+  if (star_loc != std::string::npos) {
+    key = key.substr(star_loc+1);
+    is_wild = true;
+  }
+  
+  bool set_iter = false;
+  std::deque<DomainNameNode *>::iterator sibPtr;
+  DomainNameNode *current_node = root;
+  while (current_node != NULL) {
+    bool partial_match = false;
+    int relative;
+    if (current_node->prunedCompare(key, relative, is_wild)) {
+      if (relative == 0) {
+        retval = current_node;
+        if (NULL == first || retval->order < first->order) {
+          first = retval;
+        }
+        break;
+      }
+      else if (relative < 0) {
+        retval = current_node;
+        partial_match = true;
+        if (NULL == first || retval->order < first->order) {
+          first = retval;
+        }
+      }
+    }
+    if (partial_match) {
+      // Check out the children, maybe there is something better there
+      sibPtr = current_node->children.begin();
+      set_iter = true;
+      if (sibPtr == current_node->children.end()) break;  // We are done
+      current_node = *(sibPtr++);
+    } 
+    else { // No match here.  Look at next sibling?
+      // Is there another sibling to look at?
+      if (set_iter && sibPtr != current_node->children.end()) {
+        current_node = *(sibPtr++);
+      }
+      else {	// No more siblings to check, give it up.
+        break;
+      }
+    }
+  }
+  return best_match ? retval : first;
+}
+
+DomainNameTree::DomainNameNode *
+DomainNameTree::insert(std::string key, void *payload, int order) {
+  TSMutexLock(this->tree_mutex);
+  DomainNameNode *retval = NULL;
+  DomainNameNode *node = this->findBestMatch(key);
+  int relative;
+  if (node->compare(key, relative)) {
+    size_t star_loc = key.find("*");
+    bool is_wild = false;
+    if (star_loc != std::string::npos) {
+      star_loc++;
+      key = key.substr(star_loc);
+      is_wild = true;
+    }
+    if (relative < 0) {
+      // Make a new node that is a child of node
+      DomainNameNode *new_node = new DomainNameNode(key, payload, order, is_wild);
+      new_node->parent = node;
+      node->children.push_back(new_node);
+      retval = new_node;
+    }
+    else if (relative > 0) {
+      // Insert new node as parent of node
+      DomainNameNode *new_node = new DomainNameNode(key, payload, order, is_wild);
+      new_node->parent = node->parent;
+      new_node->children.push_back(node);
+      // Replace the node with new_node in the child list of the parent; 
+      std::deque<DomainNameNode *>::iterator iter = node->parent->children.begin();
+      for (; iter != node->parent->children.end(); ++iter) {
+        if (*(iter) == node) {
+          *(iter) = new_node;
+        }
+      }
+      retval =  new_node;
+    }
+    // Will not replace in the equal case
+    // Unless this is the root node
+    else {
+      if (node->key == "" && node->order == 0x7fffffff){
+        node->key = key;
+        node->payload = payload;
+        node->order = order;
+        retval = node;
+      }
+    }
+  }
+  TSMutexUnlock(this->tree_mutex);
+  return retval;
+}
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/044da699/plugins/experimental/ssl_cert_loader/domain-tree.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/ssl_cert_loader/domain-tree.h b/plugins/experimental/ssl_cert_loader/domain-tree.h
new file mode 100644
index 0000000..6f524d2
--- /dev/null
+++ b/plugins/experimental/ssl_cert_loader/domain-tree.h
@@ -0,0 +1,66 @@
+# include <string>
+# include <deque>
+# include <ts/ts.h>
+
+class DomainNameTree {
+public:
+  
+  class DomainNameNode {
+  public:
+    DomainNameNode() : order(-1), payload(NULL), parent(NULL), is_wild(false) 
+    {
+    }
+    DomainNameNode(std::string key, void *payload, int order, bool is_wild) : key(key), order(order),
payload(payload), parent(NULL), is_wild(is_wild)  
+    {
+    }
+    DomainNameNode *match(std::string value);
+    ~DomainNameNode() {
+      std::deque<DomainNameNode *>::iterator iter = children.begin();
+      for (; iter != children.end(); iter++) {
+        delete *iter;
+      }
+    }
+    // return true if comparable.  Return type of compare in relative parameter
+    // 0 if eq.  < 0 if node key is broader.  > 0 if parameter key is broader
+    bool compare(std::string key, int &relative);
+    // The wildcard is pruned out of the key
+    bool prunedCompare(std::string key, int &relative, bool is_wild);
+    std::string key;	// The string trailing the * (if any)
+    int order;		// Track insert order for conflict resolution
+    void *payload;
+    std::deque<DomainNameNode *> children;
+    DomainNameNode *parent;
+    bool is_wild;
+  private:
+  };
+
+  DomainNameTree() {
+    root = new DomainNameNode();
+    root->key = "";
+    root->order = 0x7FFFFFFF;
+    root->is_wild = true;
+    tree_mutex = TSMutexCreate(); 
+  }
+  ~DomainNameTree() {
+    if (root != NULL) { delete root; }
+  }
+  DomainNameNode *findBestMatch(std::string key)  {
+    TSMutexLock(this->tree_mutex);
+    DomainNameNode *retval = this->find(key, true);
+    TSMutexUnlock(this->tree_mutex);
+    return retval;
+  } 
+  DomainNameNode *findFirstMatch(std::string key) {
+    TSMutexLock(this->tree_mutex);
+    DomainNameNode *retval = this->find(key, false);
+    TSMutexUnlock(this->tree_mutex);
+    return retval;
+  }
+  DomainNameNode *find(std::string key, bool best_match);
+  DomainNameNode *insert(std::string key, void *payload, int order);
+
+private:
+  DomainNameNode *root;
+  TSMutex tree_mutex;
+};
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/044da699/plugins/experimental/ssl_cert_loader/ssl-cert-loader.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/ssl_cert_loader/ssl-cert-loader.cc b/plugins/experimental/ssl_cert_loader/ssl-cert-loader.cc
new file mode 100644
index 0000000..54a6603
--- /dev/null
+++ b/plugins/experimental/ssl_cert_loader/ssl-cert-loader.cc
@@ -0,0 +1,541 @@
+/** @file 
+    SSL dynamic certificate loader
+    Loads certificates into a hash table as they are requested
+*/
+
+# include <stdio.h>
+# include <memory.h>
+# include <inttypes.h>
+# include <ts/ts.h>
+# include <tsconfig/TsValue.h>
+# include <alloca.h>
+# include <openssl/ssl.h>
+# include <openssl/x509.h>
+# include <openssl/x509v3.h>
+# include <ts/ink_inet.h>
+# include <ts/IpMap.h>
+# include "domain-tree.h"
+
+using ts::config::Configuration;
+using ts::config::Value;
+
+# define PN "ssl-cert-loader"
+# define PCP "[" PN " Plugin] "
+
+namespace {
+
+class CertLookup {
+public:
+  DomainNameTree tree;
+  IpMap ipmap;
+} Lookup;
+
+class SslEntry {
+public:
+  SslEntry() : ctx(NULL), op(TS_SSL_HOOK_OP_DEFAULT) 
+  { 
+    this->mutex = TSMutexCreate();
+  }
+  ~SslEntry() {
+  }
+  SSL_CTX *ctx;
+  TSSslVConnOp op;
+  // If the CTX is not already created, use these
+  // files to load things up
+  std::string certFileName;
+  std::string keyFileName; 
+  TSMutex mutex;
+  std::deque<TSVConn> waitingVConns;
+};
+
+std::string ConfigPath;
+typedef std::pair<IpAddr, IpAddr> IpRange;
+typedef std::deque<IpRange> IpRangeQueue;
+
+Configuration Config;	// global configuration
+
+void
+Parse_Addr_String(ts::ConstBuffer const &text, IpRange &range) {
+  IpAddr newAddr;
+  std::string textstr(text._ptr, text._size);
+  // Is there a hyphen?
+  size_t hyphen_pos = textstr.find("-");
+  if (hyphen_pos != std::string::npos) {
+    std::string addr1 = textstr.substr(0, hyphen_pos);
+    std::string addr2 = textstr.substr(hyphen_pos+1);
+    range.first.load(ts::ConstBuffer(addr1.c_str(), addr1.length()));
+    range.second.load(ts::ConstBuffer(addr2.c_str(), addr2.length()));
+  }
+  else { // Assume it is a single address
+    newAddr.load(text);
+    range.first = newAddr;
+    range.second = newAddr; 
+  }
+}
+
+int
+Load_Config_File() {
+  ts::Rv<Configuration> cv = Configuration::loadFromPath(ConfigPath.c_str());
+  if (!cv.isOK()) {
+    char error_buffer[1024];
+    cv._errata.write(error_buffer, sizeof(error_buffer), 0, 0, 0, "");
+    TSDebug("skh-cert","Failed to parse %s as TSConfig format", ConfigPath.c_str());
+    TSError(PCP "Failed to parse %s as TSConfig format", ConfigPath.c_str());
+    TSDebug("skh-cert", "Errors: %s", error_buffer);
+    return -1;
+  }
+  Config = cv;
+  return 1;
+}
+
+struct ParsedSslValues {
+  std::string server_priv_key_file;
+  std::string server_name;
+  std::string server_cert_name;
+  std::string action;
+  IpRangeQueue server_ips;
+};
+
+void
+Parse_Config_Rules(Value &parent, ParsedSslValues &orig_values);
+
+int
+Load_Configuration_Args(int argc, const char *argv[]) {
+ts::ConstBuffer text;
+  std::string s; // temp holder.
+  TSMgmtString config_path = NULL;
+
+  // get the path to the config file if one was specified
+  static char const * const CONFIG_ARG = "--config=";
+  int arg_idx;
+  for (arg_idx = 0; arg_idx < argc; arg_idx++) {
+    if (0 == memcmp(argv[arg_idx], CONFIG_ARG, strlen(CONFIG_ARG))) {
+       config_path = TSstrdup(argv[arg_idx] + strlen(CONFIG_ARG));
+       TSDebug(PN, "Found config path %s", config_path);
+    }
+  }
+  if (NULL == config_path) {
+    static char const * const DEFAULT_CONFIG_PATH = "ssl_start.cfg";
+    config_path = TSstrdup(DEFAULT_CONFIG_PATH);
+    TSDebug(PN, "No config path set in arguments, using default: %s", DEFAULT_CONFIG_PATH);
+  }
+
+  // translate relative paths to absolute
+  if (config_path[0] != '/') {
+    ConfigPath = std::string(TSConfigDirGet()) + '/' + std::string(config_path);
+  } else {
+    ConfigPath = config_path;
+  }
+
+  TSDebug("skh-cert", "Load from %s", ConfigPath.c_str());
+  // free up the path
+  TSfree(config_path);
+  return 0;
+}
+
+int
+Load_Configuration() {
+  int ret = Load_Config_File();
+  if (ret != 0) {
+    TSError(PCP "Failed to load the config file, check debug output for errata");
+  }
+
+  Value root = Config.getRoot();
+  Value val = root["runtime-table-size"];
+  if (val.isLiteral()) {
+    // Not evicting yet
+  }
+  val = root["ssl-server-match"];
+  if (val.isContainer()) {
+    ParsedSslValues values;
+    Parse_Config_Rules(val, values);
+  }
+
+  // Test values
+  DomainNameTree::DomainNameNode *node = Lookup.tree.findFirstMatch("calendar.google.com");
+  TSDebug("skh-cert", "Found node with key=%s and order=%d", node->key.c_str(), node->order);
+  node = Lookup.tree.findFirstMatch("www.buseyil.com");
+  TSDebug("skh-cert", "Found node with key=%s and order=%d", node->key.c_str(), node->order);
+
+  IpAddr key_ip;
+  key_ip.load(ts::ConstBuffer("107.23.60.186", strlen("107.23.60.186")));
+  IpEndpoint key_endpoint;
+  key_endpoint.assign(key_ip);
+  void *payload;
+  if (Lookup.ipmap.contains(&key_endpoint, &payload)) {
+    TSDebug("skh-cert", "Found %p for 107.23.60.186", payload);
+  }
+  else {
+    TSDebug("skh-cert", "Found nothing for 107.23.60.186");
+  }
+
+  return 0;
+}
+
+SSL_CTX *
+Load_Certificate(SslEntry const *entry, std::deque<std::string> &names) {
+  const SSL_METHOD *meth = SSLv23_client_method();
+  SSL_CTX *retval = SSL_CTX_new(meth);
+  X509* cert = NULL;
+  if (entry->certFileName.length() > 0) {
+    // Must load the cert file to fetch the names out later
+    BIO *cert_bio = BIO_new_file(entry->certFileName.c_str(), "r");
+    cert = PEM_read_bio_X509_AUX(cert_bio, NULL, NULL, NULL);
+    BIO_free(cert_bio);
+
+    if (SSL_CTX_use_certificate(retval, cert) < 1) {
+      TSDebug("skh-cert", "Failed to load cert file %s", entry->certFileName.c_str());
+      SSL_CTX_free(retval);
+      return NULL;
+    }
+  }
+  if (entry->keyFileName.length() > 0) {
+    if (!SSL_CTX_use_PrivateKey_file(retval, entry->keyFileName.c_str(), SSL_FILETYPE_PEM))
{
+      TSDebug("skh-cert", "Failed to load priv key file %s", entry->keyFileName.c_str());
+      SSL_CTX_free(retval);
+      return NULL;
+    }
+  }
+
+  // Fetch out the names associated with the certificate
+  if (cert != NULL) {
+    X509_NAME *name = X509_get_subject_name(cert);
+    char  subjectCn[256]; 
+    if (X509_NAME_get_text_by_NID(name, NID_commonName, subjectCn, sizeof(subjectCn)) >=
0) {
+      std::string tmp_name(subjectCn);
+      names.push_back(tmp_name);
+    }
+    // Look for alt names
+    GENERAL_NAMES *alt_names = (GENERAL_NAMES *)X509_get_ext_d2i(cert, NID_subject_alt_name,
NULL, NULL);
+    if (alt_names) {
+      unsigned count = sk_GENERAL_NAME_num(alt_names);
+      for (unsigned i = 0; i < count; i++) {
+        GENERAL_NAME *alt_name = sk_GENERAL_NAME_value(alt_names, i);
+  
+        if (alt_name->type == GEN_DNS) {
+          // Current name is a DNS name, let's check it
+          char *name_ptr = (char *) ASN1_STRING_data(alt_name->d.dNSName);
+          std::string tmp_name(name_ptr);
+          names.push_back(tmp_name);
+        }
+      } 
+      sk_GENERAL_NAME_pop_free(alt_names, GENERAL_NAME_free);
+    }
+  }
+
+  // Do we need to free cert? Did assigning to SSL_CTX increment its ref count
+  return retval;
+}
+
+/*
+ * Load the config information about the terminal config.
+ * Only load the certificate if no server name or ip is specified
+ */
+SslEntry *
+Load_Certificate_Entry(ParsedSslValues const &values, std::deque<std::string> &names)
{
+  SslEntry *retval = NULL; 
+  std::string cert_file_path;
+  std::string priv_file_path;
+  retval = new SslEntry();
+  if (values.server_cert_name.length() > 0) { 
+    if (values.server_cert_name[0] != '/') {
+      cert_file_path = std::string(TSConfigDirGet()) + '/' + values.server_cert_name; 
+    }
+    else { 
+      cert_file_path = values.server_cert_name;
+    }
+    retval->certFileName = cert_file_path;
+  }
+  if (values.server_priv_key_file.length() > 0) {
+    if (values.server_priv_key_file[0] != '/') {
+      priv_file_path = std::string(TSConfigDirGet()) + '/' + values.server_priv_key_file;

+    }
+    else { 
+      priv_file_path = values.server_priv_key_file;
+    }
+    retval->keyFileName = priv_file_path;
+  }
+  // Must go ahead and load the cert to get the names
+  if (values.server_name.length() == 0 &&
+      values.server_ips.size() == 0) {
+    retval->ctx = Load_Certificate(retval, names); 
+  }
+  if (values.action.length() > 0) {
+    if (values.action == "tunnel") {
+      retval->op = TS_SSL_HOOK_OP_TUNNEL;
+    }
+    else if (values.action == "teriminate") {
+      retval-> op = TS_SSL_HOOK_OP_TERMINATE;
+    }
+  }
+  return retval;
+}
+
+int Parse_order = 0;
+
+void
+Parse_Config(Value &parent, ParsedSslValues &orig_values) {
+  ParsedSslValues cur_values(orig_values);
+  Value val = parent.find("ssl-key-name");
+  if (val.hasValue()) {
+    cur_values.server_priv_key_file = std::string(val.getText()._ptr, val.getText()._size);
+  }
+  val = parent.find("server-ip");
+  if (val) {
+    IpRange ipRange;
+    Parse_Addr_String(val.getText(), ipRange);
+    cur_values.server_ips.push_back(ipRange);
+  }
+  val = parent.find("server-name");
+  if (val) {
+    cur_values.server_name = std::string(val.getText()._ptr, val.getText()._size);
+  }
+  val = parent.find("server-cert-name");
+  if (val) {
+    cur_values.server_cert_name = std::string(val.getText()._ptr, val.getText()._size);
+  }
+  val = parent.find("action");
+  if (val) {
+    cur_values.action = std::string(val.getText()._ptr, val.getText()._size);
+  }
+
+  val = parent.find("child-match");
+  if (val) {
+    Parse_Config_Rules(val, cur_values); 
+  }
+  else { // We are terminal, enter a match case
+    TSDebug("skh-cert", "Terminal SSL Config: server_priv_key_file=%s server_name=%s server_cert_name=%s
action=%s", 
+      cur_values.server_priv_key_file.c_str(), 
+      cur_values.server_name.c_str(), 
+      cur_values.server_cert_name.c_str(), 
+      cur_values.action.c_str() 
+    );
+    // Load the certificate and create a context if appropriate
+    std::deque<std::string> cert_names;
+    SslEntry *entry  = Load_Certificate_Entry(cur_values, cert_names);
+    
+    // Store in appropriate table
+    if (cur_values.server_name.length() > 0) {
+      Lookup.tree.insert(cur_values.server_name, entry, Parse_order++); 
+    }
+    if (cur_values.server_ips.size() > 0) {
+      size_t i;
+      for (i = 0; i < cur_values.server_ips.size(); i++) {
+        IpEndpoint first, second;
+        first.assign(cur_values.server_ips[i].first);
+        second.assign(cur_values.server_ips[i].second);
+        Lookup.ipmap.fill(&first, &second, entry);
+        char val1[256], val2[256];
+        cur_values.server_ips[i].first.toString(val1, sizeof(val1));
+        cur_values.server_ips[i].second.toString(val2, sizeof(val2));
+      }
+    }
+    if (entry != NULL) {
+      size_t i;
+      for (i = 0; i < cert_names.size(); i++) {
+        Lookup.tree.insert(cert_names[i], entry, Parse_order++);
+      }
+    }
+  }
+}
+
+void
+Parse_Config_Rules(Value &parent, ParsedSslValues &orig_values) {
+  size_t i;
+  for (i = 0; i < parent.childCount(); i++) {
+    Value child = parent[i];
+    Parse_Config(child, orig_values);
+  }
+}
+
+void *
+Load_Certificate_Thread(void *arg) {
+  SslEntry *entry = reinterpret_cast<SslEntry*>(arg);
+
+  TSMutexLock(entry->mutex);
+  if (entry->ctx == NULL) {
+    // Must load certificate
+    std::deque<std::string> cert_names;
+    entry->ctx = Load_Certificate(entry, cert_names);
+    while (entry->waitingVConns.begin() != entry->waitingVConns.end()) {
+      TSVConn vc = entry->waitingVConns.back();
+      entry->waitingVConns.pop_back();
+      TSSslConnection sslobj = TSVConnSSLConnectionGet(vc);
+      SSL *ssl = reinterpret_cast<SSL *>(sslobj);
+      SSL_set_SSL_CTX(ssl, entry->ctx); 
+      TSVConnReenable(vc);
+    }
+    TSMutexUnlock(entry->mutex);
+    size_t i;
+    for (i = 0; i < cert_names.size(); i++) {
+      Lookup.tree.insert(cert_names[i], entry, Parse_order++);
+    }
+  }
+  else {
+    TSMutexUnlock(entry->mutex);
+  }
+  return (void *)1;
+}
+
+int
+CB_Life_Cycle(TSCont , TSEvent , void *) {
+  // By now the SSL library should have been initialized,
+  // We can safely parse the config file and load the ctx tables
+  Load_Configuration();
+  return TS_SUCCESS;
+}
+
+int
+CB_Pre_Accept(TSCont /*contp*/, TSEvent event, void *edata) {
+  TSVConn ssl_vc = reinterpret_cast<TSVConn>(edata);
+  IpAddr ip(TSNetVConnLocalAddrGet(ssl_vc));
+  char buff[INET6_ADDRSTRLEN];
+  IpAddr ip_client(TSNetVConnRemoteAddrGet(ssl_vc));
+  char buff2[INET6_ADDRSTRLEN];
+
+  TSDebug("skh-cert", "Pre accept callback %p - event is %s, target address %s, client address
%s"
+          , ssl_vc
+          , event == TS_EVENT_VCONN_PRE_ACCEPT ? "good" : "bad"
+          , ip.toString(buff, sizeof(buff))
+          , ip_client.toString(buff2, sizeof(buff2))
+    );
+
+  // Is there a cert already defined for this IP?
+  //
+  IpEndpoint key_endpoint;
+  key_endpoint.assign(ip);
+  void *payload;
+  if (Lookup.ipmap.contains(&key_endpoint, &payload)) {
+    // Set the stored cert on this SSL object
+    TSSslConnection sslobj = TSVConnSSLConnectionGet(ssl_vc);
+    SSL *ssl = reinterpret_cast<SSL *>(sslobj);
+    SslEntry *entry = reinterpret_cast<SslEntry *>(payload);
+    TSMutexLock(entry->mutex);
+    if (entry->op == TS_SSL_HOOK_OP_TUNNEL ||
+        entry->op == TS_SSL_HOOK_OP_TERMINATE) {
+      // Push everything to blind tunnel, or terminate
+      if (entry->op == TS_SSL_HOOK_OP_TUNNEL) {
+        TSVConnTunnel(ssl_vc);
+      }
+      TSMutexUnlock(entry->mutex);
+    }
+    else {
+      if (entry->ctx == NULL) {
+        if (entry->waitingVConns.begin() == entry->waitingVConns.end()) {
+          entry->waitingVConns.push_back(ssl_vc);  
+          TSMutexUnlock(entry->mutex);
+    
+          TSThreadCreate(Load_Certificate_Thread, entry);
+        }
+        else { // Just add yourself to the queue
+          entry->waitingVConns.push_back(ssl_vc);  
+          TSMutexUnlock(entry->mutex);
+        }
+        // Return before we reenable
+        return TS_SUCCESS;
+      }
+      else { // if (entry->ctx != NULL) {
+        SSL_set_SSL_CTX(ssl, entry->ctx); 
+        TSDebug("skh-cert", "Replace cert based on IP");
+        TSMutexUnlock(entry->mutex);
+      }
+    }
+  }
+  
+  // All done, reactivate things
+  TSVConnReenable(ssl_vc);
+  return TS_SUCCESS;
+}
+
+int
+CB_servername(TSCont /*contp*/, TSEvent /*event*/, void *edata) {
+  TSVConn ssl_vc = reinterpret_cast<TSVConn>(edata);
+  TSSslConnection sslobj = TSVConnSSLConnectionGet(ssl_vc);
+  SSL *ssl = reinterpret_cast<SSL *>(sslobj);
+  const char *servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
+  if (servername != NULL) {
+    // Is there a certificated loaded up for this name
+    DomainNameTree::DomainNameNode *node = Lookup.tree.findFirstMatch(servername);
+    if (node != NULL && node->payload != NULL) {
+      SslEntry *entry = reinterpret_cast<SslEntry *>(node->payload);
+      if (entry->op == TS_SSL_HOOK_OP_TUNNEL ||
+          entry->op == TS_SSL_HOOK_OP_TERMINATE) {
+        // Push everything to blind tunnel
+        if (entry->op == TS_SSL_HOOK_OP_TUNNEL) {
+          TSVConnTunnel(ssl_vc);
+        }
+        // Make sure we stop out of the SNI callback
+        // So return before re-enabling the SSL connection
+        return TS_SUCCESS;
+      }
+      TSMutexLock(entry->mutex);
+      if (entry->ctx == NULL) {
+        // Spawn off a thread to load a potentially expensive certificate
+        if (entry->waitingVConns.begin() == entry->waitingVConns.end()) {
+          entry->waitingVConns.push_back(ssl_vc);  
+          TSMutexUnlock(entry->mutex);
+          TSThreadCreate(Load_Certificate_Thread, entry);
+        }
+        else { // Just add yourself to the queue
+          entry->waitingVConns.push_back(ssl_vc);  
+          TSMutexUnlock(entry->mutex);
+        }
+        // Won't reenable until the certificate has been loaded
+        return TS_SUCCESS;
+      }
+      else { //if (entry->ctx != NULL) {
+        SSL_set_SSL_CTX(ssl, entry->ctx); 
+        TSDebug("skh-cert", "Replace cert based on name %s", servername);
+      }
+      TSMutexUnlock(entry->mutex);
+    }
+  }
+  // All done, reactivate things
+  TSVConnReenable(ssl_vc);
+  return TS_SUCCESS;
+}
+
+} // Anon namespace
+
+// Called by ATS as our initialization point
+void
+TSPluginInit(int argc, const char *argv[]) {
+  bool success = false;
+  TSPluginRegistrationInfo info;
+  TSCont cb_pa = 0; // pre-accept callback continuation
+  TSCont cb_lc = 0; // life cycle callback continuuation
+  TSCont cb_sni = 0; // SNI callback continuuation
+
+  info.plugin_name = const_cast<char*>("SSL Certificate Loader");
+  info.vendor_name = const_cast<char*>("Network Geographics");
+  info.support_email = const_cast<char*>("shinrich@network-geographics.com");
+
+  if (TS_SUCCESS != TSPluginRegister(TS_SDK_VERSION_2_0, &info)) {
+    TSError(PCP "registration failed.");
+  } else if (TSTrafficServerVersionGetMajor() < 2) {
+    TSError(PCP "requires Traffic Server 2.0 or later.");
+  } else if (0 > Load_Configuration_Args(argc, argv)) {
+    TSError(PCP "Failed to load config file.");
+  } else if (0 == (cb_pa = TSContCreate(&CB_Pre_Accept, TSMutexCreate()))) {
+    TSError(PCP "Failed to pre-accept callback.");
+  } else if (0 == (cb_lc = TSContCreate(&CB_Life_Cycle, TSMutexCreate()))) {
+    TSError(PCP "Failed to lifecycle callback.");
+  } else if (0 == (cb_sni = TSContCreate(&CB_servername, TSMutexCreate()))) {
+    TSError(PCP "Failed to create SNI callback.");
+  } else {
+    TSLifecycleHookAdd(TS_LIFECYCLE_PORTS_INITIALIZED_HOOK, cb_lc);
+    TSHttpHookAdd(TS_VCONN_PRE_ACCEPT_HOOK, cb_pa);
+    TSHttpHookAdd(TS_SSL_SNI_HOOK, cb_sni);
+    success = true;
+  }
+ 
+  if (!success) {
+    if (cb_pa) TSContDestroy(cb_pa);
+    if (cb_lc) TSContDestroy(cb_lc);
+    TSError(PCP "not initialized");
+  }
+  TSDebug(PN, "Plugin %s", success ? "online" : "offline");
+
+  return;
+}
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/044da699/plugins/experimental/ssl_cert_loader/ssl_cert_loader.cfg
----------------------------------------------------------------------
diff --git a/plugins/experimental/ssl_cert_loader/ssl_cert_loader.cfg b/plugins/experimental/ssl_cert_loader/ssl_cert_loader.cfg
new file mode 100644
index 0000000..542d83b
--- /dev/null
+++ b/plugins/experimental/ssl_cert_loader/ssl_cert_loader.cfg
@@ -0,0 +1,135 @@
+// Describe how proxy should deal with the handshake process of SSL
+// connections passing though.
+version = "0.1";
+
+// Once the certificate load table surpasses this limit
+// Start evicting already loaded certificates
+runtime-table-size = "10000";
+
+// By default the proxy will participate in the handshake, so it needs
+// to have a certificate that it uses to handshake with the client, and
+// potentially another certificate to handshake with the origin server
+// In this case, the config must specify both the matching traffic conditions
+// and the connection attributes (certificates, tickets, etc).
+
+// Alternatively the proxy could be directed to get out of the way and
+// blind tunnel the SSL connection.  There are no options to set in this
+// case.  Only specify the matching traffic.
+
+// There are two rule lists.  One that matches on characteristics of the
+// origin server.
+// Another that matches on characteristics of the client.
+
+// The attributes specified by matches in both rule lists will be used
+// to process the connection.  If either rule list specifies a "tunnel" action
+// the connection will be blind tunneled. If either rule specifies a "deny" 
+// action, the handshake processing will stop
+
+// Each rule list  will be evaluated in order and stop on a match
+ 
+ssl-server-match =
+(
+  { server-ip = "192.168.56.0-192.168.56.255"; 
+    action="proxy"; /* Default if no action is specified */
+    server-cert = "server1.pem";
+    ssl-key-name = "privkey.pem";
+    ssl-ticket-key-name = ( "ticket-key.blob", "ticket-key-old.blob" );
+    child-match =
+      // Doing something different for a couple servers in the range
+      { server-ip = "192.168.56.45";
+        server-cert = "server11.pem";
+      },
+      { server-ip = "192.168.56.46";
+        server-cert = "server12.pem";
+      },
+    );
+  },
+  { server-name = "example.com";
+    server-cert = "server2.pem";
+    ssl-key-name = "privkey.pem";
+  },
+  {
+    /* Could include characteristics of the offered ciphers in 
+       evaluating the actions */
+    offered-cipher-constraint = {
+      compare-op = "not-include";
+      ciphers = ("3DES", "null");
+    };
+    server-cert = "server6.pem";
+    ssl-key-name = "privkey.pem";
+  },
+
+  { 
+    /* Default, if no server-ip or server-name is specified,
+       use the name in the certificate */
+    server-name = "@"; 
+    action="proxy"; 
+    server-cert = "server3.pem";
+    ssl-key-name = "privkey.pem";
+  },
+  { 
+    /* With the defaults, devolves to the base case of the
+       ssl_multicert.config */
+    server-cert = "server5.pem";
+    ssl-key-name = "privkey.pem";
+  },
+  /* You can specify the SSL options (non matching state)
+     in a separate entry and refer to it.  Anything specified
+     directly in the match rule will override the ssl-options
+  */
+  { server-ip = "192.168.100.0-192.168.100.100";
+    ssl-options = <ssl-actions.ssl-info-1>; 
+  },
+  { server-ip = "192.168.110.0-192.168.110.100";
+    ssl-options = <ssl-actions.ssl-info-1>; 
+  },
+  { server-name = "*.yahoo.com";
+    action="tunnel";
+  },
+  /* All other traffic should be blind tunneled */
+  { server-ip = "0.0.0.0-255.255.255.255";
+    action = "tunnel";
+  }
+);
+
+ssl-client-match: 
+(
+  // In all cases, use the same cipher-suites
+  { use-client-cipher-suite = < cipher-suites.ecdhe >;
+    child-match =
+    (
+      /* Traffic from lab should be blind tunneled */
+      { client-ip = ("10.10.10.0-10.10.10.255", "10.10.50.152");
+        action = "tunnel";
+      }
+      /* Clients from the office must use an authorized client certificate 
+         Proxy must verify.  Must specify cert to use with origin server */
+      { client-ip = "10.10.20.0-10.10.20.255";
+        client-cert = "valid";
+        /* Specify, or rely on your system settings for cert verification */
+        ssl-signer-cert-name = "signers.pem"; 
+        client-cert-name = "client1.pem";
+        priv-key-name = "client-priv-key.pem";
+      },
+      /* Clients from the other office are not yet set up with client
+         certs.  But must provide client certs for the origin server */
+      { client-ip = "10.10.30.0-10.10.30.255";
+        /* Could be present or not, don't care, this is the default 
+           Other options are valid, present, or none
+         */
+        client-cert = "unknown";
+        client-cert-name = "client1.pem";
+        priv-key-name = "client-priv-key.pem";
+      },
+  }
+);
+
+
+ssl-actions  =
+{
+  ssl-info-1 = {
+    server-cert = "server4.pem";
+    ssl-key-name = "privkey.pem";
+  };
+};
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/044da699/plugins/experimental/ssl_cert_loader/ssl_start.cfg
----------------------------------------------------------------------
diff --git a/plugins/experimental/ssl_cert_loader/ssl_start.cfg b/plugins/experimental/ssl_cert_loader/ssl_start.cfg
new file mode 100644
index 0000000..daff753
--- /dev/null
+++ b/plugins/experimental/ssl_cert_loader/ssl_start.cfg
@@ -0,0 +1,55 @@
+// Describe how proxy should deal with the handshake process of SSL
+// connections passing though.
+version = "0.1"
+
+// Once the certificate load table surpasses this limit
+// Start evicting already loaded certificates
+runtime-table-size = "10000"
+
+// By default the proxy will participate in the handshake, so it needs
+// to have a certificate that it uses to handshake with the client, and
+// potentially another certificate to handshake with the origin server
+// In this case, the config must specify both the matching traffic conditions
+// and the connection attributes (certificates, tickets, etc).
+
+// Alternatively the proxy could be directed to get out of the way and
+// blind tunnel the SSL connection.  There are no options to set in this
+// case.  Only specify the matching traffic.
+
+// There are two rule lists.  One that matches on characteristics of the
+// origin server.
+// Another that matches on characteristics of the client.
+
+// The attributes specified by matches in both rule lists will be used
+// to process the connection.  If either rule list specifies a "tunnel" action
+// the connection will be blind tunneled. If either rule specifies a "deny" 
+// action, the handshake processing will stop
+
+// Each rule list  will be evaluated in order and stop on a match
+ 
+ssl-server-match: 
+(
+  // Using the same private key for all of my certs
+  { ssl-key-name = "privkey.pem";
+    child-match:
+    (
+      { server-ip = "107.23.60.186";
+        action = "tunnel";
+      },
+      { server-cert-name = "safelyfiled.pem;
+      },
+      { server-cert-name = "asba.pem;
+      },
+      { server-name = "www.yahoo.com"; 
+        server-cert-name = "asba.pem;
+      },
+      { server-cert-name = "buseyil.pem;
+      },
+      { server-cert-name = "busey.pem;
+      },
+      { server-cert-name = "wildgoogle.pem";
+      }
+    );
+  }
+)
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/044da699/proxy/InkAPI.cc
----------------------------------------------------------------------
diff --git a/proxy/InkAPI.cc b/proxy/InkAPI.cc
index f03e848..f7c8927 100644
--- a/proxy/InkAPI.cc
+++ b/proxy/InkAPI.cc
@@ -363,6 +363,7 @@ tsapi int TS_HTTP_LEN_PUSH;
 tsapi const TSMLoc TS_NULL_MLOC = (TSMLoc)NULL;
 
 HttpAPIHooks *http_global_hooks = NULL;
+SslAPIHooks *ssl_hooks = NULL;
 LifecycleAPIHooks* lifecycle_hooks = NULL;
 ConfigUpdateCbTable *global_config_cbs = NULL;
 
@@ -644,6 +645,14 @@ sdk_sanity_check_lifecycle_hook_id(TSLifecycleHookID id)
 }
 
 TSReturnCode
+sdk_sanity_check_ssl_hook_id(TSHttpHookID id)
+{
+  if (id<TS_SSL_FIRST_HOOK || id> TS_SSL_LAST_HOOK)
+    return TS_ERROR;
+  return TS_SUCCESS;
+}
+
+TSReturnCode
 sdk_sanity_check_null_ptr(void *ptr)
 {
   if (ptr == NULL)
@@ -1589,6 +1598,7 @@ api_init()
     TS_HTTP_LEN_S_MAXAGE = HTTP_LEN_S_MAXAGE;
 
     http_global_hooks = new HttpAPIHooks;
+    ssl_hooks = new SslAPIHooks;
     lifecycle_hooks = new LifecycleAPIHooks;
     global_config_cbs = new ConfigUpdateCbTable;
 
@@ -4378,10 +4388,19 @@ TSContMutexGet(TSCont contp)
 void
 TSHttpHookAdd(TSHttpHookID id, TSCont contp)
 {
+  INKContInternal *icontp;
   sdk_assert(sdk_sanity_check_continuation(contp) == TS_SUCCESS);
   sdk_assert(sdk_sanity_check_hook_id(id) == TS_SUCCESS);
 
-  http_global_hooks->append(id, (INKContInternal *)contp);
+  icontp = reinterpret_cast<INKContInternal*>(contp);
+
+  if (id >= TS_SSL_FIRST_HOOK && id <= TS_SSL_LAST_HOOK) {
+    TSSslHookInternalID internalId = static_cast<TSSslHookInternalID>(id - TS_SSL_FIRST_HOOK);
+    ssl_hooks->append(internalId , icontp);
+  }
+  else { // Follow through the regular HTTP hook framework
+    http_global_hooks->append(id, icontp);
+  }
 }
 
 void
@@ -8632,3 +8651,111 @@ TSHttpEventNameLookup(TSEvent event)
 {
   return HttpDebugNames::get_event_name(static_cast<int>(event));
 }
+
+/// Re-enable SSL VC.
+class TSSslCallback : public Continuation
+{
+public:
+  TSSslCallback(SSLNetVConnection *vc)
+    : Continuation(vc->mutex), m_vc(vc)
+  {
+    SET_HANDLER(&TSSslCallback::event_handler);
+  }
+
+  int event_handler(int, void*)
+  {
+    m_vc->reenable(m_vc->nh);
+    delete this;
+    return 0;
+  }
+
+private:
+  SSLNetVConnection* m_vc;
+};
+
+
+/// SSL Hooks
+TSReturnCode
+TSVConnTunnel(TSVConn sslp)
+{
+  NetVConnection *vc = reinterpret_cast<NetVConnection*>(sslp);
+  SSLNetVConnection *ssl_vc = dynamic_cast<SSLNetVConnection*>(vc);
+  TSReturnCode zret = TS_SUCCESS;
+  if (0 != ssl_vc) {
+    ssl_vc->hookOpRequested = TS_SSL_HOOK_OP_TUNNEL;
+  } else {
+    zret = TS_ERROR;
+  }
+  return zret;
+}
+
+TSSslConnection
+TSVConnSSLConnectionGet(TSVConn sslp) 
+{
+  TSSslConnection ssl = NULL;
+  NetVConnection *vc = reinterpret_cast<NetVConnection*>(sslp);
+  SSLNetVConnection *ssl_vc = dynamic_cast<SSLNetVConnection*>(vc);
+  if (ssl_vc != NULL) {
+    ssl = reinterpret_cast<TSSslConnection>(ssl_vc->ssl);
+  } 
+  return ssl;
+}
+
+tsapi TSSslContext TSSslContextFindByName(const char *name) 
+{
+  TSSslContext ret = NULL;
+  SSLCertLookup *lookup = SSLCertificateConfig::acquire();
+  if (lookup != NULL) {
+    SSLCertContext *cc = lookup->find(name);
+    if (cc && cc->ctx) {
+      ret = reinterpret_cast<TSSslContext>(cc->ctx);
+    }
+    SSLCertificateConfig::release(lookup);
+  }
+  return ret;
+}
+tsapi TSSslContext TSSslContextFindByAddr(struct sockaddr const* addr)
+{
+  TSSslContext ret = NULL;
+  SSLCertLookup *lookup = SSLCertificateConfig::acquire();
+  if (lookup != NULL) {
+    IpEndpoint ip;
+    ip.assign(addr);
+    SSLCertContext *cc = lookup->find(ip);
+    if (cc && cc->ctx) {
+      ret = reinterpret_cast<TSSslContext>(cc->ctx);
+    }
+    SSLCertificateConfig::release(lookup);
+  }
+  return ret;
+}
+
+tsapi int TSVConnIsSsl(TSVConn sslp) 
+{
+  NetVConnection *vc = reinterpret_cast<NetVConnection*>(sslp);
+  SSLNetVConnection *ssl_vc = dynamic_cast<SSLNetVConnection*>(vc);
+  return ssl_vc != NULL;
+}
+
+void
+TSVConnReenable(TSVConn vconn)
+{
+  NetVConnection *vc = reinterpret_cast<NetVConnection *>(vconn);
+  SSLNetVConnection *ssl_vc = dynamic_cast<SSLNetVConnection*>(vc);
+  // We really only deal with a SSLNetVConnection at the moment
+  if (ssl_vc != NULL) {
+    EThread *eth = this_ethread();
+
+    // We use the VC mutex so we don't need to reschedule again if we
+    // can't get the lock. For this reason we need to execute the
+    // callback on the VC thread or it doesn't work (not sure why -
+    // deadlock or it ends up interacting with the wrong NetHandler).
+    MUTEX_TRY_LOCK(trylock, ssl_vc->mutex, eth);
+    if (!trylock) {
+      ssl_vc->thread->schedule_imm(new TSSslCallback(ssl_vc));
+    }   else {
+      ssl_vc->reenable(ssl_vc->nh);
+    }
+  }
+}
+

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/044da699/proxy/InkAPIInternal.h
----------------------------------------------------------------------
diff --git a/proxy/InkAPIInternal.h b/proxy/InkAPIInternal.h
index 49725b9..08664f1 100644
--- a/proxy/InkAPIInternal.h
+++ b/proxy/InkAPIInternal.h
@@ -290,6 +290,17 @@ class HttpAPIHooks : public FeatureAPIHooks<TSHttpHookID, TS_HTTP_LAST_HOOK>
 {
 };
 
+typedef enum {
+  TS_SSL_INTERNAL_FIRST_HOOK,
+  TS_VCONN_PRE_ACCEPT_INTERNAL_HOOK = TS_SSL_INTERNAL_FIRST_HOOK,
+  TS_SSL_SNI_INTERNAL_HOOK,
+  TS_SSL_INTERNAL_LAST_HOOK 
+} TSSslHookInternalID;
+
+class SslAPIHooks : public FeatureAPIHooks<TSSslHookInternalID, TS_SSL_INTERNAL_LAST_HOOK>
+{
+};
+
 class LifecycleAPIHooks : public FeatureAPIHooks<TSLifecycleHookID, TS_LIFECYCLE_LAST_HOOK>
 {
 };
@@ -344,6 +355,7 @@ void api_init();
 
 extern HttpAPIHooks *http_global_hooks;
 extern LifecycleAPIHooks* lifecycle_hooks;
+extern SslAPIHooks* ssl_hooks;
 extern ConfigUpdateCbTable *global_config_cbs;
 
 #endif /* __INK_API_INTERNAL_H__ */

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/044da699/proxy/api/ts/ts.h
----------------------------------------------------------------------
diff --git a/proxy/api/ts/ts.h b/proxy/api/ts/ts.h
index d28a7b7..50b7c12 100644
--- a/proxy/api/ts/ts.h
+++ b/proxy/api/ts/ts.h
@@ -1223,6 +1223,21 @@ extern "C"
   tsapi int TSHttpSsnTransactionCount(TSHttpSsn ssnp);
 
   /* --------------------------------------------------------------------------
+     SSL connections */
+  /// Re-enable an SSL connection from a hook.
+  /// This must be called exactly once before the SSL connection will resume.
+  tsapi void TSVConnReenable(TSVConn sslvcp);
+  /// Set the connection to go into blind tunnel mode
+  tsapi TSReturnCode TSVConnTunnel(TSVConn sslp);
+  // Return the SSL object associated with the connection
+  tsapi TSSslConnection TSVConnSSLConnectionGet(TSVConn sslp);
+  // Fetch a SSL context from the global lookup table
+  tsapi TSSslContext TSSslContextFindByName(const char *name);
+  tsapi TSSslContext TSSslContextFindByAddr(struct sockaddr const*);
+  // Returns 1 if the sslp argument refers to a SSL connection
+  tsapi int TSVConnIsSsl(TSVConn sslp);
+
+  /* --------------------------------------------------------------------------
      HTTP transactions */
   tsapi void TSHttpTxnHookAdd(TSHttpTxn txnp, TSHttpHookID id, TSCont contp);
   tsapi TSHttpSsn TSHttpTxnSsnGet(TSHttpTxn txnp);

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/044da699/proxy/config/ssl_multicert.config.default
----------------------------------------------------------------------
diff --git a/proxy/config/ssl_multicert.config.default b/proxy/config/ssl_multicert.config.default
index b6dff3c..648858f 100644
--- a/proxy/config/ssl_multicert.config.default
+++ b/proxy/config/ssl_multicert.config.default
@@ -5,9 +5,9 @@
 # hostname or IP address. At load time, the certificate is parsed to
 # extract the subject CN and all the DNS subjectAltNames.  The
 # certificate will be presented for connections requesting any of the
-# hostnames found in the certificate. Wildcard names are supported,
-# but only of the form '*.domain.com', ie. where '*' is the leftmost
-# domain component.
+# hostnames found in the certificate. Wildcard names in the certificates
+# are supported, but only of the form '*.domain.com', ie. where '*' 
+# is the leftmost domain component.
 #
 # The certificate file path, CA path and key path specified in
 # records.config will be used for all certificates, CAs and keys
@@ -47,9 +47,17 @@
 #     exec: - Executes a program and uses the stdout output for the pass
 #       phrase.
 #
+# action=[tunnel]
+#   If the tunnel matches this line, traffic server will not participate
+#   in the handshake.  But rather it will blind tunnel the SSL connection.
+#   If the connection is identified by server name, an openSSL patch must
+#   be applied to enable this functionality.  See TS-3006 for details.
+#
 # Examples:
 #   ssl_cert_name=foo.pem
 #   dest_ip=*	ssl_cert_name=bar.pem ssl_key_name=barKey.pem
 #   dest_ip=209.131.48.79	ssl_cert_name=server.pem ssl_key_name=serverKey.pem
 #   dest_ip=10.0.0.1:99 ssl_cert_name=port99.pem
 #   ssl_cert_name=foo.pem ssl_key_dialog="exec:/usr/bin/mypass foo 'ba r'"
+#   ssl_cert_name=foo.pem action=tunnel
+#   ssl_cert_name=wildcardcert.pem ssl_key_name=privkey.pem

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/044da699/proxy/http/HttpDebugNames.cc
----------------------------------------------------------------------
diff --git a/proxy/http/HttpDebugNames.cc b/proxy/http/HttpDebugNames.cc
index 4e907cf..7a85f6e 100644
--- a/proxy/http/HttpDebugNames.cc
+++ b/proxy/http/HttpDebugNames.cc
@@ -480,6 +480,10 @@ HttpDebugNames::get_api_hook_name(TSHttpHookID t)
     return "TS_HTTP_RESPONSE_CLIENT_HOOK";
   case TS_HTTP_LAST_HOOK:
     return "TS_HTTP_LAST_HOOK";
+  case TS_VCONN_PRE_ACCEPT_HOOK:
+    return "TS_VCONN_PRE_ACCEPT_HOOK";
+  case TS_SSL_SNI_HOOK:
+    return "TS_SSL_SNI_HOOK";
   }
 
   return "unknown hook";

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/044da699/proxy/http/HttpSM.cc
----------------------------------------------------------------------
diff --git a/proxy/http/HttpSM.cc b/proxy/http/HttpSM.cc
index deb2daf..166cb7e 100644
--- a/proxy/http/HttpSM.cc
+++ b/proxy/http/HttpSM.cc
@@ -3610,7 +3610,7 @@ HttpSM::tunnel_handler_ssl_consumer(int event, HttpTunnelConsumer *
c)
     //  read side to close so that we don't cut off
     //  pipelined responses with TCP resets
     //
-    ink_assert(c->producer->alive == false);
+    //ink_assert(c->producer->alive == false);
     c->write_success = true;
     if (c->self_producer->alive == true) {
       c->vc->do_io_shutdown(IO_SHUTDOWN_WRITE);

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/044da699/proxy/http/HttpSessionAccept.cc
----------------------------------------------------------------------
diff --git a/proxy/http/HttpSessionAccept.cc b/proxy/http/HttpSessionAccept.cc
index 9dbbef3..8a81167 100644
--- a/proxy/http/HttpSessionAccept.cc
+++ b/proxy/http/HttpSessionAccept.cc
@@ -49,7 +49,11 @@ HttpSessionAccept::accept(NetVConnection * netvc, MIOBuffer * iobuf, IOBufferRea
     return;
   }
 
-  netvc->attributes = transport_type;
+  // Set the transport type if not already set
+  if (HttpProxyPort::TRANSPORT_NONE == netvc->attributes) {
+    netvc->attributes = transport_type;
+  }
+
 
   if (is_debug_tag_set("http_seq")) {
     Debug("http_seq", "[HttpSessionAccept:mainEvent %p] accepted connection from %s transport
type = %d", netvc, ats_ip_nptop(client_ip, ipb, sizeof(ipb)), netvc->attributes);

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/044da699/proxy/http/HttpSessionAccept.h
----------------------------------------------------------------------
diff --git a/proxy/http/HttpSessionAccept.h b/proxy/http/HttpSessionAccept.h
index 05033d3..9f36436 100644
--- a/proxy/http/HttpSessionAccept.h
+++ b/proxy/http/HttpSessionAccept.h
@@ -25,6 +25,7 @@
 #define _HttpSessionAccept_h_
 
 #include "libts.h"
+#include "records/I_RecHttp.h"
 #include "P_EventSystem.h"
 #include "HttpConfig.h"
 #include "HTTP.h"

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/044da699/proxy/http/HttpTransact.cc
----------------------------------------------------------------------
diff --git a/proxy/http/HttpTransact.cc b/proxy/http/HttpTransact.cc
index 22906d8..d6986b4 100644
--- a/proxy/http/HttpTransact.cc
+++ b/proxy/http/HttpTransact.cc
@@ -596,13 +596,17 @@ HttpTransact::BadRequest(State* s)
 void
 HttpTransact::HandleBlindTunnel(State* s)
 {
+  bool inbound_transparent_p = s->state_machine->ua_session->get_netvc()->get_is_transparent();
+  URL u;
+  IpEndpoint dest_addr;
+  //ip_text_buffer new_host;
+
   DebugTxn("http_trans", "[HttpTransact::HandleBlindTunnel]");
 
   // We've received a request on a port which we blind forward
   //  For logging purposes we create a fake request
   s->hdr_info.client_request.create(HTTP_TYPE_REQUEST);
   s->hdr_info.client_request.method_set(HTTP_METHOD_CONNECT, HTTP_LEN_CONNECT);
-  URL u;
   s->hdr_info.client_request.url_create(&u);
   u.scheme_set(URL_SCHEME_TUNNEL, URL_LEN_TUNNEL);
   s->hdr_info.client_request.url_set(&u);
@@ -647,7 +651,7 @@ HttpTransact::HandleBlindTunnel(State* s)
   //    request was addressed to us to begin with.  Remap directs
   //    are something used in the normal reverse proxy and if we
   //    get them here they indicate a very bad misconfiguration!
-  if (url_remap_success == false || remap_redirect != NULL) {
+  if (!(inbound_transparent_p || url_remap_success) || remap_redirect != NULL) {
     // The error message we send back will be suppressed so
     //  the only important thing in selecting the error is what
     //  status code it gets logged as

http://git-wip-us.apache.org/repos/asf/trafficserver/blob/044da699/proxy/http/HttpTunnel.cc
----------------------------------------------------------------------
diff --git a/proxy/http/HttpTunnel.cc b/proxy/http/HttpTunnel.cc
index b7ee202..492ea8e 100644
--- a/proxy/http/HttpTunnel.cc
+++ b/proxy/http/HttpTunnel.cc
@@ -906,7 +906,6 @@ HttpTunnel::producer_run(HttpTunnelProducer * p)
           }
         }
       }
-
       c->write_vio = c->vc->do_io_write(this, c_write, c->buffer_reader);
       ink_assert(c_write > 0);
     }
@@ -969,6 +968,7 @@ HttpTunnel::producer_run(HttpTunnelProducer * p)
     }
   }
 
+
   if (p->alive) {
     ink_assert(producer_n >= 0);
 
@@ -994,6 +994,7 @@ HttpTunnel::producer_run(HttpTunnelProducer * p)
   // that it doesn't act like a buffer guard
   p->read_buffer->dealloc_reader(p->buffer_start);
   p->buffer_start = NULL;
+
 }
 
 int


Mime
View raw message