diff --git a/Garlic.cpp b/Garlic.cpp index c003b9a7..94d09a89 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -43,7 +43,7 @@ namespace garlic } } - I2NPMessage * GarlicRoutingSession::WrapSingleMessage (I2NPMessage * msg, I2NPMessage * leaseSet) + I2NPMessage * GarlicRoutingSession::WrapSingleMessage (I2NPMessage * msg, const I2NPMessage * leaseSet) { I2NPMessage * m = NewI2NPMessage (); size_t len = 0; @@ -89,7 +89,7 @@ namespace garlic return m; } - size_t GarlicRoutingSession::CreateAESBlock (uint8_t * buf, I2NPMessage * msg, I2NPMessage * leaseSet) + size_t GarlicRoutingSession::CreateAESBlock (uint8_t * buf, const I2NPMessage * msg, const I2NPMessage * leaseSet) { size_t blockSize = 0; *(uint16_t *)buf = m_NextTag < 0 ? htobe16 (m_NumTags) : 0; // tag count @@ -116,7 +116,7 @@ namespace garlic return blockSize; } - size_t GarlicRoutingSession::CreateGarlicPayload (uint8_t * payload, I2NPMessage * msg, I2NPMessage * leaseSet) + size_t GarlicRoutingSession::CreateGarlicPayload (uint8_t * payload, const I2NPMessage * msg, const I2NPMessage * leaseSet) { uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 5000; // 5 sec uint32_t msgID = m_Rnd.GenerateWord32 (); @@ -153,7 +153,7 @@ namespace garlic return size; } - size_t GarlicRoutingSession::CreateGarlicClove (uint8_t * buf, I2NPMessage * msg, bool isDestination) + size_t GarlicRoutingSession::CreateGarlicClove (uint8_t * buf, const I2NPMessage * msg, bool isDestination) { uint64_t ts = i2p::util::GetMillisecondsSinceEpoch () + 5000; // 5 sec size_t size = 0; @@ -245,7 +245,7 @@ namespace garlic } I2NPMessage * GarlicRouting::WrapMessage (const i2p::data::RoutingDestination& destination, - I2NPMessage * msg, I2NPMessage * leaseSet) + I2NPMessage * msg, const I2NPMessage * leaseSet) { auto it = m_Sessions.find (destination.GetIdentHash ()); GarlicRoutingSession * session = nullptr; diff --git a/Garlic.h b/Garlic.h index 3fb8ba50..f6c61a06 100644 --- a/Garlic.h +++ b/Garlic.h @@ -42,7 +42,7 @@ namespace garlic GarlicRoutingSession (const i2p::data::RoutingDestination& destination, int numTags); ~GarlicRoutingSession (); - I2NPMessage * WrapSingleMessage (I2NPMessage * msg, I2NPMessage * leaseSet); + I2NPMessage * WrapSingleMessage (I2NPMessage * msg, const I2NPMessage * leaseSet); int GetNextTag () const { return m_NextTag; }; uint32_t GetFirstMsgID () const { return m_FirstMsgID; }; @@ -51,9 +51,9 @@ namespace garlic private: - 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 CreateAESBlock (uint8_t * buf, const I2NPMessage * msg, const I2NPMessage * leaseSet); + size_t CreateGarlicPayload (uint8_t * payload, const I2NPMessage * msg, const I2NPMessage * leaseSet); + size_t CreateGarlicClove (uint8_t * buf, const I2NPMessage * msg, bool isDestination); size_t CreateDeliveryStatusClove (uint8_t * buf, uint32_t msgID); void GenerateSessionTags (); @@ -86,7 +86,7 @@ namespace garlic I2NPMessage * WrapSingleMessage (const i2p::data::RoutingDestination& destination, I2NPMessage * msg); I2NPMessage * WrapMessage (const i2p::data::RoutingDestination& destination, - I2NPMessage * msg, I2NPMessage * leaseSet = nullptr); + I2NPMessage * msg, const I2NPMessage * leaseSet = nullptr); private: diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index 5b2c66f1..0b34f9db 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -31,17 +31,17 @@ namespace i2p delete msg; } + static uint32_t I2NPmsgID = 0; // TODO: create class void FillI2NPMessageHeader (I2NPMessage * msg, I2NPMessageType msgType, uint32_t replyMsgID) { - static uint32_t msgID = 0; I2NPHeader * header = msg->GetHeader (); header->typeID = msgType; if (replyMsgID) // for tunnel creation header->msgID = htobe32 (replyMsgID); else { - header->msgID = htobe32 (msgID); - msgID++; + header->msgID = htobe32 (I2NPmsgID); + I2NPmsgID++; } header->expiration = htobe64 (i2p::util::GetMillisecondsSinceEpoch () + 5000); // TODO: 5 secs is a magic number int len = msg->GetLength () - sizeof (I2NPHeader); @@ -51,6 +51,17 @@ namespace i2p header->chks = hash[0]; } + void RenewI2NPMessageHeader (I2NPMessage * msg) + { + if (msg) + { + I2NPHeader * header = msg->GetHeader (); + header->msgID = htobe32 (I2NPmsgID); + I2NPmsgID++; + header->expiration = htobe64 (i2p::util::GetMillisecondsSinceEpoch () + 5000); + } + } + I2NPMessage * CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, int len, uint32_t replyMsgID) { I2NPMessage * msg = NewI2NPMessage (); diff --git a/I2NPProtocol.h b/I2NPProtocol.h index 2030bdad..5e7900aa 100644 --- a/I2NPProtocol.h +++ b/I2NPProtocol.h @@ -103,9 +103,10 @@ namespace tunnel size_t len, offset; i2p::tunnel::InboundTunnel * from; - I2NPHeader * GetHeader () { return (I2NPHeader *)(buf + offset); }; - uint8_t * GetPayload () { return buf + offset + sizeof(I2NPHeader); }; + I2NPHeader * GetHeader () { return (I2NPHeader *)GetBuffer (); }; + uint8_t * GetPayload () { return GetBuffer () + sizeof(I2NPHeader); }; uint8_t * GetBuffer () { return buf + offset; }; + const uint8_t * GetBuffer () const { return buf + offset; }; size_t GetLength () const { return len - offset; }; I2NPMessage& operator=(const I2NPMessage& other) @@ -141,6 +142,7 @@ namespace tunnel I2NPMessage * NewI2NPMessage (); void DeleteI2NPMessage (I2NPMessage * msg); void FillI2NPMessageHeader (I2NPMessage * msg, I2NPMessageType msgType, uint32_t replyMsgID = 0); + void RenewI2NPMessageHeader (I2NPMessage * msg); I2NPMessage * CreateI2NPMessage (I2NPMessageType msgType, const uint8_t * buf, int len, uint32_t replyMsgID = 0); I2NPMessage * CreateI2NPMessage (const uint8_t * buf, int len); diff --git a/Identity.cpp b/Identity.cpp index fd5c0b74..eb107ca3 100644 --- a/Identity.cpp +++ b/Identity.cpp @@ -19,6 +19,13 @@ namespace data return *this; } + PrivateKeys& PrivateKeys::operator=(const Keys& keys) + { + pub = keys; + memcpy (privateKey, keys.privateKey, 276); // 256 + 20 + return *this; + } + IdentHash CalculateIdentHash (const Identity& identity) { IdentHash hash; diff --git a/Identity.h b/Identity.h index 6552fa38..6b180999 100644 --- a/Identity.h +++ b/Identity.h @@ -28,6 +28,15 @@ namespace data Identity& operator=(const Keys& keys); }; + struct PrivateKeys // for eepsites + { + Identity pub; + uint8_t privateKey[256]; + uint8_t signingPrivateKey[20]; + + PrivateKeys& operator=(const Keys& keys); + }; + #pragma pack() class IdentHash diff --git a/NetDb.cpp b/NetDb.cpp index 2b3598fc..3d8a4212 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -55,7 +55,7 @@ namespace data NetDb::~NetDb () { - Stop (); + Stop (); for (auto l:m_LeaseSets) delete l.second; for (auto r:m_RouterInfos) @@ -160,6 +160,8 @@ namespace data { LogPrint ("New RouterInfo added"); m_RouterInfos[r->GetIdentHash ()] = r; + if (r->IsFloodfill ()) + m_Floodfills.push_back (r); } } @@ -237,6 +239,7 @@ namespace data for (auto r: m_RouterInfos) delete r.second; m_RouterInfos.clear (); + m_Floodfills.clear (); // load routers now int numRouters = 0; @@ -253,11 +256,14 @@ namespace data RouterInfo * r = new RouterInfo(it1->path().c_str()); #endif m_RouterInfos[r->GetIdentHash ()] = r; + if (r->IsFloodfill ()) + m_Floodfills.push_back (r); numRouters++; } } } LogPrint (numRouters, " routers loaded"); + LogPrint (m_Floodfills.size (), " floodfills loaded"); } void NetDb::SaveUpdated (const char * directory) @@ -594,24 +600,8 @@ namespace data delete dest; } } - - const RouterInfo * NetDb::GetRandomNTCPRouter (bool floodfillOnly) const - { - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); - uint32_t ind = rnd.GenerateWord32 (0, m_RouterInfos.size () - 1), i = 0; - RouterInfo * last = nullptr; - for (auto it: m_RouterInfos) - { - if (it.second->IsNTCP () && !it.second->IsUnreachable () && - (!floodfillOnly || it.second->IsFloodfill ())) - last = it.second; - if (i >= ind) break; - else i++; - } - return last; - } - const RouterInfo * NetDb::GetRandomRouter (const RouterInfo * compatibleWith, bool floodfillOnly) const + const RouterInfo * NetDb::GetRandomRouter (const RouterInfo * compatibleWith, uint8_t caps) const { CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); uint32_t ind = rnd.GenerateWord32 (0, m_RouterInfos.size () - 1); @@ -624,7 +614,7 @@ namespace data { if (!it.second->IsUnreachable () && (!compatibleWith || it.second->IsCompatible (*compatibleWith)) && - (!floodfillOnly || it.second->IsFloodfill ())) + (!caps || (it.second->GetCaps () & caps) == caps)) return it.second; } else @@ -633,7 +623,7 @@ namespace data // we couldn't find anything, try second pass ind = 0; } - return nullptr; // seem we have too few routers + return nullptr; // seems we have too few routers } void NetDb::PostI2NPMsg (I2NPMessage * msg) @@ -648,15 +638,15 @@ namespace data XORMetric minMetric; RoutingKey destKey = CreateRoutingKey (destination); minMetric.SetMax (); - for (auto it: m_RouterInfos) + for (auto it: m_Floodfills) { - if (it.second->IsFloodfill () &&! it.second->IsUnreachable () && !excluded.count (it.first)) + if (!it->IsUnreachable () && !excluded.count (it->GetIdentHash ())) { - XORMetric m = destKey ^ it.second->GetRoutingKey (); + XORMetric m = destKey ^ it->GetRoutingKey (); if (m < minMetric) { minMetric = m; - r = it.second; + r = it; } } } diff --git a/NetDb.h b/NetDb.h index f9cf3900..a369459b 100644 --- a/NetDb.h +++ b/NetDb.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -73,8 +74,7 @@ namespace data void HandleDatabaseStoreMsg (uint8_t * buf, size_t len); void HandleDatabaseSearchReplyMsg (I2NPMessage * msg); - const RouterInfo * GetRandomNTCPRouter (bool floodfillOnly = false) const; - const RouterInfo * GetRandomRouter (const RouterInfo * compatibleWith = nullptr, bool floodfillOnly = false) const; + const RouterInfo * GetRandomRouter (const RouterInfo * compatibleWith = nullptr, uint8_t caps = 0) const; void PostI2NPMsg (I2NPMessage * msg); @@ -98,6 +98,7 @@ namespace data std::map m_LeaseSets; std::map m_RouterInfos; + std::vector m_Floodfills; std::map m_RequestedDestinations; std::set m_Subscriptions; diff --git a/RouterInfo.cpp b/RouterInfo.cpp index adae686c..735453c8 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -18,13 +18,13 @@ namespace i2p namespace data { RouterInfo::RouterInfo (const char * filename): - m_IsUpdated (false), m_IsUnreachable (false), m_SupportedTransports (0) + m_IsUpdated (false), m_IsUnreachable (false), m_SupportedTransports (0), m_Caps (0) { ReadFromFile (filename); } RouterInfo::RouterInfo (const uint8_t * buf, int len): - m_IsUpdated (true), m_IsUnreachable (false), m_SupportedTransports (0) + m_IsUpdated (true), m_IsUnreachable (false), m_SupportedTransports (0), m_Caps (0) { memcpy (m_Buffer, buf, len); m_BufferLen = len; @@ -175,6 +175,10 @@ namespace data r += ReadString (value, s); s.seekg (1, std::ios_base::cur); r++; // ; m_Properties[key] = value; + + // extract caps + if (!strcmp (key, "caps")) + ExtractCaps (value); } CryptoPP::SHA256().CalculateDigest(m_IdentHash, (uint8_t *)&m_RouterIdentity, sizeof (m_RouterIdentity)); @@ -185,6 +189,31 @@ namespace data SetUnreachable (true); } + void RouterInfo::ExtractCaps (const char * value) + { + m_Caps = 0; + const char * cap = value; + while (*cap) + { + switch (*cap) + { + case 'f': + m_Caps |= Caps::eFloodfill; + break; + case 'M': + case 'N': + case 'O': + m_Caps |= Caps::eHighBandwidth; + break; + case 'R': + m_Caps |= Caps::eReachable; + break; + default: ; + } + cap++; + } + } + void RouterInfo::UpdateIdentHashBase64 () { size_t l = i2p::data::ByteStreamToBase64 (m_IdentHash, 32, m_IdentHashBase64, 48); @@ -337,10 +366,7 @@ namespace data bool RouterInfo::IsFloodfill () const { - const char * caps = GetProperty ("caps"); - if (caps) - return strchr (caps, 'f'); - return false; + return m_Caps & Caps::eFloodfill; } bool RouterInfo::IsNTCP (bool v4only) const @@ -361,9 +387,7 @@ namespace data bool RouterInfo::UsesIntroducer () const { - if (!IsSSU ()) return false; - auto address = GetSSUAddress (true); // no introducers for v6 - return address && !address->introducers.empty (); + return !(m_Caps & Caps::eReachable); // non-reachable } const RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only) const diff --git a/RouterInfo.h b/RouterInfo.h index 52a8d9e9..19521a6d 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -20,11 +20,18 @@ namespace data enum SupportedTranports { eNTCPV4 = 0x01, - eNTCPV6 = 0x20, - eSSUV4 = 0x40, - eSSUV6 = 0x80 + eNTCPV6 = 0x02, + eSSUV4 = 0x04, + eSSUV6 = 0x08 }; + enum Caps + { + eFloodfill = 0x01, + eHighBandwidth = 0x02, + eReachable = 0x04 + }; + enum TransportStyle { eTransportUnknown = 0, @@ -77,7 +84,8 @@ namespace data bool IsSSU (bool v4only = true) const; bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; }; bool UsesIntroducer () const; - + uint8_t GetCaps () const { return m_Caps; }; + void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; }; bool IsUnreachable () const { return m_IsUnreachable; }; @@ -102,6 +110,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 ExtractCaps (const char * value); void UpdateIdentHashBase64 (); const Address * GetAddress (TransportStyle s, bool v4only) const; @@ -117,7 +126,7 @@ namespace data std::vector
m_Addresses; std::map m_Properties; bool m_IsUpdated, m_IsUnreachable; - uint8_t m_SupportedTransports; + uint8_t m_SupportedTransports, m_Caps; }; } } diff --git a/SSU.cpp b/SSU.cpp index 64886e90..b118c70a 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -822,14 +822,19 @@ namespace ssu } else { - // connect to introducer - auto& introducer = address->introducers[0]; // TODO: - boost::asio::ip::udp::endpoint introducerEndpoint (introducer.iHost, introducer.iPort); - session = new SSUSession (this, introducerEndpoint, router); - m_Sessions[introducerEndpoint] = session; - LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (), - "] created through introducer ", introducerEndpoint.address ().to_string (), ":", introducerEndpoint.port ()); - session->ConnectThroughIntroducer (introducer); + // connect through introducer + if (address->introducers.size () > 0) + { + auto& introducer = address->introducers[0]; // TODO: + boost::asio::ip::udp::endpoint introducerEndpoint (introducer.iHost, introducer.iPort); + session = new SSUSession (this, introducerEndpoint, router); + m_Sessions[introducerEndpoint] = session; + LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (), + "] through introducer ", introducerEndpoint.address ().to_string (), ":", introducerEndpoint.port ()); + session->ConnectThroughIntroducer (introducer); + } + else + LogPrint ("Router is unreachable, but not introducers presentd. Ignored"); } } } diff --git a/Streaming.cpp b/Streaming.cpp index a537def8..eb942bd5 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include "Log.h" @@ -264,7 +264,7 @@ namespace stream bool Stream::SendPacket (uint8_t * packet, size_t size) { - I2NPMessage * leaseSet = nullptr; + const I2NPMessage * leaseSet = nullptr; if (m_LeaseSetUpdated) { leaseSet = m_LocalDestination->GetLeaseSet (); @@ -301,15 +301,23 @@ namespace stream StreamingDestination::StreamingDestination (): m_LeaseSet (nullptr) { - // TODO: read from file later m_Keys = i2p::data::CreateRandomKeys (); - m_Identity = m_Keys; - m_IdentHash = i2p::data::CalculateIdentHash (m_Identity); + m_IdentHash = i2p::data::CalculateIdentHash (m_Keys.pub); m_SigningPrivateKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag, CryptoPP::Integer (m_Keys.signingPrivateKey, 20)); m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (this); } + StreamingDestination::StreamingDestination (const std::string& fullPath): m_LeaseSet (nullptr) + { + std::ifstream s(fullPath.c_str (), std::ifstream::binary); + if (s.is_open ()) + s.read ((char *)&m_Keys, sizeof (m_Keys)); + else + LogPrint ("Can't open file ", fullPath); + m_Pool = i2p::tunnel::tunnels.CreateTunnelPool (this); + } + StreamingDestination::~StreamingDestination () { if (m_LeaseSet) @@ -359,10 +367,12 @@ namespace stream it.second->SetLeaseSetUpdated (); } - I2NPMessage * StreamingDestination::GetLeaseSet () + const I2NPMessage * StreamingDestination::GetLeaseSet () { if (!m_LeaseSet) m_LeaseSet = CreateLeaseSet (); + else + RenewI2NPMessageHeader (m_LeaseSet); return m_LeaseSet; } @@ -376,8 +386,8 @@ namespace stream 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, &m_Keys.pub, sizeof (m_Keys.pub)); + size += sizeof (m_Keys.pub); // destination memcpy (buf + size, m_Pool->GetEncryptionPublicKey (), 256); size += 256; // encryption key memset (buf + size, 0, 128); diff --git a/Streaming.h b/Streaming.h index 973c2a55..b9f52c1a 100644 --- a/Streaming.h +++ b/Streaming.h @@ -2,6 +2,7 @@ #define STREAMING_H__ #include +#include #include #include #include @@ -106,11 +107,12 @@ namespace stream public: StreamingDestination (); + StreamingDestination (const std::string& fullPath); ~StreamingDestination (); - const i2p::data::Keys& GetKeys () const { return m_Keys; }; - const i2p::data::Identity& GetIdentity () const { return m_Identity; }; - I2NPMessage * GetLeaseSet (); + const i2p::data::PrivateKeys& GetKeys () const { return m_Keys; }; + const i2p::data::Identity& GetIdentity () const { return m_Keys.pub; }; + const I2NPMessage * GetLeaseSet (); i2p::tunnel::TunnelPool * GetTunnelPool () const { return m_Pool; }; void Sign (uint8_t * buf, int len, uint8_t * signature) const; @@ -128,8 +130,7 @@ namespace stream private: std::map m_Streams; - i2p::data::Keys m_Keys; - i2p::data::Identity m_Identity; + i2p::data::PrivateKeys m_Keys; i2p::data::IdentHash m_IdentHash; i2p::tunnel::TunnelPool * m_Pool; diff --git a/TunnelGateway.cpp b/TunnelGateway.cpp index cc1189e0..c85e92e6 100644 --- a/TunnelGateway.cpp +++ b/TunnelGateway.cpp @@ -107,7 +107,7 @@ namespace tunnel } } - std::vector TunnelGatewayBuffer::GetTunnelDataMsgs () + const std::vector TunnelGatewayBuffer::GetTunnelDataMsgs () { CompleteCurrentTunnelDataMessage (); std::vector ret = m_TunnelDataMsgs; // TODO: implement it better diff --git a/TunnelGateway.h b/TunnelGateway.h index 8c390eef..aec0ca03 100644 --- a/TunnelGateway.h +++ b/TunnelGateway.h @@ -16,7 +16,7 @@ namespace tunnel TunnelGatewayBuffer (uint32_t tunnelID): m_TunnelID (tunnelID), m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0) {}; void PutI2NPMsg (const TunnelMessageBlock& block); - std::vector GetTunnelDataMsgs (); + const std::vector GetTunnelDataMsgs (); private: