You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by ma...@apache.org on 2021/01/25 23:05:00 UTC
[trafficserver] branch master updated: Add incoming PROXY Protocol
v2 support (#7340)
This is an automated email from the ASF dual-hosted git repository.
masaori 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 f7bdee6 Add incoming PROXY Protocol v2 support (#7340)
f7bdee6 is described below
commit f7bdee616ebec26b2746ce50c75eaacab7571554
Author: Masaori Koshiba <ma...@apache.org>
AuthorDate: Tue Jan 26 08:04:44 2021 +0900
Add incoming PROXY Protocol v2 support (#7340)
TCP support only for now. UDP, UNIX Domain Socket, and TLVs are out of scope.
---
.../configuration/proxy-protocol.en.rst | 6 +-
iocore/net/ProxyProtocol.cc | 137 +++++++++-
iocore/net/ProxyProtocol.h | 2 +-
iocore/net/unit_tests/test_ProxyProtocol.cc | 292 ++++++++++++++++++++-
4 files changed, 424 insertions(+), 13 deletions(-)
diff --git a/doc/admin-guide/configuration/proxy-protocol.en.rst b/doc/admin-guide/configuration/proxy-protocol.en.rst
index 8df27d1..adf61f6 100644
--- a/doc/admin-guide/configuration/proxy-protocol.en.rst
+++ b/doc/admin-guide/configuration/proxy-protocol.en.rst
@@ -31,7 +31,7 @@ TLS connections.
.. note::
- The current version only supports transforming client IP from PROXY Version 1
+ The current version only supports transforming client IP from PROXY Version 1/2
header to the Forwarded: header.
In the current implementation, the client IP address in the PROXY protocol header
@@ -41,7 +41,7 @@ is passed to the origin server via an HTTP `Forwarded:
The Proxy Protocol must be enabled on each port. See
:ts:cv:`proxy.config.http.server_ports` for information on how to enable the
Proxy Protocol on a port. Once enabled, all incoming requests must be prefaced
-with the PROXY v1 header. Any request not preface by this header will be
+with the PROXY v1/v2 header. Any request not preface by this header will be
dropped.
As a security measure, an optional list of trusted IP addresses may be
@@ -50,7 +50,7 @@ configured with :ts:cv:`proxy.config.http.proxy_protocol_allowlist`.
.. important::
If the allowlist is configured, requests will only be accepted from these
- IP addresses and must be prefaced with the PROXY v1 header.
+ IP addresses and must be prefaced with the PROXY v1/v2 header.
See :ts:cv:`proxy.config.http.insert_forwarded` for configuration information.
Detection of the PROXY protocol header is automatic. If the PROXY header
diff --git a/iocore/net/ProxyProtocol.cc b/iocore/net/ProxyProtocol.cc
index 2de8673..452f63b 100644
--- a/iocore/net/ProxyProtocol.cc
+++ b/iocore/net/ProxyProtocol.cc
@@ -34,15 +34,57 @@ namespace
using namespace std::literals;
constexpr ts::TextView PPv1_CONNECTION_PREFACE = "PROXY"sv;
-constexpr ts::TextView PPv2_CONNECTION_PREFACE = "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A\x02"sv;
+constexpr ts::TextView PPv2_CONNECTION_PREFACE = "\x0D\x0A\x0D\x0A\x00\x0D\x0A\x51\x55\x49\x54\x0A"sv;
constexpr size_t PPv1_CONNECTION_HEADER_LEN_MIN = 15;
-constexpr size_t PPv2_CONNECTION_HEADER_LEN_MIN = 16;
constexpr ts::TextView PPv1_PROTO_UNKNOWN = "UNKNOWN"sv;
constexpr ts::TextView PPv1_PROTO_TCP4 = "TCP4"sv;
constexpr ts::TextView PPv1_PROTO_TCP6 = "TCP6"sv;
+constexpr uint8_t PPv2_CMD_LOCAL = 0x20;
+constexpr uint8_t PPv2_CMD_PROXY = 0x21;
+
+constexpr uint8_t PPv2_PROTO_UNSPEC = 0x00;
+constexpr uint8_t PPv2_PROTO_TCP4 = 0x11;
+constexpr uint8_t PPv2_PROTO_UDP4 = 0x12;
+constexpr uint8_t PPv2_PROTO_TCP6 = 0x21;
+constexpr uint8_t PPv2_PROTO_UDP6 = 0x22;
+constexpr uint8_t PPv2_PROTO_UNIX_STREAM = 0x31;
+constexpr uint8_t PPv2_PROTO_UNIX_DATAGRAM = 0x32;
+
+constexpr uint16_t PPv2_ADDR_LEN_INET = 4 + 4 + 2 + 2;
+constexpr uint16_t PPv2_ADDR_LEN_INET6 = 16 + 16 + 2 + 2;
+// constexpr uint16_t PPv2_ADDR_LEN_UNIX = 108 + 108;
+
+struct PPv2Hdr {
+ uint8_t sig[12]; ///< preface
+ uint8_t ver_cmd; ///< protocol version and command
+ uint8_t fam; ///< protocol family and transport
+ uint16_t len; ///< number of following bytes part of the header
+ union {
+ // for TCP/UDP over IPv4, len = 12 (PPv2_ADDR_LEN_INET)
+ struct {
+ uint32_t src_addr;
+ uint32_t dst_addr;
+ uint16_t src_port;
+ uint16_t dst_port;
+ } ip4;
+ // for TCP/UDP over IPv6, len = 36 (PPv2_ADDR_LEN_INET6)
+ struct {
+ uint8_t src_addr[16];
+ uint8_t dst_addr[16];
+ uint16_t src_port;
+ uint16_t dst_port;
+ } ip6;
+ // for AF_UNIX sockets, len = 216 (PPv2_ADDR_LEN_UNIX)
+ struct {
+ uint8_t src_addr[108];
+ uint8_t dst_addr[108];
+ } unix;
+ } addr;
+};
+
/**
PROXY Protocol v1 Parser
@@ -166,13 +208,100 @@ proxy_protocol_v1_parse(ProxyProtocol *pp_info, ts::TextView hdr)
/**
PROXY Protocol v2 Parser
+ TODO: TLVs Support
+
@return read length
*/
size_t
-proxy_protocol_v2_parse(ProxyProtocol * /*pp_info*/, ts::TextView /*hdr*/)
+proxy_protocol_v2_parse(ProxyProtocol *pp_info, const ts::TextView &msg)
{
+ ink_release_assert(msg.size() >= PPv2_CONNECTION_HEADER_LEN);
+
+ const PPv2Hdr *hdr_v2 = reinterpret_cast<const PPv2Hdr *>(msg.data());
+
+ // Assuming PREFACE check is done
+
+ // length check
+ const uint16_t len = ntohs(hdr_v2->len);
+ const size_t total_len = PPv2_CONNECTION_HEADER_LEN + len;
+
+ if (msg.size() < total_len) {
+ return 0;
+ }
+
+ // protocol version and command
+ switch (hdr_v2->ver_cmd) {
+ case PPv2_CMD_LOCAL: {
+ // protocol byte should be UNSPEC (\x00) with LOCAL command
+ if (hdr_v2->fam != PPv2_PROTO_UNSPEC) {
+ return 0;
+ }
+
+ pp_info->version = ProxyProtocolVersion::V2;
+ pp_info->ip_family = AF_UNSPEC;
+
+ return total_len;
+ }
+ case PPv2_CMD_PROXY: {
+ switch (hdr_v2->fam) {
+ case PPv2_PROTO_TCP4: {
+ if (len < PPv2_ADDR_LEN_INET) {
+ return 0;
+ }
+
+ 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);
+
+ IpAddr dst_addr(reinterpret_cast<in_addr_t>(hdr_v2->addr.ip4.dst_addr));
+ pp_info->dst_addr.assign(dst_addr, hdr_v2->addr.ip4.dst_port);
+
+ pp_info->version = ProxyProtocolVersion::V2;
+ pp_info->ip_family = AF_INET;
+
+ break;
+ }
+ case PPv2_PROTO_TCP6: {
+ if (len < PPv2_ADDR_LEN_INET6) {
+ return 0;
+ }
+
+ 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);
+
+ IpAddr dst_addr(reinterpret_cast<in6_addr const &>(hdr_v2->addr.ip6.dst_addr));
+ pp_info->dst_addr.assign(dst_addr, hdr_v2->addr.ip6.dst_port);
+
+ pp_info->version = ProxyProtocolVersion::V2;
+ pp_info->ip_family = AF_INET6;
+
+ break;
+ }
+ case PPv2_PROTO_UDP4:
+ [[fallthrough]];
+ case PPv2_PROTO_UDP6:
+ [[fallthrough]];
+ case PPv2_PROTO_UNIX_STREAM:
+ [[fallthrough]];
+ case PPv2_PROTO_UNIX_DATAGRAM:
+ [[fallthrough]];
+ case PPv2_PROTO_UNSPEC:
+ [[fallthrough]];
+ default:
+ // unsupported
+ return 0;
+ }
+
+ // TODO: Parse TLVs
+
+ return total_len;
+ }
+ default:
+ break;
+ }
+
return 0;
}
+
} // namespace
/**
@@ -187,7 +316,7 @@ proxy_protocol_parse(ProxyProtocol *pp_info, ts::TextView tv)
if (tv.size() >= PPv1_CONNECTION_HEADER_LEN_MIN && PPv1_CONNECTION_PREFACE.isPrefixOf(tv)) {
// Client must send at least 15 bytes to get a reasonable match.
len = proxy_protocol_v1_parse(pp_info, tv);
- } else if (tv.size() >= PPv2_CONNECTION_HEADER_LEN_MIN && PPv2_CONNECTION_PREFACE.isPrefixOf(tv)) {
+ } else if (tv.size() >= PPv2_CONNECTION_HEADER_LEN && PPv2_CONNECTION_PREFACE.isPrefixOf(tv)) {
len = proxy_protocol_v2_parse(pp_info, tv);
} else {
// if we don't have the PROXY preface, we don't have a ProxyProtocol header
diff --git a/iocore/net/ProxyProtocol.h b/iocore/net/ProxyProtocol.h
index 84491bc..dedb31d 100644
--- a/iocore/net/ProxyProtocol.h
+++ b/iocore/net/ProxyProtocol.h
@@ -48,6 +48,6 @@ struct ProxyProtocol {
};
const size_t PPv1_CONNECTION_HEADER_LEN_MAX = 108;
-const size_t PPv2_CONNECTION_HEADER_LEN_MAX = 16;
+const size_t PPv2_CONNECTION_HEADER_LEN = 16;
extern size_t proxy_protocol_parse(ProxyProtocol *pp_info, ts::TextView tv);
diff --git a/iocore/net/unit_tests/test_ProxyProtocol.cc b/iocore/net/unit_tests/test_ProxyProtocol.cc
index da2b754..e4fbb03 100644
--- a/iocore/net/unit_tests/test_ProxyProtocol.cc
+++ b/iocore/net/unit_tests/test_ProxyProtocol.cc
@@ -124,13 +124,16 @@ TEST_CASE("PROXY Protocol v1 Parser", "[ProxyProtocol][ProxyProtocolv1]")
TEST_CASE("PROXY Protocol v2 Parser", "[ProxyProtocol][ProxyProtocolv2]")
{
- SECTION("TCP over IPv4")
+ IpEndpoint src_addr;
+ IpEndpoint dst_addr;
+
+ SECTION("TCP over IPv4 without TLVs")
{
uint8_t raw_data[] = {
- 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, ///< sig
+ 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, ///< preface
0x55, 0x49, 0x54, 0x0A, ///<
- 0x02, ///< ver_vmd
- 0x11, ///< fam
+ 0x21, ///< version & command
+ 0x11, ///< protocol & family
0x00, 0x0C, ///< len
0xC0, 0x00, 0x02, 0x01, ///< src_addr
0xC6, 0x33, 0x64, 0x01, ///< dst_addr
@@ -141,7 +144,286 @@ TEST_CASE("PROXY Protocol v2 Parser", "[ProxyProtocol][ProxyProtocolv2]")
ts::TextView tv(reinterpret_cast<char *>(raw_data), sizeof(raw_data));
ProxyProtocol pp_info;
- // TODO: add test when implemented. Just checking this doesn't crash for now
+ 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);
+ }
+
+ SECTION("TCP over IPv6 without TLVs")
+ {
+ uint8_t raw_data[] = {
+ 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, ///< preface
+ 0x55, 0x49, 0x54, 0x0A, ///<
+ 0x21, ///< version & command
+ 0x21, ///< protocol & family
+ 0x00, 0x24, ///< len
+ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x01, ///< src_addr
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ///<
+ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x02, ///< dst_addr
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ///<
+ 0xC3, 0x50, ///< src_port
+ 0x01, 0xBB, ///< dst_port
+ };
+
+ ts::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("[2001:db8:0:1::]:50000", src_addr) == 0);
+ REQUIRE(ats_ip_pton("[2001:db8:0:2::]:443", dst_addr) == 0);
+
+ CHECK(pp_info.version == ProxyProtocolVersion::V2);
+ CHECK(pp_info.ip_family == AF_INET6);
+ CHECK(pp_info.src_addr == src_addr);
+ CHECK(pp_info.dst_addr == dst_addr);
+ }
+
+ SECTION("LOCAL command - health check")
+ {
+ uint8_t raw_data[] = {
+ 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, ///< preface
+ 0x55, 0x49, 0x54, 0x0A, ///<
+ 0x20, ///< version & command
+ 0x00, ///< protocol & family
+ 0x00, 0x24, ///< len
+ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x01, ///< src_addr
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ///<
+ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x02, ///< dst_addr
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ///<
+ 0xC3, 0x50, ///< src_port
+ 0x01, 0xBB, ///< dst_port
+ };
+
+ ts::TextView tv(reinterpret_cast<char *>(raw_data), sizeof(raw_data));
+
+ ProxyProtocol pp_info;
+ REQUIRE(proxy_protocol_parse(&pp_info, tv) == tv.size());
+
+ CHECK(pp_info.version == ProxyProtocolVersion::V2);
+ CHECK(pp_info.ip_family == AF_UNSPEC);
+ }
+
+ SECTION("UNSPEC - unknownun/specified/unsupported transport protocol & address family")
+ {
+ uint8_t raw_data[] = {
+ 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, ///< preface
+ 0x55, 0x49, 0x54, 0x0A, ///<
+ 0x21, ///< version & command
+ 0x00, ///< protocol & family
+ 0x00, 0x24, ///< len
+ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x01, ///< src_addr
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ///<
+ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x02, ///< dst_addr
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ///<
+ 0xC3, 0x50, ///< src_port
+ 0x01, 0xBB, ///< dst_port
+ };
+
+ ts::TextView tv(reinterpret_cast<char *>(raw_data), sizeof(raw_data));
+
+ ProxyProtocol pp_info;
REQUIRE(proxy_protocol_parse(&pp_info, tv) == 0);
+
+ CHECK(pp_info.version == ProxyProtocolVersion::UNDEFINED);
+ 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[] = {
+ 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, ///< preface
+ 0x55, 0x49, 0x54, 0x0A, ///<
+ 0x21, ///< version & command
+ 0x11, ///< protocol & family
+ 0x00, 0x11, ///< 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)
+ };
+
+ ts::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);
+ }
+
+ SECTION("Malformed Headers")
+ {
+ ProxyProtocol pp_info;
+
+ SECTION("invalid preface")
+ {
+ uint8_t raw_data[] = {
+ 0xDE, 0xAD, 0xBE, 0xEF, 0xDE, 0xAD, 0xBE, 0xEF, ///< preface
+ 0xDE, 0xAD, 0xBE, 0xEF, ///<
+ 0x21, ///< version & command
+ 0x21, ///< protocol & family
+ 0x00, 0x24, ///< len
+ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x01, ///< src_addr
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ///<
+ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x02, ///< dst_addr
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ///<
+ 0xC3, 0x50, ///< src_port
+ 0x01, 0xBB, ///< dst_port
+ };
+
+ ts::TextView tv(reinterpret_cast<char *>(raw_data), sizeof(raw_data));
+
+ CHECK(proxy_protocol_parse(&pp_info, tv) == 0);
+ CHECK(pp_info.version == ProxyProtocolVersion::UNDEFINED);
+ CHECK(pp_info.ip_family == AF_UNSPEC);
+ }
+
+ SECTION("unsupported version & command")
+ {
+ uint8_t raw_data[] = {
+ 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, ///< preface
+ 0x55, 0x49, 0x54, 0x0A, ///<
+ 0xFF, ///< version & command
+ 0x21, ///< protocol & family
+ 0x00, 0x24, ///< len
+ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x01, ///< src_addr
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ///<
+ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x02, ///< dst_addr
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ///<
+ 0xC3, 0x50, ///< src_port
+ 0x01, 0xBB, ///< dst_port
+ };
+
+ ts::TextView tv(reinterpret_cast<char *>(raw_data), sizeof(raw_data));
+
+ CHECK(proxy_protocol_parse(&pp_info, tv) == 0);
+ CHECK(pp_info.version == ProxyProtocolVersion::UNDEFINED);
+ CHECK(pp_info.ip_family == AF_UNSPEC);
+ }
+
+ SECTION("unsupported protocol & family")
+ {
+ uint8_t raw_data[] = {
+ 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, ///< preface
+ 0x55, 0x49, 0x54, 0x0A, ///<
+ 0x21, ///< version & command
+ 0xFF, ///< protocol & family
+ 0x00, 0x24, ///< len
+ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x01, ///< src_addr
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ///<
+ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x02, ///< dst_addr
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ///<
+ 0xC3, 0x50, ///< src_port
+ 0x01, 0xBB, ///< dst_port
+ };
+
+ ts::TextView tv(reinterpret_cast<char *>(raw_data), sizeof(raw_data));
+
+ CHECK(proxy_protocol_parse(&pp_info, tv) == 0);
+ CHECK(pp_info.version == ProxyProtocolVersion::UNDEFINED);
+ CHECK(pp_info.ip_family == AF_UNSPEC);
+ }
+
+ SECTION("invalid len value - too long")
+ {
+ uint8_t raw_data[] = {
+ 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, ///< preface
+ 0x55, 0x49, 0x54, 0x0A, ///<
+ 0x21, ///< version & command
+ 0x21, ///< protocol & family
+ 0x00, 0x25, ///< len
+ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x01, ///< src_addr
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ///<
+ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x02, ///< dst_addr
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ///<
+ 0xC3, 0x50, ///< src_port
+ 0x01, 0xBB, ///< dst_port
+ };
+
+ ts::TextView tv(reinterpret_cast<char *>(raw_data), sizeof(raw_data));
+
+ CHECK(proxy_protocol_parse(&pp_info, tv) == 0);
+ CHECK(pp_info.version == ProxyProtocolVersion::UNDEFINED);
+ CHECK(pp_info.ip_family == AF_UNSPEC);
+ }
+
+ SECTION("invalid len - actual buffer is shorter than the value")
+ {
+ uint8_t raw_data[] = {
+ 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, ///< preface
+ 0x55, 0x49, 0x54, 0x0A, ///<
+ 0x21, ///< version & command
+ 0x21, ///< protocol & family
+ 0x00, 0x24, ///< len
+ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x01, ///< src_addr
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ///<
+ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x02, ///< dst_addr
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ///<
+ 0xC3, 0x50, ///< src_port
+ 0x01, ///< dst_port
+ };
+
+ ts::TextView tv(reinterpret_cast<char *>(raw_data), sizeof(raw_data));
+
+ CHECK(proxy_protocol_parse(&pp_info, tv) == 0);
+ CHECK(pp_info.version == ProxyProtocolVersion::UNDEFINED);
+ CHECK(pp_info.ip_family == AF_UNSPEC);
+ }
+
+ SECTION("invalid len - too short for INET")
+ {
+ uint8_t raw_data[] = {
+ 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, ///< preface
+ 0x55, 0x49, 0x54, 0x0A, ///<
+ 0x21, ///< version & command
+ 0x11, ///< protocol & family
+ 0x00, 0x0C, ///< len
+ 0xC0, 0x00, ///< src_addr
+ 0xC6, 0x33, ///< dst_addr
+ 0xC3, 0x50, ///< src_port
+ 0x01, 0xBB, ///< dst_port
+ };
+
+ ts::TextView tv(reinterpret_cast<char *>(raw_data), sizeof(raw_data));
+
+ CHECK(proxy_protocol_parse(&pp_info, tv) == 0);
+ CHECK(pp_info.version == ProxyProtocolVersion::UNDEFINED);
+ CHECK(pp_info.ip_family == AF_UNSPEC);
+ }
+
+ SECTION("invalid len - too short for INET6")
+ {
+ uint8_t raw_data[] = {
+ 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, ///< preface
+ 0x55, 0x49, 0x54, 0x0A, ///<
+ 0x21, ///< version & command
+ 0x21, ///< protocol & family
+ 0x00, 0x24, ///< len
+ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x01, ///< src_addr
+ 0x20, 0x01, 0x0D, 0xB8, 0x00, 0x00, 0x00, 0x02, ///< dst_addr
+ 0xC3, 0x50, ///< src_port
+ 0x01, 0xBB, ///< dst_port
+ };
+
+ ts::TextView tv(reinterpret_cast<char *>(raw_data), sizeof(raw_data));
+
+ CHECK(proxy_protocol_parse(&pp_info, tv) == 0);
+ CHECK(pp_info.version == ProxyProtocolVersion::UNDEFINED);
+ CHECK(pp_info.ip_family == AF_UNSPEC);
+ }
}
}