Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions doc/admin-guide/logging/formatting.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Authority to the |TS|
pptv Proxy Protocol The TLS version from Proxy Protocol context from the LB
Authority to the |TS|
===== ============== ==========================================================

.. note::
Expand Down
4 changes: 4 additions & 0 deletions include/iocore/net/ProxyProtocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ class ProxyProtocol
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;
Expand Down Expand Up @@ -134,6 +136,8 @@ class ProxyProtocol

private:
std::string additional_data;

std::optional<std::string_view> _get_tlv_ssl_subtype(int subtype) const;
};

const size_t PPv1_CONNECTION_HEADER_LEN_MAX = 108;
Expand Down
2 changes: 2 additions & 0 deletions include/proxy/logging/LogAccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,8 @@ class LogAccess
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
//
Expand Down
74 changes: 74 additions & 0 deletions src/iocore/net/ProxyProtocol.cc
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,80 @@ 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(int 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;
}

// 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 = p + len + 1;
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)
{
Expand Down
10 changes: 8 additions & 2 deletions src/iocore/net/unit_tests/test_ProxyProtocol.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -327,6 +330,9 @@ 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 extra data")
Expand Down
10 changes: 10 additions & 0 deletions src/proxy/logging/Log.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
34 changes: 34 additions & 0 deletions src/proxy/logging/LogAccess.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1660,6 +1660,40 @@ LogAccess::marshal_proxy_protocol_authority(char *buf)
return 0;
}

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_str(buf, cipher->data(), len);
buf[cipher->size()] = '\0';
}
}
}
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_str(buf, version->data(), len);
buf[version->size()] = '\0';
}
}
}
return len;
}

/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/
int
Expand Down