Skip to content
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

stream info: cleanup address handling #14432

Merged
merged 17 commits into from
Jan 7, 2021
Merged
Show file tree
Hide file tree
Changes from 15 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
27 changes: 4 additions & 23 deletions include/envoy/network/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "envoy/network/address.h"
#include "envoy/network/filter.h"
#include "envoy/network/listen_socket.h"
#include "envoy/network/socket.h"
#include "envoy/ssl/connection.h"
#include "envoy/stream_info/stream_info.h"

Expand Down Expand Up @@ -188,16 +189,10 @@ class Connection : public Event::DeferredDeletable, public FilterManager {
virtual bool readEnabled() const PURE;

/**
* @return The address of the remote client. Note that this method will never return nullptr.
* @return the address provider backing this connection.
*/
virtual const Network::Address::InstanceConstSharedPtr& remoteAddress() const PURE;

/**
* @return The address of the remote directly connected peer. Note that this method
* will never return nullptr. This address is not affected or modified by PROXY protocol
* or any other listener filter.
*/
virtual const Network::Address::InstanceConstSharedPtr& directRemoteAddress() const PURE;
virtual const SocketAddressProvider& addressProvider() const PURE;
virtual SocketAddressProviderSharedPtr addressProviderSharedPtr() const PURE;

/**
* Credentials of the peer of a socket as decided by SO_PEERCRED.
Expand All @@ -223,14 +218,6 @@ class Connection : public Event::DeferredDeletable, public FilterManager {
*/
virtual absl::optional<UnixDomainSocketPeerCredentials> unixSocketPeerCredentials() const PURE;

/**
* @return the local address of the connection. For client connections, this is the origin
* address. For server connections, this is the local destination address. For server connections
* it can be different from the proxy address if the downstream connection has been redirected or
* the proxy is operating in transparent mode. Note that this method will never return nullptr.
*/
virtual const Network::Address::InstanceConstSharedPtr& localAddress() const PURE;

/**
* Set the stats to update for various connection state changes. Note that for performance reasons
* these stats are eventually consistent and may not always accurately represent the connection
Expand Down Expand Up @@ -287,12 +274,6 @@ class Connection : public Event::DeferredDeletable, public FilterManager {
*/
virtual uint32_t bufferLimit() const PURE;

/**
* @return boolean telling if the connection's local address has been restored to an original
* destination address, rather than the address the connection was accepted at.
*/
virtual bool localAddressRestored() const PURE;

/**
* @return boolean telling if the connection is currently above the high watermark.
*/
Expand Down
36 changes: 0 additions & 36 deletions include/envoy/network/listen_socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,42 +27,6 @@ namespace Network {
*/
class ConnectionSocket : public virtual Socket {
public:
~ConnectionSocket() override = default;

/**
* @return the remote address of the socket.
*/
virtual const Address::InstanceConstSharedPtr& remoteAddress() const PURE;

/**
* @return the direct remote address of the socket. This is the address of the directly
* connected peer, and cannot be modified by listener filters.
*/
virtual const Address::InstanceConstSharedPtr& directRemoteAddress() const PURE;

/**
* Restores the local address of the socket. On accepted sockets the local address defaults to the
* one at which the connection was received at, which is the same as the listener's address, if
* the listener is bound to a specific address. Call this to restore the address to a value
* different from the one the socket was initially accepted at. This should only be called when
* restoring the original destination address of a connection redirected by iptables REDIRECT. The
* caller is responsible for making sure the new address is actually different.
*
* @param local_address the new local address.
*/
virtual void restoreLocalAddress(const Address::InstanceConstSharedPtr& local_address) PURE;

/**
* Set the remote address of the socket.
*/
virtual void setRemoteAddress(const Address::InstanceConstSharedPtr& remote_address) 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.
*/
virtual bool localAddressRestored() const PURE;

/**
* Set detected transport protocol (e.g. RAW_BUFFER, TLS).
*/
Expand Down
71 changes: 64 additions & 7 deletions include/envoy/network/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,22 +43,39 @@ struct SocketOptionName {
Network::SocketOptionName(level, option, #level "/" #option)

/**
* Base class for Sockets
* Interfaces for providing a socket's various addresses. This is split into a getters interface
* and a getters + setters interface. This is so that only the getters portion can be overridden
* in certain cases.
*/
class Socket {
class SocketAddressProvider {
public:
virtual ~Socket() = default;
virtual ~SocketAddressProvider() = default;

/**
* Type of sockets supported. See man 2 socket for more details
* @return the local address of the socket.
*/
enum class Type { Stream, Datagram };
virtual const Address::InstanceConstSharedPtr& localAddress() const PURE;

/**
* @return the local address of the socket.
* @return true if the local address has been restored to a value that is different from the
* address the socket was initially accepted at.
*/
virtual const Address::InstanceConstSharedPtr& localAddress() const PURE;
virtual bool localAddressRestored() const PURE;

/**
* @return the remote address of the socket.
*/
virtual const Address::InstanceConstSharedPtr& remoteAddress() const PURE;

/**
* @return the direct remote address of the socket. This is the address of the directly
* connected peer, and cannot be modified by listener filters.
*/
virtual const Address::InstanceConstSharedPtr& directRemoteAddress() const PURE;
};

class SocketAddressSetter : public SocketAddressProvider {
public:
/**
* Set the local address of the socket. On accepted sockets the local address defaults to the
* one at which the connection was received at, which is the same as the listener's address, if
Expand All @@ -68,6 +85,46 @@ class Socket {
*/
virtual void setLocalAddress(const Address::InstanceConstSharedPtr& local_address) PURE;

/**
* Restores the local address of the socket. On accepted sockets the local address defaults to the
* one at which the connection was received at, which is the same as the listener's address, if
* the listener is bound to a specific address. Call this to restore the address to a value
* different from the one the socket was initially accepted at. This should only be called when
* restoring the original destination address of a connection redirected by iptables REDIRECT. The
* caller is responsible for making sure the new address is actually different.
*
* @param local_address the new local address.
*/
virtual void restoreLocalAddress(const Address::InstanceConstSharedPtr& local_address) PURE;

/**
* Set the remote address of the socket.
*/
virtual void setRemoteAddress(const Address::InstanceConstSharedPtr& remote_address) PURE;
};

using SocketAddressSetterSharedPtr = std::shared_ptr<SocketAddressSetter>;
using SocketAddressProviderSharedPtr = std::shared_ptr<const SocketAddressProvider>;

/**
* Base class for Sockets
*/
class Socket {
public:
virtual ~Socket() = default;

/**
* Type of sockets supported. See man 2 socket for more details
*/
enum class Type { Stream, Datagram };

/**
* @return the address provider backing this socket.
*/
virtual SocketAddressSetter& addressProvider() PURE;
virtual const SocketAddressProvider& addressProvider() const PURE;
virtual SocketAddressProviderSharedPtr addressProviderSharedPtr() const PURE;

/**
* @return IoHandle for the underlying connection
*/
Expand Down
1 change: 1 addition & 0 deletions include/envoy/stream_info/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ envoy_cc_library(
"//include/envoy/http:header_map_interface",
"//include/envoy/http:protocol_interface",
"//include/envoy/http:request_id_extension_interface",
"//include/envoy/network:socket_interface",
"//include/envoy/ssl:connection_interface",
"//include/envoy/upstream:host_description_interface",
"//source/common/common:assert_lib",
Expand Down
39 changes: 3 additions & 36 deletions include/envoy/stream_info/stream_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "envoy/http/header_map.h"
#include "envoy/http/protocol.h"
#include "envoy/http/request_id_extension.h"
#include "envoy/network/socket.h"
#include "envoy/ssl/connection.h"
#include "envoy/stream_info/filter_state.h"
#include "envoy/upstream/host_description.h"
Expand Down Expand Up @@ -451,43 +452,9 @@ class StreamInfo {
virtual void healthCheck(bool is_health_check) PURE;

/**
* @param downstream_local_address sets the local address of the downstream connection. Note that
* it can be different than the local address of the upstream connection.
* @return the downstream address provider.
*/
virtual void setDownstreamLocalAddress(
const Network::Address::InstanceConstSharedPtr& downstream_local_address) PURE;

/**
* @return the downstream local address. Note that this will never be nullptr.
*/
virtual const Network::Address::InstanceConstSharedPtr& downstreamLocalAddress() const PURE;

/**
* @param downstream_direct_remote_address sets the direct physical address of downstream
* connection.
*/
virtual void setDownstreamDirectRemoteAddress(
const Network::Address::InstanceConstSharedPtr& downstream_direct_remote_address) PURE;

/**
* @return the downstream directly connected address. This will never be nullptr. This is
* equivalent to the address of the physical connection.
*/
virtual const Network::Address::InstanceConstSharedPtr&
downstreamDirectRemoteAddress() const PURE;

/**
* @param downstream_remote_address sets the remote address of downstream connection.
*/
virtual void setDownstreamRemoteAddress(
const Network::Address::InstanceConstSharedPtr& downstream_remote_address) PURE;

/**
* @return the downstream remote address. Note that this will never be nullptr. This may be
* equivalent to downstreamDirectRemoteAddress, unless the remote address is inferred from a
* proxy proto, x-forwarded-for, etc.
*/
virtual const Network::Address::InstanceConstSharedPtr& downstreamRemoteAddress() const PURE;
virtual const Network::SocketAddressProvider& downstreamAddressProvider() const PURE;

/**
* @param connection_info sets the downstream ssl connection.
Expand Down
14 changes: 7 additions & 7 deletions source/common/formatter/substitution_formatter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -651,37 +651,37 @@ StreamInfoFormatter::StreamInfoFormatter(const std::string& field_name) {
} else if (field_name == "DOWNSTREAM_LOCAL_ADDRESS") {
field_extractor_ =
StreamInfoAddressFieldExtractor::withPort([](const StreamInfo::StreamInfo& stream_info) {
return stream_info.downstreamLocalAddress();
return stream_info.downstreamAddressProvider().localAddress();
});
} else if (field_name == "DOWNSTREAM_LOCAL_ADDRESS_WITHOUT_PORT") {
field_extractor_ = StreamInfoAddressFieldExtractor::withoutPort(
[](const Envoy::StreamInfo::StreamInfo& stream_info) {
return stream_info.downstreamLocalAddress();
return stream_info.downstreamAddressProvider().localAddress();
});
} else if (field_name == "DOWNSTREAM_LOCAL_PORT") {
field_extractor_ = StreamInfoAddressFieldExtractor::justPort(
[](const Envoy::StreamInfo::StreamInfo& stream_info) {
return stream_info.downstreamLocalAddress();
return stream_info.downstreamAddressProvider().localAddress();
});
} else if (field_name == "DOWNSTREAM_REMOTE_ADDRESS") {
field_extractor_ =
StreamInfoAddressFieldExtractor::withPort([](const StreamInfo::StreamInfo& stream_info) {
return stream_info.downstreamRemoteAddress();
return stream_info.downstreamAddressProvider().remoteAddress();
});
} else if (field_name == "DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT") {
field_extractor_ =
StreamInfoAddressFieldExtractor::withoutPort([](const StreamInfo::StreamInfo& stream_info) {
return stream_info.downstreamRemoteAddress();
return stream_info.downstreamAddressProvider().remoteAddress();
});
} else if (field_name == "DOWNSTREAM_DIRECT_REMOTE_ADDRESS") {
field_extractor_ =
StreamInfoAddressFieldExtractor::withPort([](const StreamInfo::StreamInfo& stream_info) {
return stream_info.downstreamDirectRemoteAddress();
return stream_info.downstreamAddressProvider().directRemoteAddress();
});
} else if (field_name == "DOWNSTREAM_DIRECT_REMOTE_ADDRESS_WITHOUT_PORT") {
field_extractor_ =
StreamInfoAddressFieldExtractor::withoutPort([](const StreamInfo::StreamInfo& stream_info) {
return stream_info.downstreamDirectRemoteAddress();
return stream_info.downstreamAddressProvider().directRemoteAddress();
});
} else if (field_name == "CONNECTION_ID") {
field_extractor_ = std::make_unique<StreamInfoUInt64FieldExtractor>(
Expand Down
3 changes: 2 additions & 1 deletion source/common/http/async_client_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ AsyncClient::Stream* AsyncClientImpl::start(AsyncClient::StreamCallbacks& callba
AsyncStreamImpl::AsyncStreamImpl(AsyncClientImpl& parent, AsyncClient::StreamCallbacks& callbacks,
const AsyncClient::StreamOptions& options)
: parent_(parent), stream_callbacks_(callbacks), stream_id_(parent.config_.random_.random()),
router_(parent.config_), stream_info_(Protocol::Http11, parent.dispatcher().timeSource()),
router_(parent.config_),
stream_info_(Protocol::Http11, parent.dispatcher().timeSource(), nullptr),
tracing_config_(Tracing::EgressConfig::get()),
route_(std::make_shared<RouteImpl>(parent_.cluster_->name(), options.timeout,
options.hash_policy)),
Expand Down
21 changes: 5 additions & 16 deletions source/common/http/conn_manager_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -618,16 +618,6 @@ ConnectionManagerImpl::ActiveStream::ActiveStream(ConnectionManagerImpl& connect
} else {
connection_manager_.stats_.named_.downstream_rq_http1_total_.inc();
}
filter_manager_.streamInfo().setDownstreamLocalAddress(
connection_manager_.read_callbacks_->connection().localAddress());
filter_manager_.streamInfo().setDownstreamDirectRemoteAddress(
connection_manager_.read_callbacks_->connection().directRemoteAddress());
// Initially, the downstream remote address is the source address of the
// downstream connection. That can change later in the request's lifecycle,
// based on XFF processing, but setting the downstream remote address here
// prevents surprises for logging code in edge cases.
filter_manager_.streamInfo().setDownstreamRemoteAddress(
connection_manager_.read_callbacks_->connection().remoteAddress());

filter_manager_.streamInfo().setDownstreamSslConnection(
connection_manager_.read_callbacks_->connection().ssl());
Expand Down Expand Up @@ -826,7 +816,7 @@ const Network::Connection* ConnectionManagerImpl::ActiveStream::connection() {
}

uint32_t ConnectionManagerImpl::ActiveStream::localPort() {
auto ip = connection()->localAddress()->ip();
auto ip = connection()->addressProvider().localAddress()->ip();
if (ip == nullptr) {
return 0;
}
Expand Down Expand Up @@ -1014,12 +1004,11 @@ void ConnectionManagerImpl::ActiveStream::decodeHeaders(RequestHeaderMapPtr&& he

if (!state_.is_internally_created_) { // Only sanitize headers on first pass.
// Modify the downstream remote address depending on configuration and headers.
filter_manager_.streamInfo().setDownstreamRemoteAddress(
ConnectionManagerUtility::mutateRequestHeaders(
*request_headers_, connection_manager_.read_callbacks_->connection(),
connection_manager_.config_, *snapped_route_config_, connection_manager_.local_info_));
filter_manager_.setDownstreamRemoteAddress(ConnectionManagerUtility::mutateRequestHeaders(
*request_headers_, connection_manager_.read_callbacks_->connection(),
connection_manager_.config_, *snapped_route_config_, connection_manager_.local_info_));
}
ASSERT(filter_manager_.streamInfo().downstreamRemoteAddress() != nullptr);
ASSERT(filter_manager_.streamInfo().downstreamAddressProvider().remoteAddress() != nullptr);

ASSERT(!cached_route_);
refreshCachedRoute();
Expand Down
8 changes: 4 additions & 4 deletions source/common/http/conn_manager_utility.cc
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,13 @@ Network::Address::InstanceConstSharedPtr ConnectionManagerUtility::mutateRequest
// are but they didn't populate XFF properly, the trusted client address is the
// source address of the immediate downstream's connection to us.
if (final_remote_address == nullptr) {
final_remote_address = connection.remoteAddress();
final_remote_address = connection.addressProvider().remoteAddress();
}
if (!config.skipXffAppend()) {
if (Network::Utility::isLoopbackAddress(*connection.remoteAddress())) {
if (Network::Utility::isLoopbackAddress(*connection.addressProvider().remoteAddress())) {
Utility::appendXff(request_headers, config.localAddress());
} else {
Utility::appendXff(request_headers, *connection.remoteAddress());
Utility::appendXff(request_headers, *connection.addressProvider().remoteAddress());
}
}
// If the prior hop is not a trusted proxy, overwrite any x-forwarded-proto value it set as
Expand Down Expand Up @@ -158,7 +158,7 @@ Network::Address::InstanceConstSharedPtr ConnectionManagerUtility::mutateRequest
// After determining internal request status, if there is no final remote address, due to no XFF,
// busted XFF, etc., use the direct connection remote address for logging.
if (final_remote_address == nullptr) {
final_remote_address = connection.remoteAddress();
final_remote_address = connection.addressProvider().remoteAddress();
}

// Edge request is the request from external clients to front Envoy.
Expand Down
Loading