diff --git a/Config.cpp b/Config.cpp index aa75b8db..71fcbfbd 100644 --- a/Config.cpp +++ b/Config.cpp @@ -157,7 +157,8 @@ namespace config { options_description reseed("Reseed options"); reseed.add_options() - ("reseed.verify", value()->default_value(false), "Verify .su3 signature") + ("reseed.verify", value()->default_value(false), "Verify .su3 signature") + ("reseed.floodfill", value()->default_value(""), "Path to router info of floodfill to reseed from") ("reseed.file", value()->default_value(""), "Path to .su3 file") ("reseed.urls", value()->default_value( "https://reseed.i2p-projekt.de/," diff --git a/NetDb.cpp b/NetDb.cpp index dbfa4bcb..e667dc11 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -14,6 +14,7 @@ #include "RouterContext.h" #include "Garlic.h" #include "NetDb.h" +#include "Config.h" using namespace i2p::transport; @@ -23,7 +24,7 @@ namespace data { NetDb netdb; - NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_HiddenMode(false) + NetDb::NetDb (): m_IsRunning (false), m_Thread (nullptr), m_Reseeder (nullptr), m_Storage("netDb", "r", "routerInfo-", "dat"), m_FloodfillBootstrap(nullptr), m_HiddenMode(false) { } @@ -140,6 +141,8 @@ namespace data LogPrint(eLogError, "NetDb: no known routers, reseed seems to be totally failed"); break; } + else // we have peers now + m_FloodfillBootstrap = nullptr; if (numRouters < 2500 || ts - lastExploratory >= 90) { numRouters = 800/numRouters; @@ -295,13 +298,62 @@ namespace data m_Reseeder = new Reseeder (); m_Reseeder->LoadCertificates (); // we need certificates for SU3 verification } - int reseedRetries = 0; + int reseedRetries = 0; + + // try reseeding from floodfill first if specified + std::string riPath; + if(i2p::config::GetOption("reseed.floodfill", riPath)) { + auto ri = std::make_shared(riPath); + if (ri->IsFloodfill()) { + const uint8_t * riData = ri->GetBuffer(); + int riLen = ri->GetBufferLen(); + if(!i2p::data::netdb.AddRouterInfo(riData, riLen)) { + // bad router info + LogPrint(eLogError, "NetDb: bad router info"); + return; + } + m_FloodfillBootstrap = ri; + ReseedFromFloodfill(*ri); + // don't try reseed servers if trying to boostrap from floodfill + return; + } + } + while (reseedRetries < 10 && !m_Reseeder->ReseedNowSU3 ()) reseedRetries++; if (reseedRetries >= 10) LogPrint (eLogWarning, "NetDb: failed to reseed after 10 attempts"); } + void NetDb::ReseedFromFloodfill(const RouterInfo & ri, int numRouters, int numFloodfills) + { + LogPrint(eLogInfo, "NetDB: reseeding from floodfill ", ri.GetIdentHashBase64()); + std::vector > requests; + + i2p::data::IdentHash ourIdent = i2p::context.GetIdentHash(); + i2p::data::IdentHash ih = ri.GetIdentHash(); + i2p::data::IdentHash randomIdent; + + // make floodfill lookups + while(numFloodfills > 0) { + randomIdent.Randomize(); + auto msg = i2p::CreateRouterInfoDatabaseLookupMsg(randomIdent, ourIdent, 0, false); + requests.push_back(msg); + numFloodfills --; + } + + // make regular router lookups + while(numRouters > 0) { + randomIdent.Randomize(); + auto msg = i2p::CreateRouterInfoDatabaseLookupMsg(randomIdent, ourIdent, 0, true); + requests.push_back(msg); + numRouters --; + } + + // send them off + i2p::transport::transports.SendMessages(ih, requests); + } + bool NetDb::LoadRouterInfo (const std::string & path) { auto r = std::make_shared(path); @@ -498,6 +550,21 @@ namespace data m_Requests.RequestComplete (destination, nullptr); } } + + void NetDb::RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete) + { + + auto dest = m_Requests.CreateRequest (destination, exploritory, requestComplete); // non-exploratory + if (!dest) + { + LogPrint (eLogWarning, "NetDb: destination ", destination.ToBase64(), " is requested already"); + return; + } + LogPrint(eLogInfo, "NetDb: destination ", destination.ToBase64(), " being requested directly from ", from.ToBase64()); + // direct + transports.SendMessage (from, dest->CreateRequestMessage (nullptr, nullptr)); + } + void NetDb::HandleDatabaseStoreMsg (std::shared_ptr m) { @@ -620,7 +687,7 @@ namespace data if (!dest->IsExploratory ()) { // reply to our destination. Try other floodfills - if (outbound && inbound ) + if (outbound && inbound) { std::vector msgs; auto count = dest->GetExcludedPeers ().size (); @@ -664,7 +731,7 @@ namespace data // no more requests for detination possible. delete it m_Requests.RequestComplete (ident, nullptr); } - else + else if(!m_FloodfillBootstrap) LogPrint (eLogWarning, "NetDb: requested destination for ", key, " not found"); // try responses @@ -681,7 +748,10 @@ namespace data { // router with ident not found or too old (1 hour) LogPrint (eLogDebug, "NetDb: found new/outdated router. Requesting RouterInfo ..."); - RequestDestination (router); + if(m_FloodfillBootstrap) + RequestDestinationFrom(router, m_FloodfillBootstrap->GetIdentHash(), true); + else + RequestDestination (router); } else LogPrint (eLogDebug, "NetDb: [:|||:]"); diff --git a/NetDb.h b/NetDb.h index d295ebbe..94c8a086 100644 --- a/NetDb.h +++ b/NetDb.h @@ -60,6 +60,7 @@ namespace data std::shared_ptr FindRouterProfile (const IdentHash& ident) const; void RequestDestination (const IdentHash& destination, RequestedDestination::RequestComplete requestComplete = nullptr); + void RequestDestinationFrom (const IdentHash& destination, const IdentHash & from, bool exploritory, RequestedDestination::RequestComplete requestComplete = nullptr); void HandleDatabaseStoreMsg (std::shared_ptr msg); void HandleDatabaseSearchReplyMsg (std::shared_ptr msg); @@ -98,6 +99,9 @@ namespace data void VisitRouterInfos(RouterInfoVisitor v); /** visit N random router that match using filter, then visit them with a visitor, return number of RouterInfos that were visited */ size_t VisitRandomRouterInfos(RouterInfoFilter f, RouterInfoVisitor v, size_t n); + + + private: void Load (); @@ -110,6 +114,8 @@ namespace data void ManageRequests (); void ManageLookupResponses (); + void ReseedFromFloodfill(const RouterInfo & ri, int numRouters=40, int numFloodfills=20); + template std::shared_ptr GetRandomRouter (Filter filter) const; @@ -135,6 +141,9 @@ namespace data friend class NetDbRequests; NetDbRequests m_Requests; + /** router info we are bootstrapping from or nullptr if we are not currently doing that*/ + std::shared_ptr m_FloodfillBootstrap; + std::map, uint64_t> > m_LookupResponses; // ident->(closest FFs, timestamp) /** true if in hidden mode */ diff --git a/NetDbRequests.cpp b/NetDbRequests.cpp index 474d3693..866bc6d9 100644 --- a/NetDbRequests.cpp +++ b/NetDbRequests.cpp @@ -11,10 +11,15 @@ namespace data std::shared_ptr RequestedDestination::CreateRequestMessage (std::shared_ptr router, std::shared_ptr replyTunnel) { - auto msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination, + std::shared_ptr msg; + if(replyTunnel) + msg = i2p::CreateRouterInfoDatabaseLookupMsg (m_Destination, replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory, &m_ExcludedPeers); - m_ExcludedPeers.insert (router->GetIdentHash ()); + else + msg = i2p::CreateRouterInfoDatabaseLookupMsg(m_Destination, i2p::context.GetIdentHash(), 0, m_IsExploratory, &m_ExcludedPeers); + if(router) + m_ExcludedPeers.insert (router->GetIdentHash ()); m_CreationTime = i2p::util::GetSecondsSinceEpoch (); return msg; } diff --git a/Tag.h b/Tag.h index 30dfa654..3d21183f 100644 --- a/Tag.h +++ b/Tag.h @@ -11,6 +11,7 @@ #include #include +#include #include "Base.h" namespace i2p { @@ -49,7 +50,12 @@ public: { memset(m_Buf, c, sz); } - + + void Randomize() + { + RAND_bytes(m_Buf, sz); + } + std::string ToBase64 () const { char str[sz*2];