Skip to content
Merged
1 change: 1 addition & 0 deletions src/envoy/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ envoy_cc_binary(
"//src/envoy/http/mixer:filter_lib",
"//src/envoy/tcp/mixer:filter_lib",
"//src/envoy/tcp/tcp_cluster_rewrite:config_lib",
"//src/envoy/tcp/forward_downstream_sni:config_lib",
"@envoy//source/exe:envoy_main_entry_lib",
],
)
Expand Down
56 changes: 56 additions & 0 deletions src/envoy/tcp/forward_downstream_sni/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Copyright 2018 Istio Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
################################################################################
#

load(
"@envoy//bazel:envoy_build_system.bzl",
"envoy_cc_library",
"envoy_cc_test",
)

envoy_cc_library(
name = "config_lib",
srcs = ["config.cc"],
hdrs = ["config.h"],
repository = "@envoy",
visibility = ["//visibility:public"],
deps = [
":forward_downstream_sni_lib",
"@envoy//source/exe:envoy_common_lib",
],
)
envoy_cc_library(
name = "forward_downstream_sni_lib",
srcs = ["forward_downstream_sni.cc"],
hdrs = ["forward_downstream_sni.h"],
repository = "@envoy",
deps = [
"@envoy//source/exe:envoy_common_lib",
],
)

envoy_cc_test(
name = "forward_downstream_sni_test",
srcs = ["forward_downstream_sni_test.cc"],
repository = "@envoy",
deps = [
":forward_downstream_sni_lib",
":config_lib",
"@envoy//test/mocks/network:network_mocks",
"@envoy//test/mocks/server:server_mocks",
"@envoy//test/mocks/stream_info:stream_info_mocks",
],
)
59 changes: 59 additions & 0 deletions src/envoy/tcp/forward_downstream_sni/config.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* Copyright 2018 Istio Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "src/envoy/tcp/forward_downstream_sni/config.h"

#include "envoy/registry/registry.h"
#include "envoy/server/filter_config.h"

#include "src/envoy/tcp/forward_downstream_sni/forward_downstream_sni.h"

namespace Envoy {
namespace Tcp {
namespace ForwardDownstreamSni {

Network::FilterFactoryCb
ForwardDownstreamSniNetworkFilterConfigFactory::createFilterFactory(
const Json::Object&, Server::Configuration::FactoryContext&) {
// Only used in v1 filters.
NOT_IMPLEMENTED_GCOVR_EXCL_LINE;
}

Network::FilterFactoryCb
ForwardDownstreamSniNetworkFilterConfigFactory::createFilterFactoryFromProto(
const Protobuf::Message&, Server::Configuration::FactoryContext&) {
return [](Network::FilterManager& filter_manager) -> void {
filter_manager.addReadFilter(
std::make_shared<ForwardDownstreamSniFilter>());
};
}

ProtobufTypes::MessagePtr
ForwardDownstreamSniNetworkFilterConfigFactory::createEmptyConfigProto() {
return std::make_unique<ProtobufWkt::Empty>();
}

/**
* Static registration for the forward_original_sni filter. @see
* RegisterFactory.
*/
static Registry::RegisterFactory<
ForwardDownstreamSniNetworkFilterConfigFactory,
Server::Configuration::NamedNetworkFilterConfigFactory>
registered_;

} // namespace ForwardDownstreamSni
} // namespace Tcp
} // namespace Envoy
43 changes: 43 additions & 0 deletions src/envoy/tcp/forward_downstream_sni/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/* Copyright 2018 Istio Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include "envoy/server/filter_config.h"

namespace Envoy {
namespace Tcp {
namespace ForwardDownstreamSni {

/**
* Config registration for the forward_downstream_sni filter. @see
* NamedNetworkFilterConfigFactory.
*/
class ForwardDownstreamSniNetworkFilterConfigFactory
: public Server::Configuration::NamedNetworkFilterConfigFactory {
public:
// NamedNetworkFilterConfigFactory
Network::FilterFactoryCb createFilterFactory(
const Json::Object&, Server::Configuration::FactoryContext&) override;
Network::FilterFactoryCb createFilterFactoryFromProto(
const Protobuf::Message&,
Server::Configuration::FactoryContext&) override;
ProtobufTypes::MessagePtr createEmptyConfigProto() override;
std::string name() override { return "forward_downstream_sni"; }
};

} // namespace ForwardDownstreamSni
} // namespace Tcp
} // namespace Envoy
41 changes: 41 additions & 0 deletions src/envoy/tcp/forward_downstream_sni/forward_downstream_sni.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/* Copyright 2018 Istio Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "envoy/network/connection.h"

#include "common/network/upstream_server_name.h"
#include "src/envoy/tcp/forward_downstream_sni/forward_downstream_sni.h"

namespace Envoy {
namespace Tcp {
namespace ForwardDownstreamSni {

using ::Envoy::Network::UpstreamServerName;

Network::FilterStatus ForwardDownstreamSniFilter::onNewConnection() {
absl::string_view sni = read_callbacks_->connection().requestedServerName();

if (!sni.empty()) {
read_callbacks_->connection().streamInfo().filterState().setData(
UpstreamServerName::key(), std::make_unique<UpstreamServerName>(sni),
StreamInfo::FilterState::StateType::ReadOnly);
}

return Network::FilterStatus::Continue;
}

} // namespace ForwardDownstreamSni
} // namespace Tcp
} // namespace Envoy
46 changes: 46 additions & 0 deletions src/envoy/tcp/forward_downstream_sni/forward_downstream_sni.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* Copyright 2018 Istio Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include "envoy/network/filter.h"

namespace Envoy {
namespace Tcp {
namespace ForwardDownstreamSni {

/**
* Implementation of the forward_downstream_sni filter that sets the original
* requested server name from the SNI field in the TLS connection.
*/
class ForwardDownstreamSniFilter : public Network::ReadFilter {
public:
// Network::ReadFilter
Network::FilterStatus onData(Buffer::Instance&, bool) override {
return Network::FilterStatus::Continue;
}
Network::FilterStatus onNewConnection() override;
void initializeReadFilterCallbacks(
Network::ReadFilterCallbacks& callbacks) override {
read_callbacks_ = &callbacks;
}

private:
Network::ReadFilterCallbacks* read_callbacks_{};
};

} // namespace ForwardDownstreamSni
} // namespace Tcp
} // namespace Envoy
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/* Copyright 2018 Istio Authors. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include "test/mocks/network/mocks.h"
#include "test/mocks/server/mocks.h"
#include "test/mocks/stream_info/mocks.h"

#include "gmock/gmock.h"
#include "gtest/gtest.h"

#include "common/network/upstream_server_name.h"

#include "src/envoy/tcp/forward_downstream_sni/config.h"
#include "src/envoy/tcp/forward_downstream_sni/forward_downstream_sni.h"

using testing::_;
using testing::Matcher;
using testing::NiceMock;
using testing::Return;
using testing::ReturnRef;

namespace Envoy {
namespace Tcp {
namespace ForwardDownstreamSni {

using ::Envoy::Network::UpstreamServerName;

// Test that a ForwardDownstreamSni filter config works.
TEST(ForwardDownstreamSni, ConfigTest) {
NiceMock<Server::Configuration::MockFactoryContext> context;
ForwardDownstreamSniNetworkFilterConfigFactory factory;

Network::FilterFactoryCb cb = factory.createFilterFactoryFromProto(
*factory.createEmptyConfigProto(), context);
Network::MockConnection connection;
EXPECT_CALL(connection, addReadFilter(_));
cb(connection);
}

// Test that forward requested server name is set if SNI is available
TEST(ForwardDownstreamSni, SetUpstreamServerNameOnlyIfSniIsPresent) {
NiceMock<Network::MockReadFilterCallbacks> filter_callbacks;

NiceMock<StreamInfo::MockStreamInfo> stream_info;
ON_CALL(filter_callbacks.connection_, streamInfo())
.WillByDefault(ReturnRef(stream_info));
ON_CALL(Const(filter_callbacks.connection_), streamInfo())
.WillByDefault(ReturnRef(stream_info));

ForwardDownstreamSniFilter filter;
filter.initializeReadFilterCallbacks(filter_callbacks);

// no sni
{
ON_CALL(filter_callbacks.connection_, requestedServerName())
.WillByDefault(Return(EMPTY_STRING));
filter.onNewConnection();

EXPECT_FALSE(stream_info.filterState().hasData<UpstreamServerName>(
UpstreamServerName::key()));
}

// with sni
{
ON_CALL(filter_callbacks.connection_, requestedServerName())
.WillByDefault(Return("www.example.com"));
filter.onNewConnection();

EXPECT_TRUE(stream_info.filterState().hasData<UpstreamServerName>(
UpstreamServerName::key()));

auto forward_requested_server_name =
stream_info.filterState().getDataReadOnly<UpstreamServerName>(
UpstreamServerName::key());
EXPECT_EQ(forward_requested_server_name.value(), "www.example.com");
}
}

} // namespace ForwardDownstreamSni
} // namespace Tcp
} // namespace Envoy