diff --git a/Config.cpp b/Config.cpp index 924f244b..80a2ef8a 100644 --- a/Config.cpp +++ b/Config.cpp @@ -184,6 +184,7 @@ namespace config { trust.add_options() ("trust.enabled", value()->default_value(false), "enable explicit trust options") ("trust.family", value()->default_value(""), "Router Familiy to trust for first hops") + ("trust.routers", value()->default_value(""), "Only Connect to these routers") ("trust.hidden", value()->default_value(false), "should we hide our router from other routers?"); m_OptionsDesc diff --git a/Daemon.cpp b/Daemon.cpp index e0c45ac3..ce2f4173 100644 --- a/Daemon.cpp +++ b/Daemon.cpp @@ -194,12 +194,40 @@ namespace i2p { LogPrint(eLogInfo, "Daemon: explicit trust enabled"); std::string fam; i2p::config::GetOption("trust.family", fam); + std::string routers; i2p::config::GetOption("trust.routers", routers); + bool restricted = false; if (fam.length() > 0) { - LogPrint(eLogInfo, "Daemon: setting restricted routes to use family ", fam); - i2p::transport::transports.RestrictRoutes({fam}); - } else - LogPrint(eLogError, "Daemon: no family specified for restricted routes"); + std::set fams; + size_t pos = 0, comma; + do + { + comma = fam.find (',', pos); + fams.insert (fam.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos)); + pos = comma + 1; + } + while (comma != std::string::npos); + i2p::transport::transports.RestrictRoutesToFamilies(fams); + restricted = fams.size() > 0; + } + if (routers.length() > 0) { + std::set idents; + size_t pos = 0, comma; + do + { + comma = routers.find (',', pos); + i2p::data::IdentHash ident; + ident.FromBase64 (routers.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos)); + idents.insert (ident); + pos = comma + 1; + } + while (comma != std::string::npos); + LogPrint(eLogInfo, "Daemon: setting restricted routes to use ", idents.size(), " trusted routesrs"); + i2p::transport::transports.RestrictRoutesToRouters(idents); + restricted = idents.size() > 0; + } + if(!restricted) + LogPrint(eLogError, "Daemon: no trusted routers of families specififed"); } bool hidden; i2p::config::GetOption("trust.hidden", hidden); if (hidden) diff --git a/NetDb.cpp b/NetDb.cpp index 2c9c4395..dbfa4bcb 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -126,10 +126,8 @@ namespace data i2p::context.CleanupDestination (); lastDestinationCleanup = ts; } - // if we're in hidden mode don't publish or explore - // if (m_HiddenMode) continue; - - if (ts - lastPublish >= NETDB_PUBLISH_INTERVAL) // publish + + if (ts - lastPublish >= NETDB_PUBLISH_INTERVAL && !m_HiddenMode) // publish { Publish (); lastPublish = ts; @@ -147,8 +145,9 @@ namespace data numRouters = 800/numRouters; if (numRouters < 1) numRouters = 1; if (numRouters > 9) numRouters = 9; - m_Requests.ManageRequests (); - Explore (numRouters); + m_Requests.ManageRequests (); + if(!m_HiddenMode) + Explore (numRouters); lastExploratory = ts; } } diff --git a/Transports.cpp b/Transports.cpp index a29cac15..2efcbedf 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -240,7 +240,8 @@ namespace transport for (auto& it: msgs) i2p::HandleI2NPMessage (it); return; - } + } + if(RoutesRestricted() && ! IsRestrictedPeer(ident)) return; auto it = m_Peers.find (ident); if (it == m_Peers.end ()) { @@ -494,6 +495,12 @@ namespace transport void Transports::DetectExternalIP () { + if (RoutesRestricted()) + { + LogPrint(eLogInfo, "Transports: restricted routes enabled, not detecting ip"); + i2p::context.SetStatus (eRouterStatusFirewalled); + return; + } if (m_SSUServer) { #ifndef MESHNET @@ -520,8 +527,10 @@ namespace transport void Transports::PeerTest () { + if (RoutesRestricted()) return; if (m_SSUServer) { + bool statusChanged = false; for (int i = 0; i < 5; i++) { @@ -578,6 +587,12 @@ namespace transport } else // incoming connection { + if(RoutesRestricted() && ! IsRestrictedPeer(ident)) { + // not trusted + LogPrint(eLogWarning, "Transports: closing untrusted inbound connection from ", ident.ToBase64()); + session->Done(); + return; + } session->SendI2NPMessages ({ CreateDatabaseStoreMsg () }); // send DatabaseStore std::unique_lock l(m_PeersMutex); m_Peers.insert (std::make_pair (ident, Peer{ 0, nullptr, { session }, i2p::util::GetSecondsSinceEpoch (), {} })); @@ -655,7 +670,7 @@ namespace transport std::advance (it, rand () % m_Peers.size ()); return it != m_Peers.end () ? it->second.router : nullptr; } - void Transports::RestrictRoutes(std::vector families) + void Transports::RestrictRoutesToFamilies(std::set families) { std::lock_guard lock(m_FamilyMutex); m_TrustedFamilies.clear(); @@ -663,22 +678,71 @@ namespace transport m_TrustedFamilies.push_back(fam); } + void Transports::RestrictRoutesToRouters(std::set routers) + { + std::unique_lock lock(m_TrustedRoutersMutex); + m_TrustedRouters.clear(); + for (const auto & ri : routers ) + m_TrustedRouters.push_back(ri); + } + bool Transports::RoutesRestricted() const { - std::lock_guard lock(m_FamilyMutex); - return m_TrustedFamilies.size() > 0; + std::unique_lock famlock(m_FamilyMutex); + std::unique_lock routerslock(m_TrustedRoutersMutex); + return m_TrustedFamilies.size() > 0 || m_TrustedRouters.size() > 0; } /** XXX: if routes are not restricted this dies */ - std::shared_ptr Transports::GetRestrictedPeer() const { - std::string fam; - { - std::lock_guard lock(m_FamilyMutex); - // TODO: random family (?) - fam = m_TrustedFamilies[0]; - } - boost::to_lower(fam); - return i2p::data::netdb.GetRandomRouterInFamily(fam); + std::shared_ptr Transports::GetRestrictedPeer() const + { + { + std::lock_guard l(m_FamilyMutex); + std::string fam; + auto sz = m_TrustedFamilies.size(); + if(sz > 1) + { + auto it = m_TrustedFamilies.begin (); + std::advance(it, rand() % sz); + fam = *it; + boost::to_lower(fam); + } + else if (sz == 1) + { + fam = m_TrustedFamilies[0]; + } + if (fam.size()) + return i2p::data::netdb.GetRandomRouterInFamily(fam); + } + { + std::unique_lock l(m_TrustedRoutersMutex); + auto sz = m_TrustedRouters.size(); + if (sz) + { + if(sz == 1) + return i2p::data::netdb.FindRouter(m_TrustedRouters[0]); + auto it = m_TrustedRouters.begin(); + std::advance(it, rand() % sz); + return i2p::data::netdb.FindRouter(*it); + } + } + return nullptr; } + + bool Transports::IsRestrictedPeer(const i2p::data::IdentHash & ih) const + { + { + std::unique_lock l(m_TrustedRoutersMutex); + for (const auto & r : m_TrustedRouters ) + if ( r == ih ) return true; + } + { + std::unique_lock l(m_FamilyMutex); + auto ri = i2p::data::netdb.FindRouter(ih); + for (const auto & fam : m_TrustedFamilies) + if(ri->IsFamily(fam)) return true; + } + return false; + } } } diff --git a/Transports.h b/Transports.h index 81063916..9ecfd719 100644 --- a/Transports.h +++ b/Transports.h @@ -110,7 +110,11 @@ namespace transport /** do we want to use restricted routes? */ bool RoutesRestricted() const; /** restrict routes to use only these router families for first hops */ - void RestrictRoutes(std::vector families); + void RestrictRoutesToFamilies(std::set families); + /** restrict routes to use only these routers for first hops */ + void RestrictRoutesToRouters(std::set routers); + + bool IsRestrictedPeer(const i2p::data::IdentHash & ident) const; void PeerTest (); @@ -157,6 +161,10 @@ namespace transport /** which router families to trust for first hops */ std::vector m_TrustedFamilies; mutable std::mutex m_FamilyMutex; + + /** which routers for first hop to trust */ + std::vector m_TrustedRouters; + mutable std::mutex m_TrustedRoutersMutex; public: diff --git a/Tunnel.cpp b/Tunnel.cpp index 7d2e6735..44d92d75 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -644,7 +644,9 @@ namespace tunnel { // trying to create one more oubound tunnel auto inboundTunnel = GetNextInboundTunnel (); - auto router = i2p::data::netdb.GetRandomRouter (); + auto router = i2p::transport::transports.RoutesRestricted() ? + i2p::transport::transports.GetRestrictedPeer() : + i2p::data::netdb.GetRandomRouter (); if (!inboundTunnel || !router) return; LogPrint (eLogDebug, "Tunnel: creating one hop outbound tunnel"); CreateTunnel ( @@ -706,7 +708,9 @@ namespace tunnel if (m_OutboundTunnels.empty () || m_InboundTunnels.size () < 5) { // trying to create one more inbound tunnel - auto router = i2p::data::netdb.GetRandomRouter (); + auto router = i2p::transport::transports.RoutesRestricted() ? + i2p::transport::transports.GetRestrictedPeer() : + i2p::data::netdb.GetRandomRouter (); if (!router) { LogPrint (eLogWarning, "Tunnel: can't find any router, skip creating tunnel"); return;