face: Configurable IP subnets for "local" TCP faces
Change-Id: Idaddfe4b2c304b552d2e132235f4c3d3e6c2ebcb Refs: #4546
This commit is contained in:
@@ -24,9 +24,9 @@
|
||||
*/
|
||||
|
||||
#include "tcp-channel.hpp"
|
||||
#include "core/global-io.hpp"
|
||||
#include "generic-link-service.hpp"
|
||||
#include "tcp-transport.hpp"
|
||||
#include "core/global-io.hpp"
|
||||
|
||||
namespace nfd {
|
||||
namespace face {
|
||||
@@ -35,11 +35,13 @@ NFD_LOG_INIT("TcpChannel");
|
||||
|
||||
namespace ip = boost::asio::ip;
|
||||
|
||||
TcpChannel::TcpChannel(const tcp::Endpoint& localEndpoint, bool wantCongestionMarking)
|
||||
TcpChannel::TcpChannel(const tcp::Endpoint& localEndpoint, bool wantCongestionMarking,
|
||||
DetermineFaceScopeFromAddress determineFaceScope)
|
||||
: m_localEndpoint(localEndpoint)
|
||||
, m_acceptor(getGlobalIoService())
|
||||
, m_socket(getGlobalIoService())
|
||||
, m_wantCongestionMarking(wantCongestionMarking)
|
||||
, m_determineFaceScope(std::move(determineFaceScope))
|
||||
{
|
||||
setUri(FaceUri(m_localEndpoint));
|
||||
NFD_LOG_CHAN_INFO("Creating channel");
|
||||
@@ -122,7 +124,9 @@ TcpChannel::createFace(ip::tcp::socket&& socket,
|
||||
}
|
||||
|
||||
auto linkService = make_unique<GenericLinkService>(options);
|
||||
auto transport = make_unique<TcpTransport>(std::move(socket), params.persistency);
|
||||
auto faceScope = m_determineFaceScope(socket.local_endpoint().address(),
|
||||
socket.remote_endpoint().address());
|
||||
auto transport = make_unique<TcpTransport>(std::move(socket), params.persistency, faceScope);
|
||||
face = make_shared<Face>(std::move(linkService), std::move(transport));
|
||||
|
||||
m_channelFaces[remoteEndpoint] = face;
|
||||
|
||||
@@ -37,6 +37,9 @@ typedef boost::asio::ip::tcp::endpoint Endpoint;
|
||||
|
||||
namespace face {
|
||||
|
||||
using DetermineFaceScopeFromAddress = std::function<ndn::nfd::FaceScope(const boost::asio::ip::address& local,
|
||||
const boost::asio::ip::address& remote)>;
|
||||
|
||||
/**
|
||||
* \brief Class implementing TCP-based channel to create faces
|
||||
*
|
||||
@@ -53,7 +56,8 @@ public:
|
||||
* To enable creation faces upon incoming connections,
|
||||
* one needs to explicitly call TcpChannel::listen method.
|
||||
*/
|
||||
TcpChannel(const tcp::Endpoint& localEndpoint, bool wantCongestionMarking);
|
||||
TcpChannel(const tcp::Endpoint& localEndpoint, bool wantCongestionMarking,
|
||||
DetermineFaceScopeFromAddress determineFaceScope);
|
||||
|
||||
bool
|
||||
isListening() const override
|
||||
@@ -126,6 +130,7 @@ private:
|
||||
boost::asio::ip::tcp::socket m_socket;
|
||||
std::map<tcp::Endpoint, shared_ptr<Face>> m_channelFaces;
|
||||
bool m_wantCongestionMarking;
|
||||
DetermineFaceScopeFromAddress m_determineFaceScope;
|
||||
};
|
||||
|
||||
} // namespace face
|
||||
|
||||
@@ -72,6 +72,8 @@ TcpFactory::processConfig(OptionalConfigSection configSection,
|
||||
uint16_t port = 6363;
|
||||
bool enableV4 = true;
|
||||
bool enableV6 = true;
|
||||
IpAddressPredicate local;
|
||||
bool isLocalConfigured = false;
|
||||
|
||||
for (const auto& pair : *configSection) {
|
||||
const std::string& key = pair.first;
|
||||
@@ -88,10 +90,28 @@ TcpFactory::processConfig(OptionalConfigSection configSection,
|
||||
else if (key == "enable_v6") {
|
||||
enableV6 = ConfigFile::parseYesNo(pair, "face_system.tcp");
|
||||
}
|
||||
else if (key == "local") {
|
||||
isLocalConfigured = true;
|
||||
for (const auto& localPair : pair.second) {
|
||||
const std::string& localKey = localPair.first;
|
||||
if (localKey == "whitelist") {
|
||||
local.parseWhitelist(localPair.second);
|
||||
}
|
||||
else if (localKey == "blacklist") {
|
||||
local.parseBlacklist(localPair.second);
|
||||
}
|
||||
else {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option face_system.tcp.local." + localKey));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error("Unrecognized option face_system.tcp." + key));
|
||||
}
|
||||
}
|
||||
if (!isLocalConfigured) {
|
||||
local.assign({{"subnet", "127.0.0.0/8"}, {"subnet", "::1/128"}}, {});
|
||||
}
|
||||
|
||||
if (!enableV4 && !enableV6) {
|
||||
BOOST_THROW_EXCEPTION(ConfigFile::Error(
|
||||
@@ -125,6 +145,8 @@ TcpFactory::processConfig(OptionalConfigSection configSection,
|
||||
else if (providedSchemes.count("tcp6") > 0) {
|
||||
NFD_LOG_WARN("Cannot close tcp6 channel after its creation");
|
||||
}
|
||||
|
||||
m_local = std::move(local);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +201,8 @@ TcpFactory::createChannel(const tcp::Endpoint& endpoint)
|
||||
if (it != m_channels.end())
|
||||
return it->second;
|
||||
|
||||
auto channel = make_shared<TcpChannel>(endpoint, m_wantCongestionMarking);
|
||||
auto channel = make_shared<TcpChannel>(endpoint, m_wantCongestionMarking,
|
||||
bind(&TcpFactory::determineFaceScopeFromAddresses, this, _1, _2));
|
||||
m_channels[endpoint] = channel;
|
||||
return channel;
|
||||
}
|
||||
@@ -190,5 +213,15 @@ TcpFactory::getChannels() const
|
||||
return getChannelsFromMap(m_channels);
|
||||
}
|
||||
|
||||
ndn::nfd::FaceScope
|
||||
TcpFactory::determineFaceScopeFromAddresses(const boost::asio::ip::address& localAddress,
|
||||
const boost::asio::ip::address& remoteAddress) const
|
||||
{
|
||||
if (m_local(localAddress) && m_local(remoteAddress)) {
|
||||
return ndn::nfd::FACE_SCOPE_LOCAL;
|
||||
}
|
||||
return ndn::nfd::FACE_SCOPE_NON_LOCAL;
|
||||
}
|
||||
|
||||
} // namespace face
|
||||
} // namespace nfd
|
||||
|
||||
@@ -71,9 +71,17 @@ public:
|
||||
std::vector<shared_ptr<const Channel>>
|
||||
getChannels() const override;
|
||||
|
||||
private:
|
||||
ndn::nfd::FaceScope
|
||||
determineFaceScopeFromAddresses(const boost::asio::ip::address& local,
|
||||
const boost::asio::ip::address& remote) const;
|
||||
|
||||
private:
|
||||
bool m_wantCongestionMarking = false;
|
||||
std::map<tcp::Endpoint, shared_ptr<TcpChannel>> m_channels;
|
||||
|
||||
PUBLIC_WITH_TESTS_ELSE_PRIVATE:
|
||||
IpAddressPredicate m_local;
|
||||
};
|
||||
|
||||
} // namespace face
|
||||
|
||||
@@ -39,20 +39,14 @@ time::milliseconds TcpTransport::s_initialReconnectWait = time::seconds(1);
|
||||
time::milliseconds TcpTransport::s_maxReconnectWait = time::minutes(5);
|
||||
float TcpTransport::s_reconnectWaitMultiplier = 2.0f;
|
||||
|
||||
TcpTransport::TcpTransport(protocol::socket&& socket, ndn::nfd::FacePersistency persistency)
|
||||
TcpTransport::TcpTransport(protocol::socket&& socket, ndn::nfd::FacePersistency persistency, ndn::nfd::FaceScope faceScope)
|
||||
: StreamTransport(std::move(socket))
|
||||
, m_remoteEndpoint(m_socket.remote_endpoint())
|
||||
, m_nextReconnectWait(s_initialReconnectWait)
|
||||
{
|
||||
this->setLocalUri(FaceUri(m_socket.local_endpoint()));
|
||||
this->setRemoteUri(FaceUri(m_socket.remote_endpoint()));
|
||||
|
||||
if (m_socket.local_endpoint().address().is_loopback() &&
|
||||
m_socket.remote_endpoint().address().is_loopback())
|
||||
this->setScope(ndn::nfd::FACE_SCOPE_LOCAL);
|
||||
else
|
||||
this->setScope(ndn::nfd::FACE_SCOPE_NON_LOCAL);
|
||||
|
||||
this->setScope(faceScope);
|
||||
this->setPersistency(persistency);
|
||||
this->setLinkType(ndn::nfd::LINK_TYPE_POINT_TO_POINT);
|
||||
this->setMtu(MTU_UNLIMITED);
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace face {
|
||||
class TcpTransport FINAL_UNLESS_WITH_TESTS : public StreamTransport<boost::asio::ip::tcp>
|
||||
{
|
||||
public:
|
||||
TcpTransport(protocol::socket&& socket, ndn::nfd::FacePersistency persistency);
|
||||
TcpTransport(protocol::socket&& socket, ndn::nfd::FacePersistency persistency, ndn::nfd::FaceScope faceScope);
|
||||
|
||||
ssize_t
|
||||
getSendQueueLength() final;
|
||||
|
||||
@@ -106,6 +106,19 @@ face_system
|
||||
port 6363 ; TCP listener port number
|
||||
enable_v4 yes ; set to 'no' to disable IPv4 channels, default 'yes'
|
||||
enable_v6 yes ; set to 'no' to disable IPv6 channels, default 'yes'
|
||||
|
||||
; A TCP face has local scope if the local and remote IP addresses match the whitelist but not the blacklist
|
||||
local
|
||||
{
|
||||
whitelist
|
||||
{
|
||||
subnet 127.0.0.0/8
|
||||
subnet ::1/128
|
||||
}
|
||||
blacklist
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
; The udp section contains settings for UDP faces and channels.
|
||||
|
||||
@@ -64,11 +64,15 @@ createFace(ProtocolFactory& factory,
|
||||
const FaceUri& remoteUri,
|
||||
const ndn::optional<FaceUri>& localUri,
|
||||
const TestFaceParams& params,
|
||||
const CreateFaceExpectedResult& expected)
|
||||
const CreateFaceExpectedResult& expected,
|
||||
const std::function<void(const Face&)>& extraChecks = nullptr)
|
||||
{
|
||||
factory.createFace({remoteUri, localUri, params},
|
||||
[expected] (const shared_ptr<Face>&) {
|
||||
[expected, extraChecks] (const shared_ptr<Face>& face) {
|
||||
BOOST_CHECK_EQUAL(CreateFaceExpectedResult::SUCCESS, expected.result);
|
||||
if (extraChecks) {
|
||||
extraChecks(*face);
|
||||
}
|
||||
},
|
||||
[expected] (uint32_t actualStatus, const std::string& actualReason) {
|
||||
BOOST_CHECK_EQUAL(CreateFaceExpectedResult::FAILURE, expected.result);
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#define NFD_TESTS_DAEMON_FACE_TCP_CHANNEL_FIXTURE_HPP
|
||||
|
||||
#include "face/tcp-channel.hpp"
|
||||
#include "core/network-predicate.hpp"
|
||||
|
||||
#include "channel-fixture.hpp"
|
||||
|
||||
@@ -37,13 +38,19 @@ namespace tests {
|
||||
class TcpChannelFixture : public ChannelFixture<TcpChannel, tcp::Endpoint>
|
||||
{
|
||||
protected:
|
||||
TcpChannelFixture()
|
||||
{
|
||||
local.assign({{"subnet", "127.0.0.0/8"}, {"subnet", "::1/128"}}, {});
|
||||
}
|
||||
|
||||
unique_ptr<TcpChannel>
|
||||
makeChannel(const boost::asio::ip::address& addr, uint16_t port = 0) final
|
||||
{
|
||||
if (port == 0)
|
||||
port = getNextPort();
|
||||
|
||||
return make_unique<TcpChannel>(tcp::Endpoint(addr, port), false);
|
||||
return make_unique<TcpChannel>(tcp::Endpoint(addr, port), false,
|
||||
std::bind(&TcpChannelFixture::determineFaceScope, this, _1, _2));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -61,8 +68,21 @@ protected:
|
||||
});
|
||||
}
|
||||
|
||||
ndn::nfd::FaceScope
|
||||
determineFaceScope(const boost::asio::ip::address& localAddress,
|
||||
const boost::asio::ip::address& remoteAddress)
|
||||
{
|
||||
if (local(localAddress) && local(remoteAddress)) {
|
||||
return ndn::nfd::FACE_SCOPE_LOCAL;
|
||||
}
|
||||
else {
|
||||
return ndn::nfd::FACE_SCOPE_NON_LOCAL;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
std::vector<shared_ptr<Face>> clientFaces;
|
||||
IpAddressPredicate local;
|
||||
};
|
||||
|
||||
} // namespace tests
|
||||
|
||||
@@ -45,6 +45,9 @@ protected:
|
||||
boost::lexical_cast<uint16_t>(localPort));
|
||||
return factory.createChannel(endpoint);
|
||||
}
|
||||
|
||||
protected:
|
||||
LimitedIo limitedIo;
|
||||
};
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(Face)
|
||||
@@ -68,6 +71,11 @@ BOOST_AUTO_TEST_CASE(Defaults)
|
||||
auto channels = factory.getChannels();
|
||||
BOOST_CHECK(std::all_of(channels.begin(), channels.end(),
|
||||
[] (const shared_ptr<const Channel>& ch) { return ch->isListening(); }));
|
||||
|
||||
BOOST_CHECK_EQUAL(factory.m_local.m_whitelist.size(), 2);
|
||||
BOOST_CHECK_EQUAL(factory.m_local.m_whitelist.count("127.0.0.0/8"), 1);
|
||||
BOOST_CHECK_EQUAL(factory.m_local.m_whitelist.count("::1/128"), 1);
|
||||
BOOST_CHECK_EQUAL(factory.m_local.m_blacklist.size(), 0);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DisableListen)
|
||||
@@ -132,6 +140,88 @@ BOOST_AUTO_TEST_CASE(DisableV6)
|
||||
checkChannelListEqual(factory, {"tcp4://0.0.0.0:7001"});
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ConfigureLocal)
|
||||
{
|
||||
const std::string CONFIG = R"CONFIG(
|
||||
face_system
|
||||
{
|
||||
tcp
|
||||
{
|
||||
local {
|
||||
whitelist {
|
||||
subnet 127.0.0.0/8
|
||||
}
|
||||
|
||||
blacklist {
|
||||
subnet ::1/128
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)CONFIG";
|
||||
|
||||
parseConfig(CONFIG, true);
|
||||
parseConfig(CONFIG, false);
|
||||
|
||||
BOOST_CHECK_EQUAL(factory.m_local.m_whitelist.size(), 1);
|
||||
BOOST_CHECK_EQUAL(factory.m_local.m_whitelist.count("127.0.0.0/8"), 1);
|
||||
BOOST_CHECK_EQUAL(factory.m_local.m_blacklist.size(), 1);
|
||||
BOOST_CHECK_EQUAL(factory.m_local.m_blacklist.count("::1/128"), 1);
|
||||
|
||||
createFace(factory,
|
||||
FaceUri("tcp4://127.0.0.1:6363"),
|
||||
{},
|
||||
{ndn::nfd::FACE_PERSISTENCY_PERSISTENT, {}, {}, false, false, false},
|
||||
{CreateFaceExpectedResult::SUCCESS, 0, ""},
|
||||
[] (const nfd::Face& face) {
|
||||
BOOST_CHECK_EQUAL(face.getScope(), ndn::nfd::FACE_SCOPE_LOCAL);
|
||||
});
|
||||
|
||||
limitedIo.run(1, 100_ms);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(ConfigureNonLocal)
|
||||
{
|
||||
const std::string CONFIG = R"CONFIG(
|
||||
face_system
|
||||
{
|
||||
tcp
|
||||
{
|
||||
local {
|
||||
whitelist {
|
||||
*
|
||||
}
|
||||
|
||||
blacklist {
|
||||
subnet 127.0.0.0/8
|
||||
subnet ::1/128
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)CONFIG";
|
||||
|
||||
parseConfig(CONFIG, true);
|
||||
parseConfig(CONFIG, false);
|
||||
|
||||
BOOST_CHECK_EQUAL(factory.m_local.m_whitelist.size(), 1);
|
||||
BOOST_CHECK_EQUAL(factory.m_local.m_whitelist.count("*"), 1);
|
||||
BOOST_CHECK_EQUAL(factory.m_local.m_blacklist.size(), 2);
|
||||
BOOST_CHECK_EQUAL(factory.m_local.m_blacklist.count("127.0.0.0/8"), 1);
|
||||
BOOST_CHECK_EQUAL(factory.m_local.m_blacklist.count("::1/128"), 1);
|
||||
|
||||
createFace(factory,
|
||||
FaceUri("tcp4://127.0.0.1:6363"),
|
||||
{},
|
||||
{ndn::nfd::FACE_PERSISTENCY_PERSISTENT, {}, {}, false, false, false},
|
||||
{CreateFaceExpectedResult::SUCCESS, 0, ""},
|
||||
[] (const nfd::Face& face) {
|
||||
BOOST_CHECK_EQUAL(face.getScope(), ndn::nfd::FACE_SCOPE_NON_LOCAL);
|
||||
});
|
||||
|
||||
limitedIo.run(1, 100_ms);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(Omitted)
|
||||
{
|
||||
const std::string CONFIG = R"CONFIG(
|
||||
@@ -357,7 +447,6 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
LimitedIo limitedIo;
|
||||
shared_ptr<nfd::Face> face;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2017, Regents of the University of California,
|
||||
* Copyright (c) 2014-2018, Regents of the University of California,
|
||||
* Arizona Board of Regents,
|
||||
* Colorado State University,
|
||||
* University Pierre & Marie Curie, Sorbonne University,
|
||||
@@ -88,8 +88,17 @@ protected:
|
||||
BOOST_REQUIRE_EQUAL(limitedIo.run(2, time::seconds(1)), LimitedIo::EXCEED_OPS);
|
||||
|
||||
localEp = sock.local_endpoint();
|
||||
|
||||
ndn::nfd::FaceScope scope;
|
||||
if (sock.local_endpoint().address().is_loopback() && sock.remote_endpoint().address().is_loopback()) {
|
||||
scope = ndn::nfd::FACE_SCOPE_LOCAL;
|
||||
}
|
||||
else {
|
||||
scope = ndn::nfd::FACE_SCOPE_NON_LOCAL;
|
||||
}
|
||||
|
||||
face = make_unique<Face>(make_unique<DummyReceiveLinkService>(),
|
||||
make_unique<TcpTransport>(std::move(sock), persistency));
|
||||
make_unique<TcpTransport>(std::move(sock), persistency, scope));
|
||||
transport = static_cast<TcpTransport*>(face->getTransport());
|
||||
receivedPackets = &static_cast<DummyReceiveLinkService*>(face->getLinkService())->receivedPackets;
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ class PermanentTcpTransportReconnectObserver : public TcpTransport
|
||||
{
|
||||
public:
|
||||
PermanentTcpTransportReconnectObserver(protocol::socket&& socket, LimitedIo& io)
|
||||
: TcpTransport(std::move(socket), ndn::nfd::FACE_PERSISTENCY_PERMANENT)
|
||||
: TcpTransport(std::move(socket), ndn::nfd::FACE_PERSISTENCY_PERMANENT, ndn::nfd::FACE_SCOPE_LOCAL)
|
||||
, m_io(io)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ class FaceBenchmark
|
||||
public:
|
||||
FaceBenchmark(const char* configFileName)
|
||||
: m_terminationSignalSet{getGlobalIoService()}
|
||||
, m_tcpChannel{tcp::Endpoint{boost::asio::ip::tcp::v4(), 6363}, false}
|
||||
, m_tcpChannel{tcp::Endpoint{boost::asio::ip::tcp::v4(), 6363}, false, bind([] { return ndn::nfd::FACE_SCOPE_NON_LOCAL; })}
|
||||
, m_udpChannel{udp::Endpoint{boost::asio::ip::udp::v4(), 6363}, time::minutes{10}, false}
|
||||
{
|
||||
m_terminationSignalSet.add(SIGINT);
|
||||
|
||||
Reference in New Issue
Block a user