diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index 76918bcd..7993a79a 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -83,7 +83,7 @@ namespace i2p } I2NPMessage * CreateDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, - uint32_t replyTunnelID, bool exploratory) + uint32_t replyTunnelID, bool exploratory, std::set * excludedPeers) { I2NPMessage * m = NewI2NPMessage (); uint8_t * buf = m->GetPayload (); @@ -113,9 +113,23 @@ namespace i2p } else { - // nothing to exclude - *(uint16_t *)buf = htobe16 (0); - buf += 2; + if (excludedPeers) + { + int cnt = excludedPeers->size (); + *(uint16_t *)buf = htobe16 (cnt); + buf += 2; + for (auto& it: *excludedPeers) + { + memcpy (buf, it, 32); + buf += 32; + } + } + else + { + // nothing to exclude + *(uint16_t *)buf = htobe16 (0); + buf += 2; + } } m->len += (buf - m->GetPayload ()); FillI2NPMessageHeader (m, eI2NPDatabaseLookup); diff --git a/I2NPProtocol.h b/I2NPProtocol.h index 597c00b0..adcbd576 100644 --- a/I2NPProtocol.h +++ b/I2NPProtocol.h @@ -2,7 +2,7 @@ #define I2NP_PROTOCOL_H__ #include -#include +#include #include #include "RouterInfo.h" @@ -105,7 +105,8 @@ namespace i2p I2NPMessage * CreateDeliveryStatusMsg (); I2NPMessage * CreateDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, - uint32_t replyTunnelID, bool exploratory = false); + uint32_t replyTunnelID, bool exploratory = false, + std::set * excludedPeers = nullptr); I2NPMessage * CreateDatabaseStoreMsg (); diff --git a/NetDb.cpp b/NetDb.cpp index 264b1631..395bd461 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -15,10 +15,23 @@ namespace i2p { namespace data { + + I2NPMessage * RequestedDestination::CreateRequestMessage (const RouterInfo * router, + const i2p::tunnel::InboundTunnel * replyTunnel) + { + I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (m_Destination, + replyTunnel->GetNextIdentHash (), replyTunnel->GetNextTunnelID (), m_IsExploratory, &m_ExcludedPeers); + if (m_IsLeaseSet) // wrap lookup message into garlic + msg = i2p::garlic::routing.WrapSingleMessage (router, msg); + m_ExcludedPeers.insert (router->GetIdentHash ()); + m_LastRouter = router; + m_LastReplyTunnel = replyTunnel; + return msg; + } NetDb netdb; - NetDb::NetDb (): m_IsRunning (false), m_Thread (0), m_LastFloodfill (0) + NetDb::NetDb (): m_IsRunning (false), m_Thread (0) { } @@ -29,6 +42,8 @@ namespace data delete l.second; for (auto r:m_RouterInfos) delete r.second; + for (auto r:m_RequestedDestinations) + delete r.second; } void NetDb::Start () @@ -97,6 +112,7 @@ namespace data void NetDb::AddRouterInfo (uint8_t * buf, int len) { RouterInfo * r = new RouterInfo (buf, len); + DeleteRequestedDestination (r->GetIdentHash ()); auto it = m_RouterInfos.find(r->GetIdentHash ()); if (it != m_RouterInfos.end ()) { @@ -118,6 +134,7 @@ namespace data void NetDb::AddLeaseSet (uint8_t * buf, int len) { LeaseSet * l = new LeaseSet (buf, len); + DeleteRequestedDestination (l->GetIdentHash ()); m_LeaseSets[l->GetIdentHash ()] = l; } @@ -223,10 +240,9 @@ namespace data i2p::tunnel::InboundTunnel * inbound = i2p::tunnel::tunnels.GetNextInboundTunnel (); if (inbound) { - I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (destination, inbound->GetNextIdentHash (), - inbound->GetNextTunnelID ()); - if (isLeaseSet) // wrap lookup message into garlic - msg = i2p::garlic::routing.WrapSingleMessage (floodfill, msg); + RequestedDestination * dest = CreateRequestedDestination (destination, isLeaseSet); + dest->SetLastOutboundTunnel (outbound); + auto msg = dest->CreateRequestMessage (floodfill, inbound); outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg); } else @@ -275,87 +291,133 @@ namespace data key[l] = 0; int num = buf[32]; // num LogPrint ("DatabaseSearchReply for ", key, " num=", num); - if (num > 0) - { - bool isExploratory = !memcmp (m_Exploratory, buf, 32) && m_LastFloodfill; - i2p::tunnel::OutboundTunnel * outbound = isExploratory ? m_LastOutboundTunnel : i2p::tunnel::tunnels.GetNextOutboundTunnel (); - i2p::tunnel::InboundTunnel * inbound = isExploratory ? m_LastInboundTunnel : i2p::tunnel::tunnels.GetNextInboundTunnel (); + auto it = m_RequestedDestinations.find (IdentHash (buf)); + if (it != m_RequestedDestinations.end ()) + { + RequestedDestination * dest = it->second; + if (num > 0) + { + i2p::tunnel::OutboundTunnel * outbound = dest->GetLastOutboundTunnel (); + const i2p::tunnel::InboundTunnel * inbound = dest->GetLastReplyTunnel (); - for (int i = 0; i < num; i++) - { - uint8_t * router = buf + 33 + i*32; - char peerHash[48]; - int l1 = i2p::data::ByteStreamToBase64 (router, 32, peerHash, 48); - peerHash[l1] = 0; - LogPrint (i,": ", peerHash); + for (int i = 0; i < num; i++) + { + uint8_t * router = buf + 33 + i*32; + char peerHash[48]; + int l1 = i2p::data::ByteStreamToBase64 (router, 32, peerHash, 48); + peerHash[l1] = 0; + LogPrint (i,": ", peerHash); - if (isExploratory) - { - if (m_RouterInfos.find (IdentHash(router)) == m_RouterInfos.end ()) + if (dest->IsExploratory ()) + { + if (!FindRouter (router)) // router with ident not found + { + LogPrint ("Found new router. Requesting RouterInfo ..."); + if (outbound && inbound) + { + RequestedDestination * d1 = CreateRequestedDestination (router, false, false); + d1->SetLastOutboundTunnel (outbound); + auto msg = d1->CreateRequestMessage (dest->GetLastRouter (), dest->GetLastReplyTunnel ()); + outbound->GetTunnelGateway ().PutTunnelDataMsg (dest->GetLastRouter ()->GetIdentHash (), 0, msg); + } + } + else + LogPrint ("Bayan"); + } + else { - LogPrint ("Found new router. Requesting RouterInfo ..."); + // reply to our destination. Try other floodfills if (outbound && inbound) { - I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (router, inbound->GetNextIdentHash (), - inbound->GetNextTunnelID ()); - outbound->GetTunnelGateway ().PutTunnelDataMsg (m_LastFloodfill->GetIdentHash (), 0, msg); - } - } - else - LogPrint ("Bayan"); - } - else - { - // reply to our destination. Try other floodfills - if (outbound && inbound) - { - // do we have that floodfill router in our database? - if (!FindRouter (router)) - { - // request router - LogPrint ("Found new floodfill. Request it"); - msg = i2p::CreateDatabaseLookupMsg (router, inbound->GetNextIdentHash (), - inbound->GetNextTunnelID ()); - outbound->GetTunnelGateway ().PutTunnelDataMsg ( - GetRandomNTCPRouter (true)->GetIdentHash (), 0, msg); - // request destination - I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (buf, inbound->GetNextIdentHash (), - inbound->GetNextTunnelID ()); - outbound->GetTunnelGateway ().PutTunnelDataMsg (router, 0, msg); + auto r = FindRouter (router); + // do we have that floodfill router in our database? + if (r) + { + if (!dest->IsExcluded (r->GetIdentHash ()) && dest->GetNumExcludedPeers () < 10) // TODO: fix TunnelGateway first + { + // request destination + auto msg = dest->CreateRequestMessage (r, dest->GetLastReplyTunnel ()); + outbound->GetTunnelGateway ().PutTunnelDataMsg (r->GetIdentHash (), 0, msg); + } + } + else + { + // request router + LogPrint ("Found new floodfill. Request it"); + RequestedDestination * d2 = CreateRequestedDestination (router, false, false); + d2->SetLastOutboundTunnel (outbound); + I2NPMessage * msg = d2->CreateRequestMessage (dest->GetLastRouter (), inbound); + outbound->GetTunnelGateway ().PutTunnelDataMsg ( + dest->GetLastRouter ()->GetIdentHash (), 0, msg); + } } } - } - } + } - if (outbound) - outbound->GetTunnelGateway ().SendBuffer (); - } + if (outbound) + outbound->GetTunnelGateway ().SendBuffer (); + } + else + { + // no more requests for detination possible. delete it + m_RequestedDestinations.erase (it); + delete it->second; + } + } + else + LogPrint ("Requested destination for ", key, " not found"); i2p::DeleteI2NPMessage (msg); } void NetDb::Explore () { - m_LastOutboundTunnel = i2p::tunnel::tunnels.GetNextOutboundTunnel (); - m_LastInboundTunnel = i2p::tunnel::tunnels.GetNextInboundTunnel (); - if (m_LastOutboundTunnel && m_LastInboundTunnel) + auto outbound = i2p::tunnel::tunnels.GetNextOutboundTunnel (); + auto inbound = i2p::tunnel::tunnels.GetNextInboundTunnel (); + if (outbound && inbound) { - m_LastFloodfill = GetRandomNTCPRouter (true); - if (m_LastFloodfill) + auto floodfill = GetRandomNTCPRouter (true); + if (floodfill) { LogPrint ("Exploring new routers ..."); CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); - rnd.GenerateBlock (m_Exploratory, 32); + uint8_t randomHash[32]; + rnd.GenerateBlock (randomHash, 32); + RequestedDestination * dest = CreateRequestedDestination (IdentHash (randomHash), false, true); + dest->SetLastOutboundTunnel (outbound); - m_LastOutboundTunnel->GetTunnelGateway ().PutTunnelDataMsg (m_LastFloodfill->GetIdentHash (), 0, + outbound->GetTunnelGateway ().PutTunnelDataMsg (floodfill->GetIdentHash (), 0, CreateDatabaseStoreMsg ()); // tell floodfill about us - m_LastOutboundTunnel->GetTunnelGateway ().PutTunnelDataMsg (m_LastFloodfill->GetIdentHash (), 0, - i2p::CreateDatabaseLookupMsg (m_Exploratory, m_LastInboundTunnel->GetNextIdentHash (), - m_LastInboundTunnel->GetNextTunnelID (), true)); // explore - m_LastOutboundTunnel->GetTunnelGateway ().SendBuffer (); + outbound->GetTunnelGateway ().PutTunnelDataMsg (floodfill->GetIdentHash (), 0, + dest->CreateRequestMessage (floodfill, inbound)); // explore + outbound->GetTunnelGateway ().SendBuffer (); } } } + RequestedDestination * NetDb::CreateRequestedDestination (const IdentHash& dest, + bool isLeaseSet, bool isExploratory) + { + auto it = m_RequestedDestinations.find (dest); + if (it == m_RequestedDestinations.end ()) // not exist yet + { + RequestedDestination * d = new RequestedDestination (dest, isLeaseSet, isExploratory); + m_RequestedDestinations[dest] = d; + return d; + } + else + return it->second; + } + + void NetDb::DeleteRequestedDestination (const IdentHash& dest) + { + auto it = m_RequestedDestinations.find (dest); + if (it != m_RequestedDestinations.end ()) + { + m_RequestedDestinations.erase (it); + delete it->second; + } + } + const RouterInfo * NetDb::GetRandomNTCPRouter (bool floodfillOnly) const { CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); diff --git a/NetDb.h b/NetDb.h index 761d3a09..02a585ef 100644 --- a/NetDb.h +++ b/NetDb.h @@ -2,6 +2,7 @@ #define NETDB_H__ #include +#include #include #include #include @@ -15,6 +16,35 @@ namespace i2p { namespace data { + class RequestedDestination + { + public: + + RequestedDestination (const IdentHash& destination, bool isLeaseSet, bool isExploratory = false): + m_Destination (destination), m_IsLeaseSet (isLeaseSet), m_IsExploratory (isExploratory), + m_LastRouter (nullptr), m_LastReplyTunnel (nullptr), m_LastOutboundTunnel (nullptr) {}; + + const IdentHash& GetDestination () const { return m_Destination; }; + int GetNumExcludedPeers () const { return m_ExcludedPeers.size (); }; + const RouterInfo * GetLastRouter () const { return m_LastRouter; }; + const i2p::tunnel::InboundTunnel * GetLastReplyTunnel () const { return m_LastReplyTunnel; }; + bool IsExploratory () const { return m_IsExploratory; }; + bool IsExcluded (const IdentHash& ident) const { return m_ExcludedPeers.count (ident); }; + I2NPMessage * CreateRequestMessage (const RouterInfo * router, const i2p::tunnel::InboundTunnel * replyTunnel); + + i2p::tunnel::OutboundTunnel * GetLastOutboundTunnel () const { return m_LastOutboundTunnel; }; + void SetLastOutboundTunnel (i2p::tunnel::OutboundTunnel * tunnel) { m_LastOutboundTunnel = tunnel; }; + + private: + + IdentHash m_Destination; + bool m_IsLeaseSet, m_IsExploratory; + std::set m_ExcludedPeers; + const RouterInfo * m_LastRouter; + const i2p::tunnel::InboundTunnel * m_LastReplyTunnel; + i2p::tunnel::OutboundTunnel * m_LastOutboundTunnel; + }; + class NetDb { public: @@ -49,18 +79,19 @@ namespace data void Run (); // exploratory thread void Explore (); const RouterInfo * GetClosestFloodfill (const IdentHash& destination) const; + + RequestedDestination * CreateRequestedDestination (const IdentHash& dest, + bool isLeaseSet, bool isExploratory = false); + void DeleteRequestedDestination (const IdentHash& dest); private: std::map m_LeaseSets; std::map m_RouterInfos; - + std::map m_RequestedDestinations; + bool m_IsRunning; std::thread * m_Thread; - uint8_t m_Exploratory[32]; - const RouterInfo * m_LastFloodfill; - i2p::tunnel::OutboundTunnel * m_LastOutboundTunnel; - i2p::tunnel::InboundTunnel * m_LastInboundTunnel; i2p::util::Queue m_Queue; // of I2NPDatabaseStoreMsg };