Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Forward Downstream SNI filter #2045

Merged
merged 9 commits into from
Nov 28, 2018
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