This is an automated email from the ASF dual-hosted git repository.

maskit pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 9a11e65436 Add support for parsing Proxy protocol v2 TLV fields 
(#11999)
9a11e65436 is described below

commit 9a11e654369d0ce818bd27cc7cc365c5f2c97f0c
Author: Masakazu Kitajo <[email protected]>
AuthorDate: Wed Jan 29 18:52:06 2025 -0700

    Add support for parsing Proxy protocol v2 TLV fields (#11999)
---
 include/iocore/net/ProxyProtocol.h              | 39 ++++++++++++++++---
 src/iocore/net/ProxyProtocol.cc                 | 50 +++++++++++++++++++++++--
 src/iocore/net/unit_tests/test_ProxyProtocol.cc |  7 +++-
 3 files changed, 86 insertions(+), 10 deletions(-)

diff --git a/include/iocore/net/ProxyProtocol.h 
b/include/iocore/net/ProxyProtocol.h
index ea7e01713e..f7cbb1aa28 100644
--- a/include/iocore/net/ProxyProtocol.h
+++ b/include/iocore/net/ProxyProtocol.h
@@ -27,6 +27,8 @@
 
 #include <tscore/ink_inet.h>
 #include <swoc/TextView.h>
+#include <unordered_map>
+#include <cstdlib>
 
 enum class ProxyProtocolVersion {
   UNDEFINED,
@@ -40,11 +42,38 @@ enum class ProxyProtocolData {
   DST,
 };
 
-struct ProxyProtocol {
-  ProxyProtocolVersion version   = ProxyProtocolVersion::UNDEFINED;
-  uint16_t             ip_family = AF_UNSPEC;
-  IpEndpoint           src_addr  = {};
-  IpEndpoint           dst_addr  = {};
+constexpr uint8_t PP2_TYPE_ALPN           = 0x01;
+constexpr uint8_t PP2_TYPE_AUTHORITY      = 0x02;
+constexpr uint8_t PP2_TYPE_CRC32C         = 0x03;
+constexpr uint8_t PP2_TYPE_NOOP           = 0x04;
+constexpr uint8_t PP2_TYPE_UNIQUE_ID      = 0x05;
+constexpr uint8_t PP2_TYPE_SSL            = 0x20;
+constexpr uint8_t PP2_SUBTYPE_SSL_VERSION = 0x21;
+constexpr uint8_t PP2_SUBTYPE_SSL_CN      = 0x22;
+constexpr uint8_t PP2_SUBTYPE_SSL_CIPHER  = 0x23;
+constexpr uint8_t PP2_SUBTYPE_SSL_SIG_ALG = 0x24;
+constexpr uint8_t PP2_SUBTYPE_SSL_KEY_ALG = 0x25;
+constexpr uint8_t PP2_TYPE_NETNS          = 0x30;
+
+class ProxyProtocol
+{
+public:
+  ProxyProtocol() {}
+  ProxyProtocol(ProxyProtocolVersion pp_ver, uint16_t family, IpEndpoint src, 
IpEndpoint dst)
+    : version(pp_ver), ip_family(family), src_addr(src), dst_addr(dst)
+  {
+  }
+  ~ProxyProtocol() { ats_free(additional_data); }
+  int set_additional_data(std::string_view data);
+
+  ProxyProtocolVersion                          version   = 
ProxyProtocolVersion::UNDEFINED;
+  uint16_t                                      ip_family = AF_UNSPEC;
+  IpEndpoint                                    src_addr  = {};
+  IpEndpoint                                    dst_addr  = {};
+  std::unordered_map<uint8_t, std::string_view> tlv;
+
+private:
+  char *additional_data = nullptr;
 };
 
 const size_t PPv1_CONNECTION_HEADER_LEN_MAX = 108;
diff --git a/src/iocore/net/ProxyProtocol.cc b/src/iocore/net/ProxyProtocol.cc
index 78ac63ecff..c2c6444307 100644
--- a/src/iocore/net/ProxyProtocol.cc
+++ b/src/iocore/net/ProxyProtocol.cc
@@ -216,8 +216,6 @@ proxy_protocol_v1_parse(ProxyProtocol *pp_info, 
swoc::TextView hdr)
 /**
    PROXY Protocol v2 Parser
 
-   TODO: TLVs Support
-
    @return read length
  */
 size_t
@@ -232,6 +230,7 @@ proxy_protocol_v2_parse(ProxyProtocol *pp_info, const 
swoc::TextView &msg)
   // length check
   const uint16_t len       = ntohs(hdr_v2->len);
   const size_t   total_len = PPv2_CONNECTION_HEADER_LEN + len;
+  uint16_t       tlv_len   = 0;
 
   if (msg.size() < total_len) {
     return 0;
@@ -256,6 +255,7 @@ proxy_protocol_v2_parse(ProxyProtocol *pp_info, const 
swoc::TextView &msg)
       if (len < PPv2_ADDR_LEN_INET) {
         return 0;
       }
+      tlv_len = len - PPv2_ADDR_LEN_INET;
 
       IpAddr src_addr(reinterpret_cast<in_addr_t>(hdr_v2->addr.ip4.src_addr));
       pp_info->src_addr.assign(src_addr, hdr_v2->addr.ip4.src_port);
@@ -272,6 +272,7 @@ proxy_protocol_v2_parse(ProxyProtocol *pp_info, const 
swoc::TextView &msg)
       if (len < PPv2_ADDR_LEN_INET6) {
         return 0;
       }
+      tlv_len = len - PPv2_ADDR_LEN_INET6;
 
       IpAddr src_addr(reinterpret_cast<in6_addr const 
&>(hdr_v2->addr.ip6.src_addr));
       pp_info->src_addr.assign(src_addr, hdr_v2->addr.ip6.src_port);
@@ -299,7 +300,11 @@ proxy_protocol_v2_parse(ProxyProtocol *pp_info, const 
swoc::TextView &msg)
       return 0;
     }
 
-    // TODO: Parse TLVs
+    if (tlv_len > 0) {
+      if (pp_info->set_additional_data(msg.substr(msg.length() - tlv_len)) < 
0) {
+        return 0;
+      }
+    }
 
     return total_len;
   }
@@ -507,3 +512,42 @@ proxy_protocol_version_cast(int i)
     return ProxyProtocolVersion::UNDEFINED;
   }
 }
+
+int
+ProxyProtocol::set_additional_data(std::string_view data)
+{
+  uint16_t len    = data.length();
+  additional_data = static_cast<char *>(ats_malloc(len));
+  if (additional_data == nullptr) {
+    return -1;
+  }
+  data.copy(additional_data, len);
+
+  const char *p   = additional_data;
+  const char *end = p + len;
+  while (p != end) {
+    if (end - p < 3) {
+      // The size of a TLV entry must be 3 bytes or more
+      return -2;
+    }
+
+    // Type
+    uint8_t type  = *p;
+    p            += 1;
+
+    // Length
+    uint16_t length  = ntohs(*reinterpret_cast<const uint16_t *>(p));
+    p               += 2;
+
+    // Value
+    if (end - p < length) {
+      // Does not have enough data
+      return -3;
+    }
+    Dbg(dbg_ctl_proxyprotocol, "TLV: ID=%u LEN=%hu", type, length);
+    tlv.emplace(type, std::string_view(p, length));
+    p += length;
+  }
+
+  return 0;
+}
diff --git a/src/iocore/net/unit_tests/test_ProxyProtocol.cc 
b/src/iocore/net/unit_tests/test_ProxyProtocol.cc
index 27e39741ff..4f9c3a316d 100644
--- a/src/iocore/net/unit_tests/test_ProxyProtocol.cc
+++ b/src/iocore/net/unit_tests/test_ProxyProtocol.cc
@@ -234,7 +234,6 @@ TEST_CASE("PROXY Protocol v2 Parser", 
"[ProxyProtocol][ProxyProtocolv2]")
     CHECK(pp_info.ip_family == AF_UNSPEC);
   }
 
-  // TLVs are not supported yet. Checking TLVs are skipped as expected for now.
   SECTION("TLVs")
   {
     uint8_t raw_data[] = {
@@ -242,12 +241,13 @@ TEST_CASE("PROXY Protocol v2 Parser", 
"[ProxyProtocol][ProxyProtocolv2]")
       0x55, 0x49, 0x54, 0x0A,                         ///<
       0x21,                                           ///< version & command
       0x11,                                           ///< protocol & family
-      0x00, 0x11,                                     ///< len
+      0x00, 0x17,                                     ///< len
       0xC0, 0x00, 0x02, 0x01,                         ///< src_addr
       0xC6, 0x33, 0x64, 0x01,                         ///< dst_addr
       0xC3, 0x50,                                     ///< src_port
       0x01, 0xBB,                                     ///< dst_port
       0x01, 0x00, 0x02, 0x68, 0x32,                   /// PP2_TYPE_ALPN (h2)
+      0x02, 0x00, 0x03, 0x61, 0x62, 0x63              /// PP2_TYPE_AUTHORITY 
(abc)
     };
 
     swoc::TextView tv(reinterpret_cast<char *>(raw_data), sizeof(raw_data));
@@ -262,6 +262,9 @@ TEST_CASE("PROXY Protocol v2 Parser", 
"[ProxyProtocol][ProxyProtocolv2]")
     CHECK(pp_info.ip_family == AF_INET);
     CHECK(pp_info.src_addr == src_addr);
     CHECK(pp_info.dst_addr == dst_addr);
+
+    CHECK(pp_info.tlv[PP2_TYPE_ALPN] == "h2");
+    CHECK(pp_info.tlv[PP2_TYPE_AUTHORITY] == "abc");
   }
 
   SECTION("Malformed Headers")

Reply via email to