From 5d9f292506f70dfa9fdb0c93b2109a6fac75ce17 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 22 Dec 2013 11:29:57 -0500 Subject: [PATCH 01/16] remove dead routers --- Identity.cpp | 8 ++++++++ Identity.h | 2 ++ NTCPSession.cpp | 9 ++++----- NTCPSession.h | 11 ++++++++--- NetDb.cpp | 39 +++++++++++++++++++++++++++++++++++---- NetDb.h | 5 ++++- RouterContext.cpp | 4 +--- 7 files changed, 62 insertions(+), 16 deletions(-) diff --git a/Identity.cpp b/Identity.cpp index bbdfdbe8..b80d1cbf 100644 --- a/Identity.cpp +++ b/Identity.cpp @@ -9,6 +9,14 @@ namespace i2p { namespace data { + Identity& Identity::operator=(const Keys& keys) + { + // copy public and signing keys together + memcpy (publicKey, keys.publicKey, sizeof (publicKey) + sizeof (signingKey)); + memset (certificate, 0, sizeof (certificate)); + return *this; + } + IdentHash CalculateIdentHash (const Identity& identity) { IdentHash hash; diff --git a/Identity.h b/Identity.h index 09af9332..549e9cea 100644 --- a/Identity.h +++ b/Identity.h @@ -23,6 +23,8 @@ namespace data uint8_t publicKey[256]; uint8_t signingKey[128]; uint8_t certificate[3]; + + Identity& operator=(const Keys& keys); }; #pragma pack() diff --git a/NTCPSession.cpp b/NTCPSession.cpp index b52a6223..1d8a93f0 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -20,12 +20,10 @@ namespace i2p { namespace ntcp { - NTCPSession::NTCPSession (boost::asio::io_service& service, i2p::data::RouterInfo * in_RemoteRouterInfo): + NTCPSession::NTCPSession (boost::asio::io_service& service, i2p::data::RouterInfo& in_RemoteRouterInfo): m_Socket (service), m_TerminationTimer (service), m_IsEstablished (false), - m_ReceiveBufferOffset (0), m_NextMessage (nullptr) + m_RemoteRouterInfo (in_RemoteRouterInfo), m_ReceiveBufferOffset (0), m_NextMessage (nullptr) { - if (in_RemoteRouterInfo) - m_RemoteRouterInfo = *in_RemoteRouterInfo; } void NTCPSession::CreateAESKey (uint8_t * pubKey, uint8_t * aesKey) @@ -521,7 +519,8 @@ namespace ntcp NTCPClient::NTCPClient (boost::asio::io_service& service, const char * address, - int port, i2p::data::RouterInfo& in_RouterInfo): NTCPSession (service, &in_RouterInfo), + int port, i2p::data::RouterInfo& in_RouterInfo): + NTCPSession (service, in_RouterInfo), m_Endpoint (boost::asio::ip::address::from_string (address), port) { Connect (); diff --git a/NTCPSession.h b/NTCPSession.h index 4ef0e3dd..925643b4 100644 --- a/NTCPSession.h +++ b/NTCPSession.h @@ -66,7 +66,7 @@ namespace ntcp { public: - NTCPSession (boost::asio::io_service& service, i2p::data::RouterInfo * in_RemoteRouterInfo = 0); + NTCPSession (boost::asio::io_service& service, i2p::data::RouterInfo& in_RemoteRouterInfo); virtual ~NTCPSession () {}; boost::asio::ip::tcp::socket& GetSocket () { return m_Socket; }; @@ -126,7 +126,7 @@ namespace ntcp CryptoPP::CBC_Mode::Encryption m_Encryption; CryptoPP::Adler32 m_Adler; - i2p::data::RouterInfo m_RemoteRouterInfo; + i2p::data::RouterInfo& m_RemoteRouterInfo; NTCPPhase1 m_Phase1; NTCPPhase2 m_Phase2; @@ -163,11 +163,16 @@ namespace ntcp { public: - NTCPServerConnection (boost::asio::io_service& service): NTCPSession (service) {}; + NTCPServerConnection (boost::asio::io_service& service): + NTCPSession (service, m_DummyRemoteRouterInfo) {}; protected: virtual void Connected (); + + private: + + i2p::data::RouterInfo m_DummyRemoteRouterInfo; }; } } diff --git a/NetDb.cpp b/NetDb.cpp index 41440582..79cd903a 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -128,6 +128,15 @@ namespace data else return nullptr; } + + LeaseSet * NetDb::FindLeaseSet (const IdentHash& destination) const + { + auto it = m_LeaseSets.find (destination); + if (it != m_LeaseSets.end ()) + return it->second; + else + return nullptr; + } void NetDb::Load (const char * directory) { @@ -156,19 +165,36 @@ namespace data void NetDb::SaveUpdated (const char * directory) { - int count = 0; + auto GetFilePath = [](const char * directory, const RouterInfo * routerInfo) + { + return std::string (directory) + "/r" + + routerInfo->GetIdentHashBase64 ()[0] + "/routerInfo-" + + routerInfo->GetIdentHashBase64 () + ".dat"; + }; + + int count = 0, deletedCount = 0; for (auto it: m_RouterInfos) + { if (it.second->IsUpdated ()) { - std::ofstream r (std::string (directory) + "/r" + - it.second->GetIdentHashBase64 ()[0] + "/routerInfo-" + - it.second->GetIdentHashBase64 () + ".dat"); + std::ofstream r (GetFilePath(directory, it.second)); r.write ((char *)it.second->GetBuffer (), it.second->GetBufferLen ()); it.second->SetUpdated (false); count++; } + else if (it.second->IsUnreachable ()) + { + if (boost::filesystem::exists (GetFilePath (directory, it.second))) + { + boost::filesystem::remove (GetFilePath (directory, it.second)); + deletedCount++; + } + } + } if (count > 0) LogPrint (count," new/updated routers saved"); + if (deletedCount > 0) + LogPrint (deletedCount," routers deleted"); } void NetDb::RequestDestination (const char * b32, const uint8_t * router) @@ -197,6 +223,11 @@ namespace data LogPrint ("No outbound tunnels found"); } + void NetDb::RequestDestination (const IdentHash& destination) + { + RequestDestination ((const uint8_t *)destination, GetRandomNTCPRouter (true)->GetIdentHash ()); + } + void NetDb::HandleDatabaseStoreMsg (uint8_t * buf, size_t len) { I2NPDatabaseStoreMsg * msg = (I2NPDatabaseStoreMsg *)buf; diff --git a/NetDb.h b/NetDb.h index c76bd9f7..4d9ebbb1 100644 --- a/NetDb.h +++ b/NetDb.h @@ -27,9 +27,12 @@ namespace data void AddRouterInfo (uint8_t * buf, int len); void AddLeaseSet (uint8_t * buf, int len); RouterInfo * FindRouter (const IdentHash& ident) const; - + LeaseSet * FindLeaseSet (const IdentHash& destination) const; + void RequestDestination (const char * b32, const uint8_t * router); // in base32 void RequestDestination (const uint8_t * destination, const uint8_t * router); + void RequestDestination (const IdentHash& destination); + void HandleDatabaseStoreMsg (uint8_t * buf, size_t len); void HandleDatabaseSearchReplyMsg (I2NPMessage * msg); diff --git a/RouterContext.cpp b/RouterContext.cpp index 84fac346..718a9f36 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -26,9 +26,7 @@ namespace i2p CryptoPP::Integer (m_Keys.signingPrivateKey, 20)); i2p::data::Identity ident; - // copy public and signing keys together - memcpy (ident.publicKey, m_Keys.publicKey, sizeof (ident.publicKey) + sizeof (ident.signingKey)); - memset (ident.certificate, 0, sizeof (ident.certificate)); + ident = m_Keys; m_RouterInfo.SetRouterIdentity (ident); m_RouterInfo.AddNTCPAddress ("127.0.0.1", 17007); // TODO: From ca51567eba5657a235d007115456f04f8a1cee0d Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 25 Dec 2013 12:19:46 -0500 Subject: [PATCH 02/16] better exploratory --- NetDb.cpp | 20 ++++++++++++-------- NetDb.h | 3 +++ 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index 79cd903a..3f05dd7d 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -270,8 +270,8 @@ namespace data if (num > 0) { bool isExploratory = !memcmp (m_Exploratory, buf, 32) && m_LastFloodfill; - i2p::tunnel::OutboundTunnel * outbound = i2p::tunnel::tunnels.GetNextOutboundTunnel (); - i2p::tunnel::InboundTunnel * inbound = i2p::tunnel::tunnels.GetNextInboundTunnel (); + i2p::tunnel::OutboundTunnel * outbound = isExploratory ? m_LastOutboundTunnel : i2p::tunnel::tunnels.GetNextOutboundTunnel (); + i2p::tunnel::InboundTunnel * inbound = isExploratory ? m_LastInboundTunnel : i2p::tunnel::tunnels.GetNextInboundTunnel (); for (int i = 0; i < num; i++) { @@ -327,9 +327,9 @@ namespace data void NetDb::Explore () { - i2p::tunnel::OutboundTunnel * outbound = i2p::tunnel::tunnels.GetNextOutboundTunnel (); - i2p::tunnel::InboundTunnel * inbound = i2p::tunnel::tunnels.GetNextInboundTunnel (); - if (outbound && inbound) + m_LastOutboundTunnel = i2p::tunnel::tunnels.GetNextOutboundTunnel (); + m_LastInboundTunnel = i2p::tunnel::tunnels.GetNextInboundTunnel (); + if (m_LastOutboundTunnel && m_LastInboundTunnel) { m_LastFloodfill = GetRandomNTCPRouter (true); if (m_LastFloodfill) @@ -337,9 +337,13 @@ namespace data LogPrint ("Exploring new routers ..."); CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); rnd.GenerateBlock (m_Exploratory, 32); - I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (m_Exploratory, inbound->GetNextIdentHash (), - inbound->GetNextTunnelID (), true); - outbound->SendTunnelDataMsg (m_LastFloodfill->GetIdentHash (), 0, msg); + + m_LastOutboundTunnel->GetTunnelGateway ().PutTunnelDataMsg (m_LastFloodfill->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 (); } } } diff --git a/NetDb.h b/NetDb.h index 4d9ebbb1..3f644c7d 100644 --- a/NetDb.h +++ b/NetDb.h @@ -9,6 +9,7 @@ #include "I2NPProtocol.h" #include "RouterInfo.h" #include "LeaseSet.h" +#include "Tunnel.h" namespace i2p { @@ -57,6 +58,8 @@ namespace data 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 }; From 808d6d1fbf978286b499d9d9990c94e3dea68617 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 29 Dec 2013 10:48:57 -0500 Subject: [PATCH 03/16] improved stability --- NTCPSession.cpp | 8 +++---- NTCPSession.h | 3 --- RouterInfo.cpp | 8 ++++++- RouterInfo.h | 2 ++ Transports.cpp | 56 ++++++++++++++++++++++++++++--------------------- Transports.h | 2 ++ Tunnel.cpp | 22 +++++++++++++------ 7 files changed, 62 insertions(+), 39 deletions(-) diff --git a/NTCPSession.cpp b/NTCPSession.cpp index 1d8a93f0..14b74c27 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -184,7 +184,8 @@ namespace ntcp { if (ecode) { - LogPrint ("Phase 2 read error: ", ecode.message ()); + LogPrint ("Phase 2 read error: ", ecode.message (), ". Wrong ident assumed"); + GetRemoteRouterInfo ().SetUnreachable (true); // this RouterInfo is not valid Terminate (); } else @@ -459,10 +460,7 @@ namespace ntcp m_Adler.CalculateDigest (sendBuffer + len + 2 + padding, sendBuffer, len + 2+ padding); int l = len + padding + 6; - { - std::lock_guard lock (m_EncryptionMutex); - m_Encryption.ProcessData(sendBuffer, sendBuffer, l); - } + m_Encryption.ProcessData(sendBuffer, sendBuffer, l); boost::asio::async_write (m_Socket, boost::asio::buffer (sendBuffer, l), boost::asio::transfer_all (), boost::bind(&NTCPSession::HandleSent, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, msg)); diff --git a/NTCPSession.h b/NTCPSession.h index 925643b4..5d33ef10 100644 --- a/NTCPSession.h +++ b/NTCPSession.h @@ -2,7 +2,6 @@ #define NTCP_SESSION_H__ #include -#include #include #include #include @@ -139,8 +138,6 @@ namespace ntcp i2p::I2NPMessage * m_NextMessage; std::list m_DelayedMessages; size_t m_NextMessageOffset; - - std::mutex m_EncryptionMutex; }; class NTCPClient: public NTCPSession diff --git a/RouterInfo.cpp b/RouterInfo.cpp index c6666dfd..417466c6 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -34,6 +34,7 @@ namespace data { m_RouterIdentity = identity; m_IdentHash = CalculateIdentHash (m_RouterIdentity); + UpdateIdentHashBase64 (); m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); } @@ -124,12 +125,17 @@ namespace data } CryptoPP::SHA256().CalculateDigest(m_IdentHash, (uint8_t *)&m_RouterIdentity, sizeof (m_RouterIdentity)); + UpdateIdentHashBase64 (); + } + + void RouterInfo::UpdateIdentHashBase64 () + { size_t l = i2p::data::ByteStreamToBase64 (m_IdentHash, 32, m_IdentHashBase64, 48); m_IdentHashBase64[l] = 0; memcpy (m_IdentHashAbbreviation, m_IdentHashBase64, 4); m_IdentHashAbbreviation[4] = 0; } - + void RouterInfo::WriteToStream (std::ostream& s) { s.write ((char *)&m_RouterIdentity, sizeof (m_RouterIdentity)); diff --git a/RouterInfo.h b/RouterInfo.h index 780eb8c7..3111fbf3 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -36,6 +36,7 @@ namespace data RouterInfo (const char * filename); RouterInfo () = default; RouterInfo (const RouterInfo& ) = default; + RouterInfo& operator=(const RouterInfo& ) = default; RouterInfo (const uint8_t * buf, int len); const Identity& GetRouterIdentity () const { return m_RouterIdentity; }; @@ -74,6 +75,7 @@ namespace data void WriteToStream (std::ostream& s); size_t ReadString (char * str, std::istream& s); void WriteString (const std::string& str, std::ostream& s); + void UpdateIdentHashBase64 (); private: diff --git a/Transports.cpp b/Transports.cpp index e938c85b..9204cea9 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -23,6 +23,7 @@ namespace i2p void Transports::Start () { + m_IsRunning = true; m_Thread = new std::thread (std::bind (&Transports::Run, this)); // create acceptors auto addresses = context.GetRouterInfo ().GetAddresses (); @@ -48,6 +49,7 @@ namespace i2p m_NTCPSessions.clear (); delete m_NTCPAcceptor; + m_IsRunning = false; m_Service.stop (); if (m_Thread) { @@ -59,13 +61,16 @@ namespace i2p void Transports::Run () { - try - { - m_Service.run (); - } - catch (std::exception& ex) + while (m_IsRunning) { - LogPrint ("Transports: ", ex.what ()); + try + { + m_Service.run (); + } + catch (std::exception& ex) + { + LogPrint ("Transports: ", ex.what ()); + } } } @@ -120,25 +125,28 @@ namespace i2p // we send it to ourself i2p::HandleI2NPMessage (msg); else - { - auto session = FindNTCPSession (ident); - if (!session) - { - RouterInfo * r = netdb.FindRouter (ident); - if (r) + m_Service.post (boost::bind (&Transports::PostMessage, this, ident, msg)); + } + + void Transports::PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg) + { + auto session = FindNTCPSession (ident); + if (!session) + { + RouterInfo * r = netdb.FindRouter (ident); + if (r) + { + auto address = r->GetNTCPAddress (); + if (address) { - auto address = r->GetNTCPAddress (); - if (address) - { - session = new i2p::ntcp::NTCPClient (m_Service, address->host.c_str (), address->port, *r); - AddNTCPSession (session); - } - } - } - if (session) - session->SendI2NPMessage (msg); - else - LogPrint ("Session not found"); + session = new i2p::ntcp::NTCPClient (m_Service, address->host.c_str (), address->port, *r); + AddNTCPSession (session); + } + } } + if (session) + session->SendI2NPMessage (msg); + else + LogPrint ("Session not found"); } } diff --git a/Transports.h b/Transports.h index ea5453cc..d6b08227 100644 --- a/Transports.h +++ b/Transports.h @@ -36,9 +36,11 @@ namespace i2p void Run (); void HandleAccept (i2p::ntcp::NTCPServerConnection * conn, const boost::system::error_code& error); + void PostMessage (const i2p::data::IdentHash& ident, i2p::I2NPMessage * msg); private: + bool m_IsRunning; std::thread * m_Thread; boost::asio::io_service m_Service; boost::asio::io_service::work m_Work; diff --git a/Tunnel.cpp b/Tunnel.cpp index f45ba1d4..eebb85fa 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -219,7 +219,17 @@ namespace tunnel OutboundTunnel * Tunnels::GetNextOutboundTunnel () { - OutboundTunnel * tunnel = nullptr; + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + uint32_t ind = rnd.GenerateWord32 (0, m_OutboundTunnels.size () - 1), i = 0; + for (auto it: m_OutboundTunnels) + { + if (i >= ind) return it; + else i++; + } + return nullptr; + + // TODO: implement it base on profiling + /*OutboundTunnel * tunnel = nullptr; size_t minSent = 0; for (auto it : m_OutboundTunnels) if (!tunnel || it->GetNumSentBytes () < minSent) @@ -227,7 +237,7 @@ namespace tunnel tunnel = it; minSent = it->GetNumSentBytes (); } - return tunnel; + return tunnel;*/ } void Tunnels::AddTransitTunnel (TransitTunnel * tunnel) @@ -353,13 +363,13 @@ namespace tunnel } else { - OutboundTunnel * outboundTunnel = GetNextOutboundTunnel (); + //OutboundTunnel * outboundTunnel = GetNextOutboundTunnel (); LogPrint ("Creating two hops outbound tunnel..."); CreateTunnel ( new TunnelConfig (i2p::data::netdb.GetRandomNTCPRouter (), i2p::data::netdb.GetRandomNTCPRouter (), - inboundTunnel->GetTunnelConfig ()), - outboundTunnel); + inboundTunnel->GetTunnelConfig ())/*, + outboundTunnel*/); } } } @@ -395,7 +405,7 @@ namespace tunnel } else { - OutboundTunnel * outboundTunnel = GetNextOutboundTunnel (); + OutboundTunnel * outboundTunnel = GetNextOutboundTunnel (); LogPrint ("Creating two hops inbound tunnel..."); CreateTunnel ( new TunnelConfig (i2p::data::netdb.GetRandomNTCPRouter (), From 24ad2550539d1821e3fdfd5bb64a405d9e03f873 Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 30 Dec 2013 20:46:33 -0500 Subject: [PATCH 04/16] Create and send local LeaseSet --- Garlic.cpp | 70 ++++++++++++++++++++++++++++++----------------- Garlic.h | 10 ++++--- Streaming.cpp | 75 ++++++++++++++++++++++++++++++++++++++++++++++----- Streaming.h | 16 ++++++++--- 4 files changed, 133 insertions(+), 38 deletions(-) diff --git a/Garlic.cpp b/Garlic.cpp index 50da90a3..7a450c2c 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -29,7 +29,7 @@ namespace garlic delete[] m_SessionTags; } - I2NPMessage * GarlicRoutingSession::WrapSingleMessage (I2NPMessage * msg) + I2NPMessage * GarlicRoutingSession::WrapSingleMessage (I2NPMessage * msg, I2NPMessage * leaseSet) { I2NPMessage * m = NewI2NPMessage (); size_t len = 0; @@ -46,7 +46,7 @@ namespace garlic buf += 514; // AES block m_Encryption.SetKeyWithIV (m_SessionKey, 32, iv); - len += 514 + CreateAESBlock (buf, msg); + len += 514 + CreateAESBlock (buf, msg, leaseSet); } else // existing session { @@ -57,7 +57,7 @@ namespace garlic CryptoPP::SHA256().CalculateDigest(iv, m_SessionTags + m_NextTag*32, 32); m_Encryption.SetKeyWithIV (m_SessionKey, 32, iv); // AES block - len += 32 + CreateAESBlock (buf, msg); + len += 32 + CreateAESBlock (buf, msg, leaseSet); } m_NextTag++; *(uint32_t *)(m->GetPayload ()) = htobe32 (len); @@ -67,7 +67,7 @@ namespace garlic return m; } - size_t GarlicRoutingSession::CreateAESBlock (uint8_t * buf, I2NPMessage * msg) + size_t GarlicRoutingSession::CreateAESBlock (uint8_t * buf, I2NPMessage * msg, I2NPMessage * leaseSet) { size_t blockSize = 0; *(uint16_t *)buf = htobe16 (m_NumTags); // tag count @@ -80,7 +80,7 @@ namespace garlic blockSize += 32; buf[blockSize] = 0; // flag blockSize++; - size_t len = CreateGarlicPayload (buf + blockSize, msg); + size_t len = CreateGarlicPayload (buf + blockSize, msg, leaseSet); *payloadSize = htobe32 (len); CryptoPP::SHA256().CalculateDigest(payloadHash, buf + blockSize, len); blockSize += len; @@ -91,41 +91,62 @@ namespace garlic return blockSize; } - size_t GarlicRoutingSession::CreateGarlicPayload (uint8_t * payload, I2NPMessage * msg) + size_t GarlicRoutingSession::CreateGarlicPayload (uint8_t * payload, I2NPMessage * msg, I2NPMessage * leaseSet) { uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 5000; // 5 sec size_t size = 0; - payload[size] = 1; // 1 clove + uint8_t * numCloves = payload + size; + *numCloves = 0; size++; - if (m_Destination->IsDestination ()) + + if (leaseSet) // first clove is our leaseSet if presented + { + size += CreateGarlicClove (payload + size, leaseSet, false); + (*numCloves)++; + } + if (msg) // next clove message ifself if presented + { + size += CreateGarlicClove (payload + size, msg, true); + (*numCloves)++; + } + + memset (payload + size, 0, 3); // certificate of message + size += 3; + *(uint32_t *)(payload + size) = htobe32 (m_Rnd.GenerateWord32 ()); // MessageID + size += 4; + *(uint64_t *)(payload + size) = htobe64 (ts); // Expiration of message + size += 8; + return size; + } + + size_t GarlicRoutingSession::CreateGarlicClove (uint8_t * buf, I2NPMessage * msg, bool isDestination) + { + uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 5000; // 5 sec + size_t size = 0; + if (isDestination) { - payload[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination + buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination size++; - memcpy (payload + size, m_Destination->GetIdentHash (), 32); + memcpy (buf + size, m_Destination->GetIdentHash (), 32); size += 32; } else { - payload[size] = 0;// delivery instructions flag local + buf[size] = 0;// delivery instructions flag local size++; } - memcpy (payload + size, msg->GetBuffer (), msg->GetLength ()); + + memcpy (buf + size, msg->GetBuffer (), msg->GetLength ()); size += msg->GetLength (); - *(uint32_t *)(payload + size) = htobe32 (m_Rnd.GenerateWord32 ()); // CloveID + *(uint32_t *)(buf + size) = htobe32 (m_Rnd.GenerateWord32 ()); // CloveID size += 4; - *(uint64_t *)(payload + size) = htobe64 (ts); // Expiration of clove + *(uint64_t *)(buf + size) = htobe64 (ts); // Expiration of clove size += 8; - memset (payload + size, 0, 3); // certificate of clove - size += 3; - memset (payload + size, 0, 3); // certificate of message + memset (buf + size, 0, 3); // certificate of clove size += 3; - *(uint32_t *)(payload + size) = htobe32 (m_Rnd.GenerateWord32 ()); // MessageID - size += 4; - *(uint64_t *)(payload + size) = htobe64 (ts); // Expiration of message - size += 8; return size; } - + GarlicRouting routing; GarlicRouting::GarlicRouting () { @@ -138,7 +159,8 @@ namespace garlic m_Sessions.clear (); } - I2NPMessage * GarlicRouting::WrapSingleMessage (const i2p::data::RoutingDestination * destination, I2NPMessage * msg) + I2NPMessage * GarlicRouting::WrapSingleMessage (const i2p::data::RoutingDestination * destination, + I2NPMessage * msg, I2NPMessage * leaseSet) { if (!destination) return nullptr; auto it = m_Sessions.find (destination->GetIdentHash ()); @@ -151,7 +173,7 @@ namespace garlic m_Sessions[destination->GetIdentHash ()] = session; } - I2NPMessage * ret = session->WrapSingleMessage (msg); + I2NPMessage * ret = session->WrapSingleMessage (msg, leaseSet); if (session->GetNumRemainingSessionTags () <= 0) { m_Sessions.erase (destination->GetIdentHash ()); diff --git a/Garlic.h b/Garlic.h index cdc251f6..db1f008d 100644 --- a/Garlic.h +++ b/Garlic.h @@ -40,13 +40,14 @@ namespace garlic GarlicRoutingSession (const i2p::data::RoutingDestination * destination, int numTags); ~GarlicRoutingSession (); - I2NPMessage * WrapSingleMessage (I2NPMessage * msg); + I2NPMessage * WrapSingleMessage (I2NPMessage * msg, I2NPMessage * leaseSet); int GetNumRemainingSessionTags () const { return m_NumTags - m_NextTag; }; private: - size_t CreateAESBlock (uint8_t * buf, I2NPMessage * msg); - size_t CreateGarlicPayload (uint8_t * payload, I2NPMessage * msg); + size_t CreateAESBlock (uint8_t * buf, I2NPMessage * msg, I2NPMessage * leaseSet); + size_t CreateGarlicPayload (uint8_t * payload, I2NPMessage * msg, I2NPMessage * leaseSet); + size_t CreateGarlicClove (uint8_t * buf, I2NPMessage * msg, bool isDestination); private: @@ -68,7 +69,8 @@ namespace garlic void HandleGarlicMessage (uint8_t * buf, size_t len); - I2NPMessage * WrapSingleMessage (const i2p::data::RoutingDestination * destination, I2NPMessage * msg); + I2NPMessage * WrapSingleMessage (const i2p::data::RoutingDestination * destination, + I2NPMessage * msg, I2NPMessage * leaseSet = nullptr); private: diff --git a/Streaming.cpp b/Streaming.cpp index 7a8c18ef..84bd9a28 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -1,17 +1,21 @@ #include #include #include +#include #include "Log.h" #include "RouterInfo.h" #include "RouterContext.h" +#include "Tunnel.h" +#include "Timestamp.h" +#include "CryptoConst.h" #include "Streaming.h" namespace i2p { namespace stream { - Stream::Stream (const i2p::data::IdentHash& destination): - m_SendStreamID (0) + Stream::Stream (StreamingDestination * local, const i2p::data::IdentHash& remote): + m_SendStreamID (0), m_LocalDestination (local) { m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); } @@ -57,8 +61,16 @@ namespace stream LogPrint ("Payload: ", str); } - StreamingDestination m_SharedLocalDestination; - + StreamingDestination * sharedLocalDestination = nullptr; + + StreamingDestination::StreamingDestination () + { + // TODO: read from file later + m_Keys = i2p::data::CreateRandomKeys (); + m_Identity = m_Keys; + m_IdentHash = i2p::data::CalculateIdentHash (m_Identity); + } + void StreamingDestination::HandleNextPacket (const uint8_t * buf, size_t len) { uint32_t sendStreamID = *(uint32_t *)(buf); @@ -83,11 +95,59 @@ namespace stream return nullptr; } } */ - Stream * s = new Stream (destination); + Stream * s = new Stream (this, destination); m_Streams[s->GetRecvStreamID ()] = s; return s; } - + + I2NPMessage * StreamingDestination::CreateLeaseSet () const + { + I2NPMessage * m = NewI2NPMessage (); + I2NPDatabaseStoreMsg * msg = (I2NPDatabaseStoreMsg *)m->GetPayload (); + memcpy (msg->key, (const uint8_t *)m_IdentHash, 32); + msg->type = 1; // LeaseSet + msg->replyToken = 0; + + uint8_t * buf = m->GetPayload () + sizeof (I2NPDatabaseStoreMsg); + size_t size = 0; + memcpy (buf + size, &m_Identity, sizeof (m_Identity)); + size += sizeof (m_Identity); // destination + memcpy (buf + size, i2p::context.GetLeaseSetPublicKey (), 256); + size += 256; // encryption key + memset (buf + size, 0, 128); + size += 128; // signing key + auto tunnel = i2p::tunnel::tunnels.GetNextInboundTunnel (); + if (tunnel) + { + buf[size] = 1; // 1 lease + size++; // num + memcpy (buf + size, (const uint8_t *)tunnel->GetNextIdentHash (), 32); + size += 32; // tunnel_gw + *(uint32_t *)(buf + size) = htobe32 (tunnel->GetNextTunnelID ()); + size += 4; // tunnel_id + uint64_t ts = tunnel->GetCreationTime () + i2p::tunnel::TUNNEL_EXPIRATION_TIMEOUT; + ts *= 1000; // in milliseconds + *(uint64_t *)(buf + size) = htobe64 (ts); + size += 8; // end_date + } + else + { + buf[size] = 0; // zero leases + size++; // num + } + + CryptoPP::DSA::PrivateKey signingPrivateKey; + signingPrivateKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag, + CryptoPP::Integer (m_Keys.signingPrivateKey, 20)); + CryptoPP::DSA::Signer signer (signingPrivateKey); + signer.SignMessage (i2p::context.GetRandomNumberGenerator (), buf, size, buf+ size); + size += 40; // signature + + m->len += size + sizeof (I2NPDatabaseStoreMsg); + FillI2NPMessageHeader (m, eI2NPDatabaseStore); + return m; + } + void HandleDataMessage (i2p::data::IdentHash * destination, const uint8_t * buf, size_t len) { uint32_t length = be32toh (*(uint32_t *)buf); @@ -104,7 +164,8 @@ namespace stream decompressor.Get (uncompressed, uncompressedSize); // then forward to streaming engine // TODO: we have onle one destination, might be more - m_SharedLocalDestination.HandleNextPacket (uncompressed, uncompressedSize); + if (sharedLocalDestination) + sharedLocalDestination->HandleNextPacket (uncompressed, uncompressedSize); } else LogPrint ("Data: protocol ", buf[9], " is not supported"); diff --git a/Streaming.h b/Streaming.h index c75f0b13..6db5ecd0 100644 --- a/Streaming.h +++ b/Streaming.h @@ -3,7 +3,7 @@ #include #include -#include "LeaseSet.h" +#include "Identity.h" #include "I2NPProtocol.h" namespace i2p @@ -22,11 +22,12 @@ namespace stream const uint16_t PACKET_FLAG_ECHO = 0x0200; const uint16_t PACKET_FLAG_NO_ACK = 0x0400; + class StreamingDestination; class Stream { public: - Stream (const i2p::data::IdentHash& destination); + Stream (StreamingDestination * local, const i2p::data::IdentHash& remote); uint32_t GetSendStreamID () const { return m_SendStreamID; }; uint32_t GetRecvStreamID () const { return m_RecvStreamID; }; @@ -35,18 +36,27 @@ namespace stream private: uint32_t m_SendStreamID, m_RecvStreamID; + StreamingDestination * m_LocalDestination; }; class StreamingDestination { public: + StreamingDestination (); + + const i2p::data::Keys GetKeys () const { return m_Keys; }; + I2NPMessage * CreateLeaseSet () const; + Stream * CreateNewStream (const i2p::data::IdentHash& destination); void HandleNextPacket (const uint8_t * buf, size_t len); - + private: std::map m_Streams; + i2p::data::Keys m_Keys; + i2p::data::Identity m_Identity; + i2p::data::IdentHash m_IdentHash; }; // assuming data is I2CP message From 1130287d28798ec7b0c47ff77bbecd6eee25f4d0 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 1 Jan 2014 18:19:03 -0500 Subject: [PATCH 05/16] send streaming protocol data --- Garlic.cpp | 5 ++- LeaseSet.h | 5 ++- Streaming.cpp | 102 ++++++++++++++++++++++++++++++++++++++------------ Streaming.h | 26 ++++++++++--- 4 files changed, 107 insertions(+), 31 deletions(-) diff --git a/Garlic.cpp b/Garlic.cpp index 7a450c2c..7d0e703f 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -63,7 +63,10 @@ namespace garlic *(uint32_t *)(m->GetPayload ()) = htobe32 (len); m->len += len + 4; FillI2NPMessageHeader (m, eI2NPGarlic); - DeleteI2NPMessage (msg); + if (msg) + DeleteI2NPMessage (msg); + if (leaseSet) + DeleteI2NPMessage (leaseSet); return m; } diff --git a/LeaseSet.h b/LeaseSet.h index 55a2e4b1..5bb75741 100644 --- a/LeaseSet.h +++ b/LeaseSet.h @@ -3,7 +3,7 @@ #include #include -#include +#include #include "Identity.h" namespace i2p @@ -31,12 +31,13 @@ namespace data // implements RoutingDestination const Identity& GetIdentity () const { return m_Identity; }; const IdentHash& GetIdentHash () const { return m_IdentHash; }; + const std::vector& GetLeases () const { return m_Leases; }; const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionKey; }; bool IsDestination () const { return true; }; private: - std::list m_Leases; + std::vector m_Leases; Identity m_Identity; IdentHash m_IdentHash; uint8_t m_EncryptionKey[256]; diff --git a/Streaming.cpp b/Streaming.cpp index 84bd9a28..e0d64a77 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -1,21 +1,21 @@ #include #include #include -#include #include "Log.h" #include "RouterInfo.h" #include "RouterContext.h" #include "Tunnel.h" #include "Timestamp.h" #include "CryptoConst.h" +#include "Garlic.h" #include "Streaming.h" namespace i2p { namespace stream { - Stream::Stream (StreamingDestination * local, const i2p::data::IdentHash& remote): - m_SendStreamID (0), m_LocalDestination (local) + Stream::Stream (StreamingDestination * local, const i2p::data::LeaseSet * remote): + m_SendStreamID (0), m_SequenceNumber (0), m_LocalDestination (local), m_RemoteLeaseSet (remote) { m_RecvStreamID = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); } @@ -60,6 +60,49 @@ namespace stream std::string str((const char *)buf, end-buf); LogPrint ("Payload: ", str); } + + size_t Stream::Send (uint8_t * buf, size_t len, int timeout) + { + uint8_t packet[STREAMING_MTU]; + size_t size = 0; + *(uint32_t *)(packet + size) = htobe32 (m_SendStreamID); + size += 4; // sendStreamID + *(uint32_t *)(packet + size) = htobe32 (m_RecvStreamID); + size += 4; // receiveStreamID + *(uint32_t *)(packet + size) = htobe32 (m_SequenceNumber); + size += 4; // sequenceNum + *(uint32_t *)(packet + size) = 0; // TODO + size += 4; // ack Through + packet[size] = 0; + size++; // NACK count + size++; // resend delay + // TODO: for initial packet only, following packets have different falgs + *(uint16_t *)(packet + size) = htobe16 (PACKET_FLAG_SYNCHRONIZE | + PACKET_FLAG_FROM_INCLUDED | PACKET_FLAG_SIGNATURE_INCLUDED | PACKET_FLAG_NO_ACK); + size += 2; // flags + *(uint16_t *)(packet + size) = htobe16 (sizeof (i2p::data::Identity) + 40); // identity + signature + size += 2; // options size + memcpy (packet + size, &m_LocalDestination->GetIdentity (), sizeof (i2p::data::Identity)); + size += sizeof (i2p::data::Identity); // from + uint8_t * signature = packet + size; // set it later + memset (signature, 0, 40); // zeroes for now + size += 40; // signature + memcpy (packet + size, buf, len); + size += len; // payload + m_LocalDestination->Sign (packet, size, signature); + I2NPMessage * msg = i2p::garlic::routing.WrapSingleMessage (m_RemoteLeaseSet, + CreateDataMessage (this, packet, size), m_LocalDestination->CreateLeaseSet ()); + + auto outbound = i2p::tunnel::tunnels.GetNextOutboundTunnel (); + if (outbound) + { + auto lease = m_RemoteLeaseSet->GetLeases ()[0]; // TODO: + outbound->SendTunnelDataMsg (lease.tunnelGateway, lease.tunnelID, msg); + } + else + DeleteI2NPMessage (msg); + return len; + } StreamingDestination * sharedLocalDestination = nullptr; @@ -69,6 +112,8 @@ namespace stream m_Keys = i2p::data::CreateRandomKeys (); m_Identity = m_Keys; m_IdentHash = i2p::data::CalculateIdentHash (m_Identity); + m_SigningPrivateKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag, + CryptoPP::Integer (m_Keys.signingPrivateKey, 20)); } void StreamingDestination::HandleNextPacket (const uint8_t * buf, size_t len) @@ -81,25 +126,22 @@ namespace stream LogPrint ("Unknown stream ", sendStreamID); } - Stream * StreamingDestination::CreateNewStream (const i2p::data::IdentHash& destination) + Stream * StreamingDestination::CreateNewStream (const i2p::data::LeaseSet * remote) { - /*i2p::data::LeaseSet * leaseSet = i2p::data::netdb.FindLeaseSet (destination); - if (!leaseSet) - { - i2p::data::netdb.RequestDestination (destination); - sleep (5); // wait for 5 seconds - leaseSet = i2p::data::netdb.FindLeaseSet (destination); - if (!leaseSet) - { - LogPrint ("Couldn't find LeaseSet"); - return nullptr; - } - } */ - Stream * s = new Stream (this, destination); + Stream * s = new Stream (this, remote); m_Streams[s->GetRecvStreamID ()] = s; return s; } + void StreamingDestination::DeleteStream (Stream * stream) + { + if (stream) + { + m_Streams.erase (stream->GetRecvStreamID ()); + delete stream; + } + } + I2NPMessage * StreamingDestination::CreateLeaseSet () const { I2NPMessage * m = NewI2NPMessage (); @@ -135,18 +177,32 @@ namespace stream buf[size] = 0; // zero leases size++; // num } - - CryptoPP::DSA::PrivateKey signingPrivateKey; - signingPrivateKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag, - CryptoPP::Integer (m_Keys.signingPrivateKey, 20)); - CryptoPP::DSA::Signer signer (signingPrivateKey); - signer.SignMessage (i2p::context.GetRandomNumberGenerator (), buf, size, buf+ size); + Sign (buf, size, buf+ size); size += 40; // signature m->len += size + sizeof (I2NPDatabaseStoreMsg); FillI2NPMessageHeader (m, eI2NPDatabaseStore); return m; } + + void StreamingDestination::Sign (uint8_t * buf, int len, uint8_t * signature) const + { + CryptoPP::DSA::Signer signer (m_SigningPrivateKey); + signer.SignMessage (i2p::context.GetRandomNumberGenerator (), buf, len, signature); + } + + Stream * CreateStream (const i2p::data::LeaseSet * remote) + { + if (!sharedLocalDestination) + sharedLocalDestination = new StreamingDestination (); + return sharedLocalDestination->CreateNewStream (remote); + } + + void CloseStream (Stream * stream) + { + if (sharedLocalDestination) + sharedLocalDestination->DeleteStream (stream); + } void HandleDataMessage (i2p::data::IdentHash * destination, const uint8_t * buf, size_t len) { diff --git a/Streaming.h b/Streaming.h index 6db5ecd0..c3c97bd8 100644 --- a/Streaming.h +++ b/Streaming.h @@ -3,7 +3,9 @@ #include #include +#include #include "Identity.h" +#include "LeaseSet.h" #include "I2NPProtocol.h" namespace i2p @@ -22,21 +24,27 @@ namespace stream const uint16_t PACKET_FLAG_ECHO = 0x0200; const uint16_t PACKET_FLAG_NO_ACK = 0x0400; + const size_t STREAMING_MTU = 1730; + class StreamingDestination; class Stream { public: - Stream (StreamingDestination * local, const i2p::data::IdentHash& remote); + Stream (StreamingDestination * local, const i2p::data::LeaseSet * remote); uint32_t GetSendStreamID () const { return m_SendStreamID; }; uint32_t GetRecvStreamID () const { return m_RecvStreamID; }; - + const i2p::data::LeaseSet * GetRemoteLeaseSet () const { return m_RemoteLeaseSet; }; + bool IsEstablished () const { return !m_SendStreamID; }; + void HandleNextPacket (const uint8_t * buf, size_t len); + size_t Send (uint8_t * buf, size_t len, int timeout); // timeout in seconds private: - uint32_t m_SendStreamID, m_RecvStreamID; + uint32_t m_SendStreamID, m_RecvStreamID, m_SequenceNumber; StreamingDestination * m_LocalDestination; + const i2p::data::LeaseSet * m_RemoteLeaseSet; }; class StreamingDestination @@ -45,10 +53,13 @@ namespace stream StreamingDestination (); - const i2p::data::Keys GetKeys () const { return m_Keys; }; + const i2p::data::Keys& GetKeys () const { return m_Keys; }; + const i2p::data::Identity& GetIdentity () const { return m_Identity; }; I2NPMessage * CreateLeaseSet () const; + void Sign (uint8_t * buf, int len, uint8_t * signature) const; - Stream * CreateNewStream (const i2p::data::IdentHash& destination); + Stream * CreateNewStream (const i2p::data::LeaseSet * remote); + void DeleteStream (Stream * stream); void HandleNextPacket (const uint8_t * buf, size_t len); private: @@ -57,7 +68,12 @@ namespace stream i2p::data::Keys m_Keys; i2p::data::Identity m_Identity; i2p::data::IdentHash m_IdentHash; + + CryptoPP::DSA::PrivateKey m_SigningPrivateKey; }; + + Stream * CreateStream (const i2p::data::LeaseSet * remote); + void CloseStream (Stream * stream); // assuming data is I2CP message void HandleDataMessage (i2p::data::IdentHash * destination, const uint8_t * buf, size_t len); From 4f9a977022ae9dd09234600d5c4d196dde1a44a0 Mon Sep 17 00:00:00 2001 From: orignal Date: Thu, 2 Jan 2014 21:22:48 -0500 Subject: [PATCH 06/16] wrap LeaseSet lookups into garlic --- Garlic.cpp | 2 +- NetDb.cpp | 26 +++++++++++++++++--------- NetDb.h | 6 +++--- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/Garlic.cpp b/Garlic.cpp index 7d0e703f..f9b88126 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -109,7 +109,7 @@ namespace garlic } if (msg) // next clove message ifself if presented { - size += CreateGarlicClove (payload + size, msg, true); + size += CreateGarlicClove (payload + size, msg, m_Destination->IsDestination ()); (*numCloves)++; } diff --git a/NetDb.cpp b/NetDb.cpp index 3f05dd7d..77e2ce72 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -8,6 +8,7 @@ #include "I2NPProtocol.h" #include "Tunnel.h" #include "RouterContext.h" +#include "Garlic.h" #include "NetDb.h" namespace i2p @@ -197,15 +198,25 @@ namespace data LogPrint (deletedCount," routers deleted"); } - void NetDb::RequestDestination (const char * b32, const uint8_t * router) + void NetDb::RequestDestination (const char * b32) { uint8_t destination[32]; Base32ToByteStream (b32, strlen(b32), destination, 32); - RequestDestination (destination, router); + RequestDestination (destination, true); + } + + void NetDb::RequestDestination (const IdentHash& destination, bool isLeaseSet) + { + auto floodfill= GetRandomNTCPRouter (true); + if (floodfill) + RequestDestination (destination, floodfill, isLeaseSet); + else + LogPrint ("No floodfill routers found"); } - void NetDb::RequestDestination (const uint8_t * destination, const uint8_t * router) + void NetDb::RequestDestination (const IdentHash& destination, const RouterInfo * floodfill, bool isLeaseSet) { + if (!floodfill) return; i2p::tunnel::OutboundTunnel * outbound = i2p::tunnel::tunnels.GetNextOutboundTunnel (); if (outbound) { @@ -214,7 +225,9 @@ namespace data { I2NPMessage * msg = i2p::CreateDatabaseLookupMsg (destination, inbound->GetNextIdentHash (), inbound->GetNextTunnelID ()); - outbound->SendTunnelDataMsg (router, 0, msg); + if (isLeaseSet) // wrap lookup message into garlic + msg = i2p::garlic::routing.WrapSingleMessage (floodfill, msg); + outbound->SendTunnelDataMsg (floodfill->GetIdentHash (), 0, msg); } else LogPrint ("No inbound tunnels found"); @@ -222,11 +235,6 @@ namespace data else LogPrint ("No outbound tunnels found"); } - - void NetDb::RequestDestination (const IdentHash& destination) - { - RequestDestination ((const uint8_t *)destination, GetRandomNTCPRouter (true)->GetIdentHash ()); - } void NetDb::HandleDatabaseStoreMsg (uint8_t * buf, size_t len) { diff --git a/NetDb.h b/NetDb.h index 3f644c7d..ca63a239 100644 --- a/NetDb.h +++ b/NetDb.h @@ -30,9 +30,9 @@ namespace data RouterInfo * FindRouter (const IdentHash& ident) const; LeaseSet * FindLeaseSet (const IdentHash& destination) const; - void RequestDestination (const char * b32, const uint8_t * router); // in base32 - void RequestDestination (const uint8_t * destination, const uint8_t * router); - void RequestDestination (const IdentHash& destination); + void RequestDestination (const char * b32); // in base32 + void RequestDestination (const IdentHash& destination, bool isLeaseSet = false); + void RequestDestination (const IdentHash& destination, const RouterInfo * floodfill, bool isLeaseSet = false); void HandleDatabaseStoreMsg (uint8_t * buf, size_t len); void HandleDatabaseSearchReplyMsg (I2NPMessage * msg); From 4f1f08b8057cfda0ac391ef78b38714d738c0436 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 3 Jan 2014 21:24:20 -0500 Subject: [PATCH 07/16] kademlia --- Identity.cpp | 27 +++++++++++++++++++++++++++ Identity.h | 19 +++++++++++++++++++ NetDb.cpp | 21 +++++++++++++++++++++ NetDb.h | 1 + RouterInfo.cpp | 7 +++++++ RouterInfo.h | 3 +++ 6 files changed, 78 insertions(+) diff --git a/Identity.cpp b/Identity.cpp index b80d1cbf..f57ab97b 100644 --- a/Identity.cpp +++ b/Identity.cpp @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -43,5 +45,30 @@ namespace data return keys; } + + RoutingKey CreateRoutingKey (const IdentHash& ident) + { + uint8_t buf[41]; // ident + yyyymmdd + memcpy (buf, (const uint8_t *)ident, 32); + time_t t = time (nullptr); + struct tm tm; + gmtime_r (&t, &tm); + sprintf ((char *)(buf + 32),"%4i%2i%2i", tm.tm_year, tm.tm_mon, tm.tm_mday); + + RoutingKey key; + CryptoPP::SHA256().CalculateDigest(key.hash, buf, 40); + return key; + } + + XORMetric operator^(const RoutingKey& key1, const RoutingKey& key2) + { + // TODO: implementation depends on CPU + XORMetric m; + ((uint64_t *)m.metric)[0] = ((uint64_t *)key1.hash)[0] ^ ((uint64_t *)key2.hash)[0]; + ((uint64_t *)m.metric)[1] = ((uint64_t *)key1.hash)[1] ^ ((uint64_t *)key2.hash)[1]; + ((uint64_t *)m.metric)[2] = ((uint64_t *)key1.hash)[2] ^ ((uint64_t *)key2.hash)[2]; + ((uint64_t *)m.metric)[3] = ((uint64_t *)key1.hash)[3] ^ ((uint64_t *)key2.hash)[3]; + return m; + } } } diff --git a/Identity.h b/Identity.h index 549e9cea..9e8b62ac 100644 --- a/Identity.h +++ b/Identity.h @@ -57,7 +57,26 @@ namespace data IdentHash CalculateIdentHash (const Identity& identity); Keys CreateRandomKeys (); + + // kademlia + struct RoutingKey + { + uint8_t hash[32]; + }; + + struct XORMetric + { + uint8_t metric[32]; + + void SetMin () { memset (metric, 0, 32); }; + void SetMax () { memset (metric, 0xFF, 32); }; + bool operator< (const XORMetric& other) const { return memcmp (metric, other.metric, 32) < 0; }; + }; + + RoutingKey CreateRoutingKey (const IdentHash& ident); + XORMetric operator^(const RoutingKey& key1, const RoutingKey& key2); + // destination for delivery instuctions class RoutingDestination { public: diff --git a/NetDb.cpp b/NetDb.cpp index 77e2ce72..89364c1b 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -388,5 +388,26 @@ namespace data { if (msg) m_Queue.Put (msg); } + + const RouterInfo * NetDb::GetClosestFloodfill (const IdentHash& destination) const + { + RouterInfo * r = nullptr; + XORMetric minMetric; + RoutingKey destKey = CreateRoutingKey (destination); + minMetric.SetMax (); + for (auto it: m_RouterInfos) + { + if (it.second->IsFloodfill () &&! it.second->IsUnreachable ()) + { + XORMetric m = destKey ^ it.second->GetRoutingKey (); + if (m < minMetric) + { + minMetric = m; + r = it.second; + } + } + } + return r; + } } } diff --git a/NetDb.h b/NetDb.h index ca63a239..761d3a09 100644 --- a/NetDb.h +++ b/NetDb.h @@ -48,6 +48,7 @@ namespace data void SaveUpdated (const char * directory); void Run (); // exploratory thread void Explore (); + const RouterInfo * GetClosestFloodfill (const IdentHash& destination) const; private: diff --git a/RouterInfo.cpp b/RouterInfo.cpp index 417466c6..45ab4c20 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -35,6 +35,7 @@ namespace data m_RouterIdentity = identity; m_IdentHash = CalculateIdentHash (m_RouterIdentity); UpdateIdentHashBase64 (); + UpdateRoutingKey (); m_Timestamp = i2p::util::GetMillisecondsSinceEpoch (); } @@ -126,6 +127,7 @@ namespace data CryptoPP::SHA256().CalculateDigest(m_IdentHash, (uint8_t *)&m_RouterIdentity, sizeof (m_RouterIdentity)); UpdateIdentHashBase64 (); + UpdateRoutingKey (); } void RouterInfo::UpdateIdentHashBase64 () @@ -135,6 +137,11 @@ namespace data memcpy (m_IdentHashAbbreviation, m_IdentHashBase64, 4); m_IdentHashAbbreviation[4] = 0; } + + void RouterInfo::UpdateRoutingKey () + { + m_RoutingKey = CreateRoutingKey (m_IdentHash); + } void RouterInfo::WriteToStream (std::ostream& s) { diff --git a/RouterInfo.h b/RouterInfo.h index 3111fbf3..ceda10cb 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -46,6 +46,7 @@ namespace data uint64_t GetTimestamp () const { return m_Timestamp; }; const std::vector
& GetAddresses () const { return m_Addresses; }; Address * GetNTCPAddress (); + const RoutingKey& GetRoutingKey () const { return m_RoutingKey; }; void AddNTCPAddress (const char * host, int port); void SetProperty (const char * key, const char * value); @@ -56,6 +57,7 @@ namespace data bool IsUnreachable () const { return m_IsUnreachable; }; void CreateBuffer (); + void UpdateRoutingKey (); const char * GetBuffer () const { return m_Buffer; }; int GetBufferLen () const { return m_BufferLen; }; @@ -81,6 +83,7 @@ namespace data Identity m_RouterIdentity; IdentHash m_IdentHash; + RoutingKey m_RoutingKey; char m_IdentHashBase64[48], m_IdentHashAbbreviation[5]; char m_Buffer[2048]; int m_BufferLen; From 5997cb80bd17fe0f19dec911d7c3a37357bd5513 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 3 Jan 2014 22:25:22 -0500 Subject: [PATCH 08/16] differentiate garlic message received from tunnel and directly --- Garlic.cpp | 8 +++++--- Garlic.h | 2 +- I2NPProtocol.cpp | 8 ++++---- I2NPProtocol.h | 4 ++-- NTCPSession.cpp | 7 ++++--- NetDb.cpp | 2 +- Transports.cpp | 2 +- TunnelEndpoint.cpp | 2 +- 8 files changed, 19 insertions(+), 16 deletions(-) diff --git a/Garlic.cpp b/Garlic.cpp index f9b88126..202949bb 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -185,7 +185,7 @@ namespace garlic return ret; } - void GarlicRouting::HandleGarlicMessage (uint8_t * buf, size_t len) + void GarlicRouting::HandleGarlicMessage (uint8_t * buf, size_t len, bool isFromTunnel) { uint32_t length = be32toh (*(uint32_t *)buf); buf += 4; @@ -203,7 +203,9 @@ namespace garlic { // new session ElGamalBlock elGamal; - i2p::crypto::ElGamalDecrypt (i2p::context.GetLeaseSetPrivateKey (), buf, (uint8_t *)&elGamal, true); + i2p::crypto::ElGamalDecrypt ( + isFromTunnel ? i2p::context.GetLeaseSetPrivateKey () : i2p::context.GetPrivateKey (), + buf, (uint8_t *)&elGamal, true); memcpy (m_SessionKey, elGamal.sessionKey, 32); uint8_t iv[32]; // IV is first 16 bytes CryptoPP::SHA256().CalculateDigest(iv, elGamal.preIV, 32); @@ -252,7 +254,7 @@ namespace garlic { case eGarlicDeliveryTypeLocal: LogPrint ("Garlic type local"); - i2p::HandleI2NPMessage (buf, len); + i2p::HandleI2NPMessage (buf, len, false); break; case eGarlicDeliveryTypeDestination: { diff --git a/Garlic.h b/Garlic.h index db1f008d..536ed173 100644 --- a/Garlic.h +++ b/Garlic.h @@ -67,7 +67,7 @@ namespace garlic GarlicRouting (); ~GarlicRouting (); - void HandleGarlicMessage (uint8_t * buf, size_t len); + void HandleGarlicMessage (uint8_t * buf, size_t len, bool isFromTunnel); I2NPMessage * WrapSingleMessage (const i2p::data::RoutingDestination * destination, I2NPMessage * msg, I2NPMessage * leaseSet = nullptr); diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index 58622fb8..76918bcd 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -370,7 +370,7 @@ namespace i2p return be16toh (header->size) + sizeof (I2NPHeader); } - void HandleI2NPMessage (uint8_t * msg, size_t len) + void HandleI2NPMessage (uint8_t * msg, size_t len, bool isFromTunnel) { I2NPHeader * header = (I2NPHeader *)msg; uint32_t msgID = be32toh (header->msgID); @@ -382,7 +382,7 @@ namespace i2p { case eI2NPGarlic: LogPrint ("Garlic"); - i2p::garlic::routing.HandleGarlicMessage (buf, size); + i2p::garlic::routing.HandleGarlicMessage (buf, size, isFromTunnel); break; break; case eI2NPDeliveryStatus: @@ -401,7 +401,7 @@ namespace i2p } } - void HandleI2NPMessage (I2NPMessage * msg) + void HandleI2NPMessage (I2NPMessage * msg, bool isFromTunnel) { if (msg) { @@ -424,7 +424,7 @@ namespace i2p i2p::data::netdb.PostI2NPMsg (msg); break; default: - HandleI2NPMessage (msg->GetBuffer (), msg->GetLength ()); + HandleI2NPMessage (msg->GetBuffer (), msg->GetLength (), isFromTunnel); DeleteI2NPMessage (msg); } } diff --git a/I2NPProtocol.h b/I2NPProtocol.h index 2b85744c..597c00b0 100644 --- a/I2NPProtocol.h +++ b/I2NPProtocol.h @@ -132,8 +132,8 @@ namespace i2p I2NPMessage * CreateTunnelGatewayMsg (uint32_t tunnelID, I2NPMessage * msg); size_t GetI2NPMessageLength (uint8_t * msg); - void HandleI2NPMessage (uint8_t * msg, size_t len); - void HandleI2NPMessage (I2NPMessage * msg); + void HandleI2NPMessage (uint8_t * msg, size_t len, bool isFromTunnel); + void HandleI2NPMessage (I2NPMessage * msg, bool isFromTunnel); } #endif diff --git a/NTCPSession.cpp b/NTCPSession.cpp index 14b74c27..be50e02b 100644 --- a/NTCPSession.cpp +++ b/NTCPSession.cpp @@ -384,7 +384,8 @@ namespace ntcp if (m_ReceiveBufferOffset > 0) memcpy (m_ReceiveBuffer, nextBlock, m_ReceiveBufferOffset); } - + + ScheduleTermination (); // reset termination timer Receive (); } } @@ -423,7 +424,7 @@ namespace ntcp if (m_NextMessageOffset >= m_NextMessage->len + 4) // +checksum { // we have a complete I2NP message - i2p::HandleI2NPMessage (m_NextMessage); + i2p::HandleI2NPMessage (m_NextMessage, false); m_NextMessage = nullptr; } } @@ -464,7 +465,6 @@ namespace ntcp boost::asio::async_write (m_Socket, boost::asio::buffer (sendBuffer, l), boost::asio::transfer_all (), boost::bind(&NTCPSession::HandleSent, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, msg)); - ScheduleTermination (); // reset termination timer } void NTCPSession::HandleSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, i2p::I2NPMessage * msg) @@ -479,6 +479,7 @@ namespace ntcp else { LogPrint ("Msg sent: ", bytes_transferred); + ScheduleTermination (); // reset termination timer } } diff --git a/NetDb.cpp b/NetDb.cpp index 89364c1b..264b1631 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -71,7 +71,7 @@ namespace data else // WTF? { LogPrint ("NetDb: unexpected message type ", msg->GetHeader ()->typeID); - i2p::HandleI2NPMessage (msg); + i2p::HandleI2NPMessage (msg, false); } msg = m_Queue.Get (); } diff --git a/Transports.cpp b/Transports.cpp index 9204cea9..e9953eca 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -123,7 +123,7 @@ namespace i2p { if (ident == i2p::context.GetRouterInfo ().GetIdentHash ()) // we send it to ourself - i2p::HandleI2NPMessage (msg); + i2p::HandleI2NPMessage (msg, false); else m_Service.post (boost::bind (&Transports::PostMessage, this, ident, msg)); } diff --git a/TunnelEndpoint.cpp b/TunnelEndpoint.cpp index 1d856e4a..68e741a0 100644 --- a/TunnelEndpoint.cpp +++ b/TunnelEndpoint.cpp @@ -147,7 +147,7 @@ namespace tunnel switch (msg.deliveryType) { case eDeliveryTypeLocal: - i2p::HandleI2NPMessage (msg.data); + i2p::HandleI2NPMessage (msg.data, true); break; case eDeliveryTypeTunnel: i2p::transports.SendMessage (msg.hash, i2p::CreateTunnelGatewayMsg (msg.tunnelID, msg.data)); From e1716bc05ea6d025785f83a3aa0f40f336ea5a76 Mon Sep 17 00:00:00 2001 From: orignal Date: Fri, 3 Jan 2014 22:56:28 -0500 Subject: [PATCH 09/16] manage transit tunnels --- Tunnel.cpp | 24 ++++++++++++++++++++---- Tunnel.h | 12 ++++++------ TunnelBase.h | 10 ++++++++++ 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/Tunnel.cpp b/Tunnel.cpp index eebb85fa..0a75649a 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -13,8 +13,7 @@ namespace i2p namespace tunnel { - Tunnel::Tunnel (TunnelConfig * config): m_Config (config), - m_CreationTime (i2p::util::GetSecondsSinceEpoch ()), m_IsEstablished (false) + Tunnel::Tunnel (TunnelConfig * config): m_Config (config), m_IsEstablished (false) { } @@ -320,6 +319,7 @@ namespace tunnel ManageInboundTunnels (); ManageOutboundTunnels (); + ManageTransitTunnels (); /* if (!m_IsTunnelCreated) { @@ -407,13 +407,29 @@ namespace tunnel { OutboundTunnel * outboundTunnel = GetNextOutboundTunnel (); LogPrint ("Creating two hops inbound tunnel..."); + auto router = outboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router; CreateTunnel ( - new TunnelConfig (i2p::data::netdb.GetRandomNTCPRouter (), - outboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router), + new TunnelConfig (i2p::data::netdb.GetRandomNTCPRouter (), + router != &i2p::context.GetRouterInfo () ? router : i2p::data::netdb.GetRandomNTCPRouter ()), outboundTunnel); } } } + + void Tunnels::ManageTransitTunnels () + { + uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + for (auto it = m_TransitTunnels.begin (); it != m_TransitTunnels.end ();) + { + if (ts > it->second->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) + { + LogPrint ("Transit tunnel ", it->second->GetTunnelID (), " expired"); + it = m_TransitTunnels.erase (it); + } + else + it++; + } + } void Tunnels::PostTunnelData (I2NPMessage * msg) { diff --git a/Tunnel.h b/Tunnel.h index 9ecf6ff3..cec82958 100644 --- a/Tunnel.h +++ b/Tunnel.h @@ -33,9 +33,7 @@ namespace tunnel void Build (uint32_t replyMsgID, OutboundTunnel * outboundTunnel = 0); - virtual uint32_t GetTunnelID () const = 0; // as known at our side TunnelConfig * GetTunnelConfig () const { return m_Config; } - uint32_t GetCreationTime () const { return m_CreationTime; }; bool IsEstablished () const { return m_IsEstablished; }; bool HandleTunnelBuildResponse (uint8_t * msg, size_t len); @@ -54,7 +52,6 @@ namespace tunnel private: TunnelConfig * m_Config; - uint32_t m_CreationTime; // seconds since epoch bool m_IsEstablished; CryptoPP::ECB_Mode::Decryption m_ECBDecryption; @@ -70,9 +67,11 @@ namespace tunnel void SendTunnelDataMsg (i2p::I2NPMessage * msg); //local void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); - uint32_t GetTunnelID () const { return GetNextTunnelID (); }; TunnelGateway& GetTunnelGateway () { return m_Gateway; }; size_t GetNumSentBytes () const { return m_Gateway.GetNumSentBytes (); }; + + // implements TunnelBase + uint32_t GetTunnelID () const { return GetNextTunnelID (); }; private: @@ -85,10 +84,10 @@ namespace tunnel InboundTunnel (TunnelConfig * config): Tunnel (config) {}; void HandleTunnelDataMsg (I2NPMessage * msg); + size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }; + // implements TunnelBase uint32_t GetTunnelID () const { return GetTunnelConfig ()->GetLastHop ()->nextTunnelID; }; - size_t GetNumReceivedBytes () const { return m_Endpoint.GetNumReceivedBytes (); }; - private: TunnelEndpoint m_Endpoint; @@ -128,6 +127,7 @@ namespace tunnel void ManageTunnels (); void ManageOutboundTunnels (); void ManageInboundTunnels (); + void ManageTransitTunnels (); void CreateZeroHopsInboundTunnel (); diff --git a/TunnelBase.h b/TunnelBase.h index 829270ce..bd760989 100644 --- a/TunnelBase.h +++ b/TunnelBase.h @@ -2,6 +2,7 @@ #define TUNNEL_BASE_H__ #include +#include "Timestamp.h" #include "I2NPProtocol.h" namespace i2p @@ -30,11 +31,20 @@ namespace tunnel { public: + TunnelBase (): m_CreationTime (i2p::util::GetSecondsSinceEpoch ()) {}; virtual ~TunnelBase () {}; virtual void EncryptTunnelMsg (I2NPMessage * tunnelMsg) = 0; virtual uint32_t GetNextTunnelID () const = 0; virtual const i2p::data::IdentHash& GetNextIdentHash () const = 0; + virtual uint32_t GetTunnelID () const = 0; // as known at our side + + uint32_t GetCreationTime () const { return m_CreationTime; }; + void SetCreationTime (uint32_t t) { m_CreationTime = t; }; + + private: + + uint32_t m_CreationTime; // seconds since epoch }; } } From c93402ab409cd9c3eb211d7854836df32b984ce8 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 5 Jan 2014 09:53:44 -0500 Subject: [PATCH 10/16] deep exploratory --- I2NPProtocol.cpp | 22 +++++- I2NPProtocol.h | 5 +- NetDb.cpp | 188 +++++++++++++++++++++++++++++++---------------- NetDb.h | 41 +++++++++-- 4 files changed, 182 insertions(+), 74 deletions(-) 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 }; From 4b9d2d60e2b2abc5723d0e6b427f01cceed8cfbc Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 5 Jan 2014 21:25:48 -0500 Subject: [PATCH 11/16] long tunnel messages --- Tunnel.cpp | 7 +- TunnelGateway.cpp | 276 +++++++++++++++++++--------------------------- TunnelGateway.h | 23 ++-- 3 files changed, 119 insertions(+), 187 deletions(-) diff --git a/Tunnel.cpp b/Tunnel.cpp index 0a75649a..b4cd41a0 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -65,14 +65,9 @@ namespace tunnel FillI2NPMessageHeader (msg, eI2NPVariableTunnelBuild); if (outboundTunnel) - { - outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg); - DeleteI2NPMessage (msg); - } + outboundTunnel->SendTunnelDataMsg (GetNextIdentHash (), 0, msg); else - { i2p::transports.SendMessage (GetNextIdentHash (), msg); - } } bool Tunnel::HandleTunnelBuildResponse (uint8_t * msg, size_t len) diff --git a/TunnelGateway.cpp b/TunnelGateway.cpp index d70763e6..6e0db1f0 100644 --- a/TunnelGateway.cpp +++ b/TunnelGateway.cpp @@ -12,198 +12,144 @@ namespace tunnel { void TunnelGatewayBuffer::PutI2NPMsg (const uint8_t * gwHash, uint32_t gwTunnel, I2NPMessage * msg) { - TunnelMessageBlockExt * block = new TunnelMessageBlockExt; - block->deliveryInstructionsLen = 1; // flag + if (!m_CurrentTunnelDataMsg) + CreateCurrentTunnelDataMessage (); + + // create delivery instructions + uint8_t di[40]; + size_t diLen = 1;// flag + TunnelDeliveryType dt = eDeliveryTypeLocal; if (gwHash) { - block->deliveryInstructionsLen += 32; // hash - memcpy (block->hash, gwHash, 32); if (gwTunnel) - { - block->deliveryType = eDeliveryTypeTunnel; - block->deliveryInstructionsLen += 4; // tunnelID - block->tunnelID = gwTunnel; - } + { + *(uint32_t *)(di + diLen) = htobe32 (gwTunnel); + diLen += 4; // tunnelID + dt = eDeliveryTypeTunnel; + } else - block->deliveryType = eDeliveryTypeRouter; + dt = eDeliveryTypeRouter; + + memcpy (di + diLen, gwHash, 32); + diLen += 32; //len } - else - block->deliveryType = eDeliveryTypeLocal; - block->deliveryInstructionsLen += 2; // size - // we don't reserve 4 bytes for msgID yet - block->totalLen = block->deliveryInstructionsLen + msg->GetLength (); - block->data = msg; - m_I2NPMsgs.push_back (block); + di[0] = dt << 5; // set delivery type - if (!m_Remaining) m_Remaining = TUNNEL_DATA_MAX_PAYLOAD_SIZE; - if (block->totalLen <= m_Remaining) // message fits + // create fragments + if (diLen + msg->GetLength () + 2<= m_RemainingSize) { - block->isFragmented = false; - m_Remaining -= block->totalLen; + // message fits. First and last fragment + *(uint16_t *)(di + diLen) = htobe16 (msg->GetLength ()); + diLen += 2; // size + memcpy (m_CurrentTunnelDataMsg->buf + m_CurrentTunnelDataMsg->len, di, diLen); + memcpy (m_CurrentTunnelDataMsg->buf + m_CurrentTunnelDataMsg->len + diLen, msg->GetBuffer (), msg->GetLength ()); + m_CurrentTunnelDataMsg->len += diLen + msg->GetLength (); + m_RemainingSize -= diLen + msg->GetLength (); + if (!m_RemainingSize) + CompleteCurrentTunnelDataMessage (); + DeleteI2NPMessage (msg); } - else // message doesn't fit + else { - if (block->deliveryInstructionsLen + 4 <= m_Remaining) + if (diLen + 6 <= m_RemainingSize) { - // delivery instructions of first fragment fits - block->isFragmented = true; - block->deliveryInstructionsLen += 4; - block->totalLen += 4; - m_Remaining = m_Remaining + TUNNEL_DATA_MAX_PAYLOAD_SIZE - block->totalLen - 7; // TODO: handle case if more than two fragments + // delivery instructions fit + uint32_t msgID = msg->GetHeader ()->msgID; + size_t size = m_RemainingSize - diLen - 6; // 6 = 4 (msgID) + 2 (size) + + // first fragment + di[0] |= 0x08; // fragmented + *(uint32_t *)(di + diLen) = htobe32 (msgID); + diLen += 4; // Message ID + *(uint16_t *)(di + diLen) = htobe16 (size); + diLen += 2; // size + memcpy (m_CurrentTunnelDataMsg->buf + m_CurrentTunnelDataMsg->len, di, diLen); + memcpy (m_CurrentTunnelDataMsg->buf + m_CurrentTunnelDataMsg->len + diLen, msg->GetBuffer (), size); + m_CurrentTunnelDataMsg->len += diLen + size; + CompleteCurrentTunnelDataMessage (); + // follow on fragments + int fragmentNumber = 1; + while (size < msg->GetLength ()) + { + CreateCurrentTunnelDataMessage (); + uint8_t * buf = m_CurrentTunnelDataMsg->GetBuffer (); + buf[0] = 0x80 | (fragmentNumber << 1); // frag + bool isLastFragment = false; + size_t s = msg->GetLength () - size; + if (s > TUNNEL_DATA_MAX_PAYLOAD_SIZE - 7) // 7 follow on instructions + s = TUNNEL_DATA_MAX_PAYLOAD_SIZE - 7; + else // last fragment + { + buf[0] |= 0x01; + isLastFragment = true; + } + *(uint32_t *)(buf + 1) = htobe32 (msgID); //Message ID + *(uint16_t *)(buf + 5) = htobe16 (s); // size + memcpy (buf + 7, msg->GetBuffer () + size, s); + m_CurrentTunnelDataMsg->len += s+7; + if (isLastFragment) + { + m_RemainingSize -= s+7; + if (!m_RemainingSize) + CompleteCurrentTunnelDataMessage (); + } + else + CompleteCurrentTunnelDataMessage (); + size += s; + fragmentNumber++; + } + DeleteI2NPMessage (msg); } else { - // delivery instructions of first fragment don't fit - block->isFragmented = false; - m_Remaining = 0; + // delivery instructions don't fit. Create new message + CompleteCurrentTunnelDataMessage (); + PutI2NPMsg (gwHash, gwTunnel, msg); + // don't delete msg because it's taken care inside } - } - } - - std::vector TunnelGatewayBuffer::GetTunnelDataMsgs () - { - m_Remaining = 0; - m_NextOffset = 0; - std::vector res; - int cnt = m_I2NPMsgs.size (); - if (cnt > 0) - { - int ind = 0; - while (ind < cnt) - { - auto tunnelMsg = CreateNextTunnelMessage (ind); - if (!tunnelMsg) break; - res.push_back (tunnelMsg); - } - for (auto msg: m_I2NPMsgs) - delete msg; - m_I2NPMsgs.clear (); - } - - return res; + } } - - size_t TunnelGatewayBuffer::CreateFirstFragment (TunnelMessageBlockExt * block, uint8_t * buf, size_t len) + + std::vector TunnelGatewayBuffer::GetTunnelDataMsgs () { - size_t ret = 1; - buf[0] = block->deliveryType << 5; // flag - if (block->deliveryType == eDeliveryTypeTunnel) - { - *(uint32_t *)(buf + ret) = htobe32 (block->tunnelID); - ret += 4; - } - if (block->deliveryType == eDeliveryTypeTunnel || block->deliveryType == eDeliveryTypeRouter) - { - memcpy (buf + ret, block->hash, 32); - ret += 32; - } - size_t size = block->data->GetLength (); - if (block->totalLen > len) // entire message doesn't fit - { - buf[0] |= 0x08; // set fragmented bit - m_NextMsgID = block->data->GetHeader ()->msgID; - *(uint32_t *)(buf + ret) = m_NextMsgID; - ret += 4; // msgID - m_NextSeqn = 1; - size = len - ret - 2; // 2 bytes for size field - m_NextOffset = size; - } - *(uint16_t *)(buf + ret) = htobe16 (size); // size - ret += 2; - memcpy (buf + ret, block->data->GetBuffer (), size); - ret += size; - return ret; + CompleteCurrentTunnelDataMessage (); + std::vector ret = m_TunnelDataMsgs; // TODO: implement it better + m_TunnelDataMsgs.clear (); + return ret; } - size_t TunnelGatewayBuffer::CreateFollowOnFragment (TunnelMessageBlockExt * block, uint8_t * buf, size_t len) + void TunnelGatewayBuffer::CreateCurrentTunnelDataMessage () { - int ret = 0; - buf[0] = 0x80 | (m_NextSeqn << 1);// follow-on flag and seqn - size_t fragmentLen = len - 7; // 7 bytes of header - if (fragmentLen >= block->data->GetLength () - m_NextOffset) - { - // fragment fits - fragmentLen = block->data->GetLength () - m_NextOffset; - buf[0] |= 0x01; // last fragment - } - else - m_NextSeqn++; - - *(uint32_t *)(buf + 1) = m_NextMsgID; // msgID - *(uint16_t *)(buf + 5) = htobe16 (fragmentLen); // size - memcpy (buf + 7, block->data->GetBuffer () + m_NextOffset, fragmentLen); - - m_NextOffset += fragmentLen; - ret += fragmentLen + 7; - - return ret; + m_CurrentTunnelDataMsg = NewI2NPMessage (); + // we reserve space for padding + m_CurrentTunnelDataMsg->offset += TUNNEL_DATA_MSG_SIZE + sizeof (I2NPHeader); + m_CurrentTunnelDataMsg->len = m_CurrentTunnelDataMsg->offset; + m_RemainingSize = TUNNEL_DATA_MAX_PAYLOAD_SIZE; } - - I2NPMessage * TunnelGatewayBuffer::CreateNextTunnelMessage (int& ind) + + void TunnelGatewayBuffer::CompleteCurrentTunnelDataMessage () { - int cnt = m_I2NPMsgs.size (); - if (ind > cnt - 1) return nullptr; // no more messages - // calculate payload size - size_t size = 0; - int i = ind; - if (m_NextOffset) - { - size = m_I2NPMsgs[i]->data->GetLength () - m_NextOffset + 7; // including follow-on header - i++; - } - while (i < cnt) - { - auto msg = m_I2NPMsgs[i]; - size += msg->totalLen; - if (size >= TUNNEL_DATA_MAX_PAYLOAD_SIZE) - { - size = TUNNEL_DATA_MAX_PAYLOAD_SIZE; - break; - } - if (msg->isFragmented) break; - i++; - } + if (!m_CurrentTunnelDataMsg) return; + uint8_t * payload = m_CurrentTunnelDataMsg->GetBuffer (); + size_t size = m_CurrentTunnelDataMsg->len - m_CurrentTunnelDataMsg->offset; - I2NPMessage * tunnelMsg = NewI2NPMessage (); - uint8_t * buf = tunnelMsg->GetPayload (); + m_CurrentTunnelDataMsg->offset = m_CurrentTunnelDataMsg->len - TUNNEL_DATA_MSG_SIZE - sizeof (I2NPHeader); + uint8_t * buf = m_CurrentTunnelDataMsg->GetPayload (); *(uint32_t *)(buf) = htobe32 (m_TunnelID); CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); rnd.GenerateBlock (buf + 4, 16); // original IV - memcpy (buf + TUNNEL_DATA_MSG_SIZE, buf + 4, 16); // copy IV for checksum - size_t zero = TUNNEL_DATA_MSG_SIZE - size -1; - buf[zero] = 0; // zero - size_t s = 0; - while (ind < cnt) - { - auto msg = m_I2NPMsgs[ind]; - if (m_NextOffset) - { - s += CreateFollowOnFragment (msg, buf + zero + 1 + s, size - s); - m_NextOffset = 0; // TODO: - } - else - { - s += CreateFirstFragment (msg, buf + zero + 1 + s, size - s); - if (msg->isFragmented) break; // payload is full, but we stay at the same message - } - ind++; - if (s >= size) break; // payload is full but we moved to next message - } - - if (s != size) - { - LogPrint ("TunnelData payload size mismatch ", s, "!=", size); - return nullptr; - } - + memcpy (payload + size, buf + 4, 16); // copy IV for checksum uint8_t hash[32]; - CryptoPP::SHA256().CalculateDigest(hash, buf+zero+1, size+16); - memcpy (buf+20, hash, 4); // checksum - if (zero > 24) - memset (buf+24, 1, zero-24); // padding TODO: fill with random data - tunnelMsg->len += TUNNEL_DATA_MSG_SIZE; + CryptoPP::SHA256().CalculateDigest (hash, payload, size+16); + memcpy (buf+20, hash, 4); // checksum + payload[-1] = 0; // zero + ssize_t paddingSize = payload - buf - 25; // 25 = 24 + 1 + if (paddingSize > 0) + memset (buf + 24, 1, paddingSize); // padding TODO: fill with random data + // we can't fill message header yet because encryption is required - return tunnelMsg; + m_TunnelDataMsgs.push_back (m_CurrentTunnelDataMsg); + m_CurrentTunnelDataMsg = nullptr; } void TunnelGateway::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) diff --git a/TunnelGateway.h b/TunnelGateway.h index 9c679888..d68c8580 100644 --- a/TunnelGateway.h +++ b/TunnelGateway.h @@ -12,32 +12,23 @@ namespace tunnel { class TunnelGatewayBuffer { - struct TunnelMessageBlockExt: public TunnelMessageBlock - { - size_t deliveryInstructionsLen, totalLen; - bool isFragmented; - }; - public: - - TunnelGatewayBuffer (uint32_t tunnelID): m_TunnelID (tunnelID), m_Remaining (0) {}; - + TunnelGatewayBuffer (uint32_t tunnelID): m_TunnelID (tunnelID), + m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0) {}; void PutI2NPMsg (const uint8_t * gwHash, uint32_t gwTunnel, I2NPMessage * msg); std::vector GetTunnelDataMsgs (); private: - size_t CreateFirstFragment (TunnelMessageBlockExt * block, uint8_t * buf, size_t len); - size_t CreateFollowOnFragment (TunnelMessageBlockExt * block, uint8_t * buf, size_t len); - I2NPMessage * CreateNextTunnelMessage (int& ind); + void CreateCurrentTunnelDataMessage (); + void CompleteCurrentTunnelDataMessage (); private: uint32_t m_TunnelID; - std::vector m_I2NPMsgs; - // for fragmented messages - size_t m_NextOffset, m_NextSeqn, m_Remaining; - uint32_t m_NextMsgID; + std::vector m_TunnelDataMsgs; + I2NPMessage * m_CurrentTunnelDataMsg; + size_t m_RemainingSize; }; class TunnelGateway From c85ae61cfcc9d7ff1457bf1bd118d5e9b7a013f1 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 5 Jan 2014 22:21:59 -0500 Subject: [PATCH 12/16] hadlle DatabaseLookup message --- I2NPProtocol.cpp | 36 +++++++++++++++++++++++++++++++++++- I2NPProtocol.h | 4 +++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index 7993a79a..11ccd757 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -136,6 +136,36 @@ namespace i2p return m; } + void HandleDatabaseLookupMsg (uint8_t * buf, size_t len) + { + char key[48]; + int l = i2p::data::ByteStreamToBase64 (buf, 32, key, 48); + key[l] = 0; + LogPrint ("DatabaseLookup for ", key, " recieved"); + uint8_t flag = buf[64]; + uint32_t replyTunnelID = 0; + if (flag & 0x01) //reply to yunnel + replyTunnelID = be32toh (*(uint32_t *)(buf + 64)); + // TODO: implement search. We send non-found for now + I2NPMessage * replyMsg = CreateDatabaseSearchReply (buf); + if (replyTunnelID) + i2p::tunnel::tunnels.GetNextOutboundTunnel ()->SendTunnelDataMsg (buf+32, replyTunnelID, replyMsg); + else + i2p::transports.SendMessage (buf, replyMsg); + } + + I2NPMessage * CreateDatabaseSearchReply (const i2p::data::IdentHash& ident) + { + I2NPMessage * m = NewI2NPMessage (); + uint8_t * buf = m->GetPayload (); + memcpy (buf, ident, 32); + buf[32] = 0; // TODO: + memcpy (buf + 33, i2p::context.GetRouterInfo ().GetIdentHash (), 32); + m->len += 65; + FillI2NPMessageHeader (m, eI2NPDatabaseSearchReply); + return m; + } + I2NPMessage * CreateDatabaseStoreMsg () { I2NPMessage * m = NewI2NPMessage (); @@ -409,7 +439,11 @@ namespace i2p case eI2NPVariableTunnelBuildReply: LogPrint ("VariableTunnelBuildReply"); HandleVariableTunnelBuildReplyMsg (msgID, buf, size); - break; + break; + case eI2NPDatabaseLookup: + LogPrint ("DatabaseLookup"); + HandleDatabaseLookupMsg (buf, size); + break; default: LogPrint ("Unexpected message ", (int)header->typeID); } diff --git a/I2NPProtocol.h b/I2NPProtocol.h index adcbd576..71b93525 100644 --- a/I2NPProtocol.h +++ b/I2NPProtocol.h @@ -107,7 +107,9 @@ namespace i2p I2NPMessage * CreateDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, uint32_t replyTunnelID, bool exploratory = false, std::set * excludedPeers = nullptr); - + void HandleDatabaseLookupMsg (uint8_t * buf, size_t len); + I2NPMessage * CreateDatabaseSearchReply (const i2p::data::IdentHash& ident); + I2NPMessage * CreateDatabaseStoreMsg (); I2NPBuildRequestRecordClearText CreateBuildRequestRecord ( From 040d0f5f58e88602e3da37a0f9adf73f6fa65048 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 5 Jan 2014 22:52:17 -0500 Subject: [PATCH 13/16] show trafic for transit tunnels --- HTTPServer.cpp | 11 +++++++++-- TransitTunnel.cpp | 4 +++- TransitTunnel.h | 4 ++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 88e7b272..577ef748 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -104,15 +104,22 @@ namespace util s << "-->" << it.second->GetTunnelID (); else s << "-->" << it.second->GetTunnelID () << "-->"; - s << "
"; + s << " " << it.second->GetNumTransmittedBytes () << "
"; } s << "

Transports

"; for (auto it: i2p::transports.GetNTCPSessions ()) { + // RouterInfo of incoming connection doesn't have address + bool outgoing = it.second->GetRemoteRouterInfo ().GetNTCPAddress (); if (it.second->IsEstablished ()) + { + if (outgoing) s << "-->"; s << it.second->GetRemoteRouterInfo ().GetIdentHashAbbreviation () << ": " - << it.second->GetSocket ().remote_endpoint().address ().to_string () << "
"; + << it.second->GetSocket ().remote_endpoint().address ().to_string (); + if (!outgoing) s << "-->"; + s << "
"; + } } } diff --git a/TransitTunnel.cpp b/TransitTunnel.cpp index 5771c385..d92b62a9 100644 --- a/TransitTunnel.cpp +++ b/TransitTunnel.cpp @@ -14,7 +14,8 @@ namespace tunnel TransitTunnel::TransitTunnel (uint32_t receiveTunnelID, const uint8_t * nextIdent, uint32_t nextTunnelID, const uint8_t * layerKey,const uint8_t * ivKey): - m_TunnelID (receiveTunnelID), m_NextTunnelID (nextTunnelID), m_NextIdent (nextIdent) + m_TunnelID (receiveTunnelID), m_NextTunnelID (nextTunnelID), + m_NextIdent (nextIdent), m_NumTransmittedBytes (0) { memcpy (m_LayerKey, layerKey, 32); memcpy (m_IVKey, ivKey, 32); @@ -43,6 +44,7 @@ namespace tunnel FillI2NPMessageHeader (tunnelMsg, eI2NPTunnelData); i2p::transports.SendMessage (m_NextIdent, tunnelMsg); + m_NumTransmittedBytes += tunnelMsg->GetLength (); } void TransitTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) diff --git a/TransitTunnel.h b/TransitTunnel.h index 2109ee31..570429f5 100644 --- a/TransitTunnel.h +++ b/TransitTunnel.h @@ -23,6 +23,7 @@ namespace tunnel virtual void HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg); virtual void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); + virtual size_t GetNumTransmittedBytes () const { return m_NumTransmittedBytes; }; uint32_t GetTunnelID () const { return m_TunnelID; }; @@ -37,6 +38,7 @@ namespace tunnel i2p::data::IdentHash m_NextIdent; uint8_t m_LayerKey[32]; uint8_t m_IVKey[32]; + size_t m_NumTransmittedBytes; CryptoPP::ECB_Mode::Encryption m_ECBEncryption; CryptoPP::CBC_Mode::Encryption m_CBCEncryption; @@ -53,6 +55,7 @@ namespace tunnel layerKey, ivKey), m_Gateway(this) {}; void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); + size_t GetNumTransmittedBytes () const { return m_Gateway.GetNumSentBytes (); }; private: @@ -69,6 +72,7 @@ namespace tunnel TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey) {}; void HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg); + size_t GetNumTransmittedBytes () const { return m_Endpoint.GetNumReceivedBytes (); } private: From cbe58c8bb1321141a4291af08d11a87f0559230f Mon Sep 17 00:00:00 2001 From: orignal Date: Mon, 6 Jan 2014 20:56:44 -0500 Subject: [PATCH 14/16] fixed out of range bug --- Streaming.cpp | 4 ++-- TunnelGateway.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Streaming.cpp b/Streaming.cpp index e0d64a77..05d9933c 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -96,7 +96,7 @@ namespace stream auto outbound = i2p::tunnel::tunnels.GetNextOutboundTunnel (); if (outbound) { - auto lease = m_RemoteLeaseSet->GetLeases ()[0]; // TODO: + auto& lease = m_RemoteLeaseSet->GetLeases ()[0]; // TODO: outbound->SendTunnelDataMsg (lease.tunnelGateway, lease.tunnelID, msg); } else @@ -235,7 +235,7 @@ namespace stream compressor.MessageEnd(); int size = compressor.MaxRetrievable (); uint8_t * buf = msg->GetPayload (); - *(uint16_t *)buf = htobe32 (size); // length + *(uint32_t *)buf = htobe32 (size); // length buf += 4; compressor.Get (buf, size); buf[9] = 6; // streaming protocol diff --git a/TunnelGateway.cpp b/TunnelGateway.cpp index 6e0db1f0..24f1a0ec 100644 --- a/TunnelGateway.cpp +++ b/TunnelGateway.cpp @@ -16,7 +16,7 @@ namespace tunnel CreateCurrentTunnelDataMessage (); // create delivery instructions - uint8_t di[40]; + uint8_t di[43]; // max delivery instruction length is 43 for tunnel size_t diLen = 1;// flag TunnelDeliveryType dt = eDeliveryTypeLocal; if (gwHash) From 3aab091e9f0318f78431cc1584a7cfcb337a05ad Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 8 Jan 2014 19:30:47 -0500 Subject: [PATCH 15/16] common constructor for TunnelConfig --- Tunnel.cpp | 42 ++++++++++++++++++++++++++++++++---------- TunnelConfig.h | 37 +++++++++++++++++-------------------- 2 files changed, 49 insertions(+), 30 deletions(-) diff --git a/Tunnel.cpp b/Tunnel.cpp index b4cd41a0..76f05a62 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -353,7 +353,10 @@ namespace tunnel { LogPrint ("Creating one hop outbound tunnel..."); CreateTunnel ( - new TunnelConfig (i2p::data::netdb.GetRandomNTCPRouter (), + new TunnelConfig (std::vector + { + i2p::data::netdb.GetRandomNTCPRouter () + }, inboundTunnel->GetTunnelConfig ())); } else @@ -361,8 +364,11 @@ namespace tunnel //OutboundTunnel * outboundTunnel = GetNextOutboundTunnel (); LogPrint ("Creating two hops outbound tunnel..."); CreateTunnel ( - new TunnelConfig (i2p::data::netdb.GetRandomNTCPRouter (), - i2p::data::netdb.GetRandomNTCPRouter (), + new TunnelConfig (std::vector + { + i2p::data::netdb.GetRandomNTCPRouter (), + i2p::data::netdb.GetRandomNTCPRouter () + }, inboundTunnel->GetTunnelConfig ())/*, outboundTunnel*/); } @@ -396,7 +402,11 @@ namespace tunnel if (m_OutboundTunnels.empty () || m_InboundTunnels.size () < 3) { LogPrint ("Creating one hop inbound tunnel..."); - CreateTunnel (new TunnelConfig (i2p::data::netdb.GetRandomNTCPRouter ())); + CreateTunnel ( + new TunnelConfig (std::vector + { + i2p::data::netdb.GetRandomNTCPRouter () + })); } else { @@ -404,9 +414,12 @@ namespace tunnel LogPrint ("Creating two hops inbound tunnel..."); auto router = outboundTunnel->GetTunnelConfig ()->GetFirstHop ()->router; CreateTunnel ( - new TunnelConfig (i2p::data::netdb.GetRandomNTCPRouter (), - router != &i2p::context.GetRouterInfo () ? router : i2p::data::netdb.GetRandomNTCPRouter ()), - outboundTunnel); + new TunnelConfig (std::vector + { + i2p::data::netdb.GetRandomNTCPRouter (), + router != &i2p::context.GetRouterInfo () ? router : i2p::data::netdb.GetRandomNTCPRouter () + }), + outboundTunnel); } } } @@ -457,7 +470,10 @@ namespace tunnel void Tunnels::CreateZeroHopsInboundTunnel () { CreateTunnel ( - new TunnelConfig (&i2p::context.GetRouterInfo ())); + new TunnelConfig (std::vector + { + &i2p::context.GetRouterInfo () + })); } OutboundTunnel * Tunnels::CreateOneHopOutboundTestTunnel (InboundTunnel * replyTunnel) @@ -471,7 +487,9 @@ namespace tunnel if (peer) { const i2p::data::RouterInfo& router = peer->GetRemoteRouterInfo (); - return CreateTunnel (new TunnelConfig (&router), outboundTunnel); + return CreateTunnel ( + new TunnelConfig (std::vector{&router}), + outboundTunnel); } else LogPrint ("No established peers"); @@ -490,7 +508,11 @@ namespace tunnel { const i2p::data::RouterInfo& router = peer->GetRemoteRouterInfo (); return CreateTunnel ( - new TunnelConfig (&router, &i2p::context.GetRouterInfo ()), + new TunnelConfig (std::vector + { + &router, + &i2p::context.GetRouterInfo () + }), outboundTunnel); } else diff --git a/TunnelConfig.h b/TunnelConfig.h index 653fe56d..29fb8575 100644 --- a/TunnelConfig.h +++ b/TunnelConfig.h @@ -3,6 +3,7 @@ #include #include +#include #include "RouterInfo.h" #include "RouterContext.h" @@ -83,34 +84,30 @@ namespace tunnel { public: - TunnelConfig (const i2p::data::RouterInfo * peer, TunnelConfig * replyTunnelConfig = 0) // one hop - { - m_FirstHop = new TunnelHopConfig (peer); - m_LastHop = m_FirstHop; - - if (replyTunnelConfig) // outbound - { - m_FirstHop->isGateway = false; - m_LastHop->SetReplyHop (replyTunnelConfig->GetFirstHop ()); - } - else - m_FirstHop->SetNextRouter (&i2p::context.GetRouterInfo ()); - } - TunnelConfig (const i2p::data::RouterInfo * peer1, const i2p::data::RouterInfo * peer2, TunnelConfig * replyTunnelConfig = 0) // two hops + TunnelConfig (std::vector peers, + TunnelConfig * replyTunnelConfig = 0) // replyTunnelConfig=0 means inbound { - m_FirstHop = new TunnelHopConfig (peer1); - m_LastHop = new TunnelHopConfig (peer2); - m_FirstHop->SetNext (m_LastHop); + TunnelHopConfig * prev = nullptr; + for (auto it: peers) + { + auto hop = new TunnelHopConfig (it); + if (prev) + prev->SetNext (hop); + else + m_FirstHop = hop; + prev = hop; + } + m_LastHop = prev; - if (replyTunnelConfig) + if (replyTunnelConfig) // outbound { m_FirstHop->isGateway = false; m_LastHop->SetReplyHop (replyTunnelConfig->GetFirstHop ()); } - else + else // inbound m_LastHop->SetNextRouter (&i2p::context.GetRouterInfo ()); - } + } ~TunnelConfig () { From 57c97208f9da13e7a6fba2e7c3da8110ff466959 Mon Sep 17 00:00:00 2001 From: orignal Date: Wed, 8 Jan 2014 22:47:22 -0500 Subject: [PATCH 16/16] include DeliveryStatus to Garlic --- Garlic.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++------ Garlic.h | 1 + I2NPProtocol.cpp | 4 ++-- I2NPProtocol.h | 2 +- LeaseSet.cpp | 16 +++++++++++++- Streaming.cpp | 19 +++++++++++++++-- Streaming.h | 11 ++++++++-- 7 files changed, 93 insertions(+), 14 deletions(-) diff --git a/Garlic.cpp b/Garlic.cpp index 202949bb..ec52550c 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -4,6 +4,8 @@ #include #include "ElGamal.h" #include "RouterContext.h" +#include "I2NPProtocol.h" +#include "Tunnel.h" #include "Timestamp.h" #include "Streaming.h" #include "Garlic.h" @@ -65,8 +67,6 @@ namespace garlic FillI2NPMessageHeader (m, eI2NPGarlic); if (msg) DeleteI2NPMessage (msg); - if (leaseSet) - DeleteI2NPMessage (leaseSet); return m; } @@ -97,17 +97,23 @@ namespace garlic size_t GarlicRoutingSession::CreateGarlicPayload (uint8_t * payload, I2NPMessage * msg, I2NPMessage * leaseSet) { uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 5000; // 5 sec + uint32_t msgID = m_Rnd.GenerateWord32 (); size_t size = 0; uint8_t * numCloves = payload + size; *numCloves = 0; size++; + + if (leaseSet) + { + // clove is DeliveryStatus is LeaseSet is presented + size += CreateDeliveryStatusClove (payload + size, msgID); + (*numCloves)++; - if (leaseSet) // first clove is our leaseSet if presented - { + // clove is our leaseSet if presented size += CreateGarlicClove (payload + size, leaseSet, false); (*numCloves)++; } - if (msg) // next clove message ifself if presented + if (msg) // clove message ifself if presented { size += CreateGarlicClove (payload + size, msg, m_Destination->IsDestination ()); (*numCloves)++; @@ -115,7 +121,7 @@ namespace garlic memset (payload + size, 0, 3); // certificate of message size += 3; - *(uint32_t *)(payload + size) = htobe32 (m_Rnd.GenerateWord32 ()); // MessageID + *(uint32_t *)(payload + size) = htobe32 (msgID); // MessageID size += 4; *(uint64_t *)(payload + size) = htobe64 (ts); // Expiration of message size += 8; @@ -149,6 +155,42 @@ namespace garlic size += 3; return size; } + + size_t GarlicRoutingSession::CreateDeliveryStatusClove (uint8_t * buf, uint32_t msgID) + { + size_t size = 0; + auto tunnel = i2p::tunnel::tunnels.GetNextInboundTunnel (); + if (tunnel) + { + buf[size] = eGarlicDeliveryTypeTunnel << 5; // delivery instructions flag tunnel + size++; + *(uint32_t *)(buf + size) = htobe32 (tunnel->GetNextTunnelID ()); // tunnelID + size += 4; + memcpy (buf + size, tunnel->GetNextIdentHash (), 32); // To Hash + size += 32; + } + else + { + LogPrint ("No reply tunnels for garlic DeliveryStatus found"); + buf[size] = 0;// delivery instructions flag local + size++; + } + + + I2NPMessage * msg = CreateDeliveryStatusMsg (msgID); + memcpy (buf + size, msg->GetBuffer (), msg->GetLength ()); + size += msg->GetLength (); + DeleteI2NPMessage (msg); + uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 5000; // 5 sec + *(uint32_t *)(buf + size) = htobe32 (m_Rnd.GenerateWord32 ()); // CloveID + size += 4; + *(uint64_t *)(buf + size) = htobe64 (ts); // Expiration of clove + size += 8; + memset (buf + size, 0, 3); // certificate of clove + size += 3; + + return size; + } GarlicRouting routing; GarlicRouting::GarlicRouting () diff --git a/Garlic.h b/Garlic.h index 536ed173..81675fa9 100644 --- a/Garlic.h +++ b/Garlic.h @@ -48,6 +48,7 @@ namespace garlic size_t CreateAESBlock (uint8_t * buf, I2NPMessage * msg, I2NPMessage * leaseSet); size_t CreateGarlicPayload (uint8_t * payload, I2NPMessage * msg, I2NPMessage * leaseSet); size_t CreateGarlicClove (uint8_t * buf, I2NPMessage * msg, bool isDestination); + size_t CreateDeliveryStatusClove (uint8_t * buf, uint32_t msgID); private: diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index 11ccd757..44862dc0 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -67,7 +67,7 @@ namespace i2p return msg; } - I2NPMessage * CreateDeliveryStatusMsg () + I2NPMessage * CreateDeliveryStatusMsg (uint32_t msgID) { #pragma pack(1) struct @@ -77,7 +77,7 @@ namespace i2p } msg; #pragma pack () - msg.msgID = 0; + msg.msgID = htobe32 (msgID); msg.timestamp = htobe64 (i2p::util::GetMillisecondsSinceEpoch ()); return CreateI2NPMessage (eI2NPDeliveryStatus, (uint8_t *)&msg, sizeof (msg)); } diff --git a/I2NPProtocol.h b/I2NPProtocol.h index 71b93525..ebba0c5e 100644 --- a/I2NPProtocol.h +++ b/I2NPProtocol.h @@ -103,7 +103,7 @@ namespace i2p I2NPMessage * CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, int len, uint32_t replyMsgID = 0); I2NPMessage * CreateI2NPMessage (const uint8_t * buf, int len); - I2NPMessage * CreateDeliveryStatusMsg (); + I2NPMessage * CreateDeliveryStatusMsg (uint32_t msgID); I2NPMessage * CreateDatabaseLookupMsg (const uint8_t * key, const uint8_t * from, uint32_t replyTunnelID, bool exploratory = false, std::set * excludedPeers = nullptr); diff --git a/LeaseSet.cpp b/LeaseSet.cpp index 9a646e98..d7939d2d 100644 --- a/LeaseSet.cpp +++ b/LeaseSet.cpp @@ -1,3 +1,5 @@ +#include +#include "CryptoConst.h" #include "Log.h" #include "LeaseSet.h" @@ -24,10 +26,22 @@ namespace data memcpy (m_EncryptionKey, header->encryptionKey, 256); LogPrint ("LeaseSet num=", (int)header->num); + const uint8_t * leases = buf + sizeof (H); for (int i = 0; i < header->num; i++) { - m_Leases.push_back (*(Lease *)(buf + sizeof (H))); + Lease lease = *(Lease *)leases; + lease.tunnelID = be32toh (lease.tunnelID); + m_Leases.push_back (lease); + leases += sizeof (Lease); } + + // verify + CryptoPP::DSA::PublicKey pubKey; + pubKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag, + CryptoPP::Integer (m_Identity.signingKey, 128)); + CryptoPP::DSA::Verifier verifier (pubKey); + if (!verifier.VerifyMessage (buf, leases - buf, leases, 40)) + LogPrint ("LeaseSet verification failed"); } } } diff --git a/Streaming.cpp b/Streaming.cpp index 05d9933c..73f2ff8a 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -91,7 +91,7 @@ namespace stream size += len; // payload m_LocalDestination->Sign (packet, size, signature); I2NPMessage * msg = i2p::garlic::routing.WrapSingleMessage (m_RemoteLeaseSet, - CreateDataMessage (this, packet, size), m_LocalDestination->CreateLeaseSet ()); + CreateDataMessage (this, packet, size), m_LocalDestination->GetLeaseSet ()); auto outbound = i2p::tunnel::tunnels.GetNextOutboundTunnel (); if (outbound) @@ -106,7 +106,7 @@ namespace stream StreamingDestination * sharedLocalDestination = nullptr; - StreamingDestination::StreamingDestination () + StreamingDestination::StreamingDestination (): m_LeaseSet (nullptr) { // TODO: read from file later m_Keys = i2p::data::CreateRandomKeys (); @@ -115,6 +115,12 @@ namespace stream m_SigningPrivateKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag, CryptoPP::Integer (m_Keys.signingPrivateKey, 20)); } + + StreamingDestination::~StreamingDestination () + { + if (m_LeaseSet) + DeleteI2NPMessage (m_LeaseSet); + } void StreamingDestination::HandleNextPacket (const uint8_t * buf, size_t len) { @@ -141,6 +147,15 @@ namespace stream delete stream; } } + + I2NPMessage * StreamingDestination::GetLeaseSet () + { + if (!m_LeaseSet) + m_LeaseSet = CreateLeaseSet (); + else + FillI2NPMessageHeader (m_LeaseSet, eI2NPDatabaseStore); // refresh msgID + return m_LeaseSet; + } I2NPMessage * StreamingDestination::CreateLeaseSet () const { diff --git a/Streaming.h b/Streaming.h index c3c97bd8..86aeac31 100644 --- a/Streaming.h +++ b/Streaming.h @@ -52,15 +52,20 @@ namespace stream public: StreamingDestination (); - + ~StreamingDestination (); + const i2p::data::Keys& GetKeys () const { return m_Keys; }; const i2p::data::Identity& GetIdentity () const { return m_Identity; }; - I2NPMessage * CreateLeaseSet () const; + I2NPMessage * GetLeaseSet (); void Sign (uint8_t * buf, int len, uint8_t * signature) const; Stream * CreateNewStream (const i2p::data::LeaseSet * remote); void DeleteStream (Stream * stream); void HandleNextPacket (const uint8_t * buf, size_t len); + + private: + + I2NPMessage * CreateLeaseSet () const; private: @@ -69,6 +74,8 @@ namespace stream i2p::data::Identity m_Identity; i2p::data::IdentHash m_IdentHash; + I2NPMessage * m_LeaseSet; + CryptoPP::DSA::PrivateKey m_SigningPrivateKey; };