From d7084e379ff3b10f4a9168ce0cc61d099e708a98 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 15 Mar 2014 22:02:33 -0400 Subject: [PATCH 1/6] create LeaseSet encryption key per tunnel pool --- RouterContext.cpp | 4 ---- RouterContext.h | 3 --- Streaming.cpp | 2 +- TunnelPool.cpp | 20 +++++++++++++------- TunnelPool.h | 8 ++++++-- 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/RouterContext.cpp b/RouterContext.cpp index cb8eb355..bde075ad 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -14,10 +14,6 @@ namespace i2p if (!Load ()) CreateNewRouter (); Save (); - - // we generate LeaseSet at every start-up - CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); - dh.GenerateKeyPair(m_Rnd, m_LeaseSetPrivateKey, m_LeaseSetPublicKey); } void RouterContext::CreateNewRouter () diff --git a/RouterContext.h b/RouterContext.h index 092c50b5..abbc3775 100644 --- a/RouterContext.h +++ b/RouterContext.h @@ -20,8 +20,6 @@ namespace i2p i2p::data::RouterInfo& GetRouterInfo () { return m_RouterInfo; }; const uint8_t * GetPrivateKey () const { return m_Keys.privateKey; }; const uint8_t * GetSigningPrivateKey () const { return m_Keys.signingPrivateKey; }; - const uint8_t * GetLeaseSetPrivateKey () const { return m_LeaseSetPrivateKey; }; - const uint8_t * GetLeaseSetPublicKey () const { return m_LeaseSetPublicKey; }; const i2p::data::Identity& GetRouterIdentity () const { return m_RouterInfo.GetRouterIdentity (); }; CryptoPP::RandomNumberGenerator& GetRandomNumberGenerator () { return m_Rnd; }; @@ -42,7 +40,6 @@ namespace i2p i2p::data::RouterInfo m_RouterInfo; i2p::data::Keys m_Keys; CryptoPP::DSA::PrivateKey m_SigningPrivateKey; - uint8_t m_LeaseSetPublicKey[256], m_LeaseSetPrivateKey[256]; CryptoPP::AutoSeededRandomPool m_Rnd; }; diff --git a/Streaming.cpp b/Streaming.cpp index b7282145..6f623f4a 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -377,7 +377,7 @@ namespace stream size_t size = 0; memcpy (buf + size, &m_Identity, sizeof (m_Identity)); size += sizeof (m_Identity); // destination - memcpy (buf + size, i2p::context.GetLeaseSetPublicKey (), 256); + memcpy (buf + size, m_Pool->GetEncryptionPublicKey (), 256); size += 256; // encryption key memset (buf + size, 0, 128); size += 128; // signing key diff --git a/TunnelPool.cpp b/TunnelPool.cpp index d9d38354..37854db2 100644 --- a/TunnelPool.cpp +++ b/TunnelPool.cpp @@ -1,15 +1,21 @@ +#include +#include "CryptoConst.h" #include "Tunnel.h" #include "NetDb.h" #include "Timestamp.h" +#include "RouterContext.h" #include "TunnelPool.h" namespace i2p { namespace tunnel { - TunnelPool::TunnelPool (i2p::data::LocalDestination * owner, int numTunnels): - m_Owner (owner), m_NumTunnels (numTunnels) + TunnelPool::TunnelPool (i2p::data::LocalDestination * localDestination, int numTunnels): + m_LocalDestination (localDestination), m_NumTunnels (numTunnels) { + CryptoPP::AutoSeededRandomPool rnd; + CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); + dh.GenerateKeyPair(i2p::context.GetRandomNumberGenerator (), m_EncryptionPrivateKey, m_EncryptionPublicKey); } TunnelPool::~TunnelPool () @@ -21,15 +27,15 @@ namespace tunnel void TunnelPool::TunnelCreated (InboundTunnel * createdTunnel) { m_InboundTunnels.insert (createdTunnel); - if (m_Owner) - m_Owner->UpdateLeaseSet (); + if (m_LocalDestination) + m_LocalDestination->UpdateLeaseSet (); } void TunnelPool::TunnelExpired (InboundTunnel * expiredTunnel) { m_InboundTunnels.erase (expiredTunnel); - if (m_Owner) - m_Owner->UpdateLeaseSet (); + if (m_LocalDestination) + m_LocalDestination->UpdateLeaseSet (); } std::vector TunnelPool::GetInboundTunnels (int num) const @@ -63,7 +69,7 @@ namespace tunnel { firstHop, secondHop - // TODO: swithc to 3-hops later + // TODO: switch to 3-hops later /*i2p::data::netdb.GetRandomRouter (secondHop) */ }), outboundTunnel); diff --git a/TunnelPool.h b/TunnelPool.h index 988e83c0..8dad4051 100644 --- a/TunnelPool.h +++ b/TunnelPool.h @@ -20,9 +20,12 @@ namespace tunnel { public: - TunnelPool (i2p::data::LocalDestination * owner, int numTunnels = 5); + TunnelPool (i2p::data::LocalDestination * localDestination, int numTunnels = 5); ~TunnelPool (); + const uint8_t * GetEncryptionPrivateKey () const { return m_EncryptionPrivateKey; }; + const uint8_t * GetEncryptionPublicKey () const { return m_EncryptionPublicKey; }; + void CreateTunnels (); void TunnelCreated (InboundTunnel * createdTunnel); void TunnelExpired (InboundTunnel * expiredTunnel); @@ -34,7 +37,8 @@ namespace tunnel private: - i2p::data::LocalDestination * m_Owner; + uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256]; + i2p::data::LocalDestination * m_LocalDestination; int m_NumTunnels; std::set m_InboundTunnels; // recent tunnel appears first From 28042926e75188d4171350f18a0d14183853b674 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 15 Mar 2014 22:09:08 -0400 Subject: [PATCH 2/6] create LeaseSet encryption key per tunnel pool --- Garlic.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Garlic.cpp b/Garlic.cpp index 3e336092..c003b9a7 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -5,6 +5,7 @@ #include "RouterContext.h" #include "I2NPProtocol.h" #include "Tunnel.h" +#include "TunnelPool.h" #include "Timestamp.h" #include "Streaming.h" #include "Garlic.h" @@ -288,9 +289,12 @@ namespace garlic else { // new session + i2p::tunnel::TunnelPool * pool = nullptr; + if (msg->from) + pool = msg->from->GetTunnelPool (); ElGamalBlock elGamal; if (i2p::crypto::ElGamalDecrypt ( - msg->from ? i2p::context.GetLeaseSetPrivateKey () : i2p::context.GetPrivateKey (), + pool ? pool->GetEncryptionPrivateKey () : i2p::context.GetPrivateKey (), buf, (uint8_t *)&elGamal, true)) { uint8_t iv[32]; // IV is first 16 bytes From 56836470cfd51841147d4d8ebed2adade046dd26 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 16 Mar 2014 08:00:34 -0400 Subject: [PATCH 3/6] pulish our RouterInfo to 3 floodfills --- NetDb.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/NetDb.cpp b/NetDb.cpp index 951f9623..2b3598fc 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -550,11 +550,15 @@ namespace data void NetDb::Publish () { std::set excluded; // TODO: fill up later - auto floodfill = GetClosestFloodfill (i2p::context.GetRouterInfo ().GetIdentHash (), excluded); - if (floodfill) - { - LogPrint ("Publishing our RouterInfo to ", floodfill->GetIdentHashAbbreviation ()); - transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg ()); + for (int i = 0; i < 3; i++) + { + auto floodfill = GetClosestFloodfill (i2p::context.GetRouterInfo ().GetIdentHash (), excluded); + if (floodfill) + { + LogPrint ("Publishing our RouterInfo to ", floodfill->GetIdentHashAbbreviation ()); + transports.SendMessage (floodfill->GetIdentHash (), CreateDatabaseStoreMsg ()); + excluded.insert (floodfill->GetIdentHash ()); + } } } From 9ef8ae99e2e98102af0aac791218ce29634f6971 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 16 Mar 2014 08:34:32 -0400 Subject: [PATCH 4/6] close SSU session if MAC verification fails --- SSU.cpp | 11 +++++++++++ SSU.h | 4 +++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/SSU.cpp b/SSU.cpp index 196c0a72..64886e90 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -418,7 +418,10 @@ namespace ssu LogPrint ("Unexpected payload type ", (int)(header->flag >> 4)); } else + { LogPrint ("MAC verification failed"); + Failed (); + } } else LogPrint ("SSU is not supported"); @@ -511,6 +514,14 @@ namespace ssu m_DelayedMessages.clear (); } } + + void SSUSession::Failed () + { + m_State = eSessionStateFailed; + Close (); + if (m_Server) + m_Server->DeleteSession (this); // delete this + } const uint8_t * SSUSession::GetIntroKey () const { diff --git a/SSU.h b/SSU.h index c61d09bb..c0c82e3e 100644 --- a/SSU.h +++ b/SSU.h @@ -58,7 +58,8 @@ namespace ssu eSessionRelayRequestSent, eSessionRelayRequestReceived, eSessionRelayResponseReceived, - eSessionStateEstablished + eSessionStateEstablished, + eSessionStateFailed }; class SSUServer; @@ -91,6 +92,7 @@ namespace ssu void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag); void ProcessRelayResponse (uint8_t * buf, size_t len); void Established (); + void Failed (); void ProcessData (uint8_t * buf, size_t len); void SendMsgAck (uint32_t msgID); void SendSesionDestroyed (); From c9ba7da0b0f8355f0757df3f0cc674b4ea8a05f0 Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 16 Mar 2014 16:03:20 -0400 Subject: [PATCH 5/6] outbound tunnel pool --- HTTPServer.cpp | 2 ++ Streaming.cpp | 2 +- Streaming.h | 1 + Tunnel.cpp | 8 ++++++- TunnelPool.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++++++++-- TunnelPool.h | 11 +++++++--- 6 files changed, 74 insertions(+), 7 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index c7d1fcaf..f02b0ba9 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -139,6 +139,8 @@ namespace util for (auto it: i2p::tunnel::tunnels.GetOutboundTunnels ()) { it->GetTunnelConfig ()->Print (s); + if (it->GetTunnelPool ()) + s << " " << "Pool"; s << " " << (int)it->GetNumSentBytes () << "
"; } diff --git a/Streaming.cpp b/Streaming.cpp index 6f623f4a..d365e57c 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -171,7 +171,7 @@ namespace stream CreateDataMessage (this, packet, size), m_LocalDestination->GetLeaseSet ()); if (!m_OutboundTunnel) - m_OutboundTunnel = i2p::tunnel::tunnels.GetNextOutboundTunnel (); + m_OutboundTunnel = m_LocalDestination->GetTunnelPool ()->GetNextOutboundTunnel (); auto leases = m_RemoteLeaseSet.GetNonExpiredLeases (); if (m_OutboundTunnel && !leases.empty ()) { diff --git a/Streaming.h b/Streaming.h index 8f0f289a..b0f7fda9 100644 --- a/Streaming.h +++ b/Streaming.h @@ -108,6 +108,7 @@ namespace stream const i2p::data::Keys& GetKeys () const { return m_Keys; }; const i2p::data::Identity& GetIdentity () const { return m_Identity; }; I2NPMessage * GetLeaseSet (); + i2p::tunnel::TunnelPool * GetTunnelPool () const { return m_Pool; }; void Sign (uint8_t * buf, int len, uint8_t * signature) const; Stream * CreateNewStream (const i2p::data::LeaseSet& remote); diff --git a/Tunnel.cpp b/Tunnel.cpp index e9e59b86..5d93c50a 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -390,13 +390,16 @@ namespace tunnel if (ts > (*it)->GetCreationTime () + TUNNEL_EXPIRATION_TIMEOUT) { LogPrint ("Tunnel ", (*it)->GetTunnelID (), " expired"); + auto pool = (*it)->GetTunnelPool (); + if (pool) + pool->TunnelExpired (*it); it = m_OutboundTunnels.erase (it); } else it++; } - if (m_OutboundTunnels.size () < 10) + if (m_OutboundTunnels.size () < 15) // TODO: store exploratory tunnels explicitly { // trying to create one more oubound tunnel if (m_InboundTunnels.empty ()) return; @@ -520,6 +523,9 @@ namespace tunnel void Tunnels::AddOutboundTunnel (OutboundTunnel * newTunnel) { m_OutboundTunnels.push_back (newTunnel); + auto pool = newTunnel->GetTunnelPool (); + if (pool) + pool->TunnelCreated (newTunnel); } void Tunnels::AddInboundTunnel (InboundTunnel * newTunnel) diff --git a/TunnelPool.cpp b/TunnelPool.cpp index 37854db2..6d6516ec 100644 --- a/TunnelPool.cpp +++ b/TunnelPool.cpp @@ -11,7 +11,7 @@ namespace i2p namespace tunnel { TunnelPool::TunnelPool (i2p::data::LocalDestination * localDestination, int numTunnels): - m_LocalDestination (localDestination), m_NumTunnels (numTunnels) + m_LocalDestination (localDestination), m_NumTunnels (numTunnels), m_LastOutboundTunnel (nullptr) { CryptoPP::AutoSeededRandomPool rnd; CryptoPP::DH dh (i2p::crypto::elgp, i2p::crypto::elgg); @@ -22,6 +22,8 @@ namespace tunnel { for (auto it: m_InboundTunnels) it->SetTunnelPool (nullptr); + for (auto it: m_OutboundTunnels) + it->SetTunnelPool (nullptr); } void TunnelPool::TunnelCreated (InboundTunnel * createdTunnel) @@ -37,6 +39,16 @@ namespace tunnel if (m_LocalDestination) m_LocalDestination->UpdateLeaseSet (); } + + void TunnelPool::TunnelCreated (OutboundTunnel * createdTunnel) + { + m_OutboundTunnels.insert (createdTunnel); + } + + void TunnelPool::TunnelExpired (OutboundTunnel * expiredTunnel) + { + m_OutboundTunnels.erase (expiredTunnel); + } std::vector TunnelPool::GetInboundTunnels (int num) const { @@ -51,16 +63,37 @@ namespace tunnel return v; } + OutboundTunnel * TunnelPool::GetNextOutboundTunnel () + { + if (m_OutboundTunnels.empty ()) return nullptr; + auto tunnel = *m_OutboundTunnels.begin (); + if (m_LastOutboundTunnel && tunnel == m_LastOutboundTunnel) + { + for (auto it: m_OutboundTunnels) + if (it != m_LastOutboundTunnel) + { + tunnel = it; + break; + } + } + m_LastOutboundTunnel = tunnel; + return tunnel; + } + void TunnelPool::CreateTunnels () { int num = m_InboundTunnels.size (); for (int i = num; i < m_NumTunnels; i++) CreateInboundTunnel (); + num = m_OutboundTunnels.size (); + for (int i = num; i < m_NumTunnels; i++) + CreateOutboundTunnel (); } void TunnelPool::CreateInboundTunnel () { - OutboundTunnel * outboundTunnel = tunnels.GetNextOutboundTunnel (); + OutboundTunnel * outboundTunnel = m_OutboundTunnels.size () > 0 ? + *m_OutboundTunnels.begin () : tunnels.GetNextOutboundTunnel (); LogPrint ("Creating destination inbound tunnel..."); auto firstHop = i2p::data::netdb.GetRandomRouter (outboundTunnel ? outboundTunnel->GetEndpointRouter () : nullptr); auto secondHop = i2p::data::netdb.GetRandomRouter (firstHop); @@ -75,5 +108,25 @@ namespace tunnel outboundTunnel); tunnel->SetTunnelPool (this); } + + void TunnelPool::CreateOutboundTunnel () + { + InboundTunnel * inboundTunnel = m_InboundTunnels.size () > 0 ? + *m_InboundTunnels.begin () : tunnels.GetNextInboundTunnel (); + if (inboundTunnel) + { + LogPrint ("Creating destination outbound tunnel..."); + auto firstHop = i2p::data::netdb.GetRandomRouter (&i2p::context.GetRouterInfo ()); + auto secondHop = i2p::data::netdb.GetRandomRouter (firstHop); + auto * tunnel = tunnels.CreateTunnel ( + new TunnelConfig (std::vector + { + firstHop, + secondHop + }, + inboundTunnel->GetTunnelConfig ())); + tunnel->SetTunnelPool (this); + } + } } } diff --git a/TunnelPool.h b/TunnelPool.h index 8dad4051..f8b6aab5 100644 --- a/TunnelPool.h +++ b/TunnelPool.h @@ -29,19 +29,24 @@ namespace tunnel void CreateTunnels (); void TunnelCreated (InboundTunnel * createdTunnel); void TunnelExpired (InboundTunnel * expiredTunnel); + void TunnelCreated (OutboundTunnel * createdTunnel); + void TunnelExpired (OutboundTunnel * expiredTunnel); std::vector GetInboundTunnels (int num) const; - + OutboundTunnel * GetNextOutboundTunnel (); + private: void CreateInboundTunnel (); - + void CreateOutboundTunnel (); + private: uint8_t m_EncryptionPublicKey[256], m_EncryptionPrivateKey[256]; i2p::data::LocalDestination * m_LocalDestination; int m_NumTunnels; std::set m_InboundTunnels; // recent tunnel appears first - + std::set m_OutboundTunnels; + OutboundTunnel * m_LastOutboundTunnel; }; } } From 6066b7073ff5d0961ba6304b865121d771defe4c Mon Sep 17 00:00:00 2001 From: orignal Date: Sun, 16 Mar 2014 21:18:23 -0400 Subject: [PATCH 6/6] handle .i2p addresses --- HTTPServer.cpp | 31 ++++++++++++++++++++++++------- HTTPServer.h | 2 +- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/HTTPServer.cpp b/HTTPServer.cpp index f02b0ba9..f914fefd 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -197,14 +197,31 @@ namespace util s << "

Flibusta

"; } - void HTTPConnection::HandleDestinationRequest (const std::string& b32, const std::string& uri) + void HTTPConnection::HandleDestinationRequest (const std::string& address, const std::string& uri) { - uint8_t destination[32]; - if (i2p::data::Base32ToByteStream (b32.c_str (), b32.length (), destination, 32) != 32) - { - LogPrint ("Invalid Base32 address ", b32); - return; + i2p::data::IdentHash destination; + std::string fullAddress; + if (address.find (".i2p") != std::string::npos) + { + auto addr = i2p::data::netdb.FindAddress(address); + if (!addr) + { + LogPrint ("Unknown address ", address); + return; + } + destination = *addr; + fullAddress = address; + } + else + { + if (i2p::data::Base32ToByteStream (address.c_str (), address.length (), (uint8_t *)destination, 32) != 32) + { + LogPrint ("Invalid Base32 address ", address); + return; + } + fullAddress = address + ".b32.i2p"; } + auto leaseSet = i2p::data::netdb.FindLeaseSet (destination); if (!leaseSet || !leaseSet->HasNonExpiredLeases ()) { @@ -225,7 +242,7 @@ namespace util auto s = i2p::stream::CreateStream (*leaseSet); if (s) { - std::string request = "GET " + uri + " HTTP/1.1\n Host:" + b32 + ".b32.i2p\n"; + std::string request = "GET " + uri + " HTTP/1.1\n Host:" + fullAddress + "\n"; s->Send ((uint8_t *)request.c_str (), request.length (), 10); std::stringstream ss; uint8_t buf[8192]; diff --git a/HTTPServer.h b/HTTPServer.h index a62a2074..546f5bc2 100644 --- a/HTTPServer.h +++ b/HTTPServer.h @@ -48,7 +48,7 @@ namespace util void HandleWrite(const boost::system::error_code& ecode); void HandleRequest (); - void HandleDestinationRequest (const std::string& b32, const std::string& uri); + void HandleDestinationRequest (const std::string& address, const std::string& uri); void FillContent (std::stringstream& s); std::string ExtractAddress ();