Skip to content
Merged
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
5 changes: 5 additions & 0 deletions changelogs/current.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,10 @@ removed_config_or_runtime:
# *Normally occurs at the end of the* :ref:`deprecation period <deprecated>`

new_features:
- area: formatter
change: |
Extended ``*_WITHOUT_PORT`` address formatters to accept an optional ``MASK_PREFIX_LEN`` parameter that masks IP addresses
and returns them in CIDR notation (e.g., ``%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT(16)%`` returns ``10.1.0.0/16`` for
client IP ``10.1.10.23``).

deprecated:
78 changes: 72 additions & 6 deletions docs/root/configuration/advanced/substitution_formatter.rst
Original file line number Diff line number Diff line change
Expand Up @@ -561,10 +561,21 @@ Current supported substitution commands include:
Local address of the upstream connection. If the address is an IP address, it includes both
address and port.

``%UPSTREAM_LOCAL_ADDRESS_WITHOUT_PORT%``
``%UPSTREAM_LOCAL_ADDRESS_WITHOUT_PORT(MASK_PREFIX_LEN)%``
Local address of the upstream connection, without any port component.
IP addresses are the only address type with a port component.

- If ``MASK_PREFIX_LEN`` is specified, the IP address is masked to that many bits and returned in CIDR notation.
- If ``MASK_PREFIX_LEN`` is omitted, the unmasked address is returned (without port).
- For IPv4, ``MASK_PREFIX_LEN`` must be between 0-32.
- For IPv6, ``MASK_PREFIX_LEN`` must be between 0-128.

Examples:

- ``%UPSTREAM_LOCAL_ADDRESS_WITHOUT_PORT(16)%`` returns ``10.1.0.0/16`` for source IP ``10.1.10.23``
- ``%UPSTREAM_LOCAL_ADDRESS_WITHOUT_PORT(64)%`` returns ``2001:db8:1234:5678::/64`` for source IP ``2001:db8:1234:5678:9abc:def0:1234:5678``
- ``%UPSTREAM_LOCAL_ADDRESS_WITHOUT_PORT%`` returns ``10.1.10.23`` for source IP ``10.1.10.23``

``%UPSTREAM_LOCAL_PORT%``
Local port of the upstream connection.
IP addresses are the only address type with a port component.
Expand All @@ -576,10 +587,21 @@ Current supported substitution commands include:
address and port. Identical to the :ref:`UPSTREAM_HOST <config_access_log_format_upstream_host>` value if the upstream
host only has one address and connection is established successfully.

``%UPSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%``
``%UPSTREAM_REMOTE_ADDRESS_WITHOUT_PORT(MASK_PREFIX_LEN)%``
Remote address of the upstream connection, without any port component.
IP addresses are the only address type with a port component.

- If ``MASK_PREFIX_LEN`` is specified, the IP address is masked to that many bits and returned in CIDR notation.
- If ``MASK_PREFIX_LEN`` is omitted, the unmasked address is returned (without port).
- For IPv4, ``MASK_PREFIX_LEN`` must be between 0-32.
- For IPv6, ``MASK_PREFIX_LEN`` must be between 0-128.

Examples:

- ``%UPSTREAM_REMOTE_ADDRESS_WITHOUT_PORT(16)%`` returns ``10.1.0.0/16`` for upstream IP ``10.1.10.23``
- ``%UPSTREAM_REMOTE_ADDRESS_WITHOUT_PORT(64)%`` returns ``2001:db8:1234:5678::/64`` for upstream IP ``2001:db8:1234:5678:9abc:def0:1234:5678``
- ``%UPSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%`` returns ``10.1.10.23`` for upstream IP ``10.1.10.23``

``%UPSTREAM_REMOTE_PORT%``
Remote port of the upstream connection.
IP addresses are the only address type with a port component.
Expand Down Expand Up @@ -624,10 +646,21 @@ Current supported substitution commands include:
:ref:`Proxy Protocol filter <config_listener_filters_proxy_protocol>` or :ref:`x-forwarded-for
<config_http_conn_man_headers_x-forwarded-for>`.

``%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%``
``%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT(MASK_PREFIX_LEN)%``
Remote address of the downstream connection, without any port component.
IP addresses are the only address type with a port component.

- If ``MASK_PREFIX_LEN`` is specified, the IP address is masked to that many bits and returned in CIDR notation.
- If ``MASK_PREFIX_LEN`` is omitted, the unmasked address is returned (without port).
- For IPv4, ``MASK_PREFIX_LEN`` must be between 0-32.
- For IPv6, ``MASK_PREFIX_LEN`` must be between 0-128.

Examples:

- ``%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT(16)%`` returns ``10.1.0.0/16`` for client IP ``10.1.10.23``
- ``%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT(64)%`` returns ``2001:db8:1234:5678::/64`` for client IP ``2001:db8:1234:5678:9abc:def0:1234:5678``
- ``%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%`` returns ``10.1.10.23`` for client IP ``10.1.10.23``

.. note::

This may not be the physical remote address of the peer if the address has been inferred from
Expand All @@ -654,10 +687,21 @@ Current supported substitution commands include:
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>`.

``%DOWNSTREAM_DIRECT_REMOTE_ADDRESS_WITHOUT_PORT%``
``%DOWNSTREAM_DIRECT_REMOTE_ADDRESS_WITHOUT_PORT(MASK_PREFIX_LEN)%``
Direct remote address of the downstream connection, without any port component.
IP addresses are the only address type with a port component.

- If ``MASK_PREFIX_LEN`` is specified, the IP address is masked to that many bits and returned in CIDR notation.
- If ``MASK_PREFIX_LEN`` is omitted, the unmasked address is returned (without port).
- For IPv4, ``MASK_PREFIX_LEN`` must be between 0-32.
- For IPv6, ``MASK_PREFIX_LEN`` must be between 0-128.

Examples:

- ``%DOWNSTREAM_DIRECT_REMOTE_ADDRESS_WITHOUT_PORT(16)%`` returns ``10.1.0.0/16`` for client IP ``10.1.10.23``
- ``%DOWNSTREAM_DIRECT_REMOTE_ADDRESS_WITHOUT_PORT(64)%`` returns ``2001:db8:1234:5678::/64`` for client IP ``2001:db8:1234:5678:9abc:def0:1234:5678``
- ``%DOWNSTREAM_DIRECT_REMOTE_ADDRESS_WITHOUT_PORT%`` returns ``10.1.10.23`` for client IP ``10.1.10.23``

.. note::

This is always the physical remote address of the peer even if the downstream remote address has
Expand Down Expand Up @@ -697,18 +741,40 @@ Current supported substitution commands include:
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%``
``%DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT(MASK_PREFIX_LEN)%``
Local address of the downstream connection, without any port component.
IP addresses are the only address type with a port component.

- If ``MASK_PREFIX_LEN`` is specified, the IP address is masked to that many bits and returned in CIDR notation.
- If ``MASK_PREFIX_LEN`` is omitted, the unmasked address is returned (without port).
- For IPv4, ``MASK_PREFIX_LEN`` must be between 0-32.
- For IPv6, ``MASK_PREFIX_LEN`` must be between 0-128.

Examples:

- ``%DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT(16)%`` returns ``10.1.0.0/16`` for local IP ``10.1.10.23``
- ``%DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT(64)%`` returns ``2001:db8:1234:5678::/64`` for local IP ``2001:db8:1234:5678:9abc:def0:1234:5678``
- ``%DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT%`` returns ``10.1.10.23`` for local IP ``10.1.10.23``

.. 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%``
``%DOWNSTREAM_DIRECT_LOCAL_ADDRESS_WITHOUT_PORT(MASK_PREFIX_LEN)%``
Direct local address of the downstream connection, without any port component.

- If ``MASK_PREFIX_LEN`` is specified, the IP address is masked to that many bits and returned in CIDR notation.
- If ``MASK_PREFIX_LEN`` is omitted, the unmasked address is returned (without port).
- For IPv4, ``MASK_PREFIX_LEN`` must be between 0-32.
- For IPv6, ``MASK_PREFIX_LEN`` must be between 0-128.

Examples:

- ``%DOWNSTREAM_DIRECT_LOCAL_ADDRESS_WITHOUT_PORT(16)%`` returns ``10.1.0.0/16`` for local IP ``10.1.10.23``
- ``%DOWNSTREAM_DIRECT_LOCAL_ADDRESS_WITHOUT_PORT(64)%`` returns ``2001:db8:1234:5678::/64`` for local IP ``2001:db8:1234:5678:9abc:def0:1234:5678``
- ``%DOWNSTREAM_DIRECT_LOCAL_ADDRESS_WITHOUT_PORT%`` returns ``10.1.10.23`` for local IP ``10.1.10.23``

.. note::

This is always the physical local address even if the downstream local address has been inferred from
Expand Down
97 changes: 74 additions & 23 deletions source/common/formatter/stream_info_formatter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -802,9 +802,10 @@ class StreamInfoAddressFormatterProvider : public StreamInfoFormatterProvider {
f, StreamInfoAddressFieldExtractionType::WithPort);
}

static std::unique_ptr<StreamInfoAddressFormatterProvider> withoutPort(FieldExtractor f) {
static std::unique_ptr<StreamInfoAddressFormatterProvider>
withoutPort(FieldExtractor f, absl::optional<int> mask_prefix_len = absl::nullopt) {
return std::make_unique<StreamInfoAddressFormatterProvider>(
f, StreamInfoAddressFieldExtractionType::WithoutPort);
f, StreamInfoAddressFieldExtractionType::WithoutPort, mask_prefix_len);
}

static std::unique_ptr<StreamInfoAddressFormatterProvider> justPort(FieldExtractor f) {
Expand All @@ -818,8 +819,9 @@ class StreamInfoAddressFormatterProvider : public StreamInfoFormatterProvider {
}

StreamInfoAddressFormatterProvider(FieldExtractor f,
StreamInfoAddressFieldExtractionType extraction_type)
: field_extractor_(f), extraction_type_(extraction_type) {}
StreamInfoAddressFieldExtractionType extraction_type,
absl::optional<int> mask_prefix_len = absl::nullopt)
: field_extractor_(f), extraction_type_(extraction_type), mask_prefix_len_(mask_prefix_len) {}

// StreamInfoFormatterProvider
// Don't hide the other structure of format and formatValue.
Expand Down Expand Up @@ -854,7 +856,7 @@ class StreamInfoAddressFormatterProvider : public StreamInfoFormatterProvider {
std::string toString(const Network::Address::Instance& address) const {
switch (extraction_type_) {
case StreamInfoAddressFieldExtractionType::WithoutPort:
return StreamInfo::Utility::formatDownstreamAddressNoPort(address);
return StreamInfo::Utility::formatDownstreamAddressNoPort(address, mask_prefix_len_);
case StreamInfoAddressFieldExtractionType::JustPort:
return StreamInfo::Utility::formatDownstreamAddressJustPort(address);
case StreamInfoAddressFieldExtractionType::JustEndpointId:
Expand All @@ -867,6 +869,7 @@ class StreamInfoAddressFormatterProvider : public StreamInfoFormatterProvider {

FieldExtractor field_extractor_;
const StreamInfoAddressFieldExtractionType extraction_type_;
const absl::optional<int> mask_prefix_len_;
};

// Ssl::ConnectionInfo std::string field extractor.
Expand Down Expand Up @@ -1368,16 +1371,24 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide
});
}}},
{"UPSTREAM_LOCAL_ADDRESS_WITHOUT_PORT",
{CommandSyntaxChecker::COMMAND_ONLY,
[](absl::string_view, absl::optional<size_t>) {
{CommandSyntaxChecker::PARAMS_OPTIONAL,
[](absl::string_view format, absl::optional<size_t>) {
absl::optional<int> mask_prefix_len;
if (!format.empty()) {
int len;
if (absl::SimpleAtoi(format, &len)) {
mask_prefix_len = len;
}
}
return StreamInfoAddressFormatterProvider::withoutPort(
[](const StreamInfo::StreamInfo& stream_info)
-> Network::Address::InstanceConstSharedPtr {
if (stream_info.upstreamInfo().has_value()) {
return stream_info.upstreamInfo().value().get().upstreamLocalAddress();
}
return nullptr;
});
},
mask_prefix_len);
}}},
{"UPSTREAM_LOCAL_PORT",
{CommandSyntaxChecker::COMMAND_ONLY,
Expand All @@ -1401,13 +1412,21 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide
});
}}},
{"UPSTREAM_REMOTE_ADDRESS_WITHOUT_PORT",
{CommandSyntaxChecker::COMMAND_ONLY,
[](absl::string_view, absl::optional<size_t>) {
{CommandSyntaxChecker::PARAMS_OPTIONAL,
[](absl::string_view format, absl::optional<size_t>) {
absl::optional<int> mask_prefix_len;
if (!format.empty()) {
int len;
if (absl::SimpleAtoi(format, &len)) {
mask_prefix_len = len;
}
}
return StreamInfoAddressFormatterProvider::withoutPort(
[](const StreamInfo::StreamInfo& stream_info)
-> Network::Address::InstanceConstSharedPtr {
return getUpstreamRemoteAddress(stream_info);
});
},
mask_prefix_len);
}}},
{"UPSTREAM_REMOTE_PORT",
{CommandSyntaxChecker::COMMAND_ONLY,
Expand Down Expand Up @@ -1500,20 +1519,36 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide
});
}}},
{"DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT",
{CommandSyntaxChecker::COMMAND_ONLY,
[](absl::string_view, absl::optional<size_t>) {
{CommandSyntaxChecker::PARAMS_OPTIONAL,
[](absl::string_view format, absl::optional<size_t>) {
absl::optional<int> mask_prefix_len;
if (!format.empty()) {
int len;
if (absl::SimpleAtoi(format, &len)) {
mask_prefix_len = len;
}
}
return StreamInfoAddressFormatterProvider::withoutPort(
[](const Envoy::StreamInfo::StreamInfo& stream_info) {
return stream_info.downstreamAddressProvider().localAddress();
});
},
mask_prefix_len);
}}},
{"DOWNSTREAM_DIRECT_LOCAL_ADDRESS_WITHOUT_PORT",
{CommandSyntaxChecker::COMMAND_ONLY,
[](absl::string_view, absl::optional<size_t>) {
{CommandSyntaxChecker::PARAMS_OPTIONAL,
[](absl::string_view format, absl::optional<size_t>) {
absl::optional<int> mask_prefix_len;
if (!format.empty()) {
int len;
if (absl::SimpleAtoi(format, &len)) {
mask_prefix_len = len;
}
}
return StreamInfoAddressFormatterProvider::withoutPort(
[](const Envoy::StreamInfo::StreamInfo& stream_info) {
return stream_info.downstreamAddressProvider().directLocalAddress();
});
},
mask_prefix_len);
}}},
{"DOWNSTREAM_LOCAL_PORT",
{CommandSyntaxChecker::COMMAND_ONLY,
Expand Down Expand Up @@ -1556,12 +1591,20 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide
});
}}},
{"DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT",
{CommandSyntaxChecker::COMMAND_ONLY,
[](absl::string_view, absl::optional<size_t>) {
{CommandSyntaxChecker::PARAMS_OPTIONAL,
[](absl::string_view format, absl::optional<size_t>) {
absl::optional<int> mask_prefix_len;
if (!format.empty()) {
int len;
if (absl::SimpleAtoi(format, &len)) {
mask_prefix_len = len;
}
}
return StreamInfoAddressFormatterProvider::withoutPort(
[](const StreamInfo::StreamInfo& stream_info) {
return stream_info.downstreamAddressProvider().remoteAddress();
});
},
mask_prefix_len);
}}},
{"DOWNSTREAM_REMOTE_PORT",
{CommandSyntaxChecker::COMMAND_ONLY,
Expand All @@ -1580,12 +1623,20 @@ const StreamInfoFormatterProviderLookupTable& getKnownStreamInfoFormatterProvide
});
}}},
{"DOWNSTREAM_DIRECT_REMOTE_ADDRESS_WITHOUT_PORT",
{CommandSyntaxChecker::COMMAND_ONLY,
[](absl::string_view, absl::optional<size_t>) {
{CommandSyntaxChecker::PARAMS_OPTIONAL,
[](absl::string_view format, absl::optional<size_t>) {
absl::optional<int> mask_prefix_len;
if (!format.empty()) {
int len;
if (absl::SimpleAtoi(format, &len)) {
mask_prefix_len = len;
}
}
return StreamInfoAddressFormatterProvider::withoutPort(
[](const StreamInfo::StreamInfo& stream_info) {
return stream_info.downstreamAddressProvider().directRemoteAddress();
});
},
mask_prefix_len);
}}},
{"DOWNSTREAM_DIRECT_REMOTE_PORT",
{CommandSyntaxChecker::COMMAND_ONLY,
Expand Down
1 change: 1 addition & 0 deletions source/common/stream_info/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ envoy_cc_library(
"//envoy/http:codes_interface",
"//envoy/stream_info:stream_info_interface",
"//source/common/http:default_server_string_lib",
"//source/common/network:cidr_range_lib",
"//source/common/runtime:runtime_features_lib",
"@com_google_absl//absl/container:node_hash_map",
"@com_google_absl//absl/types:optional",
Expand Down
38 changes: 32 additions & 6 deletions source/common/stream_info/utility.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
#include "envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.pb.h"

#include "source/common/http/default_server_string.h"
#include "source/common/network/cidr_range.h"
#include "source/common/runtime/runtime_features.h"

#include "absl/status/statusor.h"
#include "absl/strings/str_format.h"

namespace Envoy {
Expand Down Expand Up @@ -240,13 +242,37 @@ absl::optional<std::chrono::nanoseconds> TimingUtility::lastDownstreamAckReceive
return duration(timing.value().get().lastDownstreamAckReceived(), stream_info_);
}

const std::string&
Utility::formatDownstreamAddressNoPort(const Network::Address::Instance& address) {
if (address.type() == Network::Address::Type::Ip) {
return address.ip()->addressAsString();
} else {
return address.asString();
const std::string Utility::formatDownstreamAddressNoPort(const Network::Address::Instance& address,
absl::optional<int> mask_prefix_len) {
// No masking - return address without port
if (!mask_prefix_len.has_value()) {
if (address.type() == Network::Address::Type::Ip) {
return address.ip()->addressAsString();
} else {
return address.asString();
}
}

std::string masked_address;
if (address.type() != Network::Address::Type::Ip) {
return masked_address;
}

int length = mask_prefix_len.value_or(
address.ip()->version() == Network::Address::IpVersion::v4 ? 32 : 128);

// CidrRange::create() requires a shared_ptr. We create one with a no-op deleter since we don't
// own the address and shouldn't delete it.
Network::Address::InstanceConstSharedPtr address_ptr(&address,
[](const Network::Address::Instance*) {});

auto cidr_range_or_error =
Network::Address::CidrRange::create(address_ptr, length, absl::nullopt);

if (cidr_range_or_error.ok()) {
masked_address = cidr_range_or_error.value().asString();
}
return masked_address;
}

const std::string
Expand Down
Loading
Loading