ri, transports, binding, reserved ip ranges

This commit is contained in:
R4SAS 2019-05-15 13:57:46 +03:00
parent 743fa745b7
commit 1e91b59f67
7 changed files with 128 additions and 94 deletions

View file

@ -14,6 +14,7 @@
#include "NTCPSession.h"
#include "HTTP.h"
#include "util.h"
#include "Config.h"
#ifdef WITH_EVENTS
#include "Event.h"
#endif
@ -815,43 +816,52 @@ namespace transport
else
{
// create acceptors
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
auto& addresses = context.GetRouterInfo ().GetAddresses ();
for (const auto& address: addresses)
{
if (!address) continue;
if (address->transportStyle == i2p::data::RouterInfo::eTransportNTCP && !address->IsNTCP2 ())
{
if (address->host.is_v4())
if (address->host.is_v4() && context.SupportsV4 () && ipv4)
{
try
{
m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port));
m_NTCPAcceptor = new boost::asio::ip::tcp::acceptor (m_Service);
m_NTCPAcceptor->open (boost::asio::ip::tcp::v4());
m_NTCPAcceptor->set_option (boost::asio::socket_base::reuse_address (true));
m_NTCPAcceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), address->port));
m_NTCPAcceptor->listen ();
LogPrint (eLogInfo, "NTCP: Start listening IPv4 TCP port ", address->port);
auto conn = std::make_shared<NTCPSession>(*this);
m_NTCPAcceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAccept, this, conn, std::placeholders::_1));
} catch ( std::exception & ex ) {
/** fail to bind ip4 */
LogPrint(eLogError, "NTCP: Failed to bind to ip4 port ",address->port, ex.what());
/** fail to bind IPv4 */
LogPrint(eLogError, "NTCP: Failed to bind to IPv4 port ",address->port, ex.what());
continue;
}
LogPrint (eLogInfo, "NTCP: Start listening TCP port ", address->port);
auto conn = std::make_shared<NTCPSession>(*this);
m_NTCPAcceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAccept, this, conn, std::placeholders::_1));
}
else if (address->host.is_v6() && context.SupportsV6 ())
else if (address->host.is_v6() && context.SupportsV6 () && ipv6)
{
m_NTCPV6Acceptor = new boost::asio::ip::tcp::acceptor (m_Service);
try
{
m_NTCPV6Acceptor = new boost::asio::ip::tcp::acceptor (m_Service);
m_NTCPV6Acceptor->open (boost::asio::ip::tcp::v6());
m_NTCPV6Acceptor->set_option (boost::asio::ip::v6_only (true));
m_NTCPV6Acceptor->set_option (boost::asio::socket_base::reuse_address (true));
m_NTCPV6Acceptor->bind (boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port));
m_NTCPV6Acceptor->listen ();
LogPrint (eLogInfo, "NTCP: Start listening V6 TCP port ", address->port);
LogPrint (eLogInfo, "NTCP: Start listening IPv6 TCP port ", address->port);
auto conn = std::make_shared<NTCPSession> (*this);
m_NTCPV6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCPServer::HandleAcceptV6, this, conn, std::placeholders::_1));
} catch ( std::exception & ex ) {
LogPrint(eLogError, "NTCP: failed to bind to ip6 port ", address->port);
/** fail to bind IPv6 */
LogPrint(eLogError, "NTCP: failed to bind to IPv6 port ", address->port);
continue;
}
}

View file

@ -570,8 +570,10 @@ namespace i2p
bool RouterContext::Load ()
{
// read router keys
std::ifstream fk (i2p::fs::DataDirPath (ROUTER_KEYS), std::ifstream::in | std::ifstream::binary);
if (!fk.is_open ()) return false;
if (!fk.is_open ())
return false;
fk.seekg (0, std::ios::end);
size_t len = fk.tellg();
fk.seekg (0, std::ios::beg);
@ -589,6 +591,8 @@ namespace i2p
m_Keys.FromBuffer (buf, len);
delete[] buf;
}
fk.close();
// read NTCP2 keys if available
std::ifstream n2k (i2p::fs::DataDirPath (NTCP2_KEYS), std::ifstream::in | std::ifstream::binary);
if (n2k)
@ -603,6 +607,7 @@ namespace i2p
}
n2k.close ();
}
// read RouterInfo
m_RouterInfo.SetRouterIdentity (GetIdentity ());
i2p::data::RouterInfo routerInfo(i2p::fs::DataDirPath (ROUTER_INFO));
@ -615,6 +620,11 @@ namespace i2p
// Migration to 0.9.24. TODO: remove later
m_RouterInfo.DeleteProperty ("coreVersion");
m_RouterInfo.DeleteProperty ("stat_uptime");
bool ipv4; i2p::config::GetOption("ipv4", ipv4);
bool ipv6; i2p::config::GetOption("ipv6", ipv6);
SetSupportsV4(ipv4);
SetSupportsV6(ipv6);
}
else
{
@ -626,14 +636,14 @@ namespace i2p
SetReachable (); // we assume reachable until we discover firewall through peer tests
// read NTCP2
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2);
if (ntcp2)
{
if (!m_NTCP2Keys) NewNTCP2Keys ();
UpdateNTCP2Address (true); // enable NTCP2
}
else
UpdateNTCP2Address (false); // disable NTCP2
UpdateNTCP2Address (false); // disable NTCP2
return true;
}

View file

@ -245,13 +245,15 @@ namespace data
ExtractCaps (value);
else if (!strcmp (key, "s")) // ntcp2 static key
{
if (!address->ntcp2) address->ntcp2.reset (new NTCP2Ext ());
if (!address->ntcp2)
address->ntcp2.reset (new NTCP2Ext ());
supportedTransports |= (address->host.is_v4 ()) ? eNTCP2V4 : eNTCP2V6;
Base64ToByteStream (value, strlen (value), address->ntcp2->staticKey, 32);
}
else if (!strcmp (key, "i")) // ntcp2 iv
{
if (!address->ntcp2) address->ntcp2.reset (new NTCP2Ext ());
if (!address->ntcp2)
address->ntcp2.reset (new NTCP2Ext ());
supportedTransports |= (address->host.is_v4 ()) ? eNTCP2V4 : eNTCP2V6;
Base64ToByteStream (value, strlen (value), address->ntcp2->iv, 16);
address->ntcp2->isPublished = true; // presence if "i" means "published"
@ -292,8 +294,10 @@ namespace data
}
if (!s) return;
}
if (introducers) supportedTransports |= eSSUV4; // in case if host is not presented
if (isNTCP2Only && address->ntcp2) address->ntcp2->isNTCP2Only = true;
if (introducers)
supportedTransports |= eSSUV4; // in case if host is not presented
if (isNTCP2Only && address->ntcp2)
address->ntcp2->isNTCP2Only = true;
if (supportedTransports)
{
addresses->push_back(address);
@ -354,9 +358,9 @@ namespace data
SetUnreachable (true);
}
bool RouterInfo::IsFamily(const std::string & fam) const {
return m_Family == fam;
}
bool RouterInfo::IsFamily(const std::string & fam) const {
return m_Family == fam;
}
void RouterInfo::ExtractCaps (const char * value)
{
@ -799,7 +803,7 @@ namespace data
bool RouterInfo::IsV6 () const
{
return m_SupportedTransports & (eNTCPV6 | eSSUV6);
return m_SupportedTransports & (eNTCPV6 | eSSUV6 | eNTCP2V6);
}
bool RouterInfo::IsV4 () const
@ -813,13 +817,12 @@ namespace data
m_SupportedTransports |= eNTCPV6 | eSSUV6 | eNTCP2V6;
}
void RouterInfo::EnableV4 ()
void RouterInfo::EnableV4 ()
{
if (!IsV4 ())
m_SupportedTransports |= eNTCPV4 | eSSUV4 | eNTCP2V4;
}
void RouterInfo::DisableV6 ()
{
if (IsV6 ())
@ -836,7 +839,7 @@ namespace data
}
}
void RouterInfo::DisableV4 ()
void RouterInfo::DisableV4 ()
{
if (IsV4 ())
{
@ -852,7 +855,6 @@ namespace data
}
}
bool RouterInfo::UsesIntroducer () const
{
return m_Caps & Caps::eUnreachable; // non-reachable

View file

@ -10,31 +10,18 @@ namespace i2p
{
namespace transport
{
SSUServer::SSUServer (const boost::asio::ip::address & addr, int port):
m_OnlyV6(true), m_IsRunning(false),
m_Thread (nullptr), m_ThreadV6 (nullptr), m_ReceiversThread (nullptr),
m_ReceiversThreadV6 (nullptr), m_Work (m_Service), m_WorkV6 (m_ServiceV6),
m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6),
m_EndpointV6 (addr, port), m_Socket (m_ReceiversService, m_Endpoint),
m_SocketV6 (m_ReceiversServiceV6), m_IntroducersUpdateTimer (m_Service),
m_PeerTestsCleanupTimer (m_Service), m_TerminationTimer (m_Service),
m_TerminationTimerV6 (m_ServiceV6)
{
OpenSocketV6 ();
}
SSUServer::SSUServer (int port):
m_OnlyV6(false), m_IsRunning(false),
m_Thread (nullptr), m_ThreadV6 (nullptr), m_ReceiversThread (nullptr),
m_ReceiversThreadV6 (nullptr), m_Work (m_Service), m_WorkV6 (m_ServiceV6),
m_IsRunning(false), m_Thread (nullptr), m_ThreadV6 (nullptr),
m_ReceiversThread (nullptr), m_ReceiversThreadV6 (nullptr),
m_Work (m_Service), m_WorkV6 (m_ServiceV6),
m_ReceiversWork (m_ReceiversService), m_ReceiversWorkV6 (m_ReceiversServiceV6),
m_Endpoint (boost::asio::ip::udp::v4 (), port), m_EndpointV6 (boost::asio::ip::udp::v6 (), port),
m_Socket (m_ReceiversService), m_SocketV6 (m_ReceiversServiceV6),
m_IntroducersUpdateTimer (m_Service), m_PeerTestsCleanupTimer (m_Service),
m_TerminationTimer (m_Service), m_TerminationTimerV6 (m_ServiceV6)
{
OpenSocket ();
if (context.SupportsV4 ())
OpenSocket ();
if (context.SupportsV6 ())
OpenSocketV6 ();
}
@ -63,7 +50,7 @@ namespace transport
void SSUServer::Start ()
{
m_IsRunning = true;
if (!m_OnlyV6)
if (context.SupportsV4 ())
{
m_ReceiversThread = new std::thread (std::bind (&SSUServer::RunReceivers, this));
m_Thread = new std::thread (std::bind (&SSUServer::Run, this));
@ -597,7 +584,7 @@ namespace transport
session->GetState () == eSessionStateEstablished &&
ts < session->GetCreationTime () + SSU_TO_INTRODUCER_SESSION_DURATION;
}
);
);
if (session)
{
ret.insert (session.get ());
@ -795,4 +782,3 @@ namespace transport
}
}
}

View file

@ -80,7 +80,7 @@ namespace transport
{
auto pair = std::make_shared<i2p::crypto::DHKeys> ();
pair->GenerateKeys ();
std::unique_lock<std::mutex> l(m_AcquiredMutex);
std::unique_lock<std::mutex> l(m_AcquiredMutex);
m_Queue.push (pair);
}
}
@ -89,7 +89,7 @@ namespace transport
std::shared_ptr<i2p::crypto::DHKeys> DHKeysPairSupplier::Acquire ()
{
{
std::unique_lock<std::mutex> l(m_AcquiredMutex);
std::unique_lock<std::mutex> l(m_AcquiredMutex);
if (!m_Queue.empty ())
{
auto pair = m_Queue.front ();
@ -227,10 +227,7 @@ namespace transport
{
if (m_SSUServer == nullptr && enableSSU)
{
if (address->host.is_v4())
m_SSUServer = new SSUServer (address->port);
else
m_SSUServer = new SSUServer (address->host, address->port);
m_SSUServer = new SSUServer (address->port);
LogPrint (eLogInfo, "Transports: Start listening UDP port ", address->port);
try {
m_SSUServer->Start ();
@ -249,11 +246,11 @@ namespace transport
m_PeerCleanupTimer->expires_from_now (boost::posix_time::seconds(5*SESSION_CREATION_TIMEOUT));
m_PeerCleanupTimer->async_wait (std::bind (&Transports::HandlePeerCleanupTimer, this, std::placeholders::_1));
if (m_IsNAT)
{
m_PeerTestTimer->expires_from_now (boost::posix_time::minutes(PEER_TEST_INTERVAL));
m_PeerTestTimer->async_wait (std::bind (&Transports::HandlePeerTestTimer, this, std::placeholders::_1));
}
if (m_IsNAT)
{
m_PeerTestTimer->expires_from_now (boost::posix_time::minutes(PEER_TEST_INTERVAL));
m_PeerTestTimer->async_wait (std::bind (&Transports::HandlePeerTestTimer, this, std::placeholders::_1));
}
}
void Transports::Stop ()
@ -408,23 +405,19 @@ namespace transport
if (!peer.numAttempts) // NTCP2
{
peer.numAttempts++;
if (m_NTCP2Server) // we support NTCP2
{
// NTCP2 have priority over NTCP
auto address = peer.router->GetNTCP2Address (true, !context.SupportsV6 ()); // published only
if (address)
{
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router);
m_NTCP2Server->Connect (address->host, address->port, s);
return true;
}
auto address = peer.router->GetNTCP2Address (true, !context.SupportsV6 ()); // published only
if (address && m_NTCP2Server && !i2p::util::net::IsInReservedRange(address->host))
{ // we support NTCP2, it has priority over NTCP and remote address is not in reserved range
auto s = std::make_shared<NTCP2Session> (*m_NTCP2Server, peer.router);
m_NTCP2Server->Connect (address->host, address->port, s);
return true;
}
}
if (peer.numAttempts == 1) // NTCP1
{
peer.numAttempts++;
auto address = peer.router->GetNTCPAddress (!context.SupportsV6 ());
if (address && m_NTCPServer)
if (address && m_NTCPServer && !i2p::util::net::IsInReservedRange(address->host))
{
if (!peer.router->UsesIntroducer () && !peer.router->IsUnreachable ())
{
@ -457,14 +450,14 @@ namespace transport
if (peer.numAttempts == 2)// SSU
{
peer.numAttempts++;
if (m_SSUServer && peer.router->IsSSU (!context.SupportsV6 ()))
auto address = peer.router->GetSSUAddress (!context.SupportsV6 ());
if (address && m_SSUServer && !i2p::util::net::IsInReservedRange(address->host))
{
auto address = peer.router->GetSSUAddress (!context.SupportsV6 ());
m_SSUServer->CreateSession (peer.router, address->host, address->port);
return true;
}
}
LogPrint (eLogInfo, "Transports: No NTCP or SSU addresses available");
LogPrint (eLogInfo, "Transports: No valid NTCP2, NTCP or SSU remote addresses available");
peer.Done ();
std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.erase (ident);
@ -633,7 +626,7 @@ namespace transport
EmitEvent({{"type" , "transport.connected"}, {"ident", ident.ToBase64()}, {"inbound", "true"}});
#endif
session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); // send DatabaseStore
std::unique_lock<std::mutex> l(m_PeersMutex);
std::unique_lock<std::mutex> l(m_PeersMutex);
m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, i2p::util::GetSecondsSinceEpoch (), {} }));
}
});
@ -689,7 +682,7 @@ namespace transport
{
profile->TunnelNonReplied();
}
std::unique_lock<std::mutex> l(m_PeersMutex);
std::unique_lock<std::mutex> l(m_PeersMutex);
it = m_Peers.erase (it);
}
else

View file

@ -337,9 +337,41 @@ namespace net
LogPrint(eLogWarning, "NetIface: cannot find ipv4 address for interface ", ifname);
}
return boost::asio::ip::address::from_string(fallback);
#endif
}
}
bool IsInReservedRange(const boost::asio::ip::address& host) {
if(host.is_v6())
return false; // for now checking only v4
// https://en.wikipedia.org/wiki/Reserved_IP_addresses
std::string reservedIPv4Ranges[][2] = {
{"0.0.0.0", "0.255.255.255"},
{"10.0.0.0", "10.255.255.255"},
{"100.64.0.0", "100.127.255.255"},
{"127.0.0.0", "127.255.255.255"},
{"169.254.0.0", "169.254.255.255"},
{"172.16.0.0", "172.31.255.255"},
{"192.0.0.0", "192.0.0.255"},
{"192.0.2.0", "192.0.2.255"},
{"192.88.99.0", "192.88.99.255"},
{"192.168.0.0", "192.168.255.255"},
{"198.18.0.0", "192.19.255.255"},
{"198.51.100.0", "198.51.100.255"},
{"203.0.113.0", "203.0.113.255"},
{"224.0.0.0", "255.255.255.255"}
};
for(int i = 0; i < sizeof(reservedIPv4Ranges); i++) {
uint32_t rangeStart = boost::asio::ip::address_v4::from_string(reservedIPv4Ranges[i][0]).to_ulong();
uint32_t rangeEnd = boost::asio::ip::address_v4::from_string(reservedIPv4Ranges[i][1]).to_ulong();
uint32_t ip_address = host.to_v4().to_ulong();
if (ip_address >= rangeStart && ip_address <= rangeEnd)
return true;
}
return false;
}
} // net
} // util
} // i2p

View file

@ -126,6 +126,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);
}
}
}