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 6669251085 Add support for more PP fields (#12864)
6669251085 is described below
commit 66692510853a4f9a324af7e67cc33f21578c138f
Author: Masakazu Kitajo <[email protected]>
AuthorDate: Tue Feb 10 16:33:18 2026 -0700
Add support for more PP fields (#12864)
* Add support for PP2_SUBTYPE_SSL_CIPHER
* Add pptc log field for PP2_SUBTYPE_SSL_CIPHER
* Add support for PP2_SUBTYPE_SSL_VERSION
* Add pptv log field for PP2_SUBTYPE_SSL_VERSION
* Fix copy pasta in documentation
* Change parameter type
* Fix off by one error
* Add a length check
* Print the default value if data sources are unavailable
* Add a test case
---
doc/admin-guide/logging/formatting.en.rst | 4 ++
include/iocore/net/ProxyProtocol.h | 4 ++
include/proxy/logging/LogAccess.h | 2 +
src/iocore/net/ProxyProtocol.cc | 78 +++++++++++++++++++++++++
src/iocore/net/unit_tests/test_ProxyProtocol.cc | 42 ++++++++++++-
src/proxy/logging/Log.cc | 10 ++++
src/proxy/logging/LogAccess.cc | 42 +++++++++++++
7 files changed, 180 insertions(+), 2 deletions(-)
diff --git a/doc/admin-guide/logging/formatting.en.rst
b/doc/admin-guide/logging/formatting.en.rst
index bac1fbeeb6..b85e6407ad 100644
--- a/doc/admin-guide/logging/formatting.en.rst
+++ b/doc/admin-guide/logging/formatting.en.rst
@@ -532,6 +532,10 @@ ppd Proxy Protocol Destination IP received via Proxy
Protocol context from the
Dest IP to the |TS|
ppa Proxy Protocol The Authority TLV from Proxy Protocol context from the LB
Authority to the |TS|
+pptc Proxy Protocol The TLS cipher from Proxy Protocol context from the LB
+ TLS Cipher to the |TS|
+pptv Proxy Protocol The TLS version from Proxy Protocol context from the LB
+ TLS version to the |TS|
===== ============== ==========================================================
.. note::
diff --git a/include/iocore/net/ProxyProtocol.h
b/include/iocore/net/ProxyProtocol.h
index 2cc4848dfb..5c73019144 100644
--- a/include/iocore/net/ProxyProtocol.h
+++ b/include/iocore/net/ProxyProtocol.h
@@ -86,6 +86,8 @@ public:
void set_ipv6_addrs(const in6_addr &src_addr, uint16_t src_port, const
in6_addr &dst_addr, uint16_t dst_port);
std::optional<std::string_view> get_tlv(const uint8_t tlvCode) const;
+ std::optional<std::string_view> get_tlv_ssl_version() const;
+ std::optional<std::string_view> get_tlv_ssl_cipher() const;
ProxyProtocolVersion version =
ProxyProtocolVersion::UNDEFINED;
uint16_t ip_family = AF_UNSPEC;
@@ -134,6 +136,8 @@ public:
private:
std::string additional_data;
+
+ std::optional<std::string_view> _get_tlv_ssl_subtype(uint8_t subtype) const;
};
const size_t PPv1_CONNECTION_HEADER_LEN_MAX = 108;
diff --git a/include/proxy/logging/LogAccess.h
b/include/proxy/logging/LogAccess.h
index 0cdd6e1098..7cdf8ed48b 100644
--- a/include/proxy/logging/LogAccess.h
+++ b/include/proxy/logging/LogAccess.h
@@ -270,6 +270,8 @@ public:
int marshal_proxy_protocol_src_ip(char *); // STR
int marshal_proxy_protocol_dst_ip(char *); // STR
int marshal_proxy_protocol_authority(char *); // STR
+ int marshal_proxy_protocol_tls_cipher(char *); // STR
+ int marshal_proxy_protocol_tls_version(char *); // STR
// named fields from within a http header
//
diff --git a/src/iocore/net/ProxyProtocol.cc b/src/iocore/net/ProxyProtocol.cc
index 0422e70771..96939412c8 100644
--- a/src/iocore/net/ProxyProtocol.cc
+++ b/src/iocore/net/ProxyProtocol.cc
@@ -547,6 +547,84 @@ ProxyProtocol::get_tlv(const uint8_t tlvCode) const
return std::nullopt;
}
+/*
+ * PP2_TYPE_SSL
+ * struct pp2_tlv_ssl {
+ * uint8_t client;
+ * uint32_t verify;
+ * struct pp2_tlv sub_tlv[0];
+ * };
+ */
+
+std::optional<std::string_view>
+ProxyProtocol::_get_tlv_ssl_subtype(uint8_t subtype) const
+{
+ if (auto v = tlv.find(PP2_TYPE_SSL); v != tlv.end() && v->second.length() !=
0) {
+ auto ssl = v->second;
+
+ // Is the client connected over TLS
+ if ((ssl.data()[0] & 0x01) == 0) {
+ // Not over TLS
+ return std::nullopt;
+ }
+
+ if (ssl.length() < 5) {
+ return std::nullopt;
+ }
+
+ // Find the given subtype
+ uint16_t len = ssl.length();
+ const char *p = ssl.data() + 5; // Skip client (uint8_t) + verify
(uint32_t)
+ const char *end = ssl.data() + len;
+ while (p != end) {
+ if (end - p < 3) {
+ // The size of a sub TLV entry must be 3 bytes or more
+ Dbg(dbg_ctl_proxyprotocol_v2, "Remaining data (%ld bytes) is not
enough for a sub TLV field", end - p);
+ return std::nullopt;
+ }
+
+ // 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
+ Dbg(dbg_ctl_proxyprotocol_v2, "Remaining data (%ld bytes) is not
enough for a TLV field (ID:%u LEN:%hu)", end - p, type,
+ length);
+ return std::nullopt;
+ }
+
+ // Found it?
+ if (type == subtype) {
+ Dbg(dbg_ctl_proxyprotocol, "TLV: ID=%u LEN=%hu", type, length);
+ return std::string_view(p, length);
+ }
+
+ p += length;
+ }
+ }
+ return std::nullopt;
+}
+
+std::optional<std::string_view>
+ProxyProtocol::get_tlv_ssl_version() const
+{
+ // The specification only says "the US-ASCII string representation of the
TLS version".
+ // HAProxy sends a string returned by SSL_get_version.
+ return this->_get_tlv_ssl_subtype(PP2_SUBTYPE_SSL_VERSION);
+}
+
+std::optional<std::string_view>
+ProxyProtocol::get_tlv_ssl_cipher() const
+{
+ return this->_get_tlv_ssl_subtype(PP2_SUBTYPE_SSL_CIPHER);
+}
+
int
ProxyProtocol::set_additional_data(std::string_view data)
{
diff --git a/src/iocore/net/unit_tests/test_ProxyProtocol.cc
b/src/iocore/net/unit_tests/test_ProxyProtocol.cc
index 70ead688be..53958b30b2 100644
--- a/src/iocore/net/unit_tests/test_ProxyProtocol.cc
+++ b/src/iocore/net/unit_tests/test_ProxyProtocol.cc
@@ -303,13 +303,16 @@ TEST_CASE("PROXY Protocol v2 Parser",
"[ProxyProtocol][ProxyProtocolv2]")
0x55, 0x49, 0x54, 0x0A, ///<
0x21, ///< version & command
0x11, ///< protocol & family
- 0x00, 0x17, ///< len
+ 0x00, 0x2B, ///< 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)
+ 0x02, 0x00, 0x03, 0x61, 0x62, 0x63, /// PP2_TYPE_AUTHORITY
(abc)
+ 0x20, 0x00, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, /// PP2_TYPE_SSL
(client=0x01, verify=0)
+ 0x23, 0x00, 0x03, 0x58, 0x59, 0x5A, ///
PP2_SUBTYPE_SSL_CIPHER (XYZ)
+ 0x21, 0x00, 0x03, 0x54, 0x4C, 0x53, ///
PP2_SUBTYPE_SSL_VERSION (TLS)
};
swoc::TextView tv(reinterpret_cast<char *>(raw_data), sizeof(raw_data));
@@ -327,6 +330,41 @@ TEST_CASE("PROXY Protocol v2 Parser",
"[ProxyProtocol][ProxyProtocolv2]")
CHECK(pp_info.tlv[PP2_TYPE_ALPN] == "h2");
CHECK(pp_info.tlv[PP2_TYPE_AUTHORITY] == "abc");
+
+ CHECK(pp_info.get_tlv_ssl_cipher() == "XYZ");
+ CHECK(pp_info.get_tlv_ssl_version() == "TLS");
+ }
+
+ SECTION("TLVs with PP2_TYPE_SSL but SSL is unused")
+ {
+ uint8_t raw_data[] = {
+ 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, ///< preface
+ 0x55, 0x49, 0x54, 0x0A, ///<
+ 0x21, ///< version & command
+ 0x11, ///< protocol & family
+ 0x00, 0x14, ///< len
+ 0xC0, 0x00, 0x02, 0x01, ///< src_addr
+ 0xC6, 0x33, 0x64, 0x01, ///< dst_addr
+ 0xC3, 0x50, ///< src_port
+ 0x01, 0xBB, ///< dst_port
+ 0x20, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, /// PP2_TYPE_SSL
(client=0x00, verify=0)
+ };
+
+ swoc::TextView tv(reinterpret_cast<char *>(raw_data), sizeof(raw_data));
+
+ ProxyProtocol pp_info;
+ REQUIRE(proxy_protocol_parse(&pp_info, tv) == tv.size());
+
+ REQUIRE(ats_ip_pton("192.0.2.1:50000", src_addr) == 0);
+ REQUIRE(ats_ip_pton("198.51.100.1:443", dst_addr) == 0);
+
+ CHECK(pp_info.version == ProxyProtocolVersion::V2);
+ CHECK(pp_info.ip_family == AF_INET);
+ CHECK(pp_info.src_addr == src_addr);
+ CHECK(pp_info.dst_addr == dst_addr);
+
+ CHECK(pp_info.get_tlv_ssl_cipher().has_value() == false);
+ CHECK(pp_info.get_tlv_ssl_version().has_value() == false);
}
SECTION("TLVs with extra data")
diff --git a/src/proxy/logging/Log.cc b/src/proxy/logging/Log.cc
index 35d2c87187..50e975e284 100644
--- a/src/proxy/logging/Log.cc
+++ b/src/proxy/logging/Log.cc
@@ -1034,6 +1034,16 @@ Log::init_fields()
global_field_list.add(field, false);
field_symbol_hash.emplace("ppa", field);
+ field = new LogField("proxy_protocol_tls_cipher", "pptc", LogField::STRING,
&LogAccess::marshal_proxy_protocol_tls_cipher,
+ &LogAccess::unmarshal_str);
+ global_field_list.add(field, false);
+ field_symbol_hash.emplace("pptc", field);
+
+ field = new LogField("proxy_protocol_tls_version", "pptv", LogField::STRING,
&LogAccess::marshal_proxy_protocol_tls_version,
+ &LogAccess::unmarshal_str);
+ global_field_list.add(field, false);
+ field_symbol_hash.emplace("pptv", field);
+
field = new LogField("version_build_number", "vbn", LogField::STRING,
&LogAccess::marshal_version_build_number,
&LogAccess::unmarshal_str);
global_field_list.add(field, false);
diff --git a/src/proxy/logging/LogAccess.cc b/src/proxy/logging/LogAccess.cc
index 9c0ce48bd4..908ec8c22f 100644
--- a/src/proxy/logging/LogAccess.cc
+++ b/src/proxy/logging/LogAccess.cc
@@ -1664,6 +1664,48 @@ LogAccess::marshal_proxy_protocol_authority(char *buf)
return len;
}
+int
+LogAccess::marshal_proxy_protocol_tls_cipher(char *buf)
+{
+ int len = INK_MIN_ALIGN;
+
+ if (m_http_sm) {
+ if (auto cipher = m_http_sm->t_state.pp_info.get_tlv_ssl_cipher(); cipher)
{
+ len = padded_length(cipher->size() + 1);
+ if (buf) {
+ marshal_mem(buf, cipher->data(), cipher->size(), len);
+ }
+ } else {
+ if (buf) {
+ // This prints the default value ("-")
+ marshal_mem(buf, nullptr, 0, len);
+ }
+ }
+ }
+ return len;
+}
+
+int
+LogAccess::marshal_proxy_protocol_tls_version(char *buf)
+{
+ int len = INK_MIN_ALIGN;
+
+ if (m_http_sm) {
+ if (auto version = m_http_sm->t_state.pp_info.get_tlv_ssl_version();
version) {
+ len = padded_length(version->size() + 1);
+ if (buf) {
+ marshal_mem(buf, version->data(), version->size(), len);
+ }
+ } else {
+ if (buf) {
+ // This prints the default value ("-")
+ marshal_mem(buf, nullptr, 0, len);
+ }
+ }
+ }
+ return len;
+}
+
/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
int