[transports] validate IP when trying connect to remote peer for being in reserved IP range

Signed-off-by: R4SAS <r4sas@i2pmail.org>
This commit is contained in:
R4SAS 2020-10-12 17:36:44 +03:00 committed by R4SAS
parent 99d046ca11
commit 85e9da82b0
7 changed files with 84 additions and 26 deletions

View File

@ -299,14 +299,16 @@ namespace i2p
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
bool ssu; i2p::config::GetOption("ssu", ssu);
bool checkInReserved; i2p::config::GetOption("reservedrange", checkInReserved);
LogPrint(eLogInfo, "Daemon: starting Transports");
if(!ssu) LogPrint(eLogInfo, "Daemon: ssu disabled");
if(!ntcp2) LogPrint(eLogInfo, "Daemon: ntcp2 disabled");
i2p::transport::transports.SetCheckReserved(checkInReserved);
i2p::transport::transports.Start(ntcp2, ssu);
if (i2p::transport::transports.IsBoundSSU() || i2p::transport::transports.IsBoundNTCP2())
if (i2p::transport::transports.IsBoundSSU() || i2p::transport::transports.IsBoundNTCP2())
LogPrint(eLogInfo, "Daemon: Transports started");
else
else
{
LogPrint(eLogError, "Daemon: failed to start Transports");
/** shut down netdb right away */

View File

@ -51,6 +51,7 @@ namespace config {
("port", value<uint16_t>()->default_value(0), "Port to listen for incoming connections (default: auto)")
("ipv4", value<bool>()->default_value(true), "Enable communication through ipv4 (default: enabled)")
("ipv6", bool_switch()->default_value(false), "Enable communication through ipv6 (default: disabled)")
("reservedrange", value<bool>()->default_value(true), "Check remote RI for being in blacklist of reserved IP ranges (default: enabled)")
("netid", value<int>()->default_value(I2PD_NET_ID), "Specify NetID. Main I2P is 2")
("daemon", bool_switch()->default_value(false), "Router will go to background after start (default: disabled)")
("service", bool_switch()->default_value(false), "Router will use system folders like '/var/lib/i2pd' (default: disabled)")

View File

@ -459,6 +459,7 @@ namespace transport
// otherwise create new session
auto session = std::make_shared<SSUSession> (*this, remoteEndpoint, router, peerTest);
sessions[remoteEndpoint] = session;
// connect
LogPrint (eLogDebug, "SSU: Creating new session to [", i2p::data::GetIdentHashAbbreviation (router->GetIdentHash ()), "] ",
remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port ());

View File

@ -27,20 +27,20 @@ namespace transport
{
}
template<typename Keys>
template<typename Keys>
EphemeralKeysSupplier<Keys>::~EphemeralKeysSupplier ()
{
Stop ();
}
template<typename Keys>
template<typename Keys>
void EphemeralKeysSupplier<Keys>::Start ()
{
m_IsRunning = true;
m_Thread = new std::thread (std::bind (&EphemeralKeysSupplier<Keys>::Run, this));
}
template<typename Keys>
template<typename Keys>
void EphemeralKeysSupplier<Keys>::Stop ()
{
{
@ -56,7 +56,7 @@ namespace transport
}
}
template<typename Keys>
template<typename Keys>
void EphemeralKeysSupplier<Keys>::Run ()
{
while (m_IsRunning)
@ -81,7 +81,7 @@ namespace transport
}
}
template<typename Keys>
template<typename Keys>
void EphemeralKeysSupplier<Keys>::CreateEphemeralKeys (int num)
{
if (num > 0)
@ -96,7 +96,7 @@ namespace transport
}
}
template<typename Keys>
template<typename Keys>
std::shared_ptr<Keys> EphemeralKeysSupplier<Keys>::Acquire ()
{
{
@ -115,7 +115,7 @@ namespace transport
return pair;
}
template<typename Keys>
template<typename Keys>
void EphemeralKeysSupplier<Keys>::Return (std::shared_ptr<Keys> pair)
{
if (pair)
@ -131,8 +131,8 @@ namespace transport
Transports transports;
Transports::Transports ():
m_IsOnline (true), m_IsRunning (false), m_IsNAT (true), m_Thread (nullptr), m_Service (nullptr),
m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr),
m_IsOnline (true), m_IsRunning (false), m_IsNAT (true), m_СheckReserved(true), m_Thread (nullptr),
m_Service (nullptr), m_Work (nullptr), m_PeerCleanupTimer (nullptr), m_PeerTestTimer (nullptr),
m_SSUServer (nullptr), m_NTCP2Server (nullptr),
m_DHKeysPairSupplier (5), m_X25519KeysPairSupplier (5), // 5 pre-generated keys
m_TotalSentBytes(0), m_TotalReceivedBytes(0), m_TotalTransitTransmittedBytes (0),
@ -170,7 +170,7 @@ namespace transport
m_IsRunning = true;
m_Thread = new std::thread (std::bind (&Transports::Run, this));
std::string ntcp2proxy; i2p::config::GetOption("ntcp2.proxy", ntcp2proxy);
i2p::http::URL proxyurl;
i2p::http::URL proxyurl;
// create NTCP2. TODO: move to acceptor
if (enableNTCP2)
{
@ -252,7 +252,7 @@ namespace transport
delete m_SSUServer;
m_SSUServer = nullptr;
}
if (m_NTCP2Server)
{
m_NTCP2Server->Stop ();
@ -372,7 +372,7 @@ namespace transport
}
else
{
LogPrint (eLogWarning, "Transports: delayed messages queue size to ",
LogPrint (eLogWarning, "Transports: delayed messages queue size to ",
ident.ToBase64 (), " exceeds ", MAX_NUM_DELAYED_MESSAGES);
std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.erase (it);
@ -393,7 +393,7 @@ namespace transport
{
// NTCP2 have priority over NTCP
auto address = peer.router->GetNTCP2Address (true, !context.SupportsV6 ()); // published only
if (address && !peer.router->IsUnreachable ())
if (address && !peer.router->IsUnreachable () && (!m_СheckReserved || !i2p::util::net::IsInReservedRange(address->host)))
{
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router);
@ -419,8 +419,11 @@ namespace transport
if (m_SSUServer && peer.router->IsSSU (!context.SupportsV6 ()))
{
auto address = peer.router->GetSSUAddress (!context.SupportsV6 ());
m_SSUServer->CreateSession (peer.router, address->host, address->port);
return true;
if (!m_СheckReserved || !i2p::util::net::IsInReservedRange(address->host))
{
m_SSUServer->CreateSession (peer.router, address->host, address->port);
return true;
}
}
}
LogPrint (eLogInfo, "Transports: No NTCP or SSU addresses available");
@ -556,7 +559,7 @@ namespace transport
{
m_X25519KeysPairSupplier.Return (pair);
}
void Transports::PeerConnected (std::shared_ptr<TransportSession> session)
{
m_Service->post([session, this]()
@ -758,16 +761,16 @@ namespace transport
return false;
}
void Transports::SetOnline (bool online)
{
void Transports::SetOnline (bool online)
{
if (m_IsOnline != online)
{
m_IsOnline = online;
{
m_IsOnline = online;
if (online)
PeerTest ();
else
i2p::context.SetError (eRouterErrorOffline);
}
}
}
}
}
}

View File

@ -136,6 +136,9 @@ namespace transport
void PeerTest ();
void SetCheckReserved (bool check) { m_СheckReserved = check; };
bool IsCheckReserved () { return m_СheckReserved; };
private:
void Run ();
@ -152,7 +155,7 @@ namespace transport
private:
volatile bool m_IsOnline;
bool m_IsRunning, m_IsNAT;
bool m_IsRunning, m_IsNAT, m_СheckReserved;
std::thread * m_Thread;
boost::asio::io_service * m_Service;
boost::asio::io_service::work * m_Work;

View File

@ -61,6 +61,9 @@ int inet_pton_xp(int af, const char *src, void *dst)
#include <ifaddrs.h>
#endif
#define address_pair_v4(a,b) { boost::asio::ip::address_v4::from_string (a).to_ulong (), boost::asio::ip::address_v4::from_string (b).to_ulong () }
#define address_pair_v6(a,b) { boost::asio::ip::address_v6::from_string (a).to_bytes (), boost::asio::ip::address_v6::from_string (b).to_bytes () }
namespace i2p
{
namespace util
@ -391,6 +394,50 @@ namespace net
return boost::asio::ip::address::from_string(fallback);
#endif
}
}
bool IsInReservedRange(const boost::asio::ip::address& host) {
// https://en.wikipedia.org/wiki/Reserved_IP_addresses
if(host.is_v4())
{
static const std::vector< std::pair<uint32_t, uint32_t> > reservedIPv4Ranges {
address_pair_v4("0.0.0.0", "0.255.255.255"),
address_pair_v4("10.0.0.0", "10.255.255.255"),
address_pair_v4("100.64.0.0", "100.127.255.255"),
address_pair_v4("127.0.0.0", "127.255.255.255"),
address_pair_v4("169.254.0.0", "169.254.255.255"),
address_pair_v4("172.16.0.0", "172.31.255.255"),
address_pair_v4("192.0.0.0", "192.0.0.255"),
address_pair_v4("192.0.2.0", "192.0.2.255"),
address_pair_v4("192.88.99.0", "192.88.99.255"),
address_pair_v4("192.168.0.0", "192.168.255.255"),
address_pair_v4("198.18.0.0", "192.19.255.255"),
address_pair_v4("198.51.100.0", "198.51.100.255"),
address_pair_v4("203.0.113.0", "203.0.113.255"),
address_pair_v4("224.0.0.0", "255.255.255.255")
};
uint32_t ipv4_address = host.to_v4 ().to_ulong ();
for(const auto& it : reservedIPv4Ranges) {
if (ipv4_address >= it.first && ipv4_address <= it.second)
return true;
}
}
if(host.is_v6())
{
static const std::vector< std::pair<boost::asio::ip::address_v6::bytes_type, boost::asio::ip::address_v6::bytes_type> > reservedIPv6Ranges {
address_pair_v6("2001:db8::", "2001:db8:ffff:ffff:ffff:ffff:ffff:ffff"),
address_pair_v6("fc00::", "fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"),
address_pair_v6("fe80::", "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
};
boost::asio::ip::address_v6::bytes_type ipv6_address = host.to_v6 ().to_bytes ();
for(const auto& it : reservedIPv6Ranges) {
if (ipv6_address >= it.first && ipv6_address <= it.second)
return true;
}
}
return false;
}
} // net
} // util
} // i2p

View File

@ -172,6 +172,7 @@ namespace util
{
int GetMTU (const boost::asio::ip::address& localAddress);
const boost::asio::ip::address GetInterfaceAddress(const std::string & ifname, bool ipv6=false);
bool IsInReservedRange(const boost::asio::ip::address& host);
}
}
}