diff --git a/ClientContext.h b/ClientContext.h index 73001934..db74a19e 100644 --- a/ClientContext.h +++ b/ClientContext.h @@ -66,6 +66,7 @@ namespace client AddressBook& GetAddressBook () { return m_AddressBook; }; const SAMBridge * GetSAMBridge () const { return m_SamBridge; }; + const I2CPServer * GetI2CPServer () const { return m_I2CPServer; }; std::vector > GetForwardInfosFor(const i2p::data::IdentHash & destination); diff --git a/Config.cpp b/Config.cpp index fb587e61..d8dd6a27 100644 --- a/Config.cpp +++ b/Config.cpp @@ -163,7 +163,7 @@ namespace config { reseed.add_options() ("reseed.verify", value()->default_value(false), "Verify .su3 signature") ("reseed.floodfill", value()->default_value(""), "Path to router info of floodfill to reseed from") - ("reseed.file", value()->default_value(""), "Path to .su3 file") + ("reseed.file", value()->default_value(""), "Path to local .su3 file or HTTPS URL to reseed from") ("reseed.urls", value()->default_value( "https://reseed.i2p-projekt.de/," "https://i2p.mooo.com/netDb/," diff --git a/Crypto.cpp b/Crypto.cpp index f9478646..54180677 100644 --- a/Crypto.cpp +++ b/Crypto.cpp @@ -595,16 +595,16 @@ namespace crypto "jnz 1b \n" "movups %%xmm1, (%[iv]) \n" : - : [iv]"r"(&m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()), + : [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()), [in]"r"(in), [out]"r"(out), [num]"r"(numBlocks) : "%xmm0", "%xmm1", "cc", "memory" ); #else for (int i = 0; i < numBlocks; i++) { - m_LastBlock ^= in[i]; - m_ECBEncryption.Encrypt (&m_LastBlock, &m_LastBlock); - out[i] = m_LastBlock; + *m_LastBlock.GetChipherBlock () ^= in[i]; + m_ECBEncryption.Encrypt (m_LastBlock.GetChipherBlock (), m_LastBlock.GetChipherBlock ()); + out[i] = *m_LastBlock.GetChipherBlock (); } #endif } @@ -629,7 +629,7 @@ namespace crypto "movups %%xmm0, (%[out]) \n" "movups %%xmm0, (%[iv]) \n" : - : [iv]"r"(&m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()), + : [iv]"r"((uint8_t *)m_LastBlock), [sched]"r"(m_ECBEncryption.GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "%xmm1", "memory" ); @@ -657,7 +657,7 @@ namespace crypto "jnz 1b \n" "movups %%xmm1, (%[iv]) \n" : - : [iv]"r"(&m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()), + : [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()), [in]"r"(in), [out]"r"(out), [num]"r"(numBlocks) : "%xmm0", "%xmm1", "%xmm2", "cc", "memory" ); @@ -666,8 +666,8 @@ namespace crypto { ChipherBlock tmp = in[i]; m_ECBDecryption.Decrypt (in + i, out + i); - out[i] ^= m_IV; - m_IV = tmp; + out[i] ^= *m_IV.GetChipherBlock (); + *m_IV.GetChipherBlock () = tmp; } #endif } @@ -691,7 +691,7 @@ namespace crypto "pxor %%xmm1, %%xmm0 \n" "movups %%xmm0, (%[out]) \n" : - : [iv]"r"(&m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()), + : [iv]"r"((uint8_t *)m_IV), [sched]"r"(m_ECBDecryption.GetKeySchedule ()), [in]"r"(in), [out]"r"(out) : "%xmm0", "%xmm1", "memory" ); diff --git a/Crypto.h b/Crypto.h index 476d2a26..b9d25216 100644 --- a/Crypto.h +++ b/Crypto.h @@ -112,7 +112,9 @@ namespace crypto operator uint8_t * () { return m_Buf; }; operator const uint8_t * () const { return m_Buf; }; - + ChipherBlock * GetChipherBlock () { return (ChipherBlock *)m_Buf; }; + const ChipherBlock * GetChipherBlock () const { return (const ChipherBlock *)m_Buf; }; + private: uint8_t m_UnalignedBuffer[sz + 15]; // up to 15 bytes alignment @@ -200,10 +202,10 @@ namespace crypto { public: - CBCEncryption () { memset (m_LastBlock.buf, 0, 16); }; + CBCEncryption () { memset ((uint8_t *)m_LastBlock, 0, 16); }; void SetKey (const AESKey& key) { m_ECBEncryption.SetKey (key); }; // 32 bytes - void SetIV (const uint8_t * iv) { memcpy (m_LastBlock.buf, iv, 16); }; // 16 bytes + void SetIV (const uint8_t * iv) { memcpy ((uint8_t *)m_LastBlock, iv, 16); }; // 16 bytes void Encrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out); void Encrypt (const uint8_t * in, std::size_t len, uint8_t * out); @@ -211,7 +213,7 @@ namespace crypto private: - ChipherBlock m_LastBlock; + AESAlignedBuffer<16> m_LastBlock; ECBEncryption m_ECBEncryption; }; @@ -220,10 +222,10 @@ namespace crypto { public: - CBCDecryption () { memset (m_IV.buf, 0, 16); }; + CBCDecryption () { memset ((uint8_t *)m_IV, 0, 16); }; void SetKey (const AESKey& key) { m_ECBDecryption.SetKey (key); }; // 32 bytes - void SetIV (const uint8_t * iv) { memcpy (m_IV.buf, iv, 16); }; // 16 bytes + void SetIV (const uint8_t * iv) { memcpy ((uint8_t *)m_IV, iv, 16); }; // 16 bytes void Decrypt (int numBlocks, const ChipherBlock * in, ChipherBlock * out); void Decrypt (const uint8_t * in, std::size_t len, uint8_t * out); @@ -231,7 +233,7 @@ namespace crypto private: - ChipherBlock m_IV; + AESAlignedBuffer<16> m_IV; ECBDecryption m_ECBDecryption; }; @@ -320,8 +322,6 @@ inline int DH_set0_key(DH *dh, BIGNUM *pub_key, BIGNUM *priv_key) inline void DH_get0_key(const DH *dh, const BIGNUM **pub_key, const BIGNUM **priv_key) { *pub_key = dh->pub_key; *priv_key = dh->priv_key; } -inline int EVP_PKEY_base_id(const EVP_PKEY *pkey) - { return EVP_PKEY_type(pkey->type); } inline RSA *EVP_PKEY_get0_RSA(EVP_PKEY *pkey) { return pkey->pkey.rsa; } #endif diff --git a/Daemon.cpp b/Daemon.cpp index 9c0d15f8..a007995f 100644 --- a/Daemon.cpp +++ b/Daemon.cpp @@ -113,7 +113,6 @@ namespace i2p } else { // use stdout -- default } - i2p::log::Logger().Ready(); LogPrint(eLogInfo, "i2pd v", VERSION, " starting"); LogPrint(eLogDebug, "FS: main config file: ", config); @@ -246,6 +245,7 @@ namespace i2p bool Daemon_Singleton::start() { + i2p::log::Logger().Start(); LogPrint(eLogInfo, "Daemon: starting NetDB"); i2p::data::netdb.Start(); @@ -351,6 +351,7 @@ namespace i2p } #endif i2p::crypto::TerminateCrypto (); + i2p::log::Logger().Stop(); return true; } diff --git a/Destination.cpp b/Destination.cpp index f0bc52cb..7b2e896d 100644 --- a/Destination.cpp +++ b/Destination.cpp @@ -86,7 +86,7 @@ namespace client if (m_IsRunning) Stop (); for (auto& it: m_LeaseSetRequests) - if (it.second->requestComplete) it.second->requestComplete (nullptr); + it.second->Complete (nullptr); m_LeaseSetRequests.clear (); if (m_Pool) i2p::tunnel::tunnels.DeleteTunnelPool (m_Pool); @@ -345,7 +345,7 @@ namespace client if (it1 != m_LeaseSetRequests.end ()) { it1->second->requestTimeoutTimer.cancel (); - if (it1->second->requestComplete) it1->second->requestComplete (leaseSet); + if (it1->second) it1->second->Complete (leaseSet); m_LeaseSetRequests.erase (it1); } } @@ -383,7 +383,7 @@ namespace client if (!found) { LogPrint (eLogInfo, "Destination: ", key.ToBase64 (), " was not found on ", MAX_NUM_FLOODFILLS_PER_REQUEST, " floodfills"); - if (request->requestComplete) request->requestComplete (nullptr); + request->Complete (nullptr); m_LeaseSetRequests.erase (key); } } @@ -512,9 +512,9 @@ namespace client auto it = s->m_LeaseSetRequests.find (dest); if (it != s->m_LeaseSetRequests.end ()) { - auto requestComplete = it->second->requestComplete; + auto requestComplete = it->second; s->m_LeaseSetRequests.erase (it); - if (notify && requestComplete) requestComplete (nullptr); + if (notify && requestComplete) requestComplete->Complete (nullptr); } }); } @@ -526,28 +526,33 @@ namespace client if (floodfill) { auto request = std::make_shared (m_Service); - request->requestComplete = requestComplete; + request->requestComplete.push_back (requestComplete); + auto ts = i2p::util::GetSecondsSinceEpoch (); auto ret = m_LeaseSetRequests.insert (std::pair >(dest,request)); if (ret.second) // inserted { + request->requestTime = ts; if (!SendLeaseSetRequest (dest, floodfill, request)) { // request failed - m_LeaseSetRequests.erase (dest); - if (request->requestComplete) request->requestComplete (nullptr); + m_LeaseSetRequests.erase (ret.first); + requestComplete (nullptr); } } else // duplicate { - LogPrint (eLogWarning, "Destination: Request of LeaseSet ", dest.ToBase64 (), " is pending already"); - // TODO: queue up requests - if (request->requestComplete) request->requestComplete (nullptr); + LogPrint (eLogInfo, "Destination: Request of LeaseSet ", dest.ToBase64 (), " is pending already"); + // TODO: implement it properly + //ret.first->second->requestComplete.push_back (requestComplete); + if (ts > ret.first->second->requestTime + MAX_LEASESET_REQUEST_TIMEOUT) + m_LeaseSetRequests.erase (ret.first); + requestComplete (nullptr); } } else { LogPrint (eLogError, "Destination: Can't request LeaseSet, no floodfills found"); - if (requestComplete) requestComplete (nullptr); + requestComplete (nullptr); } } @@ -564,7 +569,6 @@ namespace client if (request->replyTunnel && request->outboundTunnel) { request->excluded.insert (nextFloodfill->GetIdentHash ()); - request->requestTime = i2p::util::GetSecondsSinceEpoch (); request->requestTimeoutTimer.cancel (); uint8_t replyKey[32], replyTag[32]; @@ -622,9 +626,9 @@ namespace client if (done) { - auto requestComplete = it->second->requestComplete; + auto requestComplete = it->second; m_LeaseSetRequests.erase (it); - if (requestComplete) requestComplete (nullptr); + if (requestComplete) requestComplete->Complete (nullptr); } } } diff --git a/Destination.h b/Destination.h index 0d3b3b4a..5b3ee655 100644 --- a/Destination.h +++ b/Destination.h @@ -69,9 +69,15 @@ namespace client std::set excluded; uint64_t requestTime; boost::asio::deadline_timer requestTimeoutTimer; - RequestComplete requestComplete; + std::list requestComplete; std::shared_ptr outboundTunnel; std::shared_ptr replyTunnel; + + void Complete (std::shared_ptr ls) + { + for (auto& it: requestComplete) it (ls); + requestComplete.clear (); + } }; diff --git a/Garlic.cpp b/Garlic.cpp index b7d44d5e..94ca82eb 100644 --- a/Garlic.cpp +++ b/Garlic.cpp @@ -20,6 +20,7 @@ namespace garlic std::shared_ptr destination, int numTags, bool attachLeaseSet): m_Owner (owner), m_Destination (destination), m_NumTags (numTags), m_LeaseSetUpdateStatus (attachLeaseSet ? eLeaseSetUpdated : eLeaseSetDoNotSend), + m_LeaseSetUpdateMsgID (0), m_ElGamalEncryption (new i2p::crypto::ElGamalEncryption (destination->GetEncryptionPublicKey ())) { // create new session tags and session key @@ -28,7 +29,7 @@ namespace garlic } GarlicRoutingSession::GarlicRoutingSession (const uint8_t * sessionKey, const SessionTag& sessionTag): - m_Owner (nullptr), m_Destination (nullptr), m_NumTags (1), m_LeaseSetUpdateStatus (eLeaseSetDoNotSend) + m_Owner (nullptr), m_Destination (nullptr), m_NumTags (1), m_LeaseSetUpdateStatus (eLeaseSetDoNotSend), m_LeaseSetUpdateMsgID (0) { memcpy (m_SessionKey, sessionKey, 32); m_Encryption.SetKey (m_SessionKey); @@ -83,6 +84,7 @@ namespace garlic if (msgID == m_LeaseSetUpdateMsgID) { m_LeaseSetUpdateStatus = eLeaseSetUpToDate; + m_LeaseSetUpdateMsgID = 0; LogPrint (eLogInfo, "Garlic: LeaseSet update confirmed"); } else @@ -92,32 +94,22 @@ namespace garlic void GarlicRoutingSession::TagsConfirmed (uint32_t msgID) { uint32_t ts = i2p::util::GetSecondsSinceEpoch (); - for (auto it = m_UnconfirmedTagsMsgs.begin (); it != m_UnconfirmedTagsMsgs.end ();) + auto it = m_UnconfirmedTagsMsgs.find (msgID); + if (it != m_UnconfirmedTagsMsgs.end ()) { - auto& tags = *it; - if (tags->msgID == msgID) - { - if (ts < tags->tagsCreationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT) - { - for (int i = 0; i < tags->numTags; i++) - m_SessionTags.push_back (tags->sessionTags[i]); - } - it = m_UnconfirmedTagsMsgs.erase (it); - } - else if (ts >= tags->tagsCreationTime + OUTGOING_TAGS_CONFIRMATION_TIMEOUT) - { - if (m_Owner) - m_Owner->RemoveDeliveryStatusSession (tags->msgID); - it = m_UnconfirmedTagsMsgs.erase (it); + auto& tags = it->second; + if (ts < tags->tagsCreationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT) + { + for (int i = 0; i < tags->numTags; i++) + m_SessionTags.push_back (tags->sessionTags[i]); } - else - ++it; + m_UnconfirmedTagsMsgs.erase (it); } } bool GarlicRoutingSession::CleanupExpiredTags () { - uint32_t ts = i2p::util::GetSecondsSinceEpoch (); + auto ts = i2p::util::GetSecondsSinceEpoch (); for (auto it = m_SessionTags.begin (); it != m_SessionTags.end ();) { if (ts >= it->creationTime + OUTGOING_TAGS_EXPIRATION_TIMEOUT) @@ -126,6 +118,12 @@ namespace garlic ++it; } CleanupUnconfirmedTags (); + if (m_LeaseSetUpdateMsgID && ts*1000LL > m_LeaseSetSubmissionTime + LEASET_CONFIRMATION_TIMEOUT) + { + if (m_Owner) + m_Owner->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID); + m_LeaseSetUpdateMsgID = 0; + } return !m_SessionTags.empty () || !m_UnconfirmedTagsMsgs.empty (); } @@ -136,10 +134,10 @@ namespace garlic // delete expired unconfirmed tags for (auto it = m_UnconfirmedTagsMsgs.begin (); it != m_UnconfirmedTagsMsgs.end ();) { - if (ts >= (*it)->tagsCreationTime + OUTGOING_TAGS_CONFIRMATION_TIMEOUT) + if (ts >= it->second->tagsCreationTime + OUTGOING_TAGS_CONFIRMATION_TIMEOUT) { if (m_Owner) - m_Owner->RemoveDeliveryStatusSession ((*it)->msgID); + m_Owner->RemoveDeliveryStatusSession (it->first); it = m_UnconfirmedTagsMsgs.erase (it); ret = true; } @@ -276,7 +274,7 @@ namespace garlic if (newTags) // new tags created { newTags->msgID = msgID; - m_UnconfirmedTagsMsgs.emplace_back (newTags); + m_UnconfirmedTagsMsgs.insert (std::make_pair(msgID, std::unique_ptr(newTags))); newTags = nullptr; // got acquired } m_Owner->DeliveryStatusSent (shared_from_this (), msgID); @@ -287,6 +285,7 @@ namespace garlic // attach LeaseSet if (m_LeaseSetUpdateStatus == eLeaseSetUpdated) { + if (m_LeaseSetUpdateMsgID) m_Owner->RemoveDeliveryStatusSession (m_LeaseSetUpdateMsgID); // remove previous m_LeaseSetUpdateStatus = eLeaseSetSubmitted; m_LeaseSetUpdateMsgID = msgID; m_LeaseSetSubmissionTime = ts; @@ -625,42 +624,64 @@ namespace garlic LogPrint (eLogDebug, "Garlic: ", numExpiredTags, " tags expired for ", GetIdentHash().ToBase64 ()); // outgoing - std::unique_lock l(m_SessionsMutex); - for (auto it = m_Sessions.begin (); it != m_Sessions.end ();) { - it->second->GetSharedRoutingPath (); // delete shared path if necessary - if (!it->second->CleanupExpiredTags ()) + std::unique_lock l(m_SessionsMutex); + for (auto it = m_Sessions.begin (); it != m_Sessions.end ();) { - LogPrint (eLogInfo, "Routing session to ", it->first.ToBase32 (), " deleted"); - it = m_Sessions.erase (it); + it->second->GetSharedRoutingPath (); // delete shared path if necessary + if (!it->second->CleanupExpiredTags ()) + { + LogPrint (eLogInfo, "Routing session to ", it->first.ToBase32 (), " deleted"); + it->second->SetOwner (nullptr); + it = m_Sessions.erase (it); + } + else + ++it; } - else - ++it; } + // delivery status sessions + { + std::unique_lock l(m_DeliveryStatusSessionsMutex); + for (auto it = m_DeliveryStatusSessions.begin (); it != m_DeliveryStatusSessions.end (); ) + { + if (it->second->GetOwner () != this) + it = m_DeliveryStatusSessions.erase (it); + else + ++it; + } + } } void GarlicDestination::RemoveDeliveryStatusSession (uint32_t msgID) { + std::unique_lock l(m_DeliveryStatusSessionsMutex); m_DeliveryStatusSessions.erase (msgID); } void GarlicDestination::DeliveryStatusSent (GarlicRoutingSessionPtr session, uint32_t msgID) { + std::unique_lock l(m_DeliveryStatusSessionsMutex); m_DeliveryStatusSessions[msgID] = session; } void GarlicDestination::HandleDeliveryStatusMessage (std::shared_ptr msg) { uint32_t msgID = bufbe32toh (msg->GetPayload ()); + GarlicRoutingSessionPtr session; { + std::unique_lock l(m_DeliveryStatusSessionsMutex); auto it = m_DeliveryStatusSessions.find (msgID); if (it != m_DeliveryStatusSessions.end ()) { - it->second->MessageConfirmed (msgID); + session = it->second; m_DeliveryStatusSessions.erase (it); - LogPrint (eLogDebug, "Garlic: message ", msgID, " acknowledged"); } } + if (session) + { + session->MessageConfirmed (msgID); + LogPrint (eLogDebug, "Garlic: message ", msgID, " acknowledged"); + } } void GarlicDestination::SetLeaseSetUpdated () diff --git a/Garlic.h b/Garlic.h index a3ab7d92..010338cd 100644 --- a/Garlic.h +++ b/Garlic.h @@ -111,6 +111,9 @@ namespace garlic std::shared_ptr GetSharedRoutingPath (); void SetSharedRoutingPath (std::shared_ptr path); + const GarlicDestination * GetOwner () const { return m_Owner; } + void SetOwner (GarlicDestination * owner) { m_Owner = owner; } + private: size_t CreateAESBlock (uint8_t * buf, std::shared_ptr msg); @@ -128,7 +131,7 @@ namespace garlic i2p::crypto::AESKey m_SessionKey; std::list m_SessionTags; int m_NumTags; - std::list > m_UnconfirmedTagsMsgs; + std::map > m_UnconfirmedTagsMsgs; // msgID->tags LeaseSetUpdateStatus m_LeaseSetUpdateStatus; uint32_t m_LeaseSetUpdateMsgID; @@ -192,6 +195,7 @@ namespace garlic // incoming std::map> m_Tags; // DeliveryStatus + std::mutex m_DeliveryStatusSessionsMutex; std::map m_DeliveryStatusSessions; // msgID -> session public: diff --git a/HTTPProxy.cpp b/HTTPProxy.cpp index 60b6bc33..c40989d1 100644 --- a/HTTPProxy.cpp +++ b/HTTPProxy.cpp @@ -29,7 +29,7 @@ namespace proxy { static const char *pageHead = "\r\n" - " I2P HTTP proxy: error\r\n" + " I2Pd HTTP proxy\r\n" "