diff --git a/docs/root/configuration/http/http_conn_man/headers.rst b/docs/root/configuration/http/http_conn_man/headers.rst index 33b844f86028..e8f420710a11 100644 --- a/docs/root/configuration/http/http_conn_man/headers.rst +++ b/docs/root/configuration/http/http_conn_man/headers.rst @@ -587,11 +587,60 @@ Supported variable names are: `. %DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT% - Same as **%DOWNSTREAM_REMOTE_ADDRESS%** excluding port if the address is an IP address. + Remote address of the downstream connection, without any port component. + IP addresses are the only address type with a port component. + + .. note:: + + This may not be the physical remote address of the peer if the address has been inferred from + :ref:`Proxy Protocol filter ` or :ref:`x-forwarded-for + `. + +%DOWNSTREAM_REMOTE_PORT% + Remote port of the downstream connection. + IP addresses are the only address type with a port component. + + .. note:: + + This may not be the physical remote address of the peer if the address has been inferred from + :ref:`Proxy Protocol filter ` or :ref:`x-forwarded-for + `. + +%DOWNSTREAM_DIRECT_REMOTE_ADDRESS% + Direct remote address of the downstream connection. If the address is an IP address it includes both + address and port. + + .. note:: + + This is always the physical remote address of the peer even if the downstream remote address has + been inferred from :ref:`Proxy Protocol filter ` + or :ref:`x-forwarded-for `. + +%DOWNSTREAM_DIRECT_REMOTE_ADDRESS_WITHOUT_PORT% + Direct remote address of the downstream connection, without any port component. + IP addresses are the only address type with a port component. + + .. note:: + + This is always the physical remote address of the peer even if the downstream remote address has + been inferred from :ref:`Proxy Protocol filter ` + or :ref:`x-forwarded-for `. + +%DOWNSTREAM_DIRECT_REMOTE_PORT% + Direct remote port of the downstream connection. + IP addresses are the only address type with a port component. + + .. note:: + + This is always the physical remote address of the peer even if the downstream remote address has + been inferred from :ref:`Proxy Protocol filter ` + or :ref:`x-forwarded-for `. + %DOWNSTREAM_LOCAL_ADDRESS% Local address of the downstream connection. If the address is an IP address it includes both address and port. + If the original connection was redirected by iptables REDIRECT, this represents the original destination address restored by the :ref:`Original Destination Filter ` using SO_ORIGINAL_DST socket option. @@ -599,10 +648,12 @@ Supported variable names are: option was set to true, this represents the original destination address and port. %DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT% - Same as **%DOWNSTREAM_LOCAL_ADDRESS%** excluding port if the address is an IP address. + Local address of the downstream connection, without any port component. + IP addresses are the only address type with a port component. %DOWNSTREAM_LOCAL_PORT% - Similar to **%DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT%**, but only extracts the port portion of the **%DOWNSTREAM_LOCAL_ADDRESS%** + Local port of the downstream connection. + IP addresses are the only address type with a port component. %DOWNSTREAM_LOCAL_URI_SAN% HTTP @@ -726,11 +777,36 @@ Supported variable names are: This works both on request and response headers. +%UPSTREAM_LOCAL_ADDRESS% + Local address of the upstream connection. If the address is an IP address it includes both + address and port. + + The upstream local address cannot be added to request headers as the upstream host + hremote as not been selected when custom request headers are generated. + +%UPSTREAM_LOCAL_ADDRESS_WITHOUT_PORT% + Local address of the upstream connection, without any port component. + IP addresses are the only address type with a port component. + +%UPSTREAM_LOCAL_PORT% + Local port of the upstream connection. + IP addresses are the only address type with a port component. + %UPSTREAM_REMOTE_ADDRESS% - Remote address of the upstream host. If the address is an IP address it includes both address - and port. The upstream remote address cannot be added to request headers as the upstream host + Remote address of the upstream connection. If the address is an IP address it includes both + address and port. + + The upstream remote address cannot be added to request headers as the upstream host has not been selected when custom request headers are generated. +%UPSTREAM_REMOTE_ADDRESS_WITHOUT_PORT% + Remote address of the upstream connection, without any port component. + IP addresses are the only address type with a port component. + +%UPSTREAM_REMOTE_PORT% + Remote port of the upstream connection. + IP addresses are the only address type with a port component. + %PER_REQUEST_STATE(reverse.dns.data.name)% Populates the header with values set on the stream info filterState() object. To be usable in custom request/response headers, these values must be of type diff --git a/docs/root/configuration/observability/access_log/usage.rst b/docs/root/configuration/observability/access_log/usage.rst index 8599f838f4f3..e2381553e2cc 100644 --- a/docs/root/configuration/observability/access_log/usage.rst +++ b/docs/root/configuration/observability/access_log/usage.rst @@ -414,6 +414,26 @@ The following command operators are supported: Local address of the upstream connection. If the address is an IP address it includes both address and port. +%UPSTREAM_LOCAL_ADDRESS_WITHOUT_PORT% + Local address of the upstream connection, without any port component. + IP addresses are the only address type with a port component. + +%UPSTREAM_LOCAL_PORT% + Local port of the upstream connection. + IP addresses are the only address type with a port component. + +%UPSTREAM_REMOTE_ADDRESS% + Remote address of the upstream connection. If the address is an IP address it includes both + address and port. + +%UPSTREAM_REMOTE_ADDRESS_WITHOUT_PORT% + Remote address of the upstream connection, without any port component. + IP addresses are the only address type with a port component. + +%UPSTREAM_REMOTE_PORT% + Remote port of the upstream connection. + IP addresses are the only address type with a port component. + .. _config_access_log_format_upstream_transport_failure_reason: %UPSTREAM_TRANSPORT_FAILURE_REASON% @@ -436,8 +456,18 @@ The following command operators are supported: `. %DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT% - Remote address of the downstream connection. If the address is an IP address the output does - *not* include port. + Remote address of the downstream connection, without any port component. + IP addresses are the only address type with a port component. + + .. note:: + + This may not be the physical remote address of the peer if the address has been inferred from + :ref:`Proxy Protocol filter ` or :ref:`x-forwarded-for + `. + +%DOWNSTREAM_REMOTE_PORT% + Remote port of the downstream connection. + IP addresses are the only address type with a port component. .. note:: @@ -456,8 +486,18 @@ The following command operators are supported: or :ref:`x-forwarded-for `. %DOWNSTREAM_DIRECT_REMOTE_ADDRESS_WITHOUT_PORT% - The direct remote address of the downstream connection. If the address is an IP address the output does - *not* include port. + Direct remote address of the downstream connection, without any port component. + IP addresses are the only address type with a port component. + + .. note:: + + This is always the physical remote address of the peer even if the downstream remote address has + been inferred from :ref:`Proxy Protocol filter ` + or :ref:`x-forwarded-for `. + +%DOWNSTREAM_DIRECT_REMOTE_PORT% + Direct remote port of the downstream connection. + IP addresses are the only address type with a port component. .. note:: @@ -468,6 +508,7 @@ The following command operators are supported: %DOWNSTREAM_LOCAL_ADDRESS% Local address of the downstream connection. If the address is an IP address it includes both address and port. + If the original connection was redirected by iptables REDIRECT, this represents the original destination address restored by the :ref:`Original Destination Filter ` using SO_ORIGINAL_DST socket option. @@ -475,7 +516,12 @@ The following command operators are supported: option was set to true, this represents the original destination address and port. %DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT% - Same as **%DOWNSTREAM_LOCAL_ADDRESS%** excluding port if the address is an IP address. + Local address of the downstream connection, without any port component. + IP addresses are the only address type with a port component. + +%DOWNSTREAM_LOCAL_PORT% + Local port of the downstream connection. + IP addresses are the only address type with a port component. .. _config_access_log_format_connection_id: @@ -489,9 +535,6 @@ The following command operators are supported: %GRPC_STATUS% gRPC status code which is easy to interpret with text message corresponding with number. -%DOWNSTREAM_LOCAL_PORT% - Similar to **%DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT%**, but only extracts the port portion of the **%DOWNSTREAM_LOCAL_ADDRESS%** - .. _config_access_log_format_req: %REQ(X?Y):Z% diff --git a/source/common/formatter/substitution_formatter.cc b/source/common/formatter/substitution_formatter.cc index 368a51d79968..84379da62341 100644 --- a/source/common/formatter/substitution_formatter.cc +++ b/source/common/formatter/substitution_formatter.cc @@ -881,6 +881,61 @@ const StreamInfoFormatter::FieldExtractorLookupTbl& StreamInfoFormatter::getKnow return nullptr; }); }}, + {"UPSTREAM_LOCAL_ADDRESS_WITHOUT_PORT", + []() { + return StreamInfoAddressFieldExtractor::withoutPort( + [](const StreamInfo::StreamInfo& stream_info) + -> std::shared_ptr { + if (stream_info.upstreamInfo().has_value()) { + return stream_info.upstreamInfo().value().get().upstreamLocalAddress(); + } + return nullptr; + }); + }}, + {"UPSTREAM_LOCAL_PORT", + []() { + return StreamInfoAddressFieldExtractor::justPort( + [](const StreamInfo::StreamInfo& stream_info) + -> std::shared_ptr { + if (stream_info.upstreamInfo().has_value()) { + return stream_info.upstreamInfo().value().get().upstreamLocalAddress(); + } + return nullptr; + }); + }}, + {"UPSTREAM_REMOTE_ADDRESS", + []() { + return StreamInfoAddressFieldExtractor::withPort( + [](const StreamInfo::StreamInfo& stream_info) + -> std::shared_ptr { + if (stream_info.upstreamInfo() && stream_info.upstreamInfo()->upstreamHost()) { + return stream_info.upstreamInfo()->upstreamHost()->address(); + } + return nullptr; + }); + }}, + {"UPSTREAM_REMOTE_ADDRESS_WITHOUT_PORT", + []() { + return StreamInfoAddressFieldExtractor::withoutPort( + [](const StreamInfo::StreamInfo& stream_info) + -> std::shared_ptr { + if (stream_info.upstreamInfo() && stream_info.upstreamInfo()->upstreamHost()) { + return stream_info.upstreamInfo()->upstreamHost()->address(); + } + return nullptr; + }); + }}, + {"UPSTREAM_REMOTE_PORT", + []() { + return StreamInfoAddressFieldExtractor::justPort( + [](const StreamInfo::StreamInfo& stream_info) + -> std::shared_ptr { + if (stream_info.upstreamInfo() && stream_info.upstreamInfo()->upstreamHost()) { + return stream_info.upstreamInfo()->upstreamHost()->address(); + } + return nullptr; + }); + }}, {"UPSTREAM_REQUEST_ATTEMPT_COUNT", []() { return std::make_unique( @@ -923,6 +978,13 @@ const StreamInfoFormatter::FieldExtractorLookupTbl& StreamInfoFormatter::getKnow return stream_info.downstreamAddressProvider().remoteAddress(); }); }}, + {"DOWNSTREAM_REMOTE_PORT", + []() { + return StreamInfoAddressFieldExtractor::justPort( + [](const Envoy::StreamInfo::StreamInfo& stream_info) { + return stream_info.downstreamAddressProvider().remoteAddress(); + }); + }}, {"DOWNSTREAM_DIRECT_REMOTE_ADDRESS", []() { return StreamInfoAddressFieldExtractor::withPort( @@ -937,6 +999,13 @@ const StreamInfoFormatter::FieldExtractorLookupTbl& StreamInfoFormatter::getKnow return stream_info.downstreamAddressProvider().directRemoteAddress(); }); }}, + {"DOWNSTREAM_DIRECT_REMOTE_PORT", + []() { + return StreamInfoAddressFieldExtractor::justPort( + [](const Envoy::StreamInfo::StreamInfo& stream_info) { + return stream_info.downstreamAddressProvider().directRemoteAddress(); + }); + }}, {"CONNECTION_ID", []() { return std::make_unique( diff --git a/source/common/router/header_formatter.cc b/source/common/router/header_formatter.cc index bc0830d1a748..7959e17aebc4 100644 --- a/source/common/router/header_formatter.cc +++ b/source/common/router/header_formatter.cc @@ -263,8 +263,27 @@ StreamInfoHeaderFormatter::StreamInfoHeaderFormatter(absl::string_view field_nam return StreamInfo::Utility::formatDownstreamAddressNoPort( *stream_info.downstreamAddressProvider().remoteAddress()); }; + } else if (field_name == "DOWNSTREAM_REMOTE_PORT") { + field_extractor_ = [](const Envoy::StreamInfo::StreamInfo& stream_info) { + return StreamInfo::Utility::formatDownstreamAddressJustPort( + *stream_info.downstreamAddressProvider().remoteAddress()); + }; + } else if (field_name == "DOWNSTREAM_DIRECT_REMOTE_ADDRESS") { + field_extractor_ = [](const Envoy::StreamInfo::StreamInfo& stream_info) { + return stream_info.downstreamAddressProvider().directRemoteAddress()->asString(); + }; + } else if (field_name == "DOWNSTREAM_DIRECT_REMOTE_ADDRESS_WITHOUT_PORT") { + field_extractor_ = [](const Envoy::StreamInfo::StreamInfo& stream_info) { + return StreamInfo::Utility::formatDownstreamAddressNoPort( + *stream_info.downstreamAddressProvider().directRemoteAddress()); + }; + } else if (field_name == "DOWNSTREAM_DIRECT_REMOTE_PORT") { + field_extractor_ = [](const Envoy::StreamInfo::StreamInfo& stream_info) { + return StreamInfo::Utility::formatDownstreamAddressJustPort( + *stream_info.downstreamAddressProvider().directRemoteAddress()); + }; } else if (field_name == "DOWNSTREAM_LOCAL_ADDRESS") { - field_extractor_ = [](const StreamInfo::StreamInfo& stream_info) { + field_extractor_ = [](const Envoy::StreamInfo::StreamInfo& stream_info) { return stream_info.downstreamAddressProvider().localAddress()->asString(); }; } else if (field_name == "DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT") { @@ -337,6 +356,32 @@ StreamInfoHeaderFormatter::StreamInfoHeaderFormatter(absl::string_view field_nam field_extractor_ = parseSubstitutionFormatField(field_name, formatter_map_); } else if (absl::StartsWith(field_name, "DOWNSTREAM_PEER_CERT_V_END")) { field_extractor_ = parseSubstitutionFormatField(field_name, formatter_map_); + } else if (field_name == "UPSTREAM_LOCAL_ADDRESS") { + field_extractor_ = [](const Envoy::StreamInfo::StreamInfo& stream_info) -> std::string { + if (stream_info.upstreamInfo().has_value() && + stream_info.upstreamInfo()->upstreamLocalAddress()) { + return stream_info.upstreamInfo()->upstreamLocalAddress()->asString(); + } + return ""; + }; + } else if (field_name == "UPSTREAM_LOCAL_ADDRESS_WITHOUT_PORT") { + field_extractor_ = [](const Envoy::StreamInfo::StreamInfo& stream_info) -> std::string { + if (stream_info.upstreamInfo().has_value() && + stream_info.upstreamInfo()->upstreamLocalAddress()) { + return StreamInfo::Utility::formatDownstreamAddressNoPort( + *stream_info.upstreamInfo()->upstreamLocalAddress()); + } + return ""; + }; + } else if (field_name == "UPSTREAM_LOCAL_PORT") { + field_extractor_ = [](const Envoy::StreamInfo::StreamInfo& stream_info) -> std::string { + if (stream_info.upstreamInfo().has_value() && + stream_info.upstreamInfo()->upstreamLocalAddress()) { + return StreamInfo::Utility::formatDownstreamAddressJustPort( + *stream_info.upstreamInfo()->upstreamLocalAddress()); + } + return ""; + }; } else if (field_name == "UPSTREAM_REMOTE_ADDRESS") { field_extractor_ = [](const Envoy::StreamInfo::StreamInfo& stream_info) -> std::string { if (stream_info.upstreamInfo() && stream_info.upstreamInfo()->upstreamHost()) { @@ -344,6 +389,22 @@ StreamInfoHeaderFormatter::StreamInfoHeaderFormatter(absl::string_view field_nam } return ""; }; + } else if (field_name == "UPSTREAM_REMOTE_ADDRESS_WITHOUT_PORT") { + field_extractor_ = [](const Envoy::StreamInfo::StreamInfo& stream_info) -> std::string { + if (stream_info.upstreamInfo() && stream_info.upstreamInfo()->upstreamHost()) { + return StreamInfo::Utility::formatDownstreamAddressNoPort( + *stream_info.upstreamInfo()->upstreamHost()->address()); + } + return ""; + }; + } else if (field_name == "UPSTREAM_REMOTE_PORT") { + field_extractor_ = [](const Envoy::StreamInfo::StreamInfo& stream_info) -> std::string { + if (stream_info.upstreamInfo() && stream_info.upstreamInfo()->upstreamHost()) { + return StreamInfo::Utility::formatDownstreamAddressJustPort( + *stream_info.upstreamInfo()->upstreamHost()->address()); + } + return ""; + }; } else if (absl::StartsWith(field_name, "START_TIME")) { field_extractor_ = parseSubstitutionFormatField(field_name, formatter_map_); } else if (absl::StartsWith(field_name, "UPSTREAM_METADATA")) { diff --git a/test/common/formatter/substitution_formatter_test.cc b/test/common/formatter/substitution_formatter_test.cc index fb0e627534e7..98472e9e6e7a 100644 --- a/test/common/formatter/substitution_formatter_test.cc +++ b/test/common/formatter/substitution_formatter_test.cc @@ -515,6 +515,84 @@ TEST(SubstitutionFormatterTest, streamInfoFormatter) { ProtoEq(ValueUtil::stringValue("LR"))); } + { + StreamInfoFormatter upstream_format("UPSTREAM_LOCAL_ADDRESS"); + + // Validate for IPv4 address + auto address = Network::Address::InstanceConstSharedPtr{ + new Network::Address::Ipv4Instance("127.1.2.3", 18443)}; + stream_info.upstreamInfo()->setUpstreamLocalAddress(address); + EXPECT_EQ("127.1.2.3:18443", upstream_format.format(request_headers, response_headers, + response_trailers, stream_info, body)); + EXPECT_THAT(upstream_format.formatValue(request_headers, response_headers, response_trailers, + stream_info, body), + ProtoEq(ValueUtil::stringValue("127.1.2.3:18443"))); + + // Validate for IPv6 address + address = + Network::Address::InstanceConstSharedPtr{new Network::Address::Ipv6Instance("::1", 19443)}; + stream_info.upstreamInfo()->setUpstreamLocalAddress(address); + EXPECT_EQ("[::1]:19443", upstream_format.format(request_headers, response_headers, + response_trailers, stream_info, body)); + EXPECT_THAT(upstream_format.formatValue(request_headers, response_headers, response_trailers, + stream_info, body), + ProtoEq(ValueUtil::stringValue("[::1]:19443"))); + + // Validate for Pipe + address = Network::Address::InstanceConstSharedPtr{new Network::Address::PipeInstance("/foo")}; + stream_info.upstreamInfo()->setUpstreamLocalAddress(address); + EXPECT_EQ("/foo", upstream_format.format(request_headers, response_headers, response_trailers, + stream_info, body)); + EXPECT_THAT(upstream_format.formatValue(request_headers, response_headers, response_trailers, + stream_info, body), + ProtoEq(ValueUtil::stringValue("/foo"))); + } + + { + StreamInfoFormatter upstream_format("UPSTREAM_LOCAL_ADDRESS_WITHOUT_PORT"); + auto address = Network::Address::InstanceConstSharedPtr{ + new Network::Address::Ipv4Instance("127.0.0.3", 18443)}; + stream_info.upstreamInfo()->setUpstreamLocalAddress(address); + EXPECT_EQ("127.0.0.3", upstream_format.format(request_headers, response_headers, + response_trailers, stream_info, body)); + EXPECT_THAT(upstream_format.formatValue(request_headers, response_headers, response_trailers, + stream_info, body), + ProtoEq(ValueUtil::stringValue("127.0.0.3"))); + } + + { + StreamInfoFormatter upstream_format("UPSTREAM_LOCAL_PORT"); + + // Validate for IPv4 address + auto address = Network::Address::InstanceConstSharedPtr{ + new Network::Address::Ipv4Instance("127.1.2.3", 18443)}; + stream_info.upstreamInfo()->setUpstreamLocalAddress(address); + EXPECT_EQ("18443", upstream_format.format(request_headers, response_headers, response_trailers, + stream_info, body)); + EXPECT_THAT(upstream_format.formatValue(request_headers, response_headers, response_trailers, + stream_info, body), + ProtoEq(ValueUtil::stringValue("18443"))); + + // Validate for IPv6 address + address = + Network::Address::InstanceConstSharedPtr{new Network::Address::Ipv6Instance("::1", 19443)}; + stream_info.upstreamInfo()->setUpstreamLocalAddress(address); + EXPECT_EQ("19443", upstream_format.format(request_headers, response_headers, response_trailers, + stream_info, body)); + EXPECT_THAT(upstream_format.formatValue(request_headers, response_headers, response_trailers, + stream_info, body), + ProtoEq(ValueUtil::stringValue("19443"))); + + // Validate for Pipe + address = Network::Address::InstanceConstSharedPtr{new Network::Address::PipeInstance("/foo")}; + stream_info.upstreamInfo()->setUpstreamLocalAddress(address); + EXPECT_EQ("", upstream_format.format(request_headers, response_headers, response_trailers, + stream_info, body)); + EXPECT_THAT(upstream_format.formatValue(request_headers, response_headers, response_trailers, + stream_info, body), + ProtoEq(ValueUtil::stringValue(""))); + } + { StreamInfoFormatter upstream_format("UPSTREAM_HOST"); EXPECT_EQ("10.0.0.1:443", upstream_format.format(request_headers, response_headers, @@ -524,6 +602,31 @@ TEST(SubstitutionFormatterTest, streamInfoFormatter) { ProtoEq(ValueUtil::stringValue("10.0.0.1:443"))); } + { + StreamInfoFormatter upstream_format("UPSTREAM_REMOTE_ADDRESS"); + EXPECT_EQ("10.0.0.1:443", upstream_format.format(request_headers, response_headers, + response_trailers, stream_info, body)); + EXPECT_THAT(upstream_format.formatValue(request_headers, response_headers, response_trailers, + stream_info, body), + ProtoEq(ValueUtil::stringValue("10.0.0.1:443"))); + } + { + StreamInfoFormatter upstream_format("UPSTREAM_REMOTE_ADDRESS_WITHOUT_PORT"); + EXPECT_EQ("10.0.0.1", upstream_format.format(request_headers, response_headers, + response_trailers, stream_info, body)); + EXPECT_THAT(upstream_format.formatValue(request_headers, response_headers, response_trailers, + stream_info, body), + ProtoEq(ValueUtil::stringValue("10.0.0.1"))); + } + { + StreamInfoFormatter upstream_format("UPSTREAM_REMOTE_PORT"); + EXPECT_EQ("443", upstream_format.format(request_headers, response_headers, response_trailers, + stream_info, body)); + EXPECT_THAT(upstream_format.formatValue(request_headers, response_headers, response_trailers, + stream_info, body), + ProtoEq(ValueUtil::stringValue("443"))); + } + { StreamInfoFormatter upstream_format("UPSTREAM_CLUSTER"); const std::string observable_cluster_name = "observability_name"; @@ -679,22 +782,40 @@ TEST(SubstitutionFormatterTest, streamInfoFormatter) { ProtoEq(ValueUtil::stringValue("127.0.0.1:0"))); } + { + StreamInfoFormatter upstream_format("DOWNSTREAM_REMOTE_PORT"); + EXPECT_EQ("0", upstream_format.format(request_headers, response_headers, response_trailers, + stream_info, body)); + EXPECT_THAT(upstream_format.formatValue(request_headers, response_headers, response_trailers, + stream_info, body), + ProtoEq(ValueUtil::stringValue("0"))); + } + { StreamInfoFormatter upstream_format("DOWNSTREAM_DIRECT_REMOTE_ADDRESS_WITHOUT_PORT"); - EXPECT_EQ("127.0.0.1", upstream_format.format(request_headers, response_headers, + EXPECT_EQ("127.0.0.3", upstream_format.format(request_headers, response_headers, response_trailers, stream_info, body)); EXPECT_THAT(upstream_format.formatValue(request_headers, response_headers, response_trailers, stream_info, body), - ProtoEq(ValueUtil::stringValue("127.0.0.1"))); + ProtoEq(ValueUtil::stringValue("127.0.0.3"))); } { StreamInfoFormatter upstream_format("DOWNSTREAM_DIRECT_REMOTE_ADDRESS"); - EXPECT_EQ("127.0.0.1:0", upstream_format.format(request_headers, response_headers, - response_trailers, stream_info, body)); + EXPECT_EQ("127.0.0.3:63443", upstream_format.format(request_headers, response_headers, + response_trailers, stream_info, body)); EXPECT_THAT(upstream_format.formatValue(request_headers, response_headers, response_trailers, stream_info, body), - ProtoEq(ValueUtil::stringValue("127.0.0.1:0"))); + ProtoEq(ValueUtil::stringValue("127.0.0.3:63443"))); + } + + { + StreamInfoFormatter upstream_format("DOWNSTREAM_DIRECT_REMOTE_PORT"); + EXPECT_EQ("63443", upstream_format.format(request_headers, response_headers, response_trailers, + stream_info, body)); + EXPECT_THAT(upstream_format.formatValue(request_headers, response_headers, response_trailers, + stream_info, body), + ProtoEq(ValueUtil::stringValue("63443"))); } { diff --git a/test/common/router/header_formatter_test.cc b/test/common/router/header_formatter_test.cc index c90f9366f459..e9d0db7f7ab0 100644 --- a/test/common/router/header_formatter_test.cc +++ b/test/common/router/header_formatter_test.cc @@ -74,11 +74,52 @@ TEST_F(StreamInfoHeaderFormatterTest, TestFormatWithDownstreamRemoteAddressWitho testFormatting("DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT", "127.0.0.1"); } +TEST_F(StreamInfoHeaderFormatterTest, TestFormatWithDownstreamRemotePortVariable) { + testFormatting("DOWNSTREAM_REMOTE_PORT", "0"); +} + +TEST_F(StreamInfoHeaderFormatterTest, TestFormatWithDownstreamDirectRemoteAddressVariable) { + testFormatting("DOWNSTREAM_DIRECT_REMOTE_ADDRESS", "127.0.0.3:63443"); +} + +TEST_F(StreamInfoHeaderFormatterTest, + TestFormatWithDownstreamDirectRemoteAddressWithoutPortVariable) { + testFormatting("DOWNSTREAM_DIRECT_REMOTE_ADDRESS_WITHOUT_PORT", "127.0.0.3"); +} + +TEST_F(StreamInfoHeaderFormatterTest, TestFormatWithDownstreamDirectRemotePortVariable) { + testFormatting("DOWNSTREAM_DIRECT_REMOTE_PORT", "63443"); +} + TEST_F(StreamInfoHeaderFormatterTest, TestFormatWithDownstreamLocalAddressVariable) { testFormatting("DOWNSTREAM_LOCAL_ADDRESS", "127.0.0.2:0"); } +TEST_F(StreamInfoHeaderFormatterTest, TestFormatWithDownstreamLocalAddressVariableVariants) { + NiceMock stream_info; + // Validate for IPv4 address + auto address = Network::Address::InstanceConstSharedPtr{ + new Network::Address::Ipv4Instance("127.1.2.3", 8443)}; + stream_info.downstream_connection_info_provider_->setLocalAddress(address); + testFormatting(stream_info, "DOWNSTREAM_LOCAL_ADDRESS", "127.1.2.3:8443"); + + // Validate for IPv6 address + address = + Network::Address::InstanceConstSharedPtr{new Network::Address::Ipv6Instance("::1", 9443)}; + stream_info.downstream_connection_info_provider_->setLocalAddress(address); + testFormatting(stream_info, "DOWNSTREAM_LOCAL_ADDRESS", "[::1]:9443"); + + // Validate for Pipe + address = Network::Address::InstanceConstSharedPtr{new Network::Address::PipeInstance("/foo")}; + stream_info.downstream_connection_info_provider_->setLocalAddress(address); + testFormatting(stream_info, "DOWNSTREAM_LOCAL_ADDRESS", "/foo"); +} + TEST_F(StreamInfoHeaderFormatterTest, TestFormatWithDownstreamLocalPortVariable) { + testFormatting("DOWNSTREAM_LOCAL_PORT", "0"); +} + +TEST_F(StreamInfoHeaderFormatterTest, TestFormatWithDownstreamLocalPortVariableVariants) { NiceMock stream_info; // Validate for IPv4 address auto address = Network::Address::InstanceConstSharedPtr{ @@ -102,6 +143,27 @@ TEST_F(StreamInfoHeaderFormatterTest, TestFormatWithDownstreamLocalAddressWithou testFormatting("DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT", "127.0.0.2"); } +TEST_F(StreamInfoHeaderFormatterTest, + TestFormatWithDownstreamLocalAddressWithoutPortVariableVariants) { + NiceMock stream_info; + // Validate for IPv4 address + auto address = Network::Address::InstanceConstSharedPtr{ + new Network::Address::Ipv4Instance("127.1.2.3", 8443)}; + stream_info.downstream_connection_info_provider_->setLocalAddress(address); + testFormatting(stream_info, "DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT", "127.1.2.3"); + + // Validate for IPv6 address + address = + Network::Address::InstanceConstSharedPtr{new Network::Address::Ipv6Instance("::1", 9443)}; + stream_info.downstream_connection_info_provider_->setLocalAddress(address); + testFormatting(stream_info, "DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT", "::1"); + + // Validate for Pipe + address = Network::Address::InstanceConstSharedPtr{new Network::Address::PipeInstance("/foo")}; + stream_info.downstream_connection_info_provider_->setLocalAddress(address); + testFormatting(stream_info, "DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT", "/foo"); +} + TEST_F(StreamInfoHeaderFormatterTest, TestformatWithUpstreamRemoteAddressVariable) { testFormatting("UPSTREAM_REMOTE_ADDRESS", "10.0.0.1:443"); @@ -110,6 +172,49 @@ TEST_F(StreamInfoHeaderFormatterTest, TestformatWithUpstreamRemoteAddressVariabl testFormatting(stream_info, "UPSTREAM_REMOTE_ADDRESS", ""); } +TEST_F(StreamInfoHeaderFormatterTest, TestformatWithUpstreamRemotePortVariable) { + testFormatting("UPSTREAM_REMOTE_PORT", "443"); + + NiceMock stream_info; + stream_info.upstreamInfo()->setUpstreamHost(nullptr); + testFormatting(stream_info, "UPSTREAM_REMOTE_PORT", ""); +} + +TEST_F(StreamInfoHeaderFormatterTest, TestformatWithUpstreamRemoteAddressWithoutPortVariable) { + testFormatting("UPSTREAM_REMOTE_ADDRESS_WITHOUT_PORT", "10.0.0.1"); + + NiceMock stream_info; + stream_info.upstreamInfo()->setUpstreamHost(nullptr); + testFormatting(stream_info, "UPSTREAM_REMOTE_ADDRESS_WITHOUT_PORT", ""); +} + +TEST_F(StreamInfoHeaderFormatterTest, TestformatWithUpstreamLocalAddressVariable) { + testFormatting("UPSTREAM_LOCAL_ADDRESS", "127.1.2.3:58443"); + + NiceMock stream_info; + stream_info.upstreamInfo()->setUpstreamHost(nullptr); + stream_info.upstreamInfo()->setUpstreamLocalAddress(nullptr); + testFormatting(stream_info, "UPSTREAM_LOCAL_ADDRESS", ""); +} + +TEST_F(StreamInfoHeaderFormatterTest, TestformatWithUpstreamLocalPortVariable) { + testFormatting("UPSTREAM_LOCAL_PORT", "58443"); + + NiceMock stream_info; + stream_info.upstreamInfo()->setUpstreamHost(nullptr); + stream_info.upstreamInfo()->setUpstreamLocalAddress(nullptr); + testFormatting(stream_info, "UPSTREAM_LOCAL_PORT", ""); +} + +TEST_F(StreamInfoHeaderFormatterTest, TestformatWithUpstreamLocalAddressWithoutPortVariable) { + testFormatting("UPSTREAM_LOCAL_ADDRESS_WITHOUT_PORT", "127.1.2.3"); + + NiceMock stream_info; + stream_info.upstreamInfo()->setUpstreamHost(nullptr); + stream_info.upstreamInfo()->setUpstreamLocalAddress(nullptr); + testFormatting(stream_info, "UPSTREAM_LOCAL_ADDRESS_WITHOUT_PORT", ""); +} + TEST_F(StreamInfoHeaderFormatterTest, TestformatWithHostnameVariable) { { NiceMock os_sys_calls; @@ -879,6 +984,10 @@ TEST(HeaderParserTest, TestParseInternal) { {"%%%PROTOCOL%%%", {"%HTTP/1.1%"}, {}}, {"%DOWNSTREAM_REMOTE_ADDRESS%", {"127.0.0.1:0"}, {}}, {"%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%", {"127.0.0.1"}, {}}, + {"%DOWNSTREAM_REMOTE_PORT%", {"0"}, {}}, + {"%DOWNSTREAM_DIRECT_REMOTE_ADDRESS%", {"127.0.0.3:63443"}, {}}, + {"%DOWNSTREAM_DIRECT_REMOTE_ADDRESS_WITHOUT_PORT%", {"127.0.0.3"}, {}}, + {"%DOWNSTREAM_DIRECT_REMOTE_PORT%", {"63443"}, {}}, {"%DOWNSTREAM_LOCAL_ADDRESS%", {"127.0.0.2:0"}, {}}, {"%DOWNSTREAM_LOCAL_PORT%", {"0"}, {}}, {"%DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT%", {"127.0.0.2"}, {}}, @@ -891,6 +1000,11 @@ TEST(HeaderParserTest, TestParseInternal) { {"%UPSTREAM_METADATA( \t [ \t \"ns\" \t , \t \"key\" \t ] \t )%", {"value"}, {}}, {R"EOF(%UPSTREAM_METADATA(["\"quoted\"", "\"key\""])%)EOF", {"value"}, {}}, {"%UPSTREAM_REMOTE_ADDRESS%", {"10.0.0.1:443"}, {}}, + {"%UPSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%", {"10.0.0.1"}, {}}, + {"%UPSTREAM_REMOTE_PORT%", {"443"}, {}}, + {"%UPSTREAM_LOCAL_ADDRESS%", {"127.0.0.3:8443"}, {}}, + {"%UPSTREAM_LOCAL_ADDRESS_WITHOUT_PORT%", {"127.0.0.3"}, {}}, + {"%UPSTREAM_LOCAL_PORT%", {"8443"}, {}}, {"%REQUESTED_SERVER_NAME%", {"foo.bar"}, {}}, {"%VIRTUAL_CLUSTER_NAME%", {"authN"}, {}}, {"%PER_REQUEST_STATE(testing)%", {"test_value"}, {}}, @@ -1000,6 +1114,9 @@ TEST(HeaderParserTest, TestParseInternal) { std::shared_ptr> host( new NiceMock()); stream_info.upstreamInfo()->setUpstreamHost(host); + auto local_address = Network::Address::InstanceConstSharedPtr{ + new Network::Address::Ipv4Instance("127.0.0.3", 8443)}; + stream_info.upstreamInfo()->setUpstreamLocalAddress(local_address); Http::TestRequestHeaderMapImpl request_headers; request_headers.addCopy(Http::LowerCaseString(std::string("x-request-id")), 123); @@ -1080,6 +1197,9 @@ match: { prefix: "/new_endpoint" } - header: key: "x-client-ip-port" value: "%DOWNSTREAM_REMOTE_ADDRESS%" + - header: + key: "x-client-port" + value: "%DOWNSTREAM_REMOTE_PORT%" append: true )EOF"; @@ -1090,6 +1210,7 @@ match: { prefix: "/new_endpoint" } req_header_parser->evaluateHeaders(header_map, stream_info); EXPECT_TRUE(header_map.has("x-client-ip")); EXPECT_TRUE(header_map.has("x-client-ip-port")); + EXPECT_TRUE(header_map.has("x-client-port")); } TEST(HeaderParserTest, EvaluateHeadersWithNullStreamInfo) { @@ -1106,6 +1227,9 @@ match: { prefix: "/new_endpoint" } - header: key: "x-client-ip-port" value: "%DOWNSTREAM_REMOTE_ADDRESS%" + - header: + key: "x-client-port" + value: "%DOWNSTREAM_REMOTE_PORT%" append: true )EOF"; @@ -1115,8 +1239,10 @@ match: { prefix: "/new_endpoint" } req_header_parser->evaluateHeaders(header_map, nullptr); EXPECT_TRUE(header_map.has("x-client-ip")); EXPECT_TRUE(header_map.has("x-client-ip-port")); + EXPECT_TRUE(header_map.has("x-client-port")); EXPECT_EQ("%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%", header_map.get_("x-client-ip")); EXPECT_EQ("%DOWNSTREAM_REMOTE_ADDRESS%", header_map.get_("x-client-ip-port")); + EXPECT_EQ("%DOWNSTREAM_REMOTE_PORT%", header_map.get_("x-client-port")); } TEST(HeaderParserTest, EvaluateHeaderValuesWithNullStreamInfo) { diff --git a/test/extensions/access_loggers/grpc/http_grpc_access_log_impl_test.cc b/test/extensions/access_loggers/grpc/http_grpc_access_log_impl_test.cc index d0750d2edee8..f1ca7bde316c 100644 --- a/test/extensions/access_loggers/grpc/http_grpc_access_log_impl_test.cc +++ b/test/extensions/access_loggers/grpc/http_grpc_access_log_impl_test.cc @@ -134,12 +134,16 @@ class HttpGrpcAccessLogTest : public testing::Test { port_value: 0 downstream_direct_remote_address: socket_address: - address: "127.0.0.1" - port_value: 0 + address: "127.0.0.3" + port_value: 63443 downstream_local_address: socket_address: address: "127.0.0.2" port_value: 0 + upstream_local_address: + socket_address: + address: "127.1.2.3" + port_value: 58443 start_time: seconds: 3600 request: @@ -208,11 +212,15 @@ TEST_F(HttpGrpcAccessLogTest, Marshalling) { port_value: 0 downstream_direct_remote_address: socket_address: - address: "127.0.0.1" - port_value: 0 + address: "127.0.0.3" + port_value: 63443 downstream_local_address: pipe: path: "/foo" + upstream_local_address: + socket_address: + address: "127.1.2.3" + port_value: 58443 start_time: seconds: 3600 time_to_last_downstream_tx_byte: @@ -252,12 +260,16 @@ response: {} port_value: 0 downstream_direct_remote_address: socket_address: - address: "127.0.0.1" - port_value: 0 + address: "127.0.0.3" + port_value: 63443 downstream_local_address: socket_address: address: "127.0.0.2" port_value: 0 + upstream_local_address: + socket_address: + address: "127.1.2.3" + port_value: 58443 start_time: seconds: 3600 time_to_last_downstream_tx_byte: @@ -324,12 +336,16 @@ response: {} port_value: 0 downstream_direct_remote_address: socket_address: - address: "127.0.0.1" - port_value: 0 + address: "127.0.0.3" + port_value: 63443 downstream_local_address: socket_address: address: "127.0.0.2" port_value: 0 + upstream_local_address: + socket_address: + address: "127.1.2.3" + port_value: 58443 start_time: seconds: 3600 time_to_last_rx_byte: @@ -399,12 +415,16 @@ protocol_version: HTTP10 port_value: 0 downstream_direct_remote_address: socket_address: - address: "127.0.0.1" - port_value: 0 + address: "127.0.0.3" + port_value: 63443 downstream_local_address: socket_address: address: "127.0.0.2" port_value: 0 + upstream_local_address: + socket_address: + address: "127.1.2.3" + port_value: 58443 start_time: seconds: 3600 upstream_transport_failure_reason: "TLS error" @@ -451,12 +471,16 @@ response: {} port_value: 0 downstream_direct_remote_address: socket_address: - address: "127.0.0.1" - port_value: 0 + address: "127.0.0.3" + port_value: 63443 downstream_local_address: socket_address: address: "127.0.0.2" port_value: 0 + upstream_local_address: + socket_address: + address: "127.1.2.3" + port_value: 58443 start_time: seconds: 3600 tls_properties: @@ -511,12 +535,16 @@ response: {} port_value: 0 downstream_direct_remote_address: socket_address: - address: "127.0.0.1" - port_value: 0 + address: "127.0.0.3" + port_value: 63443 downstream_local_address: socket_address: address: "127.0.0.2" port_value: 0 + upstream_local_address: + socket_address: + address: "127.1.2.3" + port_value: 58443 start_time: seconds: 3600 tls_properties: @@ -561,12 +589,16 @@ response: {} port_value: 0 downstream_direct_remote_address: socket_address: - address: "127.0.0.1" - port_value: 0 + address: "127.0.0.3" + port_value: 63443 downstream_local_address: socket_address: address: "127.0.0.2" port_value: 0 + upstream_local_address: + socket_address: + address: "127.1.2.3" + port_value: 58443 start_time: seconds: 3600 tls_properties: @@ -611,12 +643,16 @@ response: {} port_value: 0 downstream_direct_remote_address: socket_address: - address: "127.0.0.1" - port_value: 0 + address: "127.0.0.3" + port_value: 63443 downstream_local_address: socket_address: address: "127.0.0.2" port_value: 0 + upstream_local_address: + socket_address: + address: "127.1.2.3" + port_value: 58443 start_time: seconds: 3600 tls_properties: @@ -661,12 +697,16 @@ response: {} port_value: 0 downstream_direct_remote_address: socket_address: - address: "127.0.0.1" - port_value: 0 + address: "127.0.0.3" + port_value: 63443 downstream_local_address: socket_address: address: "127.0.0.2" port_value: 0 + upstream_local_address: + socket_address: + address: "127.1.2.3" + port_value: 58443 start_time: seconds: 3600 tls_properties: @@ -738,12 +778,16 @@ TEST_F(HttpGrpcAccessLogTest, MarshallingAdditionalHeaders) { port_value: 0 downstream_direct_remote_address: socket_address: - address: "127.0.0.1" - port_value: 0 + address: "127.0.0.3" + port_value: 63443 downstream_local_address: socket_address: address: "127.0.0.2" port_value: 0 + upstream_local_address: + socket_address: + address: "127.1.2.3" + port_value: 58443 start_time: seconds: 3600 request: @@ -808,12 +852,16 @@ tag: ltag port_value: 0 downstream_direct_remote_address: socket_address: - address: "127.0.0.1" - port_value: 0 + address: "127.0.0.3" + port_value: 63443 upstream_remote_address: socket_address: address: "10.0.0.1" port_value: 443 + upstream_local_address: + socket_address: + address: "127.1.2.3" + port_value: 58443 upstream_cluster: "fake_cluster" start_time: seconds: 3600 @@ -859,6 +907,10 @@ tag: mtag socket_address: address: "10.0.0.1" port_value: 443 + upstream_local_address: + socket_address: + address: "127.1.2.3" + port_value: 58443 upstream_cluster: fake_cluster downstream_local_address: socket_address: @@ -866,8 +918,8 @@ tag: mtag port_value: 0 downstream_direct_remote_address: socket_address: - address: "127.0.0.1" - port_value: 0 + address: "127.0.0.3" + port_value: 63443 start_time: seconds: 3600 custom_tags: @@ -909,6 +961,10 @@ tag: mtag socket_address: address: "10.0.0.1" port_value: 443 + upstream_local_address: + socket_address: + address: "127.1.2.3" + port_value: 58443 upstream_cluster: fake_cluster downstream_local_address: socket_address: @@ -916,8 +972,8 @@ tag: mtag port_value: 0 downstream_direct_remote_address: socket_address: - address: "127.0.0.1" - port_value: 0 + address: "127.0.0.3" + port_value: 63443 start_time: seconds: 3600 custom_tags: diff --git a/test/mocks/stream_info/mocks.cc b/test/mocks/stream_info/mocks.cc index 528ec13a3c89..810536397cd4 100644 --- a/test/mocks/stream_info/mocks.cc +++ b/test/mocks/stream_info/mocks.cc @@ -21,10 +21,22 @@ MockStreamInfo::MockStreamInfo() downstream_connection_info_provider_(std::make_shared( std::make_shared("127.0.0.2"), std::make_shared("127.0.0.1"))) { + // downstream:direct_remote + auto downstream_direct_remote_address = Network::Address::InstanceConstSharedPtr{ + new Network::Address::Ipv4Instance("127.0.0.3", 63443)}; + downstream_connection_info_provider_->setDirectRemoteAddressForTest( + downstream_direct_remote_address); + // upstream upstream_info_ = std::make_unique(); + // upstream:host Upstream::HostDescriptionConstSharedPtr host{ new testing::NiceMock()}; upstream_info_->setUpstreamHost(host); + // upstream:local + auto upstream_local_address = Network::Address::InstanceConstSharedPtr{ + new Network::Address::Ipv4Instance("127.1.2.3", 58443)}; + upstream_info_->setUpstreamLocalAddress(upstream_local_address); + ON_CALL(*this, setResponseFlag(_)).WillByDefault(Invoke([this](ResponseFlag response_flag) { response_flags_ |= response_flag; }));