From 2deb4118bce5e6248ef0f47aac35d7130e970798 Mon Sep 17 00:00:00 2001 From: mikhail4021 Date: Sun, 23 Feb 2014 21:54:36 +0400 Subject: [PATCH] result --- ElGamal.h | 58 +++++--- Garlic.cpp | 23 ++- Garlic.h | 8 +- HTTPServer.cpp | 38 +++-- HTTPServer.h | 2 +- I2NPProtocol.cpp | 4 +- I2NPProtocol.h | 9 ++ Identity.h | 16 +++ Makefile | 3 +- NTCPSession.h | 2 +- NetDb.cpp | 100 ++++++++++--- NetDb.h | 8 +- Queue.h | 2 +- RouterContext.cpp | 32 ++++- RouterInfo.cpp | 34 ++++- RouterInfo.h | 19 ++- SSU.cpp | 348 +++++++++++++++++++++++++++++++++++++++------- SSU.h | 31 +++-- Streaming.cpp | 14 +- Streaming.h | 10 +- TransitTunnel.cpp | 9 +- TransitTunnel.h | 4 +- Transports.cpp | 32 ++++- Tunnel.cpp | 34 ++--- Tunnel.h | 2 +- TunnelGateway.cpp | 27 ++-- TunnelGateway.h | 6 +- UPnP.cpp | 68 +++++++++ UPnP.h | 41 ++++++ hmac.h | 2 +- i2p.cpp | 9 +- 31 files changed, 783 insertions(+), 212 deletions(-) create mode 100644 UPnP.cpp create mode 100644 UPnP.h diff --git a/ElGamal.h b/ElGamal.h index 387e02bb..b3f0e44f 100644 --- a/ElGamal.h +++ b/ElGamal.h @@ -12,25 +12,47 @@ namespace i2p { namespace crypto { - inline void ElGamalEncrypt (const uint8_t * key, const uint8_t * data, int len, - uint8_t * encrypted, bool zeroPadding = false) // 514 with padding and 512 without - { - CryptoPP::AutoSeededRandomPool rnd; - CryptoPP::Integer y(key, 256), k(rnd, CryptoPP::Integer::One(), elgp-1); - if (zeroPadding) - { - encrypted[0] = 0; - encrypted[257] = 0; - } - a_exp_b_mod_c (elgg, k, elgp).Encode (zeroPadding ? encrypted + 1 : encrypted, 256); - uint8_t m[255]; - m[0] = 0xFF; - memcpy (m+33, data, len); - CryptoPP::SHA256().CalculateDigest(m+1, m+33, 222); - a_times_b_mod_c (a_exp_b_mod_c (y, k, elgp), - CryptoPP::Integer (m, 255), elgp).Encode (zeroPadding ? encrypted + 258 : encrypted + 256, 256); - } + class ElGamalEncryption + { + public: + + ElGamalEncryption (const uint8_t * key): + y (key, 256), k (rnd, CryptoPP::Integer::One(), elgp-1), + a (a_exp_b_mod_c (elgg, k, elgp)), b1 (a_exp_b_mod_c (y, k, elgp)) + { + } + + void Encrypt (const uint8_t * data, int len, uint8_t * encrypted, bool zeroPadding = false) + { + // calculate b = b1*m mod p + uint8_t m[255]; + m[0] = 0xFF; + memcpy (m+33, data, len); + CryptoPP::SHA256().CalculateDigest(m+1, m+33, 222); + CryptoPP::Integer b (a_times_b_mod_c (b1, CryptoPP::Integer (m, 255), elgp)); + + // copy a and b + if (zeroPadding) + { + encrypted[0] = 0; + a.Encode (encrypted + 1, 256); + encrypted[257] = 0; + b.Encode (encrypted + 258, 256); + } + else + { + a.Encode (encrypted, 256); + b.Encode (encrypted + 256, 256); + } + } + + private: + + CryptoPP::AutoSeededRandomPool rnd; + CryptoPP::Integer y, k, a, b1; + bool m_ZeroPadding; + }; inline bool ElGamalDecrypt (const uint8_t * key, const uint8_t * encrypted, uint8_t * data, bool zeroPadding = false) diff --git a/Garlic.cpp b/Garlic.cpp index cdb8860e..e73a6f02 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -2,7 +2,6 @@ #include "I2PEndian.h" #include #include -#include "ElGamal.h" #include "RouterContext.h" #include "I2NPProtocol.h" #include "Tunnel.h" @@ -14,7 +13,7 @@ namespace i2p { namespace garlic { - GarlicRoutingSession::GarlicRoutingSession (const i2p::data::RoutingDestination * destination, int numTags): + GarlicRoutingSession::GarlicRoutingSession (const i2p::data::RoutingDestination& destination, int numTags): m_Destination (destination), m_FirstMsgID (0), m_IsAcknowledged (false), m_NumTags (numTags), m_NextTag (-1), m_SessionTags (0) { @@ -56,7 +55,7 @@ namespace garlic m_Rnd.GenerateBlock (elGamal.preIV, 32); // Pre-IV uint8_t iv[32]; // IV is first 16 bytes CryptoPP::SHA256().CalculateDigest(iv, elGamal.preIV, 32); - i2p::crypto::ElGamalEncrypt (m_Destination->GetEncryptionPublicKey (), (uint8_t *)&elGamal, sizeof(elGamal), buf, true); + m_Destination.GetElGamalEncryption ()->Encrypt ((uint8_t *)&elGamal, sizeof(elGamal), buf, true); m_Encryption.SetKeyWithIV (m_SessionKey, 32, iv); buf += 514; len += 514; @@ -140,7 +139,7 @@ namespace garlic } if (msg) // clove message ifself if presented { - size += CreateGarlicClove (payload + size, msg, m_Destination->IsDestination ()); + size += CreateGarlicClove (payload + size, msg, m_Destination.IsDestination ()); (*numCloves)++; } @@ -161,7 +160,7 @@ namespace garlic { buf[size] = eGarlicDeliveryTypeDestination << 5;// delivery instructions flag destination size++; - memcpy (buf + size, m_Destination->GetIdentHash (), 32); + memcpy (buf + size, m_Destination.GetIdentHash (), 32); size += 32; } else @@ -230,33 +229,31 @@ 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) { - if (!destination) return nullptr; - auto it = m_Sessions.find (destination->GetIdentHash ()); + auto it = m_Sessions.find (destination.GetIdentHash ()); if (it != m_Sessions.end ()) { delete it->second; m_Sessions.erase (it); } GarlicRoutingSession * session = new GarlicRoutingSession (destination, 0); // not follow-on messages expected - m_Sessions[destination->GetIdentHash ()] = session; + m_Sessions[destination.GetIdentHash ()] = session; return session->WrapSingleMessage (msg, nullptr); } - I2NPMessage * GarlicRouting::WrapMessage (const i2p::data::RoutingDestination * destination, + I2NPMessage * GarlicRouting::WrapMessage (const i2p::data::RoutingDestination& destination, I2NPMessage * msg, I2NPMessage * leaseSet) { - if (!destination) return nullptr; - auto it = m_Sessions.find (destination->GetIdentHash ()); + auto it = m_Sessions.find (destination.GetIdentHash ()); GarlicRoutingSession * session = nullptr; if (it != m_Sessions.end ()) session = it->second; if (!session) { session = new GarlicRoutingSession (destination, 4); // TODO: change it later - m_Sessions[destination->GetIdentHash ()] = session; + m_Sessions[destination.GetIdentHash ()] = session; } I2NPMessage * ret = session->WrapSingleMessage (msg, leaseSet); diff --git a/Garlic.h b/Garlic.h index c640eee3..0383b030 100644 --- a/Garlic.h +++ b/Garlic.h @@ -37,7 +37,7 @@ namespace garlic { public: - GarlicRoutingSession (const i2p::data::RoutingDestination * destination, int numTags); + GarlicRoutingSession (const i2p::data::RoutingDestination& destination, int numTags); ~GarlicRoutingSession (); I2NPMessage * WrapSingleMessage (I2NPMessage * msg, I2NPMessage * leaseSet); int GetNextTag () const { return m_NextTag; }; @@ -57,7 +57,7 @@ namespace garlic private: - const i2p::data::RoutingDestination * m_Destination; + const i2p::data::RoutingDestination& m_Destination; uint8_t m_SessionKey[32]; uint32_t m_FirstMsgID; // first message ID bool m_IsAcknowledged; @@ -78,8 +78,8 @@ namespace garlic void HandleGarlicMessage (uint8_t * buf, size_t len, bool isFromTunnel); void HandleDeliveryStatusMessage (uint8_t * buf, size_t len); - I2NPMessage * WrapSingleMessage (const i2p::data::RoutingDestination * destination, I2NPMessage * msg); - I2NPMessage * WrapMessage (const i2p::data::RoutingDestination * destination, + I2NPMessage * WrapSingleMessage (const i2p::data::RoutingDestination& destination, I2NPMessage * msg); + I2NPMessage * WrapMessage (const i2p::data::RoutingDestination& destination, I2NPMessage * msg, I2NPMessage * leaseSet = nullptr); private: diff --git a/HTTPServer.cpp b/HTTPServer.cpp index 5aeac9ed..833dca51 100644 --- a/HTTPServer.cpp +++ b/HTTPServer.cpp @@ -60,9 +60,20 @@ namespace util { m_Buffer[bytes_transferred] = 0; auto address = ExtractAddress (); - LogPrint (address); if (address.length () > 1) // not just '/' - HandleDestinationRequest (address.substr (1)); // exclude '/' + { + std::string uri ("/"), b32; + size_t pos = address.find ('/', 1); + if (pos == std::string::npos) + b32 = address.substr (1); // excluding leading '/' to end of line + else + { + b32 = address.substr (1, pos - 1); // excluding leading '/' to next '/' + uri = address.substr (pos); // rest of line + } + + HandleDestinationRequest (b32, uri); + } else HandleRequest (); boost::asio::async_write (*m_Socket, m_Reply.to_buffers(), @@ -149,14 +160,18 @@ namespace util s << "

Flibusta

"; } - void HTTPConnection::HandleDestinationRequest (std::string b32) + void HTTPConnection::HandleDestinationRequest (const std::string& b32, const std::string& uri) { uint8_t destination[32]; - i2p::data::Base32ToByteStream (b32.c_str (), b32.length (), destination, 32); + if (i2p::data::Base32ToByteStream (b32.c_str (), b32.length (), destination, 32) != 32) + { + LogPrint ("Invalid Base32 address ", b32); + return; + } auto leaseSet = i2p::data::netdb.FindLeaseSet (destination); if (!leaseSet || !leaseSet->HasNonExpiredLeases ()) { - i2p::data::netdb.RequestDestination (i2p::data::IdentHash (destination), true); + i2p::data::netdb.Subscribe(destination); std::this_thread::sleep_for (std::chrono::seconds(10)); // wait for 10 seconds leaseSet = i2p::data::netdb.FindLeaseSet (destination); if (!leaseSet || !leaseSet->HasNonExpiredLeases ()) // still no LeaseSet @@ -170,17 +185,10 @@ namespace util return; } } - // we found LeaseSet - if (leaseSet->HasExpiredLeases ()) - { - // we should re-request LeaseSet - LogPrint ("LeaseSet re-requested"); - i2p::data::netdb.RequestDestination (i2p::data::IdentHash (destination), true); - } - auto s = i2p::stream::CreateStream (leaseSet); + auto s = i2p::stream::CreateStream (*leaseSet); if (s) { - std::string request = "GET / HTTP/1.1\n Host:" + b32 + ".b32.i2p\n"; + std::string request = "GET " + uri + " HTTP/1.1\n Host:" + b32 + ".b32.i2p\n"; s->Send ((uint8_t *)request.c_str (), request.length (), 10); std::stringstream ss; uint8_t buf[8192]; @@ -200,7 +208,7 @@ namespace util else // nothing received ss << "Not responding"; s->Close (); - //DeleteStream (s); + DeleteStream (s); m_Reply.content = ss.str (); m_Reply.headers.resize(2); diff --git a/HTTPServer.h b/HTTPServer.h index 90aacfc0..a62a2074 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 (std::string b32); + void HandleDestinationRequest (const std::string& b32, const std::string& uri); void FillContent (std::stringstream& s); std::string ExtractAddress (); diff --git a/I2NPProtocol.cpp b/I2NPProtocol.cpp index 6503d70f..25549a09 100644 --- a/I2NPProtocol.cpp +++ b/I2NPProtocol.cpp @@ -212,7 +212,7 @@ namespace i2p const I2NPBuildRequestRecordClearText& clearText, I2NPBuildRequestRecordElGamalEncrypted& record) { - i2p::crypto::ElGamalEncrypt (router.GetRouterIdentity ().publicKey, (uint8_t *)&clearText, sizeof(clearText), record.encrypted); + router.GetElGamalEncryption ()->Encrypt ((uint8_t *)&clearText, sizeof(clearText), record.encrypted); memcpy (record.toPeer, (const uint8_t *)router.GetIdentHash (), 16); } @@ -392,7 +392,7 @@ namespace i2p LogPrint ("TunnelGateway of ", (int)len, " bytes for tunnel ", (unsigned int)tunnelID, ". Msg type ", (int)msg->GetHeader()->typeID); i2p::tunnel::TransitTunnel * tunnel = i2p::tunnel::tunnels.GetTransitTunnel (tunnelID); if (tunnel) - tunnel->SendTunnelDataMsg (nullptr, 0, msg); + tunnel->SendTunnelDataMsg (msg); else { LogPrint ("Tunnel ", (unsigned int)tunnelID, " not found"); diff --git a/I2NPProtocol.h b/I2NPProtocol.h index 3905da5b..e7c04d16 100644 --- a/I2NPProtocol.h +++ b/I2NPProtocol.h @@ -121,6 +121,15 @@ namespace i2p header->size = htobe16 (len - offset - sizeof (I2NPHeader)); header->chks = 0; } + uint32_t ToSSU () // return msgID + { + I2NPHeader header = *GetHeader (); + I2NPHeaderShort * ssu = (I2NPHeaderShort *)GetSSUHeader (); + ssu->typeID = header.typeID; + ssu->shortExpiration = htobe32 (be64toh (header.expiration)/1000LL); + len = offset + sizeof (I2NPHeaderShort) + be16toh (header.size); + return be32toh (header.msgID); + } }; I2NPMessage * NewI2NPMessage (); void DeleteI2NPMessage (I2NPMessage * msg); diff --git a/Identity.h b/Identity.h index e17b27be..10af227c 100644 --- a/Identity.h +++ b/Identity.h @@ -3,6 +3,7 @@ #include #include +#include "ElGamal.h" namespace i2p { @@ -84,9 +85,24 @@ namespace data class RoutingDestination { public: + + RoutingDestination (): m_ElGamalEncryption (nullptr) {}; + virtual ~RoutingDestination () { delete m_ElGamalEncryption; }; + virtual const IdentHash& GetIdentHash () const = 0; virtual const uint8_t * GetEncryptionPublicKey () const = 0; virtual bool IsDestination () const = 0; // for garlic + + i2p::crypto::ElGamalEncryption * GetElGamalEncryption () const + { + if (!m_ElGamalEncryption) + m_ElGamalEncryption = new i2p::crypto::ElGamalEncryption (GetEncryptionPublicKey ()); + return m_ElGamalEncryption; + } + + private: + + mutable i2p::crypto::ElGamalEncryption * m_ElGamalEncryption; // use lazy initialization }; } } diff --git a/Makefile b/Makefile index b5739c46..d9d9b4c9 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,8 @@ CFLAGS = -g -Wall -std=c++0x OBJECTS = obj/i2p.o obj/base64.o obj/NTCPSession.o obj/RouterInfo.o obj/Transports.o \ obj/RouterContext.o obj/NetDb.o obj/LeaseSet.o obj/Tunnel.o obj/TunnelEndpoint.o \ obj/TunnelGateway.o obj/TransitTunnel.o obj/I2NPProtocol.o obj/Log.o obj/Garlic.o \ - obj/HTTPServer.o obj/Streaming.o obj/Identity.o obj/SSU.o obj/util.o obj/Reseed.o + obj/HTTPServer.o obj/Streaming.o obj/Identity.o obj/SSU.o obj/util.o obj/Reseed.o \ + obj/UPnP.o INCFLAGS = LDFLAGS = -Wl,-rpath,/usr/local/lib -lcryptopp -lboost_system -lboost_filesystem -lboost_regex -lboost_program_options -lpthread LIBS = diff --git a/NTCPSession.h b/NTCPSession.h index 71cf5af9..eb31951d 100644 --- a/NTCPSession.h +++ b/NTCPSession.h @@ -60,7 +60,7 @@ namespace ntcp #pragma pack() - const int TERMINATION_TIMEOUT = 60; // 1 minute + const int TERMINATION_TIMEOUT = 120; // 2 minutes class NTCPSession { public: diff --git a/NetDb.cpp b/NetDb.cpp index 01234ad7..14a33353 100644 --- a/NetDb.cpp +++ b/NetDb.cpp @@ -25,7 +25,7 @@ namespace data 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); + msg = i2p::garlic::routing.WrapSingleMessage (*router, msg); m_ExcludedPeers.insert (router->GetIdentHash ()); m_LastRouter = router; m_LastReplyTunnel = replyTunnel; @@ -90,7 +90,7 @@ namespace data void NetDb::Run () { - uint32_t lastTs = 0; + uint32_t lastSave = 0, lastPublish = 0; m_IsRunning = true; while (m_IsRunning) { @@ -120,11 +120,19 @@ namespace data Explore (); uint64_t ts = i2p::util::GetSecondsSinceEpoch (); - if (ts - lastTs >= 60) // save routers every minute + if (ts - lastSave >= 60) // save routers and validate subscriptions every minute { - if (lastTs) + if (lastSave) + { SaveUpdated (m_NetDbPath); - lastTs = ts; + ValidateSubscriptions (); + } + lastSave = ts; + } + if (ts - lastPublish >= 600) // publish every 10 minutes + { + Publish (); + lastPublish = ts; } } catch (std::exception& ex) @@ -448,10 +456,18 @@ namespace data { auto r = FindRouter (router); // do we have that floodfill router in our database? - if (r) + if (r) { + // we do if (!dest->IsExcluded (r->GetIdentHash ()) && dest->GetNumExcludedPeers () < 30) // TODO: fix TunnelGateway first { + // tell floodfill about us + msgs.push_back (i2p::tunnel::TunnelMessageBlock + { + i2p::tunnel::eDeliveryTypeRouter, + r->GetIdentHash (), 0, + CreateDatabaseStoreMsg () + }); // request destination auto msg = dest->CreateRequestMessage (r, dest->GetLastReplyTunnel ()); msgs.push_back (i2p::tunnel::TunnelMessageBlock @@ -478,7 +494,10 @@ namespace data else // we should send directly { if (!dest->IsLeaseSet ()) // if not LeaseSet - i2p::transports.SendMessage (router, dest->CreateRequestMessage (router)); + { + if (!dest->IsExcluded (router) && dest->GetNumExcludedPeers () < 30) + i2p::transports.SendMessage (router, dest->CreateRequestMessage (router)); + } else LogPrint ("Can't request LeaseSet"); } @@ -506,16 +525,15 @@ namespace data auto inbound = i2p::tunnel::tunnels.GetNextInboundTunnel (); if (outbound && inbound) { - auto floodfill = GetRandomRouter (outbound->GetEndpointRouter (), true); + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + uint8_t randomHash[32]; + rnd.GenerateBlock (randomHash, 32); + RequestedDestination * dest = CreateRequestedDestination (IdentHash (randomHash), false, true); + dest->SetLastOutboundTunnel (outbound); + auto floodfill = GetClosestFloodfill (randomHash, dest->GetExcludedPeers ()); if (floodfill) - { + { LogPrint ("Exploring new routers ..."); - CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); - uint8_t randomHash[32]; - rnd.GenerateBlock (randomHash, 32); - RequestedDestination * dest = CreateRequestedDestination (IdentHash (randomHash), false, true); - dest->SetLastOutboundTunnel (outbound); - std::vector msgs; msgs.push_back (i2p::tunnel::TunnelMessageBlock { @@ -529,11 +547,24 @@ namespace data floodfill->GetIdentHash (), 0, dest->CreateRequestMessage (floodfill, inbound) // explore }); - outbound->SendTunnelDataMsg (msgs); + outbound->SendTunnelDataMsg (msgs); } + else + DeleteRequestedDestination (dest); } } + 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 ()); + } + } + RequestedDestination * NetDb::CreateRequestedDestination (const IdentHash& dest, bool isLeaseSet, bool isExploratory) { @@ -557,6 +588,15 @@ namespace data m_RequestedDestinations.erase (it); } } + + void NetDb::DeleteRequestedDestination (RequestedDestination * dest) + { + if (dest) + { + m_RequestedDestinations.erase (dest->GetDestination ()); + delete dest; + } + } const RouterInfo * NetDb::GetRandomNTCPRouter (bool floodfillOnly) const { @@ -626,5 +666,33 @@ namespace data return r; } + void NetDb::Subscribe (const IdentHash& ident) + { + LeaseSet * leaseSet = FindLeaseSet (ident); + if (!leaseSet) + { + LogPrint ("LeaseSet requested"); + RequestDestination (ident, true); + } + m_Subscriptions.insert (ident); + } + + void NetDb::Unsubscribe (const IdentHash& ident) + { + m_Subscriptions.erase (ident); + } + + void NetDb::ValidateSubscriptions () + { + for (auto it : m_Subscriptions) + { + LeaseSet * leaseSet = FindLeaseSet (it); + if (!leaseSet || leaseSet->HasExpiredLeases ()) + { + LogPrint ("LeaseSet re-requested"); + RequestDestination (it, true); + } + } + } } } diff --git a/NetDb.h b/NetDb.h index bcf1f23c..39f87df0 100644 --- a/NetDb.h +++ b/NetDb.h @@ -63,7 +63,9 @@ namespace data void AddLeaseSet (uint8_t * buf, int len); RouterInfo * FindRouter (const IdentHash& ident) const; LeaseSet * FindLeaseSet (const IdentHash& destination) const; - + void Subscribe (const IdentHash& ident); // keep LeaseSets upto date + void Unsubscribe (const IdentHash& ident); + void RequestDestination (const char * b32); // in base32 void RequestDestination (const IdentHash& destination, bool isLeaseSet = false); @@ -82,17 +84,21 @@ namespace data void SaveUpdated (const char * directory); void Run (); // exploratory thread void Explore (); + void Publish (); + void ValidateSubscriptions (); const RouterInfo * GetClosestFloodfill (const IdentHash& destination, const std::set& excluded) const; RequestedDestination * CreateRequestedDestination (const IdentHash& dest, bool isLeaseSet, bool isExploratory = false); void DeleteRequestedDestination (const IdentHash& dest); + void DeleteRequestedDestination (RequestedDestination * dest); private: std::map m_LeaseSets; std::map m_RouterInfos; std::map m_RequestedDestinations; + std::set m_Subscriptions; bool m_IsRunning; int m_ReseedRetries; diff --git a/Queue.h b/Queue.h index d103c57e..60829be8 100644 --- a/Queue.h +++ b/Queue.h @@ -125,7 +125,7 @@ namespace util private: std::thread m_Thread; - int running; + volatile int running; }; } } diff --git a/RouterContext.cpp b/RouterContext.cpp index 768b92a3..9b78e3e4 100644 --- a/RouterContext.cpp +++ b/RouterContext.cpp @@ -43,7 +43,7 @@ namespace i2p void RouterContext::OverrideNTCPAddress (const char * host, int port) { m_RouterInfo.CreateBuffer (); - auto address = m_RouterInfo.GetNTCPAddress (); + auto address = const_cast(m_RouterInfo.GetNTCPAddress ()); if (address) { address->host = boost::asio::ip::address::from_string (host); @@ -68,24 +68,46 @@ namespace i2p bool RouterContext::Load () { - std::ifstream fk (ROUTER_KEYS, std::ifstream::binary | std::ofstream::in); + std::string dataDir = i2p::util::filesystem::GetDataDir ().string (); +#ifndef _WIN32 + dataDir.append ("/"); +#else + dataDir.append ("\\"); +#endif + std::string router_keys = dataDir; + router_keys.append (ROUTER_KEYS); + std::string router_info = dataDir; + router_info.append (ROUTER_INFO); + + std::ifstream fk (router_keys.c_str (), std::ifstream::binary | std::ofstream::in); if (!fk.is_open ()) return false; fk.read ((char *)&m_Keys, sizeof (m_Keys)); m_SigningPrivateKey.Initialize (i2p::crypto::dsap, i2p::crypto::dsaq, i2p::crypto::dsag, CryptoPP::Integer (m_Keys.signingPrivateKey, 20)); - m_RouterInfo = i2p::data::RouterInfo (ROUTER_INFO); // TODO + m_RouterInfo = i2p::data::RouterInfo (router_info.c_str ()); // TODO return true; } void RouterContext::Save () { - std::ofstream fk (ROUTER_KEYS, std::ofstream::binary | std::ofstream::out); + std::string dataDir = i2p::util::filesystem::GetDataDir ().string (); +#ifndef _WIN32 + dataDir.append ("/"); +#else + dataDir.append ("\\"); +#endif + std::string router_keys = dataDir; + router_keys.append (ROUTER_KEYS); + std::string router_info = dataDir; + router_info.append (ROUTER_INFO); + + std::ofstream fk (router_keys.c_str (), std::ofstream::binary | std::ofstream::out); fk.write ((char *)&m_Keys, sizeof (m_Keys)); - std::ofstream fi (ROUTER_INFO, std::ofstream::binary | std::ofstream::out); + std::ofstream fi (router_info.c_str (), std::ofstream::binary | std::ofstream::out); fi.write ((char *)m_RouterInfo.GetBuffer (), m_RouterInfo.GetBufferLen ()); } } diff --git a/RouterInfo.cpp b/RouterInfo.cpp index f4668921..24ca7bb9 100644 --- a/RouterInfo.cpp +++ b/RouterInfo.cpp @@ -129,6 +129,27 @@ namespace data address.port = boost::lexical_cast(value); else if (!strcmp (key, "key")) Base64ToByteStream (value, strlen (value), address.key, 32); + else if (key[0] == 'i') + { + // introducers + size_t l = strlen(key); + unsigned char index = key[l-1]; // TODO: + key[l-1] = 0; + if (index >= address.introducers.size ()) + address.introducers.resize (index + 1); + Introducer& introducer = address.introducers.at (index); + if (!strcmp (key, "ihost")) + { + boost::system::error_code ecode; + introducer.iHost = boost::asio::ip::address::from_string (value, ecode); + } + else if (!strcmp (key, "iport")) + introducer.iPort = boost::lexical_cast(value); + else if (!strcmp (key, "itag")) + introducer.iTag = boost::lexical_cast(value); + else if (!strcmp (key, "ikey")) + Base64ToByteStream (value, strlen (value), introducer.iKey, 32); + } } m_Addresses.push_back(address); } @@ -302,18 +323,25 @@ namespace data else return m_SupportedTransports & (eSSUV4 | eSSUV6); } + + bool RouterInfo::UsesIntroducer () const + { + if (!IsSSU ()) return false; + auto address = GetSSUAddress (true); // no introducers for v6 + return address && !address->introducers.empty (); + } - RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only) + const RouterInfo::Address * RouterInfo::GetNTCPAddress (bool v4only) const { return GetAddress (eTransportNTCP, v4only); } - RouterInfo::Address * RouterInfo::GetSSUAddress (bool v4only) + const RouterInfo::Address * RouterInfo::GetSSUAddress (bool v4only) const { return GetAddress (eTransportSSU, v4only); } - RouterInfo::Address * RouterInfo::GetAddress (TransportStyle s, bool v4only) + const RouterInfo::Address * RouterInfo::GetAddress (TransportStyle s, bool v4only) const { for (auto& address : m_Addresses) { diff --git a/RouterInfo.h b/RouterInfo.h index 3b28fee7..990a0db3 100644 --- a/RouterInfo.h +++ b/RouterInfo.h @@ -32,6 +32,14 @@ namespace data eTransportSSU }; + struct Introducer + { + boost::asio::ip::address iHost; + int iPort; + uint8_t iKey[32]; + uint32_t iTag; + }; + struct Address { TransportStyle transportStyle; @@ -39,7 +47,9 @@ namespace data int port; uint64_t date; uint8_t cost; - uint8_t key[32]; // into key for SSU + // SSU only + uint8_t key[32]; // intro key for SSU + std::vector introducers; }; RouterInfo (const char * filename); @@ -54,8 +64,8 @@ namespace data const char * GetIdentHashAbbreviation () const { return m_IdentHashAbbreviation; }; uint64_t GetTimestamp () const { return m_Timestamp; }; std::vector
& GetAddresses () { return m_Addresses; }; - Address * GetNTCPAddress (bool v4only = true); - Address * GetSSUAddress (bool v4only = true); + const Address * GetNTCPAddress (bool v4only = true) const; + const Address * GetSSUAddress (bool v4only = true) const; const RoutingKey& GetRoutingKey () const { return m_RoutingKey; }; void AddNTCPAddress (const char * host, int port); @@ -65,6 +75,7 @@ namespace data bool IsNTCP (bool v4only = true) const; bool IsSSU (bool v4only = true) const; bool IsCompatible (const RouterInfo& other) const { return m_SupportedTransports & other.m_SupportedTransports; }; + bool UsesIntroducer () const; void SetUnreachable (bool unreachable) { m_IsUnreachable = unreachable; }; bool IsUnreachable () const { return m_IsUnreachable; }; @@ -91,7 +102,7 @@ namespace data size_t ReadString (char * str, std::istream& s); void WriteString (const std::string& str, std::ostream& s); void UpdateIdentHashBase64 (); - Address * GetAddress (TransportStyle s, bool v4only); + const Address * GetAddress (TransportStyle s, bool v4only) const; private: diff --git a/SSU.cpp b/SSU.cpp index 57ebdce9..4417733b 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -14,8 +14,8 @@ namespace i2p namespace ssu { - SSUSession::SSUSession (SSUServer * server, const boost::asio::ip::udp::endpoint& remoteEndpoint, - i2p::data::RouterInfo * router): m_Server (server), m_RemoteEndpoint (remoteEndpoint), + SSUSession::SSUSession (SSUServer * server, boost::asio::ip::udp::endpoint& remoteEndpoint, + const i2p::data::RouterInfo * router): m_Server (server), m_RemoteEndpoint (remoteEndpoint), m_RemoteRouter (router), m_State (eSessionStateUnknown) { } @@ -47,6 +47,7 @@ namespace ssu { switch (m_State) { + case eSessionStateConfirmedSent: case eSessionStateEstablished: // most common case ProcessMessage (buf, len); @@ -64,6 +65,15 @@ namespace ssu // session confirmed ProcessSessionConfirmed (buf, len); break; + case eSessionRelayRequestSent: + // relay response + ProcessRelayResponse (buf,len); + break; + case eSessionRelayRequestReceived: + // HolePunch + m_State = eSessionStateUnknown; + Connect (); + break; default: LogPrint ("SSU state not implemented yet"); } @@ -86,23 +96,42 @@ namespace ssu LogPrint ("SSU test received"); break; case PAYLOAD_TYPE_SESSION_DESTROYED: + { LogPrint ("SSU session destroy received"); - break; + if (m_Server) + m_Server->DeleteSession (this); // delete this + break; + } + case PAYLOAD_TYPE_RELAY_INTRO: + LogPrint ("SSU relay intro received"); + // TODO: + break; default: LogPrint ("Unexpected SSU payload type ", (int)payloadType); } } - // TODO: try intro key as well else - LogPrint ("MAC verifcation failed"); + { + LogPrint ("MAC key failed. Trying intro key"); + auto introKey = GetIntroKey (); + if (introKey && Validate (buf, len, introKey)) + { + Decrypt (buf, len, introKey); + SSUHeader * header = (SSUHeader *)buf; + LogPrint ("Unexpected SSU payload type ", (int)(header->flag >> 4)); + // TODO: + } + else + LogPrint ("MAC verifcation failed"); + m_State = eSessionStateUnknown; + } } void SSUSession::ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint) { LogPrint ("Process session request"); // use our intro key - if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_REQUEST, - i2p::context.GetRouterInfo (), buf, len)) + if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_REQUEST, buf, len)) { m_State = eSessionStateRequestReceived; LogPrint ("Session request received"); @@ -121,7 +150,7 @@ namespace ssu } // use remote intro key - if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_CREATED, *m_RemoteRouter, buf, len)) + if (ProcessIntroKeyEncryptedMessage (PAYLOAD_TYPE_SESSION_CREATED, buf, len)) { m_State = eSessionStateCreatedReceived; LogPrint ("Session created received"); @@ -132,7 +161,6 @@ namespace ssu i2p::context.UpdateAddress (ourIP.to_string ().c_str ()); uint32_t relayTag = be32toh (*(uint32_t *)(buf + sizeof (SSUHeader) + 263)); SendSessionConfirmed (buf + sizeof (SSUHeader), ourAddress, relayTag); - m_State = eSessionStateEstablished; } } @@ -146,9 +174,10 @@ namespace ssu if ((header->flag >> 4) == PAYLOAD_TYPE_SESSION_CONFIRMED) { m_State = eSessionStateConfirmedReceived; - LogPrint ("Session confirmed received"); - // TODO: + LogPrint ("Session confirmed received"); m_State = eSessionStateEstablished; + // TODO: send DeliverStatus + Established (); } else LogPrint ("Unexpected payload type ", (int)(header->flag >> 4)); @@ -159,10 +188,10 @@ namespace ssu void SSUSession::SendSessionRequest () { - auto address = m_RemoteRouter ? m_RemoteRouter->GetSSUAddress () : nullptr; - if (!address) + auto introKey = GetIntroKey (); + if (!introKey) { - LogPrint ("Missing remote SSU address"); + LogPrint ("SSU is not supported"); return; } @@ -175,18 +204,49 @@ namespace ssu uint8_t iv[16]; CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); rnd.GenerateBlock (iv, 16); // random iv - FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_REQUEST, buf, 304, address->key, iv, address->key); + FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_REQUEST, buf, 304, introKey, iv, introKey); m_State = eSessionStateRequestSent; m_Server->Send (buf, 304, m_RemoteEndpoint); } - void SSUSession::SendSessionCreated (const uint8_t * x) + void SSUSession::SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer) { - auto address = m_RemoteRouter ? m_RemoteRouter->GetSSUAddress () : nullptr; + auto address = i2p::context.GetRouterInfo ().GetSSUAddress (); if (!address) { - LogPrint ("Missing remote SSU address"); + LogPrint ("SSU is not supported"); + return; + } + + uint8_t buf[96 + 18]; + uint8_t * payload = buf + sizeof (SSUHeader); + *(uint32_t *)payload = htobe32 (introducer.iTag); + payload += 4; + *payload = 0; // no address + payload++; + *(uint16_t *)payload = 0; // port = 0 + payload += 2; + *payload = 0; // challenge + payload++; + memcpy (payload, address->key, 32); + payload += 32; + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + *(uint32_t *)payload = htobe32 (rnd.GenerateWord32 ()); // nonce + + uint8_t iv[16]; + rnd.GenerateBlock (iv, 16); // random iv + FillHeaderAndEncrypt (PAYLOAD_TYPE_RELAY_REQUEST, buf, 96, introducer.iKey, iv, introducer.iKey); + m_State = eSessionRelayRequestSent; + m_Server->Send (buf, 96, m_RemoteEndpoint); + } + + void SSUSession::SendSessionCreated (const uint8_t * x) + { + auto introKey = GetIntroKey (); + if (!introKey) + { + LogPrint ("SSU is not supported"); return; } uint8_t signedData[532]; // x,y, remote IP, remote port, our IP, our port, relayTag, signed on time @@ -222,20 +282,13 @@ namespace ssu m_Encryption.ProcessData (payload, payload, 48); // encrypt message with intro key - FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CREATED, buf, 368, address->key, iv, address->key); + FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_CREATED, buf, 368, introKey, iv, introKey); m_State = eSessionStateRequestSent; m_Server->Send (buf, 368, m_RemoteEndpoint); } void SSUSession::SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag) { - auto address = m_RemoteRouter ? m_RemoteRouter->GetSSUAddress () : nullptr; - if (!address) - { - LogPrint ("Missing remote SSU address"); - return; - } - uint8_t buf[480 + 18]; uint8_t * payload = buf + sizeof (SSUHeader); *payload = 1; // 1 fragment @@ -273,15 +326,55 @@ namespace ssu m_Server->Send (buf, 480, m_RemoteEndpoint); } - bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, i2p::data::RouterInfo& r, uint8_t * buf, size_t len) + void SSUSession::ProcessRelayResponse (uint8_t * buf, size_t len) { - auto address = r.GetSSUAddress (); - if (address) + LogPrint ("Process relay response"); + auto address = i2p::context.GetRouterInfo ().GetSSUAddress (); + if (!address) + { + LogPrint ("SSU is not supported"); + return; + } + + if (Validate (buf, len, address->key)) + { + Decrypt (buf, len, address->key); + SSUHeader * header = (SSUHeader *)buf; + if ((header->flag >> 4) == PAYLOAD_TYPE_RELAY_RESPONSE) + { + LogPrint ("Relay response received"); + m_State = eSessionRelayRequestReceived; + uint8_t * payload = buf + sizeof (SSUHeader); + payload++; + boost::asio::ip::address_v4 remoteIP (be32toh (*(uint32_t* )(payload))); + payload += 4; + uint16_t remotePort = be16toh (*(uint16_t *)(payload)); + payload += 2; + boost::asio::ip::udp::endpoint newRemoteEndpoint(remoteIP, remotePort); + m_Server->ReassignSession (m_RemoteEndpoint, newRemoteEndpoint); + m_RemoteEndpoint = newRemoteEndpoint; + payload++; + boost::asio::ip::address_v4 ourIP (be32toh (*(uint32_t* )(payload))); + payload += 4; + uint16_t ourPort = be16toh (*(uint16_t *)(payload)); + payload += 2; + LogPrint ("Our external address is ", ourIP.to_string (), ":", ourPort); + i2p::context.UpdateAddress (ourIP.to_string ().c_str ()); + } + else + LogPrint ("Unexpected payload type ", (int)(header->flag >> 4)); + } + } + + bool SSUSession::ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len) + { + auto introKey = GetIntroKey (); + if (introKey) { // use intro key for verification and decryption - if (Validate (buf, len, address->key)) + if (Validate (buf, len, introKey)) { - Decrypt (buf, len, address->key); + Decrypt (buf, len, introKey); SSUHeader * header = (SSUHeader *)buf; if ((header->flag >> 4) == expectedPayloadType) { @@ -292,14 +385,15 @@ namespace ssu LogPrint ("Unexpected payload type ", (int)(header->flag >> 4)); } else - LogPrint ("MAC verifcation failed"); + LogPrint ("MAC verification failed"); } else - LogPrint ("SSU is not supported by ", r.GetIdentHashAbbreviation ()); + LogPrint ("SSU is not supported"); return false; } - void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey) + void SSUSession::FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, + const uint8_t * aesKey, const uint8_t * iv, const uint8_t * macKey) { if (len < sizeof (SSUHeader)) { @@ -320,7 +414,7 @@ namespace ssu i2p::crypto::HMACMD5Digest (encrypted, encryptedLen + 18, macKey, header->mac); } - void SSUSession::Decrypt (uint8_t * buf, size_t len, uint8_t * aesKey) + void SSUSession::Decrypt (uint8_t * buf, size_t len, const uint8_t * aesKey) { if (len < sizeof (SSUHeader)) { @@ -335,7 +429,7 @@ namespace ssu m_Decryption.ProcessData (encrypted, encrypted, encryptedLen); } - bool SSUSession::Validate (uint8_t * buf, size_t len, uint8_t * macKey) + bool SSUSession::Validate (uint8_t * buf, size_t len, const uint8_t * macKey) { if (len < sizeof (SSUHeader)) { @@ -358,16 +452,60 @@ namespace ssu SendSessionRequest (); } + void SSUSession::ConnectThroughIntroducer (const i2p::data::RouterInfo::Introducer& introducer) + { + SendRelayRequest (introducer); + } + void SSUSession::Close () { SendSesionDestroyed (); - } - - void SSUSession::SendI2NPMessage (I2NPMessage * msg) - { - // TODO: + if (!m_DelayedMessages.empty ()) + { + for (auto it :m_DelayedMessages) + delete it; + m_DelayedMessages.clear (); + } } + void SSUSession::Established () + { + SendI2NPMessage (CreateDatabaseStoreMsg ()); + if (!m_DelayedMessages.empty ()) + { + for (auto it :m_DelayedMessages) + Send (it); + m_DelayedMessages.clear (); + } + } + + const uint8_t * SSUSession::GetIntroKey () const + { + if (m_RemoteRouter) + { + // we are client + auto address = m_RemoteRouter->GetSSUAddress (); + return address ? address->key : nullptr; + } + else + { + // we are server + auto address = i2p::context.GetRouterInfo ().GetSSUAddress (); + return address ? address->key : nullptr; + } + } + + void SSUSession::SendI2NPMessage (I2NPMessage * msg) + { + if (msg) + { + if (m_State == eSessionStateEstablished) + Send (msg); + else + m_DelayedMessages.push_back (msg); + } + } + void SSUSession::ProcessData (uint8_t * buf, size_t len) { //uint8_t * start = buf; @@ -438,11 +576,25 @@ namespace ssu m_IncomleteMessages[msgID] = msg; if (isLast) { + SendMsgAck (msgID); if (fragmentNum > 0) m_IncomleteMessages.erase (msgID); msg->FromSSU (msgID); - i2p::HandleI2NPMessage (msg, false); - SendMsgAck (msgID); + if (m_State == eSessionStateEstablished) + i2p::HandleI2NPMessage (msg, false); + else + { + // we expect DeliveryStatus + if (msg->GetHeader ()->typeID == eI2NPDeliveryStatus) + { + LogPrint ("SSU session established"); + m_State = eSessionStateEstablished; + Established (); + } + else + LogPrint ("SSU unexpected message ", (int)msg->GetHeader ()->typeID); + DeleteI2NPMessage (msg); + } } } buf += fragmentSize; @@ -474,10 +626,73 @@ namespace ssu uint8_t buf[48 + 18], iv[16]; CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); rnd.GenerateBlock (iv, 16); // random iv - // encrypt message with session key - FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48, m_SessionKey, iv, m_MacKey); + if (m_State == eSessionStateEstablished) + // encrypt message with session key + FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48, m_SessionKey, iv, m_MacKey); + else + { + auto introKey = GetIntroKey (); + if (introKey) + // encrypt message with intro key + FillHeaderAndEncrypt (PAYLOAD_TYPE_SESSION_DESTROYED, buf, 48, introKey, iv, introKey); + else + { + LogPrint ("SSU: can't send SessionDestroyed message"); + return; + } + } m_Server->Send (buf, 48, m_RemoteEndpoint); } + + void SSUSession::Send (i2p::I2NPMessage * msg) + { + uint32_t msgID = htobe32 (msg->ToSSU ()); + size_t payloadSize = SSU_MTU - sizeof (SSUHeader) - 9; // 9 = flag + #frg(1) + messageID(4) + frag info (3) + size_t len = msg->GetLength (); + uint8_t * msgBuf = msg->GetSSUHeader (); + + uint32_t fragmentNum = 0; + while (len > 0) + { + uint8_t buf[SSU_MTU + 18], iv[16], * payload = buf + sizeof (SSUHeader); + *payload = DATA_FLAG_WANT_REPLY; // for compatibility + payload++; + *payload = 1; // always 1 message fragment per message + payload++; + *(uint32_t *)payload = msgID; + payload += 4; + bool isLast = (len <= payloadSize); + size_t size = isLast ? len : payloadSize; + uint32_t fragmentInfo = (fragmentNum << 17); + if (isLast) + fragmentInfo |= 0x010000; + + fragmentInfo |= size; + fragmentInfo = htobe32 (fragmentInfo); + memcpy (payload, (uint8_t *)(&fragmentInfo) + 1, 3); + payload += 3; + memcpy (payload, msgBuf, size); + + size += payload - buf; + if (size % 16) // make sure 16 bytes boundary + size = (size/16 + 1)*16; + + CryptoPP::RandomNumberGenerator& rnd = i2p::context.GetRandomNumberGenerator (); + rnd.GenerateBlock (iv, 16); // random iv + // encrypt message with session key + FillHeaderAndEncrypt (PAYLOAD_TYPE_DATA, buf, size, m_SessionKey, iv, m_MacKey); + m_Server->Send (buf, size, m_RemoteEndpoint); + + if (!isLast) + { + len -= payloadSize; + msgBuf += payloadSize; + } + else + len = 0; + fragmentNum++; + } + } SSUServer::SSUServer (boost::asio::io_service& service, int port): m_Endpoint (boost::asio::ip::udp::v4 (), port), m_Socket (service, m_Endpoint) @@ -499,12 +714,14 @@ namespace ssu void SSUServer::Stop () { + DeleteAllSessions (); m_Socket.close (); } void SSUServer::Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to) { m_Socket.send_to (boost::asio::buffer (buf, len), to); + LogPrint ("SSU sent ", len, " bytes"); } void SSUServer::Receive () @@ -535,7 +752,7 @@ namespace ssu LogPrint ("SSU receive error: ", ecode.message ()); } - SSUSession * SSUServer::GetSession (i2p::data::RouterInfo * router) + SSUSession * SSUServer::GetSession (const i2p::data::RouterInfo * router) { SSUSession * session = nullptr; if (router) @@ -549,12 +766,27 @@ namespace ssu session = it->second; else { - // otherwise create new session - session = new SSUSession (this, remoteEndpoint, router); - m_Sessions[remoteEndpoint] = session; - LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (), "] ", - remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port (), " created"); - session->Connect (); + // otherwise create new session + if (!router->UsesIntroducer ()) + { + // connect directly + session = new SSUSession (this, remoteEndpoint, router); + m_Sessions[remoteEndpoint] = session; + LogPrint ("New SSU session to [", router->GetIdentHashAbbreviation (), "] ", + remoteEndpoint.address ().to_string (), ":", remoteEndpoint.port (), " created"); + session->Connect (); + } + 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); + } } } else @@ -581,6 +813,18 @@ namespace ssu delete it.second; } m_Sessions.clear (); + } + + void SSUServer::ReassignSession (const boost::asio::ip::udp::endpoint& oldEndpoint, const boost::asio::ip::udp::endpoint& newEndpoint) + { + auto it = m_Sessions.find (oldEndpoint); + if (it != m_Sessions.end ()) + { + m_Sessions.erase (it); + m_Sessions[newEndpoint] = it->second; + LogPrint ("SSU session ressigned from ", oldEndpoint.address ().to_string (), ":", oldEndpoint.port (), + " to ", newEndpoint.address ().to_string (), ":", newEndpoint.port ()); + } } } } diff --git a/SSU.h b/SSU.h index 15467262..f5efc862 100644 --- a/SSU.h +++ b/SSU.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -54,6 +55,8 @@ namespace ssu eSessionStateCreatedReceived, eSessionStateConfirmedSent, eSessionStateConfirmedReceived, + eSessionRelayRequestSent, + eSessionRelayRequestReceived, eSessionStateEstablished }; @@ -62,11 +65,12 @@ namespace ssu { public: - SSUSession (SSUServer * server, const boost::asio::ip::udp::endpoint& remoteEndpoint, - i2p::data::RouterInfo * router = nullptr); + SSUSession (SSUServer * server, boost::asio::ip::udp::endpoint& remoteEndpoint, + const i2p::data::RouterInfo * router = nullptr); void ProcessNextMessage (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void Connect (); + void ConnectThroughIntroducer (const i2p::data::RouterInfo::Introducer& introducer); void Close (); boost::asio::ip::udp::endpoint& GetRemoteEndpoint () { return m_RemoteEndpoint; }; void SendI2NPMessage (I2NPMessage * msg); @@ -78,29 +82,35 @@ namespace ssu void ProcessMessage (uint8_t * buf, size_t len); // call for established session void ProcessSessionRequest (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& senderEndpoint); void SendSessionRequest (); + void SendRelayRequest (const i2p::data::RouterInfo::Introducer& introducer); void ProcessSessionCreated (uint8_t * buf, size_t len); void SendSessionCreated (const uint8_t * x); void ProcessSessionConfirmed (uint8_t * buf, size_t len); void SendSessionConfirmed (const uint8_t * y, const uint8_t * ourAddress, uint32_t relayTag); + void ProcessRelayResponse (uint8_t * buf, size_t len); + void Established (); void ProcessData (uint8_t * buf, size_t len); void SendMsgAck (uint32_t msgID); void SendSesionDestroyed (); + void Send (i2p::I2NPMessage * msg); - bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, i2p::data::RouterInfo& r, uint8_t * buf, size_t len); - void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, uint8_t * aesKey, uint8_t * iv, uint8_t * macKey); - void Decrypt (uint8_t * buf, size_t len, uint8_t * aesKey); - bool Validate (uint8_t * buf, size_t len, uint8_t * macKey); + bool ProcessIntroKeyEncryptedMessage (uint8_t expectedPayloadType, uint8_t * buf, size_t len); + void FillHeaderAndEncrypt (uint8_t payloadType, uint8_t * buf, size_t len, const uint8_t * aesKey, const uint8_t * iv, const uint8_t * macKey); + void Decrypt (uint8_t * buf, size_t len, const uint8_t * aesKey); + bool Validate (uint8_t * buf, size_t len, const uint8_t * macKey); + const uint8_t * GetIntroKey () const; private: SSUServer * m_Server; boost::asio::ip::udp::endpoint m_RemoteEndpoint; - i2p::data::RouterInfo * m_RemoteRouter; + const i2p::data::RouterInfo * m_RemoteRouter; SessionState m_State; CryptoPP::CBC_Mode::Encryption m_Encryption; CryptoPP::CBC_Mode::Decryption m_Decryption; uint8_t m_SessionKey[32], m_MacKey[32]; std::map m_IncomleteMessages; + std::list m_DelayedMessages; }; class SSUServer @@ -111,12 +121,13 @@ namespace ssu ~SSUServer (); void Start (); void Stop (); - SSUSession * GetSession (i2p::data::RouterInfo * router); + SSUSession * GetSession (const i2p::data::RouterInfo * router); void DeleteSession (SSUSession * session); - void DeleteAllSessions (); - + void DeleteAllSessions (); + const boost::asio::ip::udp::endpoint& GetEndpoint () const { return m_Endpoint; }; void Send (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& to); + void ReassignSession (const boost::asio::ip::udp::endpoint& oldEndpoint, const boost::asio::ip::udp::endpoint& newEndpoint); private: diff --git a/Streaming.cpp b/Streaming.cpp index 05f838fa..6caa2a0f 100644 --- a/Streaming.cpp +++ b/Streaming.cpp @@ -14,7 +14,7 @@ namespace i2p { namespace stream { - Stream::Stream (StreamingDestination * local, const i2p::data::LeaseSet * remote): + Stream::Stream (StreamingDestination * local, const i2p::data::LeaseSet& remote): m_SendStreamID (0), m_SequenceNumber (0), m_LastReceivedSequenceNumber (0), m_IsOpen (false), m_LocalDestination (local), m_RemoteLeaseSet (remote), m_OutboundTunnel (nullptr) { @@ -172,7 +172,7 @@ namespace stream if (!m_OutboundTunnel) m_OutboundTunnel = i2p::tunnel::tunnels.GetNextOutboundTunnel (); - auto leases = m_RemoteLeaseSet->GetNonExpiredLeases (); + auto leases = m_RemoteLeaseSet.GetNonExpiredLeases (); if (m_OutboundTunnel && !leases.empty ()) { auto& lease = *leases.begin (); // TODO: @@ -206,7 +206,7 @@ namespace stream CreateDataMessage (this, packet, size)); if (m_OutboundTunnel) { - auto leases = m_RemoteLeaseSet->GetNonExpiredLeases (); + auto leases = m_RemoteLeaseSet.GetNonExpiredLeases (); if (!leases.empty ()) { auto& lease = *leases.begin (); // TODO: @@ -252,7 +252,7 @@ namespace stream I2NPMessage * msg = i2p::garlic::routing.WrapSingleMessage (m_RemoteLeaseSet, CreateDataMessage (this, packet, size)); - auto leases = m_RemoteLeaseSet->GetNonExpiredLeases (); + auto leases = m_RemoteLeaseSet.GetNonExpiredLeases (); if (m_OutboundTunnel && !leases.empty ()) { auto& lease = *leases.begin (); // TODO: @@ -318,7 +318,7 @@ namespace stream void StreamingDestination::HandleNextPacket (Packet * packet) { - uint32_t sendStreamID = be32toh (*(uint32_t *)(packet->buf)); + uint32_t sendStreamID = packet->GetSendStreamID (); auto it = m_Streams.find (sendStreamID); if (it != m_Streams.end ()) it->second->HandleNextPacket (packet); @@ -329,7 +329,7 @@ namespace stream } } - Stream * StreamingDestination::CreateNewStream (const i2p::data::LeaseSet * remote) + Stream * StreamingDestination::CreateNewStream (const i2p::data::LeaseSet& remote) { Stream * s = new Stream (this, remote); m_Streams[s->GetRecvStreamID ()] = s; @@ -399,7 +399,7 @@ namespace stream signer.SignMessage (i2p::context.GetRandomNumberGenerator (), buf, len, signature); } - Stream * CreateStream (const i2p::data::LeaseSet * remote) + Stream * CreateStream (const i2p::data::LeaseSet& remote) { if (!sharedLocalDestination) sharedLocalDestination = new StreamingDestination (); diff --git a/Streaming.h b/Streaming.h index 18d09b5d..4e33d111 100644 --- a/Streaming.h +++ b/Streaming.h @@ -65,11 +65,11 @@ namespace stream { public: - Stream (StreamingDestination * local, const i2p::data::LeaseSet * remote); + Stream (StreamingDestination * local, const i2p::data::LeaseSet& remote); ~Stream (); uint32_t GetSendStreamID () const { return m_SendStreamID; }; uint32_t GetRecvStreamID () const { return m_RecvStreamID; }; - const i2p::data::LeaseSet * GetRemoteLeaseSet () const { return m_RemoteLeaseSet; }; + const i2p::data::LeaseSet& GetRemoteLeaseSet () const { return m_RemoteLeaseSet; }; bool IsOpen () const { return m_IsOpen; }; bool IsEstablished () const { return m_SendStreamID; }; @@ -91,7 +91,7 @@ namespace stream uint32_t m_SendStreamID, m_RecvStreamID, m_SequenceNumber, m_LastReceivedSequenceNumber; bool m_IsOpen; StreamingDestination * m_LocalDestination; - const i2p::data::LeaseSet * m_RemoteLeaseSet; + const i2p::data::LeaseSet& m_RemoteLeaseSet; i2p::util::Queue m_ReceiveQueue; std::set m_SavedPackets; i2p::tunnel::OutboundTunnel * m_OutboundTunnel; @@ -109,7 +109,7 @@ namespace stream I2NPMessage * GetLeaseSet (); void Sign (uint8_t * buf, int len, uint8_t * signature) const; - Stream * CreateNewStream (const i2p::data::LeaseSet * remote); + Stream * CreateNewStream (const i2p::data::LeaseSet& remote); void DeleteStream (Stream * stream); void HandleNextPacket (Packet * packet); @@ -129,7 +129,7 @@ namespace stream CryptoPP::DSA::PrivateKey m_SigningPrivateKey; }; - Stream * CreateStream (const i2p::data::LeaseSet * remote); + Stream * CreateStream (const i2p::data::LeaseSet& remote); void DeleteStream (Stream * stream); // assuming data is I2CP message diff --git a/TransitTunnel.cpp b/TransitTunnel.cpp index 6c9a4f6f..a96f3d05 100644 --- a/TransitTunnel.cpp +++ b/TransitTunnel.cpp @@ -47,15 +47,18 @@ namespace tunnel m_NumTransmittedBytes += tunnelMsg->GetLength (); } - void TransitTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) + void TransitTunnel::SendTunnelDataMsg (i2p::I2NPMessage * msg) { LogPrint ("We are not a gateway for transit tunnel ", m_TunnelID); i2p::DeleteI2NPMessage (msg); } - void TransitTunnelGateway::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) + void TransitTunnelGateway::SendTunnelDataMsg (i2p::I2NPMessage * msg) { - m_Gateway.SendTunnelDataMsg (gwHash, gwTunnel, msg); + TunnelMessageBlock block; + block.deliveryType = eDeliveryTypeLocal; + block.data = msg; + m_Gateway.SendTunnelDataMsg (block); } void TransitTunnelEndpoint::HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg) diff --git a/TransitTunnel.h b/TransitTunnel.h index 570429f5..feeeaa58 100644 --- a/TransitTunnel.h +++ b/TransitTunnel.h @@ -22,7 +22,7 @@ namespace tunnel const uint8_t * layerKey,const uint8_t * ivKey); virtual void HandleTunnelDataMsg (i2p::I2NPMessage * tunnelMsg); - virtual void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); + virtual void SendTunnelDataMsg (i2p::I2NPMessage * msg); virtual size_t GetNumTransmittedBytes () const { return m_NumTransmittedBytes; }; uint32_t GetTunnelID () const { return m_TunnelID; }; @@ -54,7 +54,7 @@ namespace tunnel TransitTunnel (receiveTunnelID, nextIdent, nextTunnelID, layerKey, ivKey), m_Gateway(this) {}; - void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); + void SendTunnelDataMsg (i2p::I2NPMessage * msg); size_t GetNumTransmittedBytes () const { return m_Gateway.GetNumSentBytes (); }; private: diff --git a/Transports.cpp b/Transports.cpp index cf990bcc..cc56a86f 100644 --- a/Transports.cpp +++ b/Transports.cpp @@ -55,8 +55,7 @@ namespace i2p } } - // TODO: do it for SSU only - DetectExternalIP (); + //DetectExternalIP (); } void Transports::Stop () @@ -65,9 +64,12 @@ namespace i2p delete session.second; m_NTCPSessions.clear (); delete m_NTCPAcceptor; - - m_Timer->cancel(); - delete m_Timer; + + if (m_Timer) + { + m_Timer->cancel (); + delete m_Timer; + } if (m_SSUServer) { @@ -169,7 +171,23 @@ namespace i2p AddNTCPSession (session); } else - LogPrint ("No NTCP addresses available"); + { + // SSU always have lower prioprity than NTCP + // TODO: it shouldn't + LogPrint ("No NTCP addresses available. Trying SSU"); + address = r->GetSSUAddress (); + if (address && m_SSUServer) + { + auto s = m_SSUServer->GetSession (r); + if (s) + { + s->SendI2NPMessage (msg); + return; + } + } + else + LogPrint ("No SSU addresses available"); + } } else { @@ -189,7 +207,7 @@ namespace i2p { auto router = i2p::data::netdb.GetRandomRouter (); if (router && router->IsSSU () && m_SSUServer) - m_SSUServer->GetSession (const_cast(router)); //TODO + m_SSUServer->GetSession (router); } if (m_Timer) { diff --git a/Tunnel.cpp b/Tunnel.cpp index 1163f47e..9d58c875 100644 --- a/Tunnel.cpp +++ b/Tunnel.cpp @@ -136,28 +136,28 @@ namespace tunnel void OutboundTunnel::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) { - m_Gateway.SendTunnelDataMsg (gwHash, gwTunnel, msg); + TunnelMessageBlock block; + if (gwHash) + { + block.hash = gwHash; + if (gwTunnel) + { + block.deliveryType = eDeliveryTypeTunnel; + block.tunnelID = gwTunnel; + } + else + block.deliveryType = eDeliveryTypeRouter; + } + else + block.deliveryType = eDeliveryTypeLocal; + block.data = msg; + m_Gateway.SendTunnelDataMsg (block); } void OutboundTunnel::SendTunnelDataMsg (std::vector msgs) { for (auto& it : msgs) - { - switch (it.deliveryType) - { - case eDeliveryTypeLocal: - m_Gateway.SendTunnelDataMsg (nullptr, 0, it.data); - break; - case eDeliveryTypeTunnel: - m_Gateway.SendTunnelDataMsg (it.hash, it.tunnelID, it.data); - break; - case eDeliveryTypeRouter: - m_Gateway.SendTunnelDataMsg (it.hash, 0, it.data); - break; - default: - LogPrint ("Unexpected delivery type ", (int)it.deliveryType); - } - } + m_Gateway.PutTunnelDataMsg (it); m_Gateway.SendBuffer (); } diff --git a/Tunnel.h b/Tunnel.h index 3498eae3..7e7f94d5 100644 --- a/Tunnel.h +++ b/Tunnel.h @@ -21,7 +21,7 @@ namespace i2p { namespace tunnel { - const int TUNNEL_EXPIRATION_TIMEOUT = 600; // 10 minutes + const int TUNNEL_EXPIRATION_TIMEOUT = 660; // 11 minutes class OutboundTunnel; class InboundTunnel; diff --git a/TunnelGateway.cpp b/TunnelGateway.cpp index 55d78326..cc1189e0 100644 --- a/TunnelGateway.cpp +++ b/TunnelGateway.cpp @@ -10,7 +10,7 @@ namespace i2p { namespace tunnel { - void TunnelGatewayBuffer::PutI2NPMsg (const uint8_t * gwHash, uint32_t gwTunnel, I2NPMessage * msg) + void TunnelGatewayBuffer::PutI2NPMsg (const TunnelMessageBlock& block) { if (!m_CurrentTunnelDataMsg) CreateCurrentTunnelDataMessage (); @@ -18,24 +18,21 @@ namespace tunnel // create delivery instructions uint8_t di[43]; // max delivery instruction length is 43 for tunnel size_t diLen = 1;// flag - TunnelDeliveryType dt = eDeliveryTypeLocal; - if (gwHash) + if (block.deliveryType != eDeliveryTypeLocal) // tunnel or router { - if (gwTunnel) + if (block.deliveryType == eDeliveryTypeTunnel) { - *(uint32_t *)(di + diLen) = htobe32 (gwTunnel); + *(uint32_t *)(di + diLen) = htobe32 (block.tunnelID); diLen += 4; // tunnelID - dt = eDeliveryTypeTunnel; } - else - dt = eDeliveryTypeRouter; - memcpy (di + diLen, gwHash, 32); + memcpy (di + diLen, block.hash, 32); diLen += 32; //len } - di[0] = dt << 5; // set delivery type + di[0] = block.deliveryType << 5; // set delivery type // create fragments + I2NPMessage * msg = block.data; if (diLen + msg->GetLength () + 2<= m_RemainingSize) { // message fits. First and last fragment @@ -104,7 +101,7 @@ namespace tunnel { // delivery instructions don't fit. Create new message CompleteCurrentTunnelDataMessage (); - PutI2NPMsg (gwHash, gwTunnel, msg); + PutI2NPMsg (block); // don't delete msg because it's taken care inside } } @@ -152,15 +149,15 @@ namespace tunnel m_CurrentTunnelDataMsg = nullptr; } - void TunnelGateway::SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) + void TunnelGateway::SendTunnelDataMsg (const TunnelMessageBlock& block) { - PutTunnelDataMsg (gwHash, gwTunnel, msg); + PutTunnelDataMsg (block); SendBuffer (); } - void TunnelGateway::PutTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg) + void TunnelGateway::PutTunnelDataMsg (const TunnelMessageBlock& block) { - m_Buffer.PutI2NPMsg (gwHash, gwTunnel, msg); + m_Buffer.PutI2NPMsg (block); } void TunnelGateway::SendBuffer () diff --git a/TunnelGateway.h b/TunnelGateway.h index d68c8580..8c390eef 100644 --- a/TunnelGateway.h +++ b/TunnelGateway.h @@ -15,7 +15,7 @@ namespace tunnel public: TunnelGatewayBuffer (uint32_t tunnelID): m_TunnelID (tunnelID), m_CurrentTunnelDataMsg (nullptr), m_RemainingSize (0) {}; - void PutI2NPMsg (const uint8_t * gwHash, uint32_t gwTunnel, I2NPMessage * msg); + void PutI2NPMsg (const TunnelMessageBlock& block); std::vector GetTunnelDataMsgs (); private: @@ -37,8 +37,8 @@ namespace tunnel TunnelGateway (TunnelBase * tunnel): m_Tunnel (tunnel), m_Buffer (tunnel->GetNextTunnelID ()), m_NumSentBytes (0) {}; - void SendTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); - void PutTunnelDataMsg (const uint8_t * gwHash, uint32_t gwTunnel, i2p::I2NPMessage * msg); + void SendTunnelDataMsg (const TunnelMessageBlock& block); + void PutTunnelDataMsg (const TunnelMessageBlock& block); void SendBuffer (); size_t GetNumSentBytes () const { return m_NumSentBytes; }; diff --git a/UPnP.cpp b/UPnP.cpp new file mode 100644 index 00000000..ebadc80f --- /dev/null +++ b/UPnP.cpp @@ -0,0 +1,68 @@ +#include +#include +#include +#include "Log.h" +#include "UPnP.h" + +namespace i2p +{ + UPnP::UPnP (): m_Timer (m_Service), + m_Endpoint (boost::asio::ip::udp::v4 (), UPNP_REPLY_PORT), + m_MulticastEndpoint (boost::asio::ip::address::from_string (UPNP_GROUP), UPNP_PORT), + m_Socket (m_Service, m_Endpoint.protocol ()) + { + m_Socket.set_option (boost::asio::socket_base::receive_buffer_size (65535)); + m_Socket.set_option (boost::asio::socket_base::send_buffer_size (65535)); + m_Socket.set_option(boost::asio::ip::udp::socket::reuse_address(true)); + } + + UPnP::~UPnP () + { + } + + void UPnP::Run () + { + DiscoverRouter (); + m_Service.run (); + } + + void UPnP::DiscoverRouter () + { + m_Timer.expires_from_now (boost::posix_time::seconds(5)); // 5 seconds + m_Timer.async_wait (boost::bind (&UPnP::HandleTimer, this, boost::asio::placeholders::error)); + + std::string address = UPNP_GROUP; + address += ":" + boost::lexical_cast(UPNP_PORT); + std::string request = "M-SEARCH * HTTP/1.1\r\n" + "HOST: " + address + "\r\n" + "ST:" + UPNP_ROUTER + "\r\n" + "MAN:\"ssdp:discover\"\r\n" + "MX:3\r\n" + "\r\n\r\n"; + m_Socket.send_to (boost::asio::buffer (request.c_str (), request.length ()), m_MulticastEndpoint); + Receive (); + } + + void UPnP::Receive () + { + m_Socket.async_receive_from (boost::asio::buffer (m_ReceiveBuffer, UPNP_MAX_PACKET_LEN), m_SenderEndpoint, + boost::bind (&UPnP::HandleReceivedFrom, this, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)); + } + + void UPnP::HandleReceivedFrom (const boost::system::error_code& ecode, size_t bytes_transferred) + { + LogPrint ("UPnP: ", bytes_transferred, " received from ", m_SenderEndpoint.address ()); + std::string str (m_ReceiveBuffer, bytes_transferred); + LogPrint (str); + m_Timer.cancel (); + } + + void UPnP::HandleTimer (const boost::system::error_code& ecode) + { + if (ecode != boost::asio::error::operation_aborted) + { + LogPrint ("UPnP: timeout expired"); + m_Service.stop (); + } + } +} diff --git a/UPnP.h b/UPnP.h new file mode 100644 index 00000000..3b5122d1 --- /dev/null +++ b/UPnP.h @@ -0,0 +1,41 @@ +#ifndef UPNP_H__ +#define UPNP_H__ + +#include + +namespace i2p +{ + const int UPNP_MAX_PACKET_LEN = 1500; + const char UPNP_GROUP[] = "239.255.255.250"; + const int UPNP_PORT = 1900; + const int UPNP_REPLY_PORT = 1901; + const char UPNP_ROUTER[] = "urn:schemas-upnp-org:device:InternetGatewayDevice:1"; + + class UPnP + { + public: + + UPnP (); + ~UPnP (); + + void Run (); + + + private: + + void DiscoverRouter (); + void Receive (); + void HandleReceivedFrom (const boost::system::error_code& ecode, size_t bytes_transferred); + void HandleTimer (const boost::system::error_code& ecode); + + private: + + boost::asio::io_service m_Service; + boost::asio::deadline_timer m_Timer; + boost::asio::ip::udp::endpoint m_Endpoint, m_MulticastEndpoint, m_SenderEndpoint; + boost::asio::ip::udp::socket m_Socket; + char m_ReceiveBuffer[UPNP_MAX_PACKET_LEN]; + }; +} + +#endif diff --git a/hmac.h b/hmac.h index 6e9c042b..971b9f1a 100644 --- a/hmac.h +++ b/hmac.h @@ -13,7 +13,7 @@ namespace crypto const uint64_t IPAD = 0x3636363636363636; const uint64_t OPAD = 0x5C5C5C5C5C5C5C5C; - inline void HMACMD5Digest (uint8_t * msg, size_t len, uint8_t * key, uint8_t * digest) + inline void HMACMD5Digest (uint8_t * msg, size_t len, const uint8_t * key, uint8_t * digest) // key is 32 bytes // digest is 16 bytes // block size is 64 bytes diff --git a/i2p.cpp b/i2p.cpp index 3339b4ee..496971c4 100644 --- a/i2p.cpp +++ b/i2p.cpp @@ -48,8 +48,8 @@ #endif // Global -int running = 1; -int isDaemon; +volatile int running = 1; +volatile int isDaemon; #ifndef _WIN32 void handle_signal(int sig) @@ -82,7 +82,7 @@ void handle_signal(int sig) int main( int argc, char* argv[] ) { i2p::util::config::OptionParser(argc,argv); - isDaemon = i2p::util::config::GetArg("-daemon", 0); + volatile int isDaemon = i2p::util::config::GetArg("-daemon", 0); #ifdef _WIN32 setlocale(LC_CTYPE, ""); SetConsoleCP(1251); @@ -139,7 +139,8 @@ int main( int argc, char* argv[] ) } #endif - int isLogging = i2p::util::config::GetArg("-log", 0); + volatile int isLogging = i2p::util::config::GetArg("-log", 0); + if (isLogging == 1) { std::string logfile = i2p::util::filesystem::GetDataDir().string();