diff --git a/VERSION b/VERSION index bd8bf882d061..943f9cbc4ec7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.7.0 +1.7.1 diff --git a/api/envoy/api/v2/cds.proto b/api/envoy/api/v2/cds.proto index 8359cd51964b..bc26fd659cae 100644 --- a/api/envoy/api/v2/cds.proto +++ b/api/envoy/api/v2/cds.proto @@ -42,7 +42,7 @@ service ClusterDiscoveryService { // [#protodoc-title: Clusters] // Configuration for a single upstream cluster. -// [#comment:next free field: 34] +// [#comment:next free field: 35] message Cluster { // Supplies the name of the cluster which must be unique across all clusters. // The cluster name is used when emitting @@ -373,6 +373,22 @@ message Cluster { DeprecatedV1 deprecated_v1 = 2 [deprecated = true]; } + // Specific configuration for the + // :ref:`Original Destination ` + // load balancing policy. + message OriginalDstLbConfig { + // When true, :ref:`x-envoy-orignal-dst-host + // ` can be used to override destination + // address. + // + // .. attention:: + // + // This header isn't sanitized by default, so enabling this feature allows HTTP clients to + // route traffic to arbitrary hosts and/or ports, which may have serious security + // consequences. + bool use_http_header = 1; + } + // Optional configuration for the load balancing algorithm selected by // LbPolicy. Currently only // :ref:`RING_HASH` @@ -383,6 +399,8 @@ message Cluster { oneof lb_config { // Optional configuration for the Ring Hash load balancing policy. RingHashLbConfig ring_hash_lb_config = 23; + // Optional configuration for the Original Destination load balancing policy. + OriginalDstLbConfig original_dst_lb_config = 34; } // Common configuration for all load balancer implementations. diff --git a/docs/root/configuration/http_conn_man/headers.rst b/docs/root/configuration/http_conn_man/headers.rst index 895b048cc8af..eaf102baeafb 100644 --- a/docs/root/configuration/http_conn_man/headers.rst +++ b/docs/root/configuration/http_conn_man/headers.rst @@ -98,6 +98,18 @@ the header value to *true*. This is a convenience to avoid having to parse and understand XFF. +.. _config_http_conn_man_headers_x-envoy-original-dst-host: + +x-envoy-original-dst-host +------------------------- + +The header used to override destination address when using the +:ref:`Original Destination ` +load balancing policy. + +It is ignored, unless the use of it is enabled via +:ref:`use_http_header `. + .. _config_http_conn_man_headers_x-forwarded-client-cert: x-forwarded-client-cert diff --git a/docs/root/intro/arch_overview/load_balancing.rst b/docs/root/intro/arch_overview/load_balancing.rst index f0dbe825930d..e23cc1862ada 100644 --- a/docs/root/intro/arch_overview/load_balancing.rst +++ b/docs/root/intro/arch_overview/load_balancing.rst @@ -126,7 +126,8 @@ be used with original destination clusters. Original destination host request header ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Envoy can also pick up the original destination from a HTTP header called ``x-envoy-original-destination-host``. +Envoy can also pick up the original destination from a HTTP header called +:ref:`x-envoy-orignal-dst-host `. Please note that fully resolved IP address should be passed in this header. For example if a request has to be routed to a host with IP address 10.195.16.237 at port 8888, the request header value should be set as ``10.195.16.237:8888``. diff --git a/docs/root/intro/version_history.rst b/docs/root/intro/version_history.rst index 62213eb5cc2a..47a0b29efcca 100644 --- a/docs/root/intro/version_history.rst +++ b/docs/root/intro/version_history.rst @@ -1,6 +1,13 @@ Version history --------------- +1.7.1 +===== + +* upstream: require opt-in to use the :ref:`x-envoy-orignal-dst-host ` header + for overriding destination address when using the :ref:`Original Destination ` + load balancing policy. + 1.7.0 =============== * access log: added ability to log response trailers. diff --git a/include/envoy/upstream/upstream.h b/include/envoy/upstream/upstream.h index 2e24c7543aef..756e6f49b299 100644 --- a/include/envoy/upstream/upstream.h +++ b/include/envoy/upstream/upstream.h @@ -458,6 +458,14 @@ class ClusterInfo { virtual const absl::optional& lbRingHashConfig() const PURE; + /** + * @return const absl::optional& the configuration + * for the Original Destination load balancing policy, only used if type is set to + * ORIGINAL_DST_LB. + */ + virtual const absl::optional& + lbOriginalDstConfig() const PURE; + /** * @return Whether the cluster is currently in maintenance mode and should not be routed to. * Different filters may handle this situation in different ways. The implementation diff --git a/source/common/upstream/cluster_manager_impl.cc b/source/common/upstream/cluster_manager_impl.cc index 42e0c2b89b89..0ef78897ed9f 100644 --- a/source/common/upstream/cluster_manager_impl.cc +++ b/source/common/upstream/cluster_manager_impl.cc @@ -877,7 +877,8 @@ ClusterManagerImpl::ThreadLocalClusterManagerImpl::ClusterEntry::ClusterEntry( case LoadBalancerType::OriginalDst: { ASSERT(lb_factory_ == nullptr); lb_.reset(new OriginalDstCluster::LoadBalancer( - priority_set_, parent.parent_.active_clusters_.at(cluster->name())->cluster_)); + priority_set_, parent.parent_.active_clusters_.at(cluster->name())->cluster_, + cluster->lbOriginalDstConfig())); break; } } diff --git a/source/common/upstream/original_dst_cluster.cc b/source/common/upstream/original_dst_cluster.cc index e00f39f9410d..716d196f5b38 100644 --- a/source/common/upstream/original_dst_cluster.cc +++ b/source/common/upstream/original_dst_cluster.cc @@ -20,9 +20,11 @@ namespace Upstream { // OriginalDstCluster::LoadBalancer is never configured with any other type of cluster, // and throws an exception otherwise. -OriginalDstCluster::LoadBalancer::LoadBalancer(PrioritySet& priority_set, ClusterSharedPtr& parent) +OriginalDstCluster::LoadBalancer::LoadBalancer( + PrioritySet& priority_set, ClusterSharedPtr& parent, + const absl::optional& config) : priority_set_(priority_set), parent_(std::static_pointer_cast(parent)), - info_(parent->info()) { + info_(parent->info()), use_http_header_(config ? config.value().use_http_header() : false) { // priority_set_ is initially empty. priority_set_.addMemberUpdateCb( [this](uint32_t, const HostVector& hosts_added, const HostVector& hosts_removed) -> void { @@ -44,7 +46,10 @@ HostConstSharedPtr OriginalDstCluster::LoadBalancer::chooseHost(LoadBalancerCont if (context) { // Check if override host header is present, if yes use it otherwise check local address. - Network::Address::InstanceConstSharedPtr dst_host = requestOverrideHost(context); + Network::Address::InstanceConstSharedPtr dst_host = nullptr; + if (use_http_header_) { + dst_host = requestOverrideHost(context); + } if (dst_host == nullptr) { const Network::Connection* connection = context->downstreamConnection(); // The local address of the downstream connection is the original destination address, diff --git a/source/common/upstream/original_dst_cluster.h b/source/common/upstream/original_dst_cluster.h index 5cb5107a3a4a..c077a5d9fc16 100644 --- a/source/common/upstream/original_dst_cluster.h +++ b/source/common/upstream/original_dst_cluster.h @@ -43,7 +43,8 @@ class OriginalDstCluster : public ClusterImplBase { */ class LoadBalancer : public Upstream::LoadBalancer { public: - LoadBalancer(PrioritySet& priority_set, ClusterSharedPtr& parent); + LoadBalancer(PrioritySet& priority_set, ClusterSharedPtr& parent, + const absl::optional& config); // Upstream::LoadBalancer HostConstSharedPtr chooseHost(LoadBalancerContext* context) override; @@ -97,6 +98,7 @@ class OriginalDstCluster : public ClusterImplBase { PrioritySet& priority_set_; // Thread local priority set. std::weak_ptr parent_; // Primary cluster managed by the main thread. ClusterInfoConstSharedPtr info_; + const bool use_http_header_; HostMap host_map_; }; diff --git a/source/common/upstream/upstream_impl.cc b/source/common/upstream/upstream_impl.cc index ea36ac333fe2..03f99aaa4f80 100644 --- a/source/common/upstream/upstream_impl.cc +++ b/source/common/upstream/upstream_impl.cc @@ -276,7 +276,8 @@ ClusterInfoImpl::ClusterInfoImpl(const envoy::api::v2::Cluster& config, resource_managers_(config, runtime, name_), maintenance_mode_runtime_key_(fmt::format("upstream.maintenance_mode.{}", name_)), source_address_(getSourceAddress(config, bind_config)), - lb_ring_hash_config_(envoy::api::v2::Cluster::RingHashLbConfig(config.ring_hash_lb_config())), + lb_ring_hash_config_(config.ring_hash_lb_config()), + lb_original_dst_config_(config.original_dst_lb_config()), ssl_context_manager_(ssl_context_manager), added_via_api_(added_via_api), lb_subset_(LoadBalancerSubsetInfoImpl(config.lb_subset_config())), metadata_(config.metadata()), common_lb_config_(config.common_lb_config()), diff --git a/source/common/upstream/upstream_impl.h b/source/common/upstream/upstream_impl.h index 6540b8ac4ca8..88b7958610f8 100644 --- a/source/common/upstream/upstream_impl.h +++ b/source/common/upstream/upstream_impl.h @@ -338,6 +338,10 @@ class ClusterInfoImpl : public ClusterInfo, lbRingHashConfig() const override { return lb_ring_hash_config_; } + const absl::optional& + lbOriginalDstConfig() const override { + return lb_original_dst_config_; + } bool maintenanceMode() const override; uint64_t maxRequestsPerConnection() const override { return max_requests_per_connection_; } const std::string& name() const override { return name_; } @@ -397,6 +401,7 @@ class ClusterInfoImpl : public ClusterInfo, const Network::Address::InstanceConstSharedPtr source_address_; LoadBalancerType lb_type_; absl::optional lb_ring_hash_config_; + absl::optional lb_original_dst_config_; Ssl::ContextManager& ssl_context_manager_; const bool added_via_api_; LoadBalancerSubsetInfoImpl lb_subset_; diff --git a/test/common/upstream/original_dst_cluster_test.cc b/test/common/upstream/original_dst_cluster_test.cc index 098723c4d0dd..eb383bde6859 100644 --- a/test/common/upstream/original_dst_cluster_test.cc +++ b/test/common/upstream/original_dst_cluster_test.cc @@ -57,9 +57,12 @@ class OriginalDstClusterTest : public testing::Test { // take care of destructing it! OriginalDstClusterTest() : cleanup_timer_(new Event::MockTimer(&dispatcher_)) {} - void setup(const std::string& json) { + void setupFromJson(const std::string& json) { setup(parseClusterFromJson(json)); } + void setupFromYaml(const std::string& yaml) { setup(parseClusterFromV2Yaml(yaml)); } + + void setup(const envoy::api::v2::Cluster& cluster_config) { NiceMock cm; - cluster_.reset(new OriginalDstCluster(parseClusterFromJson(json), runtime_, stats_store_, + cluster_.reset(new OriginalDstCluster(cluster_config, runtime_, stats_store_, ssl_context_manager_, cm, dispatcher_, false)); cluster_->prioritySet().addMemberUpdateCb( [&](uint32_t, const HostVector&, const HostVector&) -> void { @@ -120,7 +123,7 @@ TEST_F(OriginalDstClusterTest, CleanupInterval) { EXPECT_CALL(initialized_, ready()); EXPECT_CALL(membership_updated_, ready()).Times(0); EXPECT_CALL(*cleanup_timer_, enableTimer(std::chrono::milliseconds(1000))); - setup(json); + setupFromJson(json); EXPECT_EQ(0UL, cluster_->prioritySet().hostSetsPerPriority()[0]->hosts().size()); EXPECT_EQ(0UL, cluster_->prioritySet().hostSetsPerPriority()[0]->healthyHosts().size()); @@ -139,7 +142,7 @@ TEST_F(OriginalDstClusterTest, NoContext) { EXPECT_CALL(initialized_, ready()); EXPECT_CALL(membership_updated_, ready()).Times(0); EXPECT_CALL(*cleanup_timer_, enableTimer(_)); - setup(json); + setupFromJson(json); EXPECT_EQ(0UL, cluster_->prioritySet().hostSetsPerPriority()[0]->hosts().size()); EXPECT_EQ(0UL, cluster_->prioritySet().hostSetsPerPriority()[0]->healthyHosts().size()); @@ -151,47 +154,11 @@ TEST_F(OriginalDstClusterTest, NoContext) { // No downstream connection => no host. { TestLoadBalancerContext lb_context(nullptr); - OriginalDstCluster::LoadBalancer lb(cluster_->prioritySet(), cluster_); - EXPECT_CALL(dispatcher_, post(_)).Times(0); - HostConstSharedPtr host = lb.chooseHost(&lb_context); - EXPECT_EQ(host, nullptr); - } - - // Request host override => overridden host. - { - TestLoadBalancerContext lb_context(nullptr, Http::Headers::get().EnvoyOriginalDstHost.get(), - "127.0.0.1:5555"); - OriginalDstCluster::LoadBalancer lb(cluster_->prioritySet(), cluster_); - Event::PostCb post_cb; - EXPECT_CALL(dispatcher_, post(_)).WillOnce(SaveArg<0>(&post_cb)); - HostConstSharedPtr host = lb.chooseHost(&lb_context); - EXPECT_EQ("127.0.0.1:5555", host->address()->asString()); - } - - // Request host override empty ip => no host. - { - TestLoadBalancerContext lb_context(nullptr, Http::Headers::get().EnvoyOriginalDstHost.get(), - ""); - OriginalDstCluster::LoadBalancer lb(cluster_->prioritySet(), cluster_); + OriginalDstCluster::LoadBalancer lb(cluster_->prioritySet(), cluster_, + cluster_->info()->lbOriginalDstConfig()); EXPECT_CALL(dispatcher_, post(_)).Times(0); HostConstSharedPtr host = lb.chooseHost(&lb_context); EXPECT_EQ(host, nullptr); - EXPECT_EQ( - 1, - TestUtility::findCounter(stats_store_, "cluster.name.original_dst_host_invalid")->value()); - } - - // Request host override malformed ip => no host. - { - TestLoadBalancerContext lb_context(nullptr, Http::Headers::get().EnvoyOriginalDstHost.get(), - "blah"); - OriginalDstCluster::LoadBalancer lb(cluster_->prioritySet(), cluster_); - EXPECT_CALL(dispatcher_, post(_)).Times(0); - HostConstSharedPtr host = lb.chooseHost(&lb_context); - EXPECT_EQ(host, nullptr); - EXPECT_EQ( - 2, - TestUtility::findCounter(stats_store_, "cluster.name.original_dst_host_invalid")->value()); } // Downstream connection is not using original dst => no host. @@ -203,7 +170,8 @@ TEST_F(OriginalDstClusterTest, NoContext) { // First argument is normally the reference to the ThreadLocalCluster's HostSet, but in these // tests we do not have the thread local clusters, so we pass a reference to the HostSet of the // primary cluster. The implementation handles both cases the same. - OriginalDstCluster::LoadBalancer lb(cluster_->prioritySet(), cluster_); + OriginalDstCluster::LoadBalancer lb(cluster_->prioritySet(), cluster_, + cluster_->info()->lbOriginalDstConfig()); EXPECT_CALL(dispatcher_, post(_)).Times(0); HostConstSharedPtr host = lb.chooseHost(&lb_context); EXPECT_EQ(host, nullptr); @@ -216,7 +184,8 @@ TEST_F(OriginalDstClusterTest, NoContext) { connection.local_address_ = std::make_shared("unix://foo"); EXPECT_CALL(connection, localAddressRestored()).WillRepeatedly(Return(true)); - OriginalDstCluster::LoadBalancer lb(cluster_->prioritySet(), cluster_); + OriginalDstCluster::LoadBalancer lb(cluster_->prioritySet(), cluster_, + cluster_->info()->lbOriginalDstConfig()); EXPECT_CALL(dispatcher_, post(_)).Times(0); HostConstSharedPtr host = lb.chooseHost(&lb_context); EXPECT_EQ(host, nullptr); @@ -235,7 +204,7 @@ TEST_F(OriginalDstClusterTest, Membership) { EXPECT_CALL(initialized_, ready()); EXPECT_CALL(*cleanup_timer_, enableTimer(_)); - setup(json); + setupFromJson(json); EXPECT_EQ(0UL, cluster_->prioritySet().hostSetsPerPriority()[0]->hosts().size()); EXPECT_EQ(0UL, cluster_->prioritySet().hostSetsPerPriority()[0]->healthyHosts().size()); @@ -253,7 +222,8 @@ TEST_F(OriginalDstClusterTest, Membership) { connection.local_address_ = std::make_shared("10.10.11.11"); EXPECT_CALL(connection, localAddressRestored()).WillRepeatedly(Return(true)); - OriginalDstCluster::LoadBalancer lb(cluster_->prioritySet(), cluster_); + OriginalDstCluster::LoadBalancer lb(cluster_->prioritySet(), cluster_, + cluster_->info()->lbOriginalDstConfig()); Event::PostCb post_cb; EXPECT_CALL(dispatcher_, post(_)).WillOnce(SaveArg<0>(&post_cb)); HostConstSharedPtr host = lb.chooseHost(&lb_context); @@ -326,7 +296,7 @@ TEST_F(OriginalDstClusterTest, Membership2) { EXPECT_CALL(initialized_, ready()); EXPECT_CALL(*cleanup_timer_, enableTimer(_)); - setup(json); + setupFromJson(json); EXPECT_EQ(0UL, cluster_->prioritySet().hostSetsPerPriority()[0]->hosts().size()); EXPECT_EQ(0UL, cluster_->prioritySet().hostSetsPerPriority()[0]->healthyHosts().size()); @@ -347,7 +317,8 @@ TEST_F(OriginalDstClusterTest, Membership2) { connection2.local_address_ = std::make_shared("10.10.11.12"); EXPECT_CALL(connection2, localAddressRestored()).WillRepeatedly(Return(true)); - OriginalDstCluster::LoadBalancer lb(cluster_->prioritySet(), cluster_); + OriginalDstCluster::LoadBalancer lb(cluster_->prioritySet(), cluster_, + cluster_->info()->lbOriginalDstConfig()); EXPECT_CALL(membership_updated_, ready()); Event::PostCb post_cb; @@ -417,7 +388,7 @@ TEST_F(OriginalDstClusterTest, Connection) { EXPECT_CALL(initialized_, ready()); EXPECT_CALL(*cleanup_timer_, enableTimer(_)); - setup(json); + setupFromJson(json); EXPECT_EQ(0UL, cluster_->prioritySet().hostSetsPerPriority()[0]->hosts().size()); EXPECT_EQ(0UL, cluster_->prioritySet().hostSetsPerPriority()[0]->healthyHosts().size()); @@ -434,7 +405,8 @@ TEST_F(OriginalDstClusterTest, Connection) { connection.local_address_ = std::make_shared("FD00::1"); EXPECT_CALL(connection, localAddressRestored()).WillRepeatedly(Return(true)); - OriginalDstCluster::LoadBalancer lb(cluster_->prioritySet(), cluster_); + OriginalDstCluster::LoadBalancer lb(cluster_->prioritySet(), cluster_, + cluster_->info()->lbOriginalDstConfig()); Event::PostCb post_cb; EXPECT_CALL(dispatcher_, post(_)).WillOnce(SaveArg<0>(&post_cb)); HostConstSharedPtr host = lb.chooseHost(&lb_context); @@ -459,7 +431,7 @@ TEST_F(OriginalDstClusterTest, MultipleClusters) { EXPECT_CALL(initialized_, ready()); EXPECT_CALL(*cleanup_timer_, enableTimer(_)); - setup(json); + setupFromJson(json); PrioritySetImpl second; cluster_->prioritySet().addMemberUpdateCb( @@ -483,8 +455,9 @@ TEST_F(OriginalDstClusterTest, MultipleClusters) { connection.local_address_ = std::make_shared("FD00::1"); EXPECT_CALL(connection, localAddressRestored()).WillRepeatedly(Return(true)); - OriginalDstCluster::LoadBalancer lb1(cluster_->prioritySet(), cluster_); - OriginalDstCluster::LoadBalancer lb2(second, cluster_); + OriginalDstCluster::LoadBalancer lb1(cluster_->prioritySet(), cluster_, + cluster_->info()->lbOriginalDstConfig()); + OriginalDstCluster::LoadBalancer lb2(second, cluster_, cluster_->info()->lbOriginalDstConfig()); Event::PostCb post_cb; EXPECT_CALL(dispatcher_, post(_)).WillOnce(SaveArg<0>(&post_cb)); HostConstSharedPtr host = lb1.chooseHost(&lb_context); @@ -500,6 +473,141 @@ TEST_F(OriginalDstClusterTest, MultipleClusters) { EXPECT_EQ(host, second.hostSetsPerPriority()[0]->hosts()[0]); } +TEST_F(OriginalDstClusterTest, UseHttpHeaderEnabled) { + std::string yaml = R"EOF( + name: "name" + connect_timeout: 1.250s + type: original_dst + lb_type: original_dst_lb + original_dst_lb_config: + use_http_header: true + )EOF"; + + EXPECT_CALL(initialized_, ready()); + EXPECT_CALL(*cleanup_timer_, enableTimer(_)); + setupFromYaml(yaml); + + EXPECT_EQ(0UL, cluster_->prioritySet().hostSetsPerPriority()[0]->hosts().size()); + EXPECT_EQ(0UL, cluster_->prioritySet().hostSetsPerPriority()[0]->healthyHosts().size()); + EXPECT_EQ(0UL, cluster_->prioritySet().hostSetsPerPriority()[0]->hostsPerLocality().get().size()); + EXPECT_EQ( + 0UL, + cluster_->prioritySet().hostSetsPerPriority()[0]->healthyHostsPerLocality().get().size()); + + OriginalDstCluster::LoadBalancer lb(cluster_->prioritySet(), cluster_, + cluster_->info()->lbOriginalDstConfig()); + Event::PostCb post_cb; + + // HTTP header override. + TestLoadBalancerContext lb_context1(nullptr, Http::Headers::get().EnvoyOriginalDstHost.get(), + "127.0.0.1:5555"); + + EXPECT_CALL(membership_updated_, ready()); + EXPECT_CALL(dispatcher_, post(_)).WillOnce(SaveArg<0>(&post_cb)); + HostConstSharedPtr host1 = lb.chooseHost(&lb_context1); + post_cb(); + ASSERT_NE(host1, nullptr); + EXPECT_EQ("127.0.0.1:5555", host1->address()->asString()); + + // HTTP header override on downstream connection which isn't using original_dst filter + // and/or is done over Unix Domain Socket. This works, because properties of the downstream + // connection are never checked when using HTTP header override. + NiceMock connection2; + EXPECT_CALL(connection2, localAddress()).Times(0); + EXPECT_CALL(connection2, localAddressRestored()).Times(0); + TestLoadBalancerContext lb_context2(&connection2, Http::Headers::get().EnvoyOriginalDstHost.get(), + "127.0.0.1:5556"); + + EXPECT_CALL(membership_updated_, ready()); + EXPECT_CALL(dispatcher_, post(_)).WillOnce(SaveArg<0>(&post_cb)); + HostConstSharedPtr host2 = lb.chooseHost(&lb_context2); + post_cb(); + ASSERT_NE(host2, nullptr); + EXPECT_EQ("127.0.0.1:5556", host2->address()->asString()); + + // HTTP header override with empty header value. + TestLoadBalancerContext lb_context3(nullptr, Http::Headers::get().EnvoyOriginalDstHost.get(), ""); + + EXPECT_CALL(membership_updated_, ready()).Times(0); + EXPECT_CALL(dispatcher_, post(_)).Times(0); + HostConstSharedPtr host3 = lb.chooseHost(&lb_context3); + EXPECT_EQ(host3, nullptr); + EXPECT_EQ( + 1, TestUtility::findCounter(stats_store_, "cluster.name.original_dst_host_invalid")->value()); + + // HTTP header override with invalid header value. + TestLoadBalancerContext lb_context4(nullptr, Http::Headers::get().EnvoyOriginalDstHost.get(), + "a.b.c.d"); + + EXPECT_CALL(membership_updated_, ready()).Times(0); + EXPECT_CALL(dispatcher_, post(_)).Times(0); + HostConstSharedPtr host4 = lb.chooseHost(&lb_context4); + EXPECT_EQ(host4, nullptr); + EXPECT_EQ( + 2, TestUtility::findCounter(stats_store_, "cluster.name.original_dst_host_invalid")->value()); +} + +TEST_F(OriginalDstClusterTest, UseHttpHeaderDisabled) { + std::string yaml = R"EOF( + name: "name" + connect_timeout: 1.250s + type: original_dst + lb_type: original_dst_lb + )EOF"; + + EXPECT_CALL(initialized_, ready()); + EXPECT_CALL(*cleanup_timer_, enableTimer(_)); + setupFromYaml(yaml); + + EXPECT_EQ(0UL, cluster_->prioritySet().hostSetsPerPriority()[0]->hosts().size()); + EXPECT_EQ(0UL, cluster_->prioritySet().hostSetsPerPriority()[0]->healthyHosts().size()); + EXPECT_EQ(0UL, cluster_->prioritySet().hostSetsPerPriority()[0]->hostsPerLocality().get().size()); + EXPECT_EQ( + 0UL, + cluster_->prioritySet().hostSetsPerPriority()[0]->healthyHostsPerLocality().get().size()); + + OriginalDstCluster::LoadBalancer lb(cluster_->prioritySet(), cluster_, + cluster_->info()->lbOriginalDstConfig()); + Event::PostCb post_cb; + + // Downstream connection with original_dst filter, HTTP header override ignored. + NiceMock connection1; + connection1.local_address_ = std::make_shared("10.10.11.11"); + EXPECT_CALL(connection1, localAddressRestored()).WillOnce(Return(true)); + TestLoadBalancerContext lb_context1(&connection1, Http::Headers::get().EnvoyOriginalDstHost.get(), + "127.0.0.1:5555"); + + EXPECT_CALL(membership_updated_, ready()); + EXPECT_CALL(dispatcher_, post(_)).WillOnce(SaveArg<0>(&post_cb)); + HostConstSharedPtr host1 = lb.chooseHost(&lb_context1); + post_cb(); + ASSERT_NE(host1, nullptr); + EXPECT_EQ(*connection1.local_address_, *host1->address()); + + // Downstream connection without original_dst filter, HTTP header override ignored. + NiceMock connection2; + connection2.local_address_ = std::make_shared("10.10.11.11"); + EXPECT_CALL(connection2, localAddressRestored()).WillOnce(Return(false)); + TestLoadBalancerContext lb_context2(&connection2, Http::Headers::get().EnvoyOriginalDstHost.get(), + "127.0.0.1:5555"); + + EXPECT_CALL(membership_updated_, ready()).Times(0); + EXPECT_CALL(dispatcher_, post(_)).Times(0); + HostConstSharedPtr host2 = lb.chooseHost(&lb_context2); + EXPECT_EQ(host2, nullptr); + + // Downstream connection over Unix Domain Socket, HTTP header override ignored. + NiceMock connection3; + connection3.local_address_ = std::make_shared("unix://foo"); + TestLoadBalancerContext lb_context3(&connection3, Http::Headers::get().EnvoyOriginalDstHost.get(), + "127.0.0.1:5555"); + + EXPECT_CALL(membership_updated_, ready()).Times(0); + EXPECT_CALL(dispatcher_, post(_)).Times(0); + HostConstSharedPtr host3 = lb.chooseHost(&lb_context3); + EXPECT_EQ(host3, nullptr); +} + } // namespace OriginalDstClusterTest } // namespace Upstream -} // namespace Envoy \ No newline at end of file +} // namespace Envoy diff --git a/test/mocks/upstream/cluster_info.cc b/test/mocks/upstream/cluster_info.cc index c0fe5cbda3b7..34396a0b596e 100644 --- a/test/mocks/upstream/cluster_info.cc +++ b/test/mocks/upstream/cluster_info.cc @@ -51,6 +51,7 @@ MockClusterInfo::MockClusterInfo() ON_CALL(*this, sourceAddress()).WillByDefault(ReturnRef(source_address_)); ON_CALL(*this, lbSubsetInfo()).WillByDefault(ReturnRef(lb_subset_)); ON_CALL(*this, lbRingHashConfig()).WillByDefault(ReturnRef(lb_ring_hash_config_)); + ON_CALL(*this, lbOriginalDstConfig()).WillByDefault(ReturnRef(lb_original_dst_config_)); ON_CALL(*this, lbConfig()).WillByDefault(ReturnRef(lb_config_)); ON_CALL(*this, clusterSocketOptions()).WillByDefault(ReturnRef(cluster_socket_options_)); } diff --git a/test/mocks/upstream/cluster_info.h b/test/mocks/upstream/cluster_info.h index 8c34157daf4d..0a661b1227c8 100644 --- a/test/mocks/upstream/cluster_info.h +++ b/test/mocks/upstream/cluster_info.h @@ -51,6 +51,8 @@ class MockClusterInfo : public ClusterInfo { MOCK_CONST_METHOD0(type, envoy::api::v2::Cluster::DiscoveryType()); MOCK_CONST_METHOD0(lbRingHashConfig, const absl::optional&()); + MOCK_CONST_METHOD0(lbOriginalDstConfig, + const absl::optional&()); MOCK_CONST_METHOD0(maintenanceMode, bool()); MOCK_CONST_METHOD0(maxRequestsPerConnection, uint64_t()); MOCK_CONST_METHOD0(name, const std::string&()); @@ -80,6 +82,7 @@ class MockClusterInfo : public ClusterInfo { envoy::api::v2::Cluster::DiscoveryType type_{envoy::api::v2::Cluster::STRICT_DNS}; NiceMock lb_subset_; absl::optional lb_ring_hash_config_; + absl::optional lb_original_dst_config_; Network::ConnectionSocket::OptionsSharedPtr cluster_socket_options_; envoy::api::v2::Cluster::CommonLbConfig lb_config_; };