Skip to content

Commit

Permalink
feature: make always accessible the original downstream local address (
Browse files Browse the repository at this point in the history
…#36920)

Signed-off-by: Florent Lecoultre <[email protected]>
  • Loading branch information
fl0Lec authored Nov 18, 2024
1 parent e2cec22 commit 090e73d
Show file tree
Hide file tree
Showing 10 changed files with 163 additions and 11 deletions.
38 changes: 36 additions & 2 deletions docs/root/configuration/observability/access_log/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -735,17 +735,51 @@ UDP
.. note::

This may not be the physical remote address of the peer if the address has been inferred from
:ref:`Proxy Protocol filter <config_listener_filters_proxy_protocol>` or :ref:`x-forwarded-for
<config_http_conn_man_headers_x-forwarded-for>`.
:ref:`Proxy Protocol filter <config_listener_filters_proxy_protocol>`.

%DOWNSTREAM_DIRECT_LOCAL_ADDRESS%
Direct local address of the downstream connection.

.. note::

This is always the physical local address even if the downstream remote address has been inferred from
:ref:`Proxy Protocol filter <config_listener_filters_proxy_protocol>`.

%DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT%
Local 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 local address if the downstream local address has been inferred from
:ref:`Proxy Protocol filter <config_listener_filters_proxy_protocol>`.

%DOWNSTREAM_DIRECT_LOCAL_ADDRESS_WITHOUT_PORT%
Direct local address of the downstream connection, without any port component.

.. note::

This is always the physical local address even if the downstream local address has been inferred from
:ref:`Proxy Protocol filter <config_listener_filters_proxy_protocol>`.

%DOWNSTREAM_LOCAL_PORT%
Local port of the downstream connection.
IP addresses are the only address type with a port component.

.. note::

This may not be the physical port if the downstream local address has been inferred from
:ref:`Proxy Protocol filter <config_listener_filters_proxy_protocol>`.

%DOWNSTREAM_DIRECT_LOCAL_PORT%
Direct local port of the downstream connection.
IP addresses are the only address type with a port component.

.. note::

This is always the listener port even if the downstream local address has been inferred from
:ref:`Proxy Protocol filter <config_listener_filters_proxy_protocol>`.

.. _config_access_log_format_connection_id:

%CONNECTION_ID%
Expand Down
6 changes: 6 additions & 0 deletions envoy/network/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,12 @@ class ConnectionInfoProvider {
*/
virtual const Address::InstanceConstSharedPtr& localAddress() const PURE;

/**
* @return the direct local address of the socket. This is the listener address and it can not be
* modified by listener filters.
*/
virtual const Address::InstanceConstSharedPtr& directLocalAddress() const PURE;

/**
* @return true if the local address has been restored to a value that is different from the
* address the socket was initially accepted at.
Expand Down
26 changes: 26 additions & 0 deletions source/common/formatter/stream_info_formatter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -823,6 +823,7 @@ using StreamInfoFormatterProviderLookupTable =
absl::flat_hash_map<absl::string_view, std::pair<CommandSyntaxChecker::CommandSyntaxFlags,
StreamInfoFormatterProviderCreateFunc>>;

// clang-format off
const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProviders() {
CONSTRUCT_ON_FIRST_USE(
StreamInfoFormatterProviderLookupTable,
Expand Down Expand Up @@ -1298,6 +1299,14 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide
return stream_info.downstreamAddressProvider().localAddress();
});
}}},
{"DOWNSTREAM_DIRECT_LOCAL_ADDRESS",
{CommandSyntaxChecker::COMMAND_ONLY,
[](absl::string_view, absl::optional<size_t>) {
return StreamInfoAddressFormatterProvider::withPort(
[](const StreamInfo::StreamInfo& stream_info) {
return stream_info.downstreamAddressProvider().directLocalAddress();
});
}}},
{"DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT",
{CommandSyntaxChecker::COMMAND_ONLY,
[](absl::string_view, absl::optional<size_t>) {
Expand All @@ -1306,6 +1315,14 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide
return stream_info.downstreamAddressProvider().localAddress();
});
}}},
{"DOWNSTREAM_DIRECT_LOCAL_ADDRESS_WITHOUT_PORT",
{CommandSyntaxChecker::COMMAND_ONLY,
[](absl::string_view, absl::optional<size_t>) {
return StreamInfoAddressFormatterProvider::withoutPort(
[](const Envoy::StreamInfo::StreamInfo& stream_info) {
return stream_info.downstreamAddressProvider().directLocalAddress();
});
}}},
{"DOWNSTREAM_LOCAL_PORT",
{CommandSyntaxChecker::COMMAND_ONLY,
[](absl::string_view, absl::optional<size_t>) {
Expand All @@ -1314,6 +1331,14 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide
return stream_info.downstreamAddressProvider().localAddress();
});
}}},
{"DOWNSTREAM_DIRECT_LOCAL_PORT",
{CommandSyntaxChecker::COMMAND_ONLY,
[](absl::string_view, absl::optional<size_t>) {
return StreamInfoAddressFormatterProvider::justPort(
[](const Envoy::StreamInfo::StreamInfo& stream_info) {
return stream_info.downstreamAddressProvider().directLocalAddress();
});
}}},
{"DOWNSTREAM_REMOTE_ADDRESS",
{CommandSyntaxChecker::COMMAND_ONLY,
[](absl::string_view, absl::optional<size_t>) {
Expand Down Expand Up @@ -1861,6 +1886,7 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide
}}},
});
}
// clang-format on

class BuiltInStreamInfoCommandParser : public StreamInfoCommandParser {
public:
Expand Down
3 changes: 3 additions & 0 deletions source/common/http/filter_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,9 @@ class OverridableRemoteConnectionInfoSetterStreamInfo : public StreamInfo::Strea
const Network::Address::InstanceConstSharedPtr& localAddress() const override {
return StreamInfoImpl::downstreamAddressProvider().localAddress();
}
const Network::Address::InstanceConstSharedPtr& directLocalAddress() const override {
return StreamInfoImpl::downstreamAddressProvider().directLocalAddress();
}
bool localAddressRestored() const override {
return StreamInfoImpl::downstreamAddressProvider().localAddressRestored();
}
Expand Down
8 changes: 6 additions & 2 deletions source/common/network/socket_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ class ConnectionInfoSetterImpl : public ConnectionInfoSetter {
public:
ConnectionInfoSetterImpl(const Address::InstanceConstSharedPtr& local_address,
const Address::InstanceConstSharedPtr& remote_address)
: local_address_(local_address), remote_address_(remote_address),
direct_remote_address_(remote_address) {}
: local_address_(local_address), direct_local_address_(local_address),
remote_address_(remote_address), direct_remote_address_(remote_address) {}

void setDirectRemoteAddressForTest(const Address::InstanceConstSharedPtr& direct_remote_address) {
direct_remote_address_ = direct_remote_address;
Expand All @@ -32,6 +32,9 @@ class ConnectionInfoSetterImpl : public ConnectionInfoSetter {

// ConnectionInfoSetter
const Address::InstanceConstSharedPtr& localAddress() const override { return local_address_; }
const Address::InstanceConstSharedPtr& directLocalAddress() const override {
return direct_local_address_;
}
void setLocalAddress(const Address::InstanceConstSharedPtr& local_address) override {
local_address_ = local_address;
}
Expand Down Expand Up @@ -89,6 +92,7 @@ class ConnectionInfoSetterImpl : public ConnectionInfoSetter {

private:
Address::InstanceConstSharedPtr local_address_;
Address::InstanceConstSharedPtr direct_local_address_;
bool local_address_restored_{false};
Address::InstanceConstSharedPtr remote_address_;
Address::InstanceConstSharedPtr direct_remote_address_;
Expand Down
7 changes: 7 additions & 0 deletions source/extensions/filters/http/lua/wrappers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,13 @@ int StreamInfoWrapper::luaDownstreamLocalAddress(lua_State* state) {
return 1;
}

int StreamInfoWrapper::luaDownstreamDirectLocalAddress(lua_State* state) {
const std::string& local_address =
stream_info_.downstreamAddressProvider().directLocalAddress()->asString();
lua_pushlstring(state, local_address.data(), local_address.size());
return 1;
}

int StreamInfoWrapper::luaDownstreamDirectRemoteAddress(lua_State* state) {
const std::string& direct_remote_address =
stream_info_.downstreamAddressProvider().directRemoteAddress()->asString();
Expand Down
8 changes: 8 additions & 0 deletions source/extensions/filters/http/lua/wrappers.h
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ class StreamInfoWrapper : public Filters::Common::Lua::BaseLuaObject<StreamInfoW
static ExportedFunctions exportedFunctions() {
return {{"protocol", static_luaProtocol},
{"dynamicMetadata", static_luaDynamicMetadata},
{"downstreamDirectLocalAddress", static_luaDownstreamDirectLocalAddress},
{"downstreamLocalAddress", static_luaDownstreamLocalAddress},
{"downstreamDirectRemoteAddress", static_luaDownstreamDirectRemoteAddress},
{"downstreamRemoteAddress", static_luaDownstreamRemoteAddress},
Expand Down Expand Up @@ -301,6 +302,13 @@ class StreamInfoWrapper : public Filters::Common::Lua::BaseLuaObject<StreamInfoW
*/
DECLARE_LUA_FUNCTION(StreamInfoWrapper, luaDownstreamLocalAddress);

/**
* Get current direct downstream local address
* @return string representation of downstream directly connected local address.
* This is equivalent to the local address of the physical connection.
*/
DECLARE_LUA_FUNCTION(StreamInfoWrapper, luaDownstreamDirectLocalAddress);

/**
* Get current direct downstream remote address
* @return string representation of downstream directly connected address.
Expand Down
66 changes: 59 additions & 7 deletions test/common/formatter/substitution_formatter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,18 @@ TEST(SubstitutionFormatterTest, streamInfoFormatter) {
ProtoEq(ValueUtil::stringValue("127.0.0.2:0")));
}

{
StreamInfoFormatter format("DOWNSTREAM_DIRECT_LOCAL_ADDRESS");
auto address = Network::Address::InstanceConstSharedPtr{new Network::Address::Ipv4Instance(
"127.1.2.3", 6745)},
original_address = stream_info.downstream_connection_info_provider_->localAddress();
stream_info.downstream_connection_info_provider_->setLocalAddress(address);
EXPECT_EQ("127.0.0.2:0", format.formatWithContext({}, stream_info));
EXPECT_THAT(format.formatValueWithContext({}, stream_info),
ProtoEq(ValueUtil::stringValue("127.0.0.2:0")));
stream_info.downstream_connection_info_provider_->setLocalAddress(original_address);
}

{
StreamInfoFormatter upstream_format("DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT");
EXPECT_EQ("127.0.0.2", upstream_format.formatWithContext({}, stream_info));
Expand All @@ -871,31 +883,71 @@ TEST(SubstitutionFormatterTest, streamInfoFormatter) {
}

{
StreamInfoFormatter upstream_format("DOWNSTREAM_LOCAL_PORT");
StreamInfoFormatter format("DOWNSTREAM_DIRECT_LOCAL_ADDRESS_WITHOUT_PORT");
EXPECT_EQ("127.0.0.2", format.formatWithContext({}, stream_info));
EXPECT_THAT(format.formatValueWithContext({}, stream_info),
ProtoEq(ValueUtil::stringValue("127.0.0.2")));
}

{
StreamInfoFormatter format("DOWNSTREAM_DIRECT_LOCAL_ADDRESS_WITHOUT_PORT");
auto address = Network::Address::InstanceConstSharedPtr{
new Network::Address::Ipv4Instance("127.1.2.3", 8900)};
stream_info.downstream_connection_info_provider_->setLocalAddress(address);
EXPECT_EQ("127.0.0.2", format.formatWithContext({}, stream_info));
EXPECT_THAT(format.formatValueWithContext({}, stream_info),
ProtoEq(ValueUtil::stringValue("127.0.0.2")));
}

{
StreamInfoFormatter format("DOWNSTREAM_DIRECT_LOCAL_PORT");
EXPECT_EQ("0", format.formatWithContext({}, stream_info));
EXPECT_THAT(format.formatValueWithContext({}, stream_info), ProtoEq(ValueUtil::numberValue(0)));
}

{
StreamInfoFormatter downstream_local_port_format("DOWNSTREAM_LOCAL_PORT"),
downstream_direct_downstream_local_port_format("DOWNSTREAM_DIRECT_LOCAL_PORT");

// 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);
EXPECT_EQ("8443", upstream_format.formatWithContext({}, stream_info));
EXPECT_THAT(upstream_format.formatValueWithContext({}, stream_info),
EXPECT_EQ("8443", downstream_local_port_format.formatWithContext({}, stream_info));
EXPECT_THAT(downstream_local_port_format.formatValueWithContext({}, stream_info),
ProtoEq(ValueUtil::numberValue(8443)));

EXPECT_EQ("0",
downstream_direct_downstream_local_port_format.formatWithContext({}, stream_info));
EXPECT_THAT(
downstream_direct_downstream_local_port_format.formatValueWithContext({}, stream_info),
ProtoEq(ValueUtil::numberValue(0)));

// Validate for IPv6 address
address =
Network::Address::InstanceConstSharedPtr{new Network::Address::Ipv6Instance("::1", 9443)};
stream_info.downstream_connection_info_provider_->setLocalAddress(address);
EXPECT_EQ("9443", upstream_format.formatWithContext({}, stream_info));
EXPECT_THAT(upstream_format.formatValueWithContext({}, stream_info),
EXPECT_EQ("9443", downstream_local_port_format.formatWithContext({}, stream_info));
EXPECT_THAT(downstream_local_port_format.formatValueWithContext({}, stream_info),
ProtoEq(ValueUtil::numberValue(9443)));

EXPECT_EQ("0",
downstream_direct_downstream_local_port_format.formatWithContext({}, stream_info));
EXPECT_THAT(
downstream_direct_downstream_local_port_format.formatValueWithContext({}, stream_info),
ProtoEq(ValueUtil::numberValue(0)));
// Validate for Pipe
address =
Network::Address::InstanceConstSharedPtr{*Network::Address::PipeInstance::create("/foo")};
stream_info.downstream_connection_info_provider_->setLocalAddress(address);
EXPECT_EQ("", upstream_format.formatWithContext({}, stream_info));
EXPECT_THAT(upstream_format.formatValueWithContext({}, stream_info),
EXPECT_EQ("", downstream_local_port_format.formatWithContext({}, stream_info));
EXPECT_THAT(downstream_local_port_format.formatValueWithContext({}, stream_info),
ProtoEq(ValueUtil::nullValue()));
EXPECT_EQ("0",
downstream_direct_downstream_local_port_format.formatWithContext({}, stream_info));
EXPECT_THAT(
downstream_direct_downstream_local_port_format.formatValueWithContext({}, stream_info),
ProtoEq(ValueUtil::numberValue(0)));
}

{
Expand Down
3 changes: 3 additions & 0 deletions test/common/router/header_formatter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ TEST(HeaderParserTest, TestParse) {
{"%DOWNSTREAM_LOCAL_ADDRESS%", {"127.0.0.2:0"}, {}},
{"%DOWNSTREAM_LOCAL_PORT%", {"0"}, {}},
{"%DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT%", {"127.0.0.2"}, {}},
{"%DOWNSTREAM_DIRECT_LOCAL_ADDRESS%", {"127.0.0.2:0"}, {}},
{"%DOWNSTREAM_DIRECT_LOCAL_PORT%", {"0"}, {}},
{"%DOWNSTREAM_DIRECT_LOCAL_ADDRESS_WITHOUT_PORT%", {"127.0.0.2"}, {}},
{"%UPSTREAM_METADATA([\"ns\", \"key\"])%", {"value"}, {}},
{"[%UPSTREAM_METADATA([\"ns\", \"key\"])%", {"[value"}, {}},
{"%UPSTREAM_METADATA([\"ns\", \"key\"])%]", {"value]"}, {}},
Expand Down
9 changes: 9 additions & 0 deletions test/extensions/filters/http/lua/lua_integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,8 @@ name: lua
end
request_handle:headers():add("request_protocol", request_handle:streamInfo():protocol())
request_handle:headers():add("request_dynamic_metadata_value", dynamic_metadata_value)
request_handle:headers():add("request_downstream_direct_local_address_value",
request_handle:streamInfo():downstreamDirectLocalAddress())
request_handle:headers():add("request_downstream_local_address_value",
request_handle:streamInfo():downstreamLocalAddress())
request_handle:headers():add("request_downstream_directremote_address_value",
Expand Down Expand Up @@ -408,6 +410,13 @@ name: lua
->value()
.getStringView());

EXPECT_TRUE(absl::StrContains(
upstream_request_->headers()
.get(Http::LowerCaseString("request_downstream_direct_local_address_value"))[0]
->value()
.getStringView(),
GetParam() == Network::Address::IpVersion::v4 ? "127.0.0.1:" : "[::1]:"));

EXPECT_TRUE(
absl::StrContains(upstream_request_->headers()
.get(Http::LowerCaseString("request_downstream_local_address_value"))[0]
Expand Down

0 comments on commit 090e73d

Please sign in to comment.