-
Notifications
You must be signed in to change notification settings - Fork 5.1k
xff: add support for configuring a list of trusted CIDRs #31831
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 41 commits
70893bc
37f82b8
5f390fd
831057e
b32b10d
b37899d
34e7d33
61ade56
0cf5c6c
4c0ff3f
d9f1a64
5842f38
2c95c9f
a016a6c
eb2f7ff
1f76584
994d4be
ebb1391
d976354
666757e
4193f48
a587a23
06eccf5
87bf560
2c15af4
901335a
6833c32
26756eb
6671ece
5ed4660
c69df1c
eab825a
9cfe9d6
774cacc
5c2cbf2
e4ff49e
e2fdae2
9a625aa
0267706
3dd64cc
a9432b4
bfaa8b3
1055b01
7721581
837cd5f
a80178e
aec2db5
57baab7
7344aa8
277fefd
91903c9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,10 @@ syntax = "proto3"; | |
|
|
||
| package envoy.extensions.http.original_ip_detection.xff.v3; | ||
|
|
||
| import "envoy/config/core/v3/address.proto"; | ||
|
|
||
| import "google/protobuf/wrappers.proto"; | ||
|
|
||
| import "udpa/annotations/status.proto"; | ||
|
|
||
| option java_package = "io.envoyproxy.envoy.extensions.http.original_ip_detection.xff.v3"; | ||
|
|
@@ -22,5 +26,49 @@ message XffConfig { | |
| // determining the origin client's IP address. The default is zero if this option | ||
| // is not specified. See the documentation for | ||
| // :ref:`config_http_conn_man_headers_x-forwarded-for` for more information. | ||
| // | ||
| // Only one of ``xff_num_trusted_hops`` and ``xff_trusted_cidrs`` should be set. | ||
| // If ``xff_trusted_cidrs`` is set, this field is ignored. | ||
| uint32 xff_num_trusted_hops = 1; | ||
|
|
||
| // The `CIDR <https://tools.ietf.org/html/rfc4632>`_ ranges to trust when | ||
| // evaluating the remote IP address to determine the original client's IP address. | ||
| // This is used instead of | ||
| // :ref:`use_remote_address <envoy_v3_api_field_extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.use_remote_address>`. | ||
| // When the remote IP address matches a trusted CIDR and the | ||
| // :ref:`config_http_conn_man_headers_x-forwarded-for` header was sent, each entry | ||
| // in the ``x-forwarded-for`` header is evaluated from right to left and the first | ||
| // public non-trusted address is used as the original client address. If all | ||
| // addresses in ``x-forwarded-for`` are within the trusted list, the first (leftmost) | ||
| // entry is used. | ||
| // | ||
| // This is typically used when requests are proxied by a | ||
| // `CDN <https://en.wikipedia.org/wiki/Content_delivery_network>`_. | ||
| // | ||
| // Only one of ``xff_num_trusted_hops`` and ``xff_trusted_cidrs`` should be set. | ||
| // If set, takes precedence over ``xff_num_trusted_hops``. | ||
| XffTrustedCidrs xff_trusted_cidrs = 2; | ||
|
|
||
| // If set, Envoy will not append the remote address to the | ||
| // :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header. | ||
| // | ||
| // .. attention:: | ||
| // | ||
| // For proper proxy behaviour it is not recommended to set this option. | ||
| // For backwards compatibility, if this option is unset and | ||
| // ``xff_num_trusted_hops`` is set, it defaults to true. When | ||
| // ``xff_trusted_cidrs`` is set, it defaults to false. | ||
|
||
| // | ||
| // This only applies when :ref:`use_remote_address | ||
| // <envoy_v3_api_field_extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.use_remote_address>` | ||
| // is false, otherwise :ref:`skip_xff_append | ||
| // <envoy_v3_api_field_extensions.filters.network.http_connection_manager.v3.HttpConnectionManager.skip_xff_append>` | ||
| // applies. | ||
| google.protobuf.BoolValue skip_xff_append = 3; | ||
wbpcode marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| message XffTrustedCidrs { | ||
mattklein123 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // The list of `CIDRs <https://tools.ietf.org/html/rfc4632>`_ from which remote | ||
| // connections are considered trusted. | ||
| repeated config.core.v3.CidrRange cidrs = 1; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,7 @@ | |
| #include "source/common/http/header_map_impl.h" | ||
| #include "source/common/http/headers.h" | ||
| #include "source/common/http/message_impl.h" | ||
| #include "source/common/network/cidr_range.h" | ||
| #include "source/common/network/utility.h" | ||
| #include "source/common/protobuf/utility.h" | ||
| #include "source/common/runtime/runtime_features.h" | ||
|
|
@@ -756,6 +757,53 @@ void Utility::sendLocalReply(const bool& is_reset, const EncodeFunctions& encode | |
| encodeLocalReply(is_reset, std::move(prepared_local_reply)); | ||
| } | ||
|
|
||
| bool Utility::remoteAddressIsTrustedProxy( | ||
| const Envoy::Network::Address::InstanceConstSharedPtr& remote, | ||
| const std::vector<Network::Address::CidrRange> trusted_cidrs) { | ||
| for (const auto& cidr : trusted_cidrs) { | ||
| if (cidr.isInRange(*remote.get())) { | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you, these have been updated. |
||
|
|
||
| Utility::GetLastAddressFromXffInfo Utility::getLastNonTrustedAddressFromXFF( | ||
| const Http::RequestHeaderMap& request_headers, | ||
| const std::vector<Network::Address::CidrRange> trusted_cidrs) { | ||
|
||
| const auto xff_header = request_headers.getForwardedForValue(); | ||
| static constexpr absl::string_view separator(","); | ||
|
|
||
| const auto xff_entries = StringUtil::splitToken(xff_header, separator, false, true); | ||
|
||
| Network::Address::InstanceConstSharedPtr last_valid_addr; | ||
|
|
||
| for (auto it = xff_entries.rbegin(); it != xff_entries.rend(); it++) { | ||
| auto addr = Network::Utility::parseInternetAddressNoThrow(std::string(*it)); | ||
alyssawilk marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (addr == nullptr) { | ||
| return {nullptr, false}; | ||
| } | ||
| last_valid_addr = addr; | ||
|
|
||
| bool remoteAddressIsTrustedProxy = false; | ||
|
||
| for (const auto& cidr : trusted_cidrs) { | ||
| if (cidr.isInRange(*addr.get())) { | ||
| remoteAddressIsTrustedProxy = true; | ||
| break; | ||
| } | ||
| } | ||
|
|
||
| if (remoteAddressIsTrustedProxy) { | ||
| continue; | ||
| } | ||
|
|
||
| // If we reach here we found a non-trusted address | ||
| return {addr, xff_entries.size() == 1}; | ||
| } | ||
| // If we reach this point all addresses in XFF were considered trusted, so return | ||
| // first IP in XFF (the last in the reverse-evaluated chain). | ||
| return {last_valid_addr, xff_entries.size() == 1}; | ||
alyssawilk marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| Utility::GetLastAddressFromXffInfo | ||
| Utility::getLastAddressFromXFF(const Http::RequestHeaderMap& request_headers, | ||
| uint32_t num_to_skip) { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.