session: https parsing support 18/42418/7
authorAdrian Villin <[email protected]>
Thu, 6 Mar 2025 12:25:50 +0000 (13:25 +0100)
committerFlorin Coras <[email protected]>
Wed, 16 Apr 2025 19:32:43 +0000 (19:32 +0000)
Type: improvement

Change-Id: I6ec29cda2cb841a70d6f5768f97666b2cc37febb
Signed-off-by: Adrian Villin <[email protected]>
extras/hs-test/http_test.go
src/plugins/hs_apps/http_client.c
src/vnet/session/application_interface.c
src/vnet/session/session_types.h

index 93317bb..5fec25a 100644 (file)
@@ -2,6 +2,7 @@ package main
 
 import (
        "bytes"
+       "crypto/tls"
        "fmt"
        "io"
        "math/rand"
@@ -33,7 +34,7 @@ func init() {
                HttpInvalidContentLengthTest, HttpInvalidTargetSyntaxTest, HttpStaticPathSanitizationTest, HttpUriDecodeTest,
                HttpHeadersTest, HttpStaticFileHandlerTest, HttpStaticFileHandlerDefaultMaxAgeTest, HttpClientTest,
                HttpClientErrRespTest, HttpClientPostFormTest, HttpClientGet128kbResponseTest, HttpClientGetResponseBodyTest,
-               HttpClientGetNoResponseBodyTest, HttpClientPostFileTest, HttpClientPostFilePtrTest,
+               HttpClientGetTlsNoRespBodyTest, HttpClientPostFileTest, HttpClientPostFilePtrTest, HttpUnitTest,
                HttpRequestLineTest, HttpClientGetTimeout, HttpStaticFileHandlerWrkTest, HttpStaticUrlHandlerWrkTest, HttpConnTimeoutTest,
                HttpClientGetRepeatTest, HttpClientPostRepeatTest, HttpIgnoreH2UpgradeTest, HttpInvalidAuthorityFormUriTest, HttpHeaderErrorConnectionDropTest)
        RegisterNoTopoSoloTests(HttpStaticPromTest, HttpGetTpsTest, HttpGetTpsInterruptModeTest, PromConcurrentConnectionsTest,
@@ -365,26 +366,43 @@ func HttpClientPostFormTest(s *NoTopoSuite) {
 func HttpClientGetResponseBodyTest(s *NoTopoSuite) {
        response := "<body>hello world</body>"
        size := len(response)
-       httpClientGet(s, response, size)
+       httpClientGet(s, response, size, "http")
 }
 
 func HttpClientGet128kbResponseTest(s *NoTopoSuite) {
        response := strings.Repeat("a", 128*1024)
        size := len(response)
-       httpClientGet(s, response, size)
+       httpClientGet(s, response, size, "http")
 }
 
-func HttpClientGetNoResponseBodyTest(s *NoTopoSuite) {
+func HttpClientGetTlsNoRespBodyTest(s *NoTopoSuite) {
        response := ""
-       httpClientGet(s, response, 0)
+       httpClientGet(s, response, 0, "https")
 }
 
-func httpClientGet(s *NoTopoSuite, response string, size int) {
-       serverAddress := s.HostAddr()
+func httpClientGet(s *NoTopoSuite, response string, size int, proto string) {
+       var l net.Listener
+       var err error
+       var port string
        vpp := s.Containers.Vpp.VppInstance
        server := ghttp.NewUnstartedServer()
-       l, err := net.Listen("tcp", serverAddress+":80")
+       serverAddress := s.HostAddr()
+
+       if proto == "https" {
+               certFile := "resources/cert/localhost.crt"
+               keyFile := "resources/cert/localhost.key"
+               cer, err := tls.LoadX509KeyPair(certFile, keyFile)
+               s.AssertNil(err)
+               tlsConfig := &tls.Config{Certificates: []tls.Certificate{cer}}
+               server.HTTPTestServer.TLS = tlsConfig
+               port = "443"
+               l, err = tls.Listen("tcp", serverAddress+":443", tlsConfig)
+       } else {
+               port = "80"
+               l, err = net.Listen("tcp", serverAddress+":80")
+       }
        s.AssertNil(err, fmt.Sprint(err))
+
        server.HTTPTestServer.Listener = l
        server.AppendHandlers(
                ghttp.CombineHandlers(
@@ -397,7 +415,7 @@ func httpClientGet(s *NoTopoSuite, response string, size int) {
        server.Start()
        defer server.Close()
 
-       uri := "http://" + serverAddress
+       uri := proto + "://" + serverAddress + ":" + port
        cmd := "http client use-ptr verbose header Hello:World header Test-H2:Test-K2 save-to response.txt uri " + uri
 
        o := vpp.Vppctl(cmd)
index 4701253..1cf96cf 100644 (file)
@@ -82,6 +82,7 @@ typedef struct
   u64 appns_secret;
   clib_spinlock_t lock;
   bool was_transport_closed;
+  u32 ckpair_index;
 } hc_main_t;
 
 typedef enum
@@ -526,6 +527,7 @@ hc_attach ()
   vnet_app_attach_args_t _a, *a = &_a;
   u64 options[18];
   u32 segment_size = 128 << 20;
+  vnet_app_add_cert_key_pair_args_t _ck_pair, *ck_pair = &_ck_pair;
   int rv;
 
   if (hcm->private_segment_size)
@@ -546,6 +548,7 @@ hc_attach ()
     hcm->fifo_size ? hcm->fifo_size : 32 << 10;
   a->options[APP_OPTIONS_FLAGS] = APP_OPTIONS_FLAGS_IS_BUILTIN;
   a->options[APP_OPTIONS_PREALLOC_FIFO_PAIRS] = hcm->prealloc_fifos;
+  a->options[APP_OPTIONS_TLS_ENGINE] = CRYPTO_ENGINE_OPENSSL;
   if (hcm->appns_id)
     {
       a->namespace_id = hcm->appns_id;
@@ -560,6 +563,14 @@ hc_attach ()
   vec_free (a->name);
   hcm->attached = 1;
 
+  clib_memset (ck_pair, 0, sizeof (*ck_pair));
+  ck_pair->cert = (u8 *) test_srv_crt_rsa;
+  ck_pair->key = (u8 *) test_srv_key_rsa;
+  ck_pair->cert_len = test_srv_crt_rsa_len;
+  ck_pair->key_len = test_srv_key_rsa_len;
+  vnet_app_add_cert_key_pair (ck_pair);
+  hcm->ckpair_index = ck_pair->index;
+
   return 0;
 }
 
@@ -599,6 +610,14 @@ hc_connect ()
     &a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_HTTP, sizeof (http_cfg));
   clib_memcpy (ext_cfg->data, &http_cfg, sizeof (http_cfg));
 
+  if (hcm->connect_sep.flags & SESSION_ENDPT_CFG_F_SECURE)
+    {
+      ext_cfg = session_endpoint_add_ext_cfg (
+       &a->sep_ext, TRANSPORT_ENDPT_EXT_CFG_CRYPTO,
+       sizeof (transport_endpt_crypto_cfg_t));
+      ext_cfg->crypto.ckpair_index = hcm->ckpair_index;
+    }
+
   session_send_rpc_evt_to_thread_force (transport_cl_thread (), hc_connect_rpc,
                                        a);
 }
index e2f9a68..c9aaceb 100644 (file)
 /**
  * unformat a vnet URI
  *
- * transport-proto://[hostname]ip46-addr:port
- * eg.         tcp://ip46-addr:port
- *     tls://[testtsl.fd.io]ip46-addr:port
+ * transport-proto://[hostname]ip4-addr:port
+ * eg.         tcp://ip4-addr:port
+ *      https://[ip6]:port
+ *      http://ip4:port
+ *         tls://[testtsl.fd.io]ip4-addr:port
  *
  * u8 ip46_address[16];
  * u16  port_in_host_byte_order;
@@ -43,78 +45,70 @@ unformat_vnet_uri (unformat_input_t *input, va_list *args)
   session_endpoint_cfg_t *sep = va_arg (*args, session_endpoint_cfg_t *);
   u32 transport_proto = 0, port;
 
-  if (unformat (input, "%U://%U:%d", unformat_transport_proto,
-               &transport_proto, unformat_ip4_address, &sep->ip.ip4, &port))
+  if (unformat (input, "%U:", unformat_transport_proto, &transport_proto))
     {
       sep->transport_proto = transport_proto;
-      sep->port = clib_host_to_net_u16 (port);
-      sep->is_ip4 = 1;
-      return 1;
     }
-  else if (unformat (input, "%U://%U/%d", unformat_transport_proto,
-                    &transport_proto, unformat_ip4_address, &sep->ip.ip4,
-                    &port))
+  else if (unformat (input, "%Us:", unformat_transport_proto,
+                    &transport_proto))
     {
+      sep->flags |= SESSION_ENDPT_CFG_F_SECURE;
       sep->transport_proto = transport_proto;
-      sep->port = clib_host_to_net_u16 (port);
+    }
+
+  if (unformat (input, "//%U:", unformat_ip4_address, &sep->ip.ip4))
+    {
       sep->is_ip4 = 1;
-      return 1;
     }
-  else if (unformat (input, "%U://%U", unformat_transport_proto,
-                    &transport_proto, unformat_ip4_address, &sep->ip.ip4))
+  /* deprecated */
+  else if (unformat (input, "//%U/", unformat_ip4_address, &sep->ip.ip4))
     {
-      sep->transport_proto = transport_proto;
-      if (sep->transport_proto == TRANSPORT_PROTO_HTTP)
-       port = 80;
-      else if (sep->transport_proto == TRANSPORT_PROTO_TLS)
-       port = 443;
-      else
-       return 0;
-
-      sep->port = clib_host_to_net_u16 (port);
       sep->is_ip4 = 1;
-      return 1;
     }
-  else if (unformat (input, "%U://[%U]:%d", unformat_transport_proto,
-                    &transport_proto, unformat_ip6_address, &sep->ip.ip6,
-                    &port))
+  else if (unformat (input, "//%U", unformat_ip4_address, &sep->ip.ip4))
+    {
+      sep->is_ip4 = 1;
+    }
+  /* deprecated */
+  else if (unformat (input, "//%U/", unformat_ip6_address, &sep->ip.ip6))
     {
-      sep->transport_proto = transport_proto;
-      sep->port = clib_host_to_net_u16 (port);
       sep->is_ip4 = 0;
-      return 1;
     }
-  else if (unformat (input, "%U://[%U]", unformat_transport_proto,
-                    &transport_proto, unformat_ip6_address, &sep->ip.ip6))
+  else if (unformat (input, "//[%U]:", unformat_ip6_address, &sep->ip.ip6))
+    {
+      sep->is_ip4 = 0;
+    }
+  /* deprecated */
+  else if (unformat (input, "//[%U]/", unformat_ip6_address, &sep->ip.ip6))
     {
-      sep->transport_proto = transport_proto;
-      if (sep->transport_proto == TRANSPORT_PROTO_HTTP)
-       port = 80;
-      else if (sep->transport_proto == TRANSPORT_PROTO_TLS)
-       port = 443;
-      else
-       return 0;
-
-      sep->port = clib_host_to_net_u16 (port);
       sep->is_ip4 = 0;
+    }
+  else if (unformat (input, "//[%U]", unformat_ip6_address, &sep->ip.ip6))
+    {
+      sep->is_ip4 = 0;
+    }
+  else if (unformat (input, "//session/%lu", &sep->parent_handle))
+    {
+      sep->ip.ip4.as_u32 = 1; /* ip need to be non zero in vnet */
       return 1;
     }
-  else if (unformat (input, "%U://%U/%d", unformat_transport_proto,
-                    &transport_proto, unformat_ip6_address, &sep->ip.ip6,
-                    &port))
+
+  if (unformat (input, "%d", &port))
     {
-      sep->transport_proto = transport_proto;
       sep->port = clib_host_to_net_u16 (port);
-      sep->is_ip4 = 0;
       return 1;
     }
-  else if (unformat (input, "%U://session/%lu", unformat_transport_proto,
-                    &transport_proto, &sep->parent_handle))
+  else if (sep->transport_proto == TRANSPORT_PROTO_HTTP)
     {
-      sep->transport_proto = transport_proto;
-      sep->ip.ip4.as_u32 = 1;  /* ip need to be non zero in vnet */
+      sep->port = clib_host_to_net_u16 (80);
       return 1;
     }
+  else if (sep->transport_proto == TRANSPORT_PROTO_TLS)
+    {
+      sep->port = clib_host_to_net_u16 (443);
+      return 1;
+    }
+
   return 0;
 }
 
index 935f8f1..0c5afd4 100644 (file)
@@ -49,7 +49,9 @@ typedef struct _session_endpoint
 #undef _
 } session_endpoint_t;
 
-#define foreach_session_endpoint_cfg_flags _ (PROXY_LISTEN, "proxy listener")
+#define foreach_session_endpoint_cfg_flags                                    \
+  _ (PROXY_LISTEN, "proxy listener")                                          \
+  _ (SECURE, "secure")
 
 typedef enum session_endpoint_cfg_flags_bits_
 {