diff --git a/libi2pd/NTCPSession.cpp b/libi2pd/NTCPSession.cpp index 68a4133f..6127ddce 100644 --- a/libi2pd/NTCPSession.cpp +++ b/libi2pd/NTCPSession.cpp @@ -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(*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(*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 (*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; } } diff --git a/libi2pd/RouterContext.cpp b/libi2pd/RouterContext.cpp index 8293f1fd..14111c33 100644 --- a/libi2pd/RouterContext.cpp +++ b/libi2pd/RouterContext.cpp @@ -542,9 +542,9 @@ namespace i2p } } else - mtu = 1472; + mtu = 1472; m_RouterInfo.AddSSUAddress (host.to_string ().c_str (), port, GetIdentHash (), mtu); - } + } updated = true; } if (updated) @@ -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; } diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index ee46a5b0..aded332b 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -245,17 +245,19 @@ 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); - } + 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); + Base64ToByteStream (value, strlen (value), address->ntcp2->iv, 16); address->ntcp2->isPublished = true; // presence if "i" means "published" - } + } else if (key[0] == 'i') { // introducers @@ -263,7 +265,7 @@ namespace data { LogPrint (eLogError, "RouterInfo: Introducer is presented for non-SSU address. Skipped"); continue; - } + } introducers = true; size_t l = strlen(key); unsigned char index = key[l-1] - '0'; // TODO: @@ -292,9 +294,11 @@ 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 (supportedTransports) + 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); m_SupportedTransports |= supportedTransports; @@ -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 diff --git a/libi2pd/SSU.cpp b/libi2pd/SSU.cpp index daf7e1e9..3e3db88f 100644 --- a/libi2pd/SSU.cpp +++ b/libi2pd/SSU.cpp @@ -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)); @@ -328,10 +315,10 @@ namespace transport { if (!session || session->GetRemoteEndpoint () != packet->from) // we received packet for other session than previous { - if (session) - { - session->FlushData (); - session = nullptr; + if (session) + { + session->FlushData (); + session = nullptr; } auto it = sessions->find (packet->from); if (it != sessions->end ()) @@ -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 } } } - diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index c00e5d52..6f32f565 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -80,7 +80,7 @@ namespace transport { auto pair = std::make_shared (); pair->GenerateKeys (); - std::unique_lock l(m_AcquiredMutex); + std::unique_lock l(m_AcquiredMutex); m_Queue.push (pair); } } @@ -89,7 +89,7 @@ namespace transport std::shared_ptr DHKeysPairSupplier::Acquire () { { - std::unique_lock l(m_AcquiredMutex); + std::unique_lock l(m_AcquiredMutex); if (!m_Queue.empty ()) { auto pair = m_Queue.front (); @@ -196,13 +196,13 @@ namespace transport LogPrint(eLogError, "Transports: invalid NTCP proxy url ", ntcpproxy); return; } - // create NTCP2. TODO: move to acceptor + // create NTCP2. TODO: move to acceptor bool ntcp2; i2p::config::GetOption("ntcp2.enabled", ntcp2); if (ntcp2) { m_NTCP2Server = new NTCP2Server (); m_NTCP2Server->Start (); - } + } // create acceptors auto& addresses = context.GetRouterInfo ().GetAddresses (); @@ -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 () @@ -405,26 +402,22 @@ namespace transport { if (peer.router) // we have RI already { - if (!peer.numAttempts) // NTCP2 + 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 (*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 (*m_NTCP2Server, peer.router); + m_NTCP2Server->Connect (address->host, address->port, s); + return true; + } } if (peer.numAttempts == 1) // NTCP1 { - peer.numAttempts++; + 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 l(m_PeersMutex); m_Peers.erase (ident); @@ -503,7 +496,7 @@ namespace transport } } } - + void Transports::CloseSession (std::shared_ptr router) { if (!router) return; @@ -633,7 +626,7 @@ namespace transport EmitEvent({{"type" , "transport.connected"}, {"ident", ident.ToBase64()}, {"inbound", "true"}}); #endif session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); // send DatabaseStore - std::unique_lock l(m_PeersMutex); + std::unique_lock 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 l(m_PeersMutex); + std::unique_lock l(m_PeersMutex); it = m_Peers.erase (it); } else diff --git a/libi2pd/util.cpp b/libi2pd/util.cpp index 96e8ad4c..020be070 100644 --- a/libi2pd/util.cpp +++ b/libi2pd/util.cpp @@ -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 diff --git a/libi2pd/util.h b/libi2pd/util.h index 6da20ad6..3d2a49b9 100644 --- a/libi2pd/util.h +++ b/libi2pd/util.h @@ -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); } } }