Skip to content

Commit

Permalink
forward proxy: ip host headers
Browse files Browse the repository at this point in the history
Support IP addresses in host headers.

This completes the MVP of dynamic forward proxy.

Fixes #1606

Signed-off-by: Matt Klein <[email protected]>
  • Loading branch information
mattklein123 committed Jul 12, 2019
1 parent 9370f5e commit 56d6ee2
Show file tree
Hide file tree
Showing 14 changed files with 262 additions and 79 deletions.
4 changes: 2 additions & 2 deletions source/extensions/clusters/dynamic_forward_proxy/cluster.cc
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@ void Cluster::onDnsHostAddOrUpdate(

// Create an override transport socket options that automatically provides both SNI as well as
// SAN verification for the resolved host if the cluster has been configured with TLS.
// TODO(mattklein123): If the host is an IP address we should not set SNI.
Network::TransportSocketOptionsSharedPtr transport_socket_options =
std::make_shared<Network::TransportSocketOptionsImpl>(
host_info->resolvedHost(), std::vector<std::string>{host_info->resolvedHost()});
!host_info->isIpAddress() ? host_info->resolvedHost() : "",
std::vector<std::string>{host_info->resolvedHost()});

const auto new_host_map = std::make_shared<HostInfoMap>(*current_map);
const auto emplaced =
Expand Down
5 changes: 5 additions & 0 deletions source/extensions/common/dynamic_forward_proxy/dns_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ class DnsHostInfo {
*/
virtual const std::string& resolvedHost() PURE;

/**
* Returns whether the original host is an IP address.
*/
virtual bool isIpAddress() PURE;

/**
* Indicates that the host has been used and should not be purged depending on any configured
* TTL policy
Expand Down
38 changes: 27 additions & 11 deletions source/extensions/common/dynamic_forward_proxy/dns_cache_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -79,34 +79,50 @@ void DnsCacheImpl::startCacheLoad(const std::string& host, uint16_t default_port
return;
}

// TODO(mattklein123): Figure out if we want to support addresses of the form <IP>:<port>. This
// seems unlikely to be useful in TLS scenarios, but it is technically
// supported. We might want to block this form for now.
const auto colon_pos = host.find(':');
// First try to see if there is a port included. This also checks to see that there is not a ']'
// as the last character which is indicative of an IPv6 address without a port. This is a best
// effort attempt.
const auto colon_pos = host.rfind(':');
absl::string_view host_to_resolve = host;
if (colon_pos != absl::string_view::npos) {
if (colon_pos != absl::string_view::npos && host_to_resolve.back() != ']') {
const absl::string_view string_view_host = host;
host_to_resolve = string_view_host.substr(0, colon_pos);
const auto port_str = string_view_host.substr(colon_pos + 1);
uint64_t port64;
if (port_str.empty() || !absl::SimpleAtoi(port_str, &port64) || port64 > 65535) {
// Just attempt to resolve whatever we were given. This will very likely fail.
// TODO(mattklein123): Should we actually fail here or do something different?
host_to_resolve = host;
} else {
default_port = port64;
}
}

// Now see if this is an IP address. We need to know this because some things (such as setting
// SNI) are special cased if this is an IP address. Either way, we still go through the normal
// resolver flow. We could short-circuit the DNS resolver in this case, but the extra code to do
// so is not worth it since the DNS resolver should handle it for us.
bool is_ip_address = false;
try {
absl::string_view potential_ip_address = host_to_resolve;
if (potential_ip_address.front() == '[' && potential_ip_address.back() == ']') {
potential_ip_address.remove_prefix(1);
potential_ip_address.remove_suffix(1);
}
Network::Utility::parseInternetAddress(std::string(potential_ip_address));
is_ip_address = true;
host_to_resolve = potential_ip_address;
} catch (const EnvoyException&) {
}

// TODO(mattklein123): Right now, the same host with different ports will become two
// independent primary hosts with independent DNS resolutions. I'm not sure how much this will
// matter, but we could consider collapsing these down and sharing the underlying DNS resolution.
auto& primary_host =
*primary_hosts_
// try_emplace() is used here for direct argument forwarding.
.try_emplace(host,
std::make_unique<PrimaryHostInfo>(*this, host_to_resolve, default_port,
[this, host]() { onReResolve(host); }))
.try_emplace(host, std::make_unique<PrimaryHostInfo>(
*this, host_to_resolve, default_port, is_ip_address,
[this, host]() { onReResolve(host); }))
.first->second;
startResolve(host, primary_host);
}
Expand Down Expand Up @@ -244,11 +260,11 @@ void DnsCacheImpl::ThreadLocalHostInfo::updateHostMap(const TlsHostMapSharedPtr&

DnsCacheImpl::PrimaryHostInfo::PrimaryHostInfo(DnsCacheImpl& parent,
absl::string_view host_to_resolve, uint16_t port,
const Event::TimerCb& timer_cb)
bool is_ip_address, const Event::TimerCb& timer_cb)
: parent_(parent), port_(port),
refresh_timer_(parent.main_thread_dispatcher_.createTimer(timer_cb)),
host_info_(std::make_shared<DnsHostInfoImpl>(parent.main_thread_dispatcher_.timeSource(),
host_to_resolve)) {
host_to_resolve, is_ip_address)) {
parent_.stats_.host_added_.inc();
parent_.stats_.num_hosts_.inc();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,18 +71,20 @@ class DnsCacheImpl : public DnsCache, Logger::Loggable<Logger::Id::forward_proxy
};

struct DnsHostInfoImpl : public DnsHostInfo {
DnsHostInfoImpl(TimeSource& time_source, absl::string_view resolved_host)
: time_source_(time_source), resolved_host_(resolved_host) {
DnsHostInfoImpl(TimeSource& time_source, absl::string_view resolved_host, bool is_ip_address)
: time_source_(time_source), resolved_host_(resolved_host), is_ip_address_(is_ip_address) {
touch();
}

// DnsHostInfo
Network::Address::InstanceConstSharedPtr address() override { return address_; }
const std::string& resolvedHost() override { return resolved_host_; }
bool isIpAddress() override { return is_ip_address_; }
void touch() override { last_used_time_ = time_source_.monotonicTime().time_since_epoch(); }

TimeSource& time_source_;
const std::string resolved_host_;
const bool is_ip_address_;
bool first_resolve_complete_{};
Network::Address::InstanceConstSharedPtr address_;
// Using std::chrono::steady_clock::duration is required for compilation within an atomic vs.
Expand All @@ -95,7 +97,7 @@ class DnsCacheImpl : public DnsCache, Logger::Loggable<Logger::Id::forward_proxy
// Primary host information that accounts for TTL, re-resolution, etc.
struct PrimaryHostInfo {
PrimaryHostInfo(DnsCacheImpl& parent, absl::string_view host_to_resolve, uint16_t port,
const Event::TimerCb& timer_cb);
bool is_ip_address, const Event::TimerCb& timer_cb);
~PrimaryHostInfo();

DnsCacheImpl& parent_;
Expand Down
1 change: 1 addition & 0 deletions source/extensions/transport_sockets/tls/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ envoy_cc_library(
"//source/common/common:base64_lib",
"//source/common/common:hex_lib",
"//source/common/common:utility_lib",
"//source/common/network:address_lib",
"//source/common/protobuf:utility_lib",
"@envoy_api//envoy/admin/v2alpha:certs_cc",
],
Expand Down
37 changes: 35 additions & 2 deletions source/extensions/transport_sockets/tls/context_impl.cc
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "extensions/transport_sockets/tls/context_impl.h"

#include <netinet/in.h>

#include <algorithm>
#include <memory>
#include <string>
Expand All @@ -13,6 +15,7 @@
#include "common/common/fmt.h"
#include "common/common/hex.h"
#include "common/common/utility.h"
#include "common/network/address_impl.h"
#include "common/protobuf/utility.h"

#include "extensions/transport_sockets/tls/utility.h"
Expand Down Expand Up @@ -491,22 +494,52 @@ bool ContextImpl::verifySubjectAltName(X509* cert,
return false;
}
for (const GENERAL_NAME* san : san_names.get()) {
if (san->type == GEN_DNS) {
switch (san->type) {
case GEN_DNS: {
ASN1_STRING* str = san->d.dNSName;
const char* dns_name = reinterpret_cast<const char*>(ASN1_STRING_data(str));
for (auto& config_san : subject_alt_names) {
if (dNSNameMatch(config_san, dns_name)) {
return true;
}
}
} else if (san->type == GEN_URI) {
break;
}
case GEN_URI: {
ASN1_STRING* str = san->d.uniformResourceIdentifier;
const char* uri = reinterpret_cast<const char*>(ASN1_STRING_data(str));
for (auto& config_san : subject_alt_names) {
if (config_san.compare(uri) == 0) {
return true;
}
}
break;
}
case GEN_IPADD: {
sockaddr_storage ss;
if (san->d.ip->length == 4) {
auto& sin = reinterpret_cast<sockaddr_in&>(ss);
sin.sin_family = AF_INET;
memcpy(&sin.sin_addr, san->d.ip->data, 4);
Network::Address::Ipv4Instance addr(&sin);
for (auto& config_san : subject_alt_names) {
if (config_san == addr.ip()->addressAsString()) {
return true;
}
}
} else if (san->d.ip->length == 16) {
auto& sin6 = reinterpret_cast<sockaddr_in6&>(ss);
sin6.sin6_family = AF_INET6;
memcpy(&sin6.sin6_addr, san->d.ip->data, 16);
Network::Address::Ipv6Instance addr(sin6);
for (auto& config_san : subject_alt_names) {
if (config_san == addr.ip()->addressAsString()) {
return true;
}
}
}
break;
}
}
}
return false;
Expand Down
4 changes: 2 additions & 2 deletions test/config/integration/certs/upstreamlocalhostcert.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ authorityKeyIdentifier = keyid:always

[alt_names]
DNS.2 = localhost
IP.1 = 0.0.0.0
IP.2 = ::
IP.1 = 127.0.0.1
IP.2 = ::1
36 changes: 18 additions & 18 deletions test/config/integration/certs/upstreamlocalhostcert.pem
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
-----BEGIN CERTIFICATE-----
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
-----END CERTIFICATE-----
4 changes: 2 additions & 2 deletions test/config/integration/certs/upstreamlocalhostcert_hash.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// NOLINT(namespace-envoy)
constexpr char TEST_UPSTREAMLOCALHOST_CERT_HASH[] =
"5B:5C:02:47:DE:17:B7:1B:98:05:0A:DB:41:2C:F6:8F:65:E3:86:E6:03:B3:9A:EC:67:33:2E:39:1F:05:88:"
"B0";
"44:A1:C4:AD:71:B5:AE:A0:A2:24:63:DA:C8:FF:0C:FC:26:6E:4B:D7:08:DE:64:60:34:A0:72:42:6E:18:BA:"
"87";
50 changes: 25 additions & 25 deletions test/config/integration/certs/upstreamlocalhostkey.pem
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class ClusterTest : public testing::Test,

// Allow touch() to still be strict.
EXPECT_CALL(*host_map_[host], address()).Times(AtLeast(0));
EXPECT_CALL(*host_map_[host], isIpAddress()).Times(AtLeast(0));
EXPECT_CALL(*host_map_[host], resolvedHost()).Times(AtLeast(0));
}

Expand Down
Loading

0 comments on commit 56d6ee2

Please sign in to comment.