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
1 change: 1 addition & 0 deletions docs/root/intro/version_history.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Version history
1.10.0 (pending)
================
* access log: added a new flag for upstream retry count exceeded.
* admin: the admin server can now be accessed via HTTP/2 (prior knowledge).
* buffer: fix vulnerabilities when allocation fails
* config: removed deprecated_v1 sds_config from :ref:`Bootstrap config <config_overview_v2_bootstrap>`.
* config: removed REST_LEGACY as a valid :ref:`ApiType <envoy_api_field_core.ApiConfigSource.api_type>`.
Expand Down
5 changes: 5 additions & 0 deletions include/envoy/server/admin.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ class AdminStream {
*/
virtual Http::StreamDecoderFilterCallbacks& getDecoderFilterCallbacks() const PURE;

/**
* @return const Buffer::Instance* the fully buffered admin request if applicable.
*/
virtual const Buffer::Instance* getRequestBody() const PURE;

/**
* @return Http::HeaderMap& to be used by handler to parse header information sent with the
* request.
Expand Down
1 change: 1 addition & 0 deletions include/envoy/singleton/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ envoy_cc_library(
hdrs = ["manager.h"],
deps = [
":instance_interface",
"//include/envoy/registry",
],
)
1 change: 1 addition & 0 deletions include/envoy/singleton/manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <string>

#include "envoy/common/pure.h"
#include "envoy/registry/registry.h"
#include "envoy/singleton/instance.h"

namespace Envoy {
Expand Down
70 changes: 51 additions & 19 deletions source/common/http/conn_manager_utility.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include "common/common/empty_string.h"
#include "common/common/utility.h"
#include "common/http/headers.h"
#include "common/http/http1/codec_impl.h"
#include "common/http/http2/codec_impl.h"
#include "common/http/utility.h"
#include "common/network/utility.h"
#include "common/runtime/uuid_util.h"
Expand All @@ -18,10 +20,40 @@
namespace Envoy {
namespace Http {

std::string ConnectionManagerUtility::determineNextProtocol(Network::Connection& connection,
const Buffer::Instance& data) {
if (!connection.nextProtocol().empty()) {
return connection.nextProtocol();
}

// See if the data we have so far shows the HTTP/2 prefix. We ignore the case where someone sends
// us the first few bytes of the HTTP/2 prefix since in all public cases we use SSL/ALPN. For
// internal cases this should practically never happen.
if (-1 != data.search(Http2::CLIENT_MAGIC_PREFIX.c_str(), Http2::CLIENT_MAGIC_PREFIX.size(), 0)) {
return Http2::ALPN_STRING;
}

return "";
}

ServerConnectionPtr ConnectionManagerUtility::autoCreateCodec(Network::Connection& connection,
const Buffer::Instance& data,
ServerConnectionCallbacks& callbacks,
Stats::Scope& scope,
const Http1Settings& http1_settings,
const Http2Settings& http2_settings) {
if (determineNextProtocol(connection, data) == Http2::ALPN_STRING) {
return ServerConnectionPtr{
new Http2::ServerConnectionImpl(connection, callbacks, scope, http2_settings)};
} else {
return ServerConnectionPtr{
new Http1::ServerConnectionImpl(connection, callbacks, http1_settings)};
}
}

Network::Address::InstanceConstSharedPtr ConnectionManagerUtility::mutateRequestHeaders(
Http::HeaderMap& request_headers, Network::Connection& connection,
ConnectionManagerConfig& config, const Router::Config& route_config,
Runtime::RandomGenerator& random, Runtime::Loader& runtime,
HeaderMap& request_headers, Network::Connection& connection, ConnectionManagerConfig& config,
const Router::Config& route_config, Runtime::RandomGenerator& random, Runtime::Loader& runtime,
const LocalInfo::LocalInfo& local_info) {
// If this is a Upgrade request, do not remove the Connection and Upgrade headers,
// as we forward them verbatim to the upstream hosts.
Expand Down Expand Up @@ -139,7 +171,7 @@ Network::Address::InstanceConstSharedPtr ConnectionManagerUtility::mutateRequest
request_headers.removeEnvoyForceTrace();
request_headers.removeEnvoyIpTags();

for (const Http::LowerCaseString& header : route_config.internalOnlyHeaders()) {
for (const LowerCaseString& header : route_config.internalOnlyHeaders()) {
request_headers.remove(header);
}
}
Expand Down Expand Up @@ -184,7 +216,7 @@ Network::Address::InstanceConstSharedPtr ConnectionManagerUtility::mutateRequest
return final_remote_address;
}

void ConnectionManagerUtility::mutateTracingRequestHeader(Http::HeaderMap& request_headers,
void ConnectionManagerUtility::mutateTracingRequestHeader(HeaderMap& request_headers,
Runtime::Loader& runtime,
ConnectionManagerConfig& config) {
if (!config.tracingConfig() || !request_headers.RequestId()) {
Expand Down Expand Up @@ -221,22 +253,22 @@ void ConnectionManagerUtility::mutateTracingRequestHeader(Http::HeaderMap& reque
request_headers.RequestId()->value(x_request_id);
}

void ConnectionManagerUtility::mutateXfccRequestHeader(Http::HeaderMap& request_headers,
void ConnectionManagerUtility::mutateXfccRequestHeader(HeaderMap& request_headers,
Network::Connection& connection,
ConnectionManagerConfig& config) {
// When AlwaysForwardOnly is set, always forward the XFCC header without modification.
if (config.forwardClientCert() == Http::ForwardClientCertType::AlwaysForwardOnly) {
if (config.forwardClientCert() == ForwardClientCertType::AlwaysForwardOnly) {
return;
}
// When Sanitize is set, or the connection is not mutual TLS, remove the XFCC header.
if (config.forwardClientCert() == Http::ForwardClientCertType::Sanitize ||
if (config.forwardClientCert() == ForwardClientCertType::Sanitize ||
!(connection.ssl() && connection.ssl()->peerCertificatePresented())) {
request_headers.removeForwardedClientCert();
return;
}

// When ForwardOnly is set, always forward the XFCC header without modification.
if (config.forwardClientCert() == Http::ForwardClientCertType::ForwardOnly) {
if (config.forwardClientCert() == ForwardClientCertType::ForwardOnly) {
return;
}

Expand All @@ -246,8 +278,8 @@ void ConnectionManagerUtility::mutateXfccRequestHeader(Http::HeaderMap& request_
std::vector<std::string> client_cert_details;
// When AppendForward or SanitizeSet is set, the client certificate information should be set into
// the XFCC header.
if (config.forwardClientCert() == Http::ForwardClientCertType::AppendForward ||
config.forwardClientCert() == Http::ForwardClientCertType::SanitizeSet) {
if (config.forwardClientCert() == ForwardClientCertType::AppendForward ||
config.forwardClientCert() == ForwardClientCertType::SanitizeSet) {
const std::string uri_san_local_cert = connection.ssl()->uriSanLocalCertificate();
if (!uri_san_local_cert.empty()) {
client_cert_details.push_back("By=" + uri_san_local_cert);
Expand All @@ -258,23 +290,23 @@ void ConnectionManagerUtility::mutateXfccRequestHeader(Http::HeaderMap& request_
}
for (const auto& detail : config.setCurrentClientCertDetails()) {
switch (detail) {
case Http::ClientCertDetailsType::Cert: {
case ClientCertDetailsType::Cert: {
const std::string peer_cert = connection.ssl()->urlEncodedPemEncodedPeerCertificate();
if (!peer_cert.empty()) {
client_cert_details.push_back("Cert=\"" + peer_cert + "\"");
}
break;
}
case Http::ClientCertDetailsType::Subject:
case ClientCertDetailsType::Subject:
// The "Subject" key still exists even if the subject is empty.
client_cert_details.push_back("Subject=\"" + connection.ssl()->subjectPeerCertificate() +
"\"");
break;
case Http::ClientCertDetailsType::URI:
case ClientCertDetailsType::URI:
// The "URI" key still exists even if the URI is empty.
client_cert_details.push_back("URI=" + connection.ssl()->uriSanPeerCertificate());
break;
case Http::ClientCertDetailsType::DNS: {
case ClientCertDetailsType::DNS: {
const std::vector<std::string> dns_sans = connection.ssl()->dnsSansPeerCertificate();
if (!dns_sans.empty()) {
for (const std::string& dns : dns_sans) {
Expand All @@ -288,18 +320,18 @@ void ConnectionManagerUtility::mutateXfccRequestHeader(Http::HeaderMap& request_
}

const std::string client_cert_details_str = absl::StrJoin(client_cert_details, ";");
if (config.forwardClientCert() == Http::ForwardClientCertType::AppendForward) {
if (config.forwardClientCert() == ForwardClientCertType::AppendForward) {
HeaderMapImpl::appendToHeader(request_headers.insertForwardedClientCert().value(),
client_cert_details_str);
} else if (config.forwardClientCert() == Http::ForwardClientCertType::SanitizeSet) {
} else if (config.forwardClientCert() == ForwardClientCertType::SanitizeSet) {
request_headers.insertForwardedClientCert().value(client_cert_details_str);
} else {
NOT_REACHED_GCOVR_EXCL_LINE;
}
}

void ConnectionManagerUtility::mutateResponseHeaders(Http::HeaderMap& response_headers,
const Http::HeaderMap* request_headers,
void ConnectionManagerUtility::mutateResponseHeaders(HeaderMap& response_headers,
const HeaderMap* request_headers,
const std::string& via) {
if (request_headers != nullptr && Utility::isUpgrade(*request_headers) &&
Utility::isUpgrade(response_headers)) {
Expand Down
33 changes: 27 additions & 6 deletions source/common/http/conn_manager_utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,28 @@ namespace Http {
*/
class ConnectionManagerUtility {
public:
/**
* Determine the next protocol to used based both on ALPN as well as protocol inspection.
* @param connection supplies the connection to determine a protocol for.
* @param data supplies the currently available read data on the connection.
*/
static std::string determineNextProtocol(Network::Connection& connection,
const Buffer::Instance& data);

/**
* Create an HTTP codec given the connection and the beginning of the incoming data.
* @param connection supplies the connection.
* @param data supplies the initial data supplied by the client.
* @param callbacks supplies the codec callbacks.
* @param scope supplies the stats scope for codec stats.
* @param http1_settings supplies the HTTP/1 settings to use if HTTP/1 is chosen.
* @param http2_settings supplies the HTTP/2 settings to use if HTTP/2 is chosen.
*/
static ServerConnectionPtr
autoCreateCodec(Network::Connection& connection, const Buffer::Instance& data,
ServerConnectionCallbacks& callbacks, Stats::Scope& scope,
const Http1Settings& http1_settings, const Http2Settings& http2_settings);

/**
* Mutates request headers in various ways. This functionality is broken out because of its
* complexity for ease of testing. See the method itself for detailed comments on what
Expand All @@ -28,23 +50,22 @@ class ConnectionManagerUtility {
* existence of the x-forwarded-for header. Again see the method for more details.
*/
static Network::Address::InstanceConstSharedPtr
mutateRequestHeaders(Http::HeaderMap& request_headers, Network::Connection& connection,
mutateRequestHeaders(HeaderMap& request_headers, Network::Connection& connection,
ConnectionManagerConfig& config, const Router::Config& route_config,
Runtime::RandomGenerator& random, Runtime::Loader& runtime,
const LocalInfo::LocalInfo& local_info);

static void mutateResponseHeaders(Http::HeaderMap& response_headers,
const Http::HeaderMap* request_headers, const std::string& via);
static void mutateResponseHeaders(HeaderMap& response_headers, const HeaderMap* request_headers,
const std::string& via);

private:
/**
* Mutate request headers if request needs to be traced.
*/
static void mutateTracingRequestHeader(Http::HeaderMap& request_headers, Runtime::Loader& runtime,
static void mutateTracingRequestHeader(HeaderMap& request_headers, Runtime::Loader& runtime,
ConnectionManagerConfig& config);

static void mutateXfccRequestHeader(Http::HeaderMap& request_headers,
Network::Connection& connection,
static void mutateXfccRequestHeader(HeaderMap& request_headers, Network::Connection& connection,
ConnectionManagerConfig& config);
};

Expand Down
2 changes: 1 addition & 1 deletion source/common/http/header_utility.cc
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ HeaderUtility::HeaderData::HeaderData(const Json::Object& config)

bool HeaderUtility::matchHeaders(const Http::HeaderMap& request_headers,
const std::vector<HeaderData>& config_headers) {
// TODO (rodaine): Should this really allow empty headers to always match?
// No headers to match is considered a match.
if (!config_headers.empty()) {
for (const HeaderData& cfg_header_data : config_headers) {
if (!matchHeaders(request_headers, cfg_header_data)) {
Expand Down
2 changes: 1 addition & 1 deletion source/common/http/header_utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class HeaderUtility {
* @param request_headers supplies the headers from the request.
* @param config_headers supplies the list of configured header conditions on which to match.
* @return bool true if all the headers (and values) in the config_headers are found in the
* request_headers
* request_headers. If no config_headers are specified, returns true.
*/
static bool matchHeaders(const Http::HeaderMap& request_headers,
const std::vector<HeaderData>& config_headers);
Expand Down
4 changes: 1 addition & 3 deletions source/common/http/http2/codec_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,15 @@
#include "envoy/network/connection.h"
#include "envoy/stats/scope.h"

//#include "envoy/stats/stats_macros.h"

#include "common/buffer/buffer_impl.h"
#include "common/buffer/watermark_buffer.h"
#include "common/common/linked_object.h"
#include "common/common/logger.h"
#include "common/http/codec_helper.h"
#include "common/http/header_map_impl.h"
#include "common/http/utility.h"
#include "common/http/http2/metadata_decoder.h"
#include "common/http/http2/metadata_encoder.h"
#include "common/http/utility.h"

#include "absl/types/optional.h"
#include "nghttp2/nghttp2.h"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "common/common/fmt.h"
#include "common/config/filter_json.h"
#include "common/config/utility.h"
#include "common/http/conn_manager_utility.h"
#include "common/http/date_provider_impl.h"
#include "common/http/default_server_string.h"
#include "common/http/http1/codec_impl.h"
Expand Down Expand Up @@ -117,24 +118,6 @@ static Registry::RegisterFactory<HttpConnectionManagerFilterConfigFactory,
Server::Configuration::NamedNetworkFilterConfigFactory>
registered_;

std::string
HttpConnectionManagerConfigUtility::determineNextProtocol(Network::Connection& connection,
const Buffer::Instance& data) {
if (!connection.nextProtocol().empty()) {
return connection.nextProtocol();
}

// See if the data we have so far shows the HTTP/2 prefix. We ignore the case where someone sends
// us the first few bytes of the HTTP/2 prefix since in all public cases we use SSL/ALPN. For
// internal cases this should practically never happen.
if (-1 != data.search(Http::Http2::CLIENT_MAGIC_PREFIX.c_str(),
Http::Http2::CLIENT_MAGIC_PREFIX.size(), 0)) {
return Http::Http2::ALPN_STRING;
}

return "";
}

InternalAddressConfig::InternalAddressConfig(
const envoy::config::filter::network::http_connection_manager::v2::HttpConnectionManager::
InternalAddressConfig& config)
Expand Down Expand Up @@ -344,14 +327,8 @@ HttpConnectionManagerConfig::createCodec(Network::Connection& connection,
return Http::ServerConnectionPtr{new Http::Http2::ServerConnectionImpl(
connection, callbacks, context_.scope(), http2_settings_)};
case CodecType::AUTO:
if (HttpConnectionManagerConfigUtility::determineNextProtocol(connection, data) ==
Http::Http2::ALPN_STRING) {
return Http::ServerConnectionPtr{new Http::Http2::ServerConnectionImpl(
connection, callbacks, context_.scope(), http2_settings_)};
} else {
return Http::ServerConnectionPtr{
new Http::Http1::ServerConnectionImpl(connection, callbacks, http1_settings_)};
}
return Http::ConnectionManagerUtility::autoCreateCodec(
connection, data, callbacks, context_.scope(), http1_settings_, http2_settings_);
}

NOT_REACHED_GCOVR_EXCL_LINE;
Expand Down
14 changes: 0 additions & 14 deletions source/extensions/filters/network/http_connection_manager/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,20 +46,6 @@ class HttpConnectionManagerFilterConfigFactory
Server::Configuration::FactoryContext& context) override;
};

/**
* Utilities for the HTTP connection manager that facilitate testing.
*/
class HttpConnectionManagerConfigUtility {
public:
/**
* Determine the next protocol to used based both on ALPN as well as protocol inspection.
* @param connection supplies the connection to determine a protocol for.
* @param data supplies the currently available read data on the connection.
*/
static std::string determineNextProtocol(Network::Connection& connection,
const Buffer::Instance& data);
};

/**
* Determines if an address is internal based on user provided config.
*/
Expand Down
1 change: 0 additions & 1 deletion source/server/http/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ envoy_cc_library(
"//source/common/http:header_map_lib",
"//source/common/http:headers_lib",
"//source/common/http:utility_lib",
"//source/common/http/http1:codec_lib",
"//source/common/memory:stats_lib",
"//source/common/network:listen_socket_lib",
"//source/common/network:raw_buffer_socket_lib",
Expand Down
Loading