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")