ldp: add option to eanble transparent TLS connections

If LDP_TRANSPARENT_TLS is set, LDP transparently converts TCP into TLS
connnection.
Verified in Nginx LD_PRELOAD mode.

Change-Id: I2229be61a0deb723bf5d94a2193ecb792dd997fb
Signed-off-by: Yu Ping <ping.yu@intel.com>
diff --git a/src/vcl/ldp.c b/src/vcl/ldp.c
index 6dc44ec..70a4299 100644
--- a/src/vcl/ldp.c
+++ b/src/vcl/ldp.c
@@ -99,6 +99,7 @@
   u32 vlsh_bit_val;
   u32 vlsh_bit_mask;
   u32 debug;
+  u8 transparent_tls;
 
   /** vcl needs next epoll_create to go to libc_epoll */
   u8 vcl_needs_real_epoll;
@@ -114,6 +115,7 @@
   .vlsh_bit_val = (1 << LDP_SID_BIT_MIN),
   .vlsh_bit_mask = (1 << LDP_SID_BIT_MIN) - 1,
   .debug = LDP_DEBUG_INIT,
+  .transparent_tls = 0,
 };
 
 static ldp_main_t *ldp = &ldp_main;
@@ -268,6 +270,11 @@
 	  return -1;
 	}
     }
+  env_var_str = getenv (LDP_ENV_TLS_TRANS);
+  if (env_var_str)
+    {
+      ldp->transparent_tls = 1;
+    }
 
   /* *INDENT-OFF* */
   pool_foreach (ldpw, ldp->workers, ({
@@ -870,6 +877,71 @@
 }
 #endif
 
+/* If transparent TLS mode is turned on, then ldp will load key and cert.
+ */
+static int
+load_tls_cert (vls_handle_t vlsh)
+{
+  char *env_var_str = getenv (LDP_ENV_TLS_CERT);
+  char inbuf[4096];
+  char *tls_cert;
+  int cert_size;
+  FILE *fp;
+
+  if (env_var_str)
+    {
+      fp = fopen (env_var_str, "r");
+      if (fp == NULL)
+	{
+	  LDBG (0, "ERROR: failed to open cert file %s \n", env_var_str);
+	  return -1;
+	}
+      cert_size = fread (inbuf, sizeof (char), sizeof (inbuf), fp);
+      tls_cert = inbuf;
+      vppcom_session_tls_add_cert (vlsh_to_session_index (vlsh), tls_cert,
+				   cert_size);
+      fclose (fp);
+    }
+  else
+    {
+      LDBG (0, "ERROR: failed to read LDP environment %s\n",
+	    LDP_ENV_TLS_CERT);
+      return -1;
+    }
+  return 0;
+}
+
+static int
+load_tls_key (vls_handle_t vlsh)
+{
+  char *env_var_str = getenv (LDP_ENV_TLS_KEY);
+  char inbuf[4096];
+  char *tls_key;
+  int key_size;
+  FILE *fp;
+
+  if (env_var_str)
+    {
+      fp = fopen (env_var_str, "r");
+      if (fp == NULL)
+	{
+	  LDBG (0, "ERROR: failed to open key file %s \n", env_var_str);
+	  return -1;
+	}
+      key_size = fread (inbuf, sizeof (char), sizeof (inbuf), fp);
+      tls_key = inbuf;
+      vppcom_session_tls_add_key (vlsh_to_session_index (vlsh), tls_key,
+				  key_size);
+      fclose (fp);
+    }
+  else
+    {
+      LDBG (0, "ERROR: failed to read LDP environment %s\n", LDP_ENV_TLS_KEY);
+      return -1;
+    }
+  return 0;
+}
+
 int
 socket (int domain, int type, int protocol)
 {
@@ -883,8 +955,14 @@
   if (((domain == AF_INET) || (domain == AF_INET6)) &&
       ((sock_type == SOCK_STREAM) || (sock_type == SOCK_DGRAM)))
     {
-      u8 proto = ((sock_type == SOCK_DGRAM) ?
-		  VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP);
+      u8 proto;
+      if (ldp->transparent_tls)
+	{
+	  proto = VPPCOM_PROTO_TLS;
+	}
+      else
+	proto = ((sock_type == SOCK_DGRAM) ?
+		 VPPCOM_PROTO_UDP : VPPCOM_PROTO_TCP);
 
       LDBG (0, "calling vls_create: proto %u (%s), is_nonblocking %u",
 	    proto, vppcom_proto_str (proto), is_nonblocking);
@@ -897,6 +975,13 @@
 	}
       else
 	{
+	  if (ldp->transparent_tls)
+	    {
+	      if (load_tls_cert (vlsh) < 0 || load_tls_key (vlsh) < 0)
+		{
+		  return -1;
+		}
+	    }
 	  rv = ldp_vlsh_to_fd (vlsh);
 	}
     }