Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 2 additions & 0 deletions CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ extensions/filters/common/original_src @snowp @klarose
/*/extensions/transport_sockets/common @alyssawilk @wez470
# starttls transport socket
/*/extensions/transport_sockets/starttls @cpakulski @lizan
# proxy transport socket
/*extensions/transport_sockets/http_11_proxy @alyssawilk @ryantheoptimist
# internal upstream transport socket
/*/extensions/transport_sockets/internal_upstream @kyessenov @lambdai
# sni_cluster extension
Expand Down
12 changes: 12 additions & 0 deletions api/envoy/extensions/transport_sockets/http_11_proxy/v3/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# DO NOT EDIT. This file is generated by tools/proto_format/proto_sync.py.

load("@envoy_api//bazel:api_build_system.bzl", "api_proto_package")

licenses(["notice"]) # Apache 2

api_proto_package(
deps = [
"//envoy/config/core/v3:pkg",
"@com_github_cncf_udpa//udpa/annotations:pkg",
],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
syntax = "proto3";

package envoy.extensions.transport_sockets.http_11_proxy.v3;

import "envoy/config/core/v3/base.proto";

import "udpa/annotations/status.proto";
import "validate/validate.proto";

option java_package = "io.envoyproxy.envoy.extensions.transport_sockets.http_11_proxy.v3";
option java_outer_classname = "UpstreamHttp11ConnectProto";
option java_multiple_files = true;
option go_package = "github.com/envoyproxy/go-control-plane/envoy/extensions/transport_sockets/http_11_proxy/v3;http_11_proxyv3";
option (udpa.annotations.file_status).package_version_status = ACTIVE;

// [#protodoc-title: Upstream HTTP/1.1 Proxy]
// [#extension: envoy.transport_sockets.http_11_proxy]

// Configuration for HTTP/1.1 proxy transport sockets.
// If this is configured and an intermediate filter adds proxy metadata to the
// stream info then

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you clarify what "proxy metadata" means in this context?

// - Upstream connections will be directed to the specified proxy address rather
// than the host's address
Comment thread
RyanTheOptimist marked this conversation as resolved.
Outdated
// - Upstream TLS connections will have a raw HTTP/1.1 CONNECT header prefaced
// to the payload, and 200 response stripped (if less than 200 bytes)
// - Plaintext HTTP/1.1 connections will be sent with a fully qualified URL.
// This transport socket is not compatible with HTTP/3, plaintext HTTP/2, or raw TCP.
message Http11ProxyUpstreamTransport {
// The underlying transport socket being wrapped.
config.core.v3.TransportSocket transport_socket = 1 [(validate.rules).message = {required: true}];
}
1 change: 1 addition & 0 deletions api/versioning/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ proto_library(
"//envoy/extensions/stat_sinks/graphite_statsd/v3:pkg",
"//envoy/extensions/stat_sinks/wasm/v3:pkg",
"//envoy/extensions/transport_sockets/alts/v3:pkg",
"//envoy/extensions/transport_sockets/http_11_proxy/v3:pkg",
"//envoy/extensions/transport_sockets/internal_upstream/v3:pkg",
"//envoy/extensions/transport_sockets/proxy_protocol/v3:pkg",
"//envoy/extensions/transport_sockets/quic/v3:pkg",
Expand Down
17 changes: 17 additions & 0 deletions envoy/network/transport_socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <vector>

#include "envoy/buffer/buffer.h"
#include "envoy/common/optref.h"
#include "envoy/common/pure.h"
#include "envoy/network/io_handle.h"
#include "envoy/network/listen_socket.h"
Expand Down Expand Up @@ -234,6 +235,22 @@ class TransportSocketOptions {
*/
virtual absl::optional<Network::ProxyProtocolData> proxyProtocolOptions() const PURE;

// Information for use by the http_11_proxy transport socket.
struct Http11ProxyInfo {
Http11ProxyInfo(std::string hostname, Network::Address::InstanceConstSharedPtr address)
: hostname(hostname), proxy_address(address) {}
// The hostname of the original request, to be used in CONNECT request if
// the underlying transport is TLS.
std::string hostname;
// The address of the proxy, where connections should be routed to.
Network::Address::InstanceConstSharedPtr proxy_address;
};

/**
* @return any proxy information if sending to an intermediate proxy over HTTP/1.1.
*/
virtual OptRef<const Http11ProxyInfo> http11ProxyInfo() const PURE;

/**
* @return filter state from the downstream request or connection.
*/
Expand Down
24 changes: 16 additions & 8 deletions source/common/http/codec_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -168,22 +168,30 @@ void CodecClient::onData(Buffer::Instance& data) {
CodecClientProd::CodecClientProd(CodecType type, Network::ClientConnectionPtr&& connection,
Upstream::HostDescriptionConstSharedPtr host,
Event::Dispatcher& dispatcher,
Random::RandomGenerator& random_generator)
: NoConnectCodecClientProd(type, std::move(connection), host, dispatcher, random_generator) {
Random::RandomGenerator& random_generator,
const Network::TransportSocketOptionsConstSharedPtr& options)
: NoConnectCodecClientProd(type, std::move(connection), host, dispatcher, random_generator,
options) {
connect();
}

NoConnectCodecClientProd::NoConnectCodecClientProd(CodecType type,
Network::ClientConnectionPtr&& connection,
Upstream::HostDescriptionConstSharedPtr host,
Event::Dispatcher& dispatcher,
Random::RandomGenerator& random_generator)
NoConnectCodecClientProd::NoConnectCodecClientProd(
CodecType type, Network::ClientConnectionPtr&& connection,
Upstream::HostDescriptionConstSharedPtr host, Event::Dispatcher& dispatcher,
Random::RandomGenerator& random_generator,
const Network::TransportSocketOptionsConstSharedPtr& options)
: CodecClient(type, std::move(connection), host, dispatcher) {
switch (type) {
case CodecType::HTTP1: {
// If the transport socket indicates this is being proxied, inform the HTTP/1.1 codec. It will
// send fully qualified URLs iff the underlying transport is plaintext.
bool proxied = false;
if (options && options->http11ProxyInfo().has_value()) {
proxied = true;
}
codec_ = std::make_unique<Http1::ClientConnectionImpl>(
*connection_, host->cluster().http1CodecStats(), *this, host->cluster().http1Settings(),
host->cluster().maxResponseHeadersCount());
host->cluster().maxResponseHeadersCount(), proxied);
break;
}
case CodecType::HTTP2: {
Expand Down
7 changes: 4 additions & 3 deletions source/common/http/codec_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -281,8 +281,8 @@ class NoConnectCodecClientProd : public CodecClient {
public:
NoConnectCodecClientProd(CodecType type, Network::ClientConnectionPtr&& connection,
Upstream::HostDescriptionConstSharedPtr host,
Event::Dispatcher& dispatcher,
Random::RandomGenerator& random_generator);
Event::Dispatcher& dispatcher, Random::RandomGenerator& random_generator,
const Network::TransportSocketOptionsConstSharedPtr& options);
};

/**
Expand All @@ -292,7 +292,8 @@ class CodecClientProd : public NoConnectCodecClientProd {
public:
CodecClientProd(CodecType type, Network::ClientConnectionPtr&& connection,
Upstream::HostDescriptionConstSharedPtr host, Event::Dispatcher& dispatcher,
Random::RandomGenerator& random_generator);
Random::RandomGenerator& random_generator,
const Network::TransportSocketOptionsConstSharedPtr& options);
};

} // namespace Http
Expand Down
6 changes: 4 additions & 2 deletions source/common/http/http1/codec_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1325,13 +1325,15 @@ void ServerConnectionImpl::ActiveRequest::dumpState(std::ostream& os, int indent

ClientConnectionImpl::ClientConnectionImpl(Network::Connection& connection, CodecStats& stats,
ConnectionCallbacks&, const Http1Settings& settings,
const uint32_t max_response_headers_count)
const uint32_t max_response_headers_count,
bool passing_through_proxy)
: ConnectionImpl(connection, stats, settings, MessageType::Response, MAX_RESPONSE_HEADERS_KB,
max_response_headers_count),
owned_output_buffer_(connection.dispatcher().getWatermarkFactory().createBuffer(
[&]() -> void { this->onBelowLowWatermark(); },
[&]() -> void { this->onAboveHighWatermark(); },
[]() -> void { /* TODO(adisuissa): handle overflow watermark */ })) {
[]() -> void { /* TODO(adisuissa): handle overflow watermark */ })),
passing_through_proxy_(passing_through_proxy) {
owned_output_buffer_->setWatermarks(connection.bufferLimit());
// Inform parent
output_buffer_ = owned_output_buffer_.get();
Expand Down
17 changes: 15 additions & 2 deletions source/common/http/http1/codec_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ class ConnectionImpl : public virtual Connection,
* @return Network::Connection& the backing network connection.
*/
Network::Connection& connection() { return connection_; }
const Network::Connection& connection() const { return connection_; }

/**
* Called when the active encoder has completed encoding the outbound half of the stream.
Expand Down Expand Up @@ -230,7 +231,7 @@ class ConnectionImpl : public virtual Connection,
virtual void maybeAddSentinelBufferFragment(Buffer::Instance&) {}
CodecStats& stats() { return stats_; }
bool enableTrailers() const { return codec_settings_.enable_trailers_; }
bool sendFullyQualifiedUrl() const { return codec_settings_.send_fully_qualified_url_; }
virtual bool sendFullyQualifiedUrl() const { return codec_settings_.send_fully_qualified_url_; }
HeaderKeyFormatterOptConstRef formatter() const {
return makeOptRefFromPtr(encode_only_header_key_formatter_.get());
}
Expand Down Expand Up @@ -563,7 +564,8 @@ class ClientConnectionImpl : public ClientConnection, public ConnectionImpl {
public:
ClientConnectionImpl(Network::Connection& connection, CodecStats& stats,
ConnectionCallbacks& callbacks, const Http1Settings& settings,
const uint32_t max_response_headers_count);
const uint32_t max_response_headers_count,
bool passing_through_proxy = false);
// Http::ClientConnection
RequestEncoder& newStream(ResponseDecoder& response_decoder) override;

Expand All @@ -578,6 +580,13 @@ class ClientConnectionImpl : public ClientConnection, public ConnectionImpl {

bool cannotHaveBody();

bool sendFullyQualifiedUrl() const override {
// Send fully qualified URLs either if the parent connection is configured to do so or this
// stream is passing through a proxy and the underlying transport is plaintext.
return ConnectionImpl::sendFullyQualifiedUrl() ||
(passing_through_proxy_ && !connection().ssl());
}

// ParserCallbacks.
Status onUrlBase(const char*, size_t) override { return okStatus(); }
Status onStatusBase(const char* data, size_t length) override;
Expand Down Expand Up @@ -649,6 +658,10 @@ class ClientConnectionImpl : public ClientConnection, public ConnectionImpl {

// The default limit of 80 KiB is the vanilla http_parser behaviour.
static constexpr uint32_t MAX_RESPONSE_HEADERS_KB = 80;

// True if the upstream connection is pointed at an HTTP/1.1 proxy, and
// plaintext HTTP should be sent with fully qualified URLs.
bool passing_through_proxy_ = false;
};

} // namespace Http1
Expand Down
6 changes: 3 additions & 3 deletions source/common/http/http1/conn_pool.cc
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,9 @@ allocateConnPool(Event::Dispatcher& dispatcher, Random::RandomGenerator& random_
return std::make_unique<ActiveClient>(*pool, absl::nullopt);
},
[](Upstream::Host::CreateConnectionData& data, HttpConnPoolImplBase* pool) {
CodecClientPtr codec{new CodecClientProd(CodecType::HTTP1, std::move(data.connection_),
data.host_description_, pool->dispatcher(),
pool->randomGenerator())};
CodecClientPtr codec{new CodecClientProd(
CodecType::HTTP1, std::move(data.connection_), data.host_description_,
pool->dispatcher(), pool->randomGenerator(), pool->transportSocketOptions())};
return codec;
},
std::vector<Protocol>{Protocol::Http11}, absl::nullopt, nullptr);
Expand Down
6 changes: 3 additions & 3 deletions source/common/http/http2/conn_pool.cc
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ allocateConnPool(Event::Dispatcher& dispatcher, Random::RandomGenerator& random_
return std::make_unique<ActiveClient>(*pool, absl::nullopt);
},
[](Upstream::Host::CreateConnectionData& data, HttpConnPoolImplBase* pool) {
CodecClientPtr codec{new CodecClientProd(CodecType::HTTP2, std::move(data.connection_),
data.host_description_, pool->dispatcher(),
pool->randomGenerator())};
CodecClientPtr codec{new CodecClientProd(
CodecType::HTTP2, std::move(data.connection_), data.host_description_,
pool->dispatcher(), pool->randomGenerator(), pool->transportSocketOptions())};
return codec;
},
std::vector<Protocol>{Protocol::Http2}, origin, cache);
Expand Down
8 changes: 4 additions & 4 deletions source/common/http/http3/conn_pool.cc
Original file line number Diff line number Diff line change
Expand Up @@ -191,10 +191,10 @@ allocateConnPool(Event::Dispatcher& dispatcher, Random::RandomGenerator& random_
"envoy.reloadable_features.postpone_h3_client_connect_to_next_loop")
? std::make_unique<NoConnectCodecClientProd>(
CodecType::HTTP3, std::move(data.connection_), data.host_description_,
pool->dispatcher(), pool->randomGenerator())
: std::make_unique<CodecClientProd>(CodecType::HTTP3, std::move(data.connection_),
data.host_description_, pool->dispatcher(),
pool->randomGenerator());
pool->dispatcher(), pool->randomGenerator(), pool->transportSocketOptions())
: std::make_unique<CodecClientProd>(
CodecType::HTTP3, std::move(data.connection_), data.host_description_,
pool->dispatcher(), pool->randomGenerator(), pool->transportSocketOptions());
return codec;
},
std::vector<Protocol>{Protocol::Http3}, connect_callback, quic_info);
Expand Down
3 changes: 2 additions & 1 deletion source/common/http/mixed_conn_pool.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ CodecClientPtr
HttpConnPoolImplMixed::createCodecClient(Upstream::Host::CreateConnectionData& data) {
auto protocol = protocol_ == Protocol::Http11 ? CodecType::HTTP1 : CodecType::HTTP2;
CodecClientPtr codec{new CodecClientProd(protocol, std::move(data.connection_),
data.host_description_, dispatcher_, random_generator_)};
data.host_description_, dispatcher_, random_generator_,
transportSocketOptions())};
return codec;
}

Expand Down
12 changes: 12 additions & 0 deletions source/common/network/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,7 @@ envoy_cc_library(
hdrs = ["transport_socket_options_impl.h"],
deps = [
":application_protocol_lib",
":filter_state_proxy_info_lib",
":proxy_protocol_filter_state_lib",
":upstream_server_name_lib",
":upstream_subject_alt_names_lib",
Expand All @@ -453,6 +454,17 @@ envoy_cc_library(
],
)

envoy_cc_library(
name = "filter_state_proxy_info_lib",
srcs = ["filter_state_proxy_info.cc"],
hdrs = ["filter_state_proxy_info.h"],
deps = [
"//envoy/network:address_interface",
"//envoy/stream_info:filter_state_interface",
"//source/common/common:macros",
],
)

envoy_cc_library(
name = "upstream_server_name_lib",
srcs = ["upstream_server_name.cc"],
Expand Down
11 changes: 11 additions & 0 deletions source/common/network/filter_state_proxy_info.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include "source/common/network/filter_state_proxy_info.h"

namespace Envoy {
namespace Network {

const std::string& Http11ProxyInfoFilterState::key() {
CONSTRUCT_ON_FIRST_USE(std::string, "envoy.network.transport_socket.http_11_proxy.info");
}

} // namespace Network
} // namespace Envoy
34 changes: 34 additions & 0 deletions source/common/network/filter_state_proxy_info.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#pragma once

#include "envoy/network/address.h"
#include "envoy/stream_info/filter_state.h"

#include "absl/strings/string_view.h"

namespace Envoy {
namespace Network {

/**
* Information which filters can add if they detect the stream should go
* upstream through an HTTP/1.1 proxy.
*/
class Http11ProxyInfoFilterState : public StreamInfo::FilterState::Object {
public:
// Returns the key for looking up the Http11ProxyInfoFilterState in the FilterState.
static const std::string& key();
Comment thread
RyanTheOptimist marked this conversation as resolved.

Http11ProxyInfoFilterState(absl::string_view hostname,
Network::Address::InstanceConstSharedPtr address)
: hostname_(hostname), address_(address) {}
Network::Address::InstanceConstSharedPtr address() const { return address_; }
Comment thread
RyanTheOptimist marked this conversation as resolved.
const std::string& hostname() const { return hostname_; }

private:
// The hostname of this individual request.
const std::string hostname_;
Comment thread
RyanTheOptimist marked this conversation as resolved.
// The address of the proxy.
const Network::Address::InstanceConstSharedPtr address_;
};

} // namespace Network
} // namespace Envoy
11 changes: 10 additions & 1 deletion source/common/network/transport_socket_options_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "source/common/common/scalar_to_byte_vector.h"
#include "source/common/common/utility.h"
#include "source/common/network/application_protocol.h"
#include "source/common/network/filter_state_proxy_info.h"
#include "source/common/network/proxy_protocol_filter_state.h"
#include "source/common/network/upstream_server_name.h"
#include "source/common/network/upstream_subject_alt_names.h"
Expand Down Expand Up @@ -52,6 +53,7 @@ TransportSocketOptionsConstSharedPtr TransportSocketOptionsUtility::fromFilterSt
std::vector<std::string> subject_alt_names;
std::vector<std::string> alpn_fallback;
absl::optional<Network::ProxyProtocolData> proxy_protocol_options;
std::unique_ptr<const TransportSocketOptions::Http11ProxyInfo> proxy_info;

if (auto typed_data =
filter_state->getDataReadOnly<UpstreamServerName>(UpstreamServerName::key());
Expand All @@ -77,9 +79,16 @@ TransportSocketOptionsConstSharedPtr TransportSocketOptionsUtility::fromFilterSt
proxy_protocol_options.emplace(typed_data->value());
}

if (auto typed_data = filter_state->getDataReadOnly<Http11ProxyInfoFilterState>(
Http11ProxyInfoFilterState::key());
typed_data != nullptr) {
proxy_info = std::make_unique<TransportSocketOptions::Http11ProxyInfo>(typed_data->hostname(),
typed_data->address());
}

return std::make_shared<Network::TransportSocketOptionsImpl>(
server_name, std::move(subject_alt_names), std::move(application_protocols),
std::move(alpn_fallback), proxy_protocol_options, filter_state);
std::move(alpn_fallback), proxy_protocol_options, filter_state, std::move(proxy_info));
}

} // namespace Network
Expand Down
Loading