Compare commits

...

10 Commits

Author SHA1 Message Date
self-related
1145f1feca Merge 32a70562c4 into c600b834e3 2025-01-19 12:46:21 +03:00
orignal
c600b834e3 postpone reading from file and updating router profile 2025-01-18 18:26:16 -05:00
orignal
b6319d78bf don't delete buffer of connected routers 2025-01-16 19:06:33 -05:00
orignal
e4fc2789fe Merge pull request #2149 from rex4539/var
Fix uninitialized variables
2025-01-16 14:21:18 -05:00
Dimitris Apostolou
4c5a1e064d Fix uninitialized variables 2025-01-16 17:54:38 +02:00
orignal
4bb82110ab don't create EVP_CIPHER_CTX for each ChaCha20 2025-01-15 21:13:50 -05:00
orignal
8c555fe592 copy fragment faster 2025-01-14 13:30:47 -05:00
orignal
5f1c599f81 fixed warning 2025-01-13 21:37:40 -05:00
orignal
f2b5606583 store fragments inside m_OutOfSequenceFragments 2025-01-13 20:36:27 -05:00
self-related
32a70562c4 Fix UPnP: error 2 2024-08-19 00:07:22 +03:00
16 changed files with 171 additions and 53 deletions

View File

@@ -122,7 +122,7 @@ namespace transport
err = UPNP_GetValidIGD (m_Devlist, &m_upnpUrls, &m_upnpData, m_NetworkAddr, sizeof (m_NetworkAddr));
#endif
m_upnpUrlsInitialized=err!=0;
if (err == UPNP_IGD_VALID_CONNECTED)
if (err == UPNP_IGD_VALID_CONNECTED || err == UPNP_IGD_VALID_NOT_CONNECTED)
{
#if (MINIUPNPC_API_VERSION < 18)
err = UPNP_GetExternalIPAddress (m_upnpUrls.controlURL, m_upnpData.first.servicetype, m_externalIPAddress);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2024, The PurpleI2P Project
* Copyright (c) 2013-2025, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -710,19 +710,41 @@ namespace crypto
{
return AEADChaCha20Poly1305 (m_Ctx, msg, msgLen, ad, adLen, key, nonce, buf, len, false);
}
void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out)
static void ChaCha20 (EVP_CIPHER_CTX *ctx, const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out)
{
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new ();
uint32_t iv[4];
iv[0] = htole32 (1); memcpy (iv + 1, nonce, 12); // counter | nonce
EVP_EncryptInit_ex(ctx, EVP_chacha20 (), NULL, key, (const uint8_t *)iv);
int outlen = 0;
EVP_EncryptUpdate(ctx, out, &outlen, msg, msgLen);
EVP_EncryptFinal_ex(ctx, NULL, &outlen);
}
void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out)
{
EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new ();
ChaCha20 (ctx, msg, msgLen, key, nonce, out);
EVP_CIPHER_CTX_free (ctx);
}
ChaCha20Context::ChaCha20Context ()
{
m_Ctx = EVP_CIPHER_CTX_new ();
}
ChaCha20Context::~ChaCha20Context ()
{
if (m_Ctx)
EVP_CIPHER_CTX_free (m_Ctx);
}
void ChaCha20Context::operator ()(const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out)
{
ChaCha20 (m_Ctx, msg, msgLen, key, nonce, out);
}
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info,
uint8_t * out, size_t outLen)
{

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2024, The PurpleI2P Project
* Copyright (c) 2013-2025, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -226,6 +226,19 @@ namespace crypto
// ChaCha20
void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out);
class ChaCha20Context
{
public:
ChaCha20Context ();
~ChaCha20Context ();
void operator ()(const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out);
private:
EVP_CIPHER_CTX * m_Ctx;
};
// HKDF
void HKDF (const uint8_t * salt, const uint8_t * key, size_t keyLen, const std::string& info, uint8_t * out, size_t outLen = 64); // salt - 32, out - 32 or 64, info <= 32

View File

@@ -195,7 +195,7 @@ namespace client
m_IsPublic = itr->second != "true";
}
int inLen, outLen, inQuant, outQuant, numTags, minLatency, maxLatency;
int inLen = 0, outLen = 0, inQuant = 0, outQuant = 0, numTags = 0, minLatency = 0, maxLatency = 0;
std::map<std::string, int&> intOpts = {
{I2CP_PARAM_INBOUND_TUNNEL_LENGTH, inLen},
{I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, outLen},

View File

@@ -193,7 +193,7 @@ namespace garlic
void SetNoiseState (const i2p::crypto::NoiseSymmetricState& state) { GetNoiseState () = state; };
void CreateNonce (uint64_t seqn, uint8_t * nonce);
void HandlePayload (const uint8_t * buf, size_t len, const std::shared_ptr<ReceiveRatchetTagSet>& receiveTagset, int index);
bool MessageConfirmed (uint32_t msgID);
bool MessageConfirmed (uint32_t msgID) override;
private:

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2024, The PurpleI2P Project
* Copyright (c) 2013-2025, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -119,8 +119,9 @@ namespace data
i2p::util::SetThreadName("NetDB");
uint64_t lastManage = 0;
uint64_t lastProfilesCleanup = i2p::util::GetMonotonicMilliseconds (), lastObsoleteProfilesCleanup = lastProfilesCleanup;
int16_t profilesCleanupVariance = 0, obsoleteProfilesCleanVariance = 0;
uint64_t lastProfilesCleanup = i2p::util::GetMonotonicMilliseconds (),
lastObsoleteProfilesCleanup = lastProfilesCleanup, lastApplingProfileUpdates = lastProfilesCleanup;
int16_t profilesCleanupVariance = 0, obsoleteProfilesCleanVariance = 0, applingProfileUpdatesVariance = 0;
std::list<std::shared_ptr<const I2NPMessage> > msgs;
while (m_IsRunning)
@@ -199,6 +200,19 @@ namespace data
lastObsoleteProfilesCleanup = mts;
obsoleteProfilesCleanVariance = rand () % i2p::data::PEER_PROFILE_OBSOLETE_PROFILES_CLEAN_VARIANCE;
}
if (mts >= lastApplingProfileUpdates + i2p::data::PEER_PROFILE_APPLY_POSTPONED_TIMEOUT + applingProfileUpdatesVariance)
{
bool isAppling = m_ApplingProfileUpdates.valid ();
if (isAppling && m_ApplingProfileUpdates.wait_for(std::chrono::seconds(0)) == std::future_status::ready) // still active?
{
m_ApplingProfileUpdates.get ();
isAppling = false;
}
if (!isAppling)
m_ApplingProfileUpdates = i2p::data::FlushPostponedRouterProfileUpdates ();
lastApplingProfileUpdates = mts;
applingProfileUpdatesVariance = rand () % i2p::data::PEER_PROFILE_APPLY_POSTPONED_TIMEOUT_VARIANCE;
}
}
catch (std::exception& ex)
{
@@ -696,9 +710,12 @@ namespace data
r->SetUnreachable (true);
}
}
// make router reachable back if connected now
if (r->IsUnreachable () && i2p::transport::transports.IsConnected (ident))
// make router reachable back and don't delete buffer if connected now
if ((r->IsUnreachable () || r->IsBufferScheduledToDelete ()) && i2p::transport::transports.IsConnected (ident))
{
r->SetUnreachable (false);
r->CancelBufferToDelete ();
}
if (r->IsUnreachable ())
{

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2024, The PurpleI2P Project
* Copyright (c) 2013-2025, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -185,7 +185,7 @@ namespace data
std::shared_ptr<NetDbRequests> m_Requests;
bool m_PersistProfiles;
std::future<void> m_SavingProfiles, m_DeletingProfiles, m_PersistingRouters;
std::future<void> m_SavingProfiles, m_DeletingProfiles, m_ApplingProfileUpdates, m_PersistingRouters;
std::vector<std::shared_ptr<const RouterInfo> > m_ExploratorySelection;
uint64_t m_LastExploratorySelectionUpdateTime; // in monotonic seconds

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2024, The PurpleI2P Project
* Copyright (c) 2013-2025, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -27,7 +27,9 @@ namespace data
static i2p::fs::HashedStorage g_ProfilesStorage("peerProfiles", "p", "profile-", "txt");
static std::unordered_map<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > g_Profiles;
static std::mutex g_ProfilesMutex;
static std::list<std::pair<i2p::data::IdentHash, std::function<void (std::shared_ptr<RouterProfile>)> > > g_PostponedUpdates;
static std::mutex g_PostponedUpdatesMutex;
RouterProfile::RouterProfile ():
m_IsUpdated (false), m_LastDeclineTime (0), m_LastUnreachableTime (0),
m_LastUpdateTime (i2p::util::GetSecondsSinceEpoch ()),
@@ -259,14 +261,14 @@ namespace data
}
auto profile = netdb.NewRouterProfile ();
profile->Load (identHash); // if possible
std::unique_lock<std::mutex> l(g_ProfilesMutex);
std::lock_guard<std::mutex> l(g_ProfilesMutex);
g_Profiles.emplace (identHash, profile);
return profile;
}
bool IsRouterBanned (const IdentHash& identHash)
{
std::unique_lock<std::mutex> l(g_ProfilesMutex);
std::lock_guard<std::mutex> l(g_ProfilesMutex);
auto it = g_Profiles.find (identHash);
if (it != g_Profiles.end ())
return it->second->IsUnreachable ();
@@ -278,7 +280,7 @@ namespace data
g_ProfilesStorage.SetPlace(i2p::fs::GetDataDir());
g_ProfilesStorage.Init(i2p::data::GetBase64SubstitutionTable(), 64);
}
static void SaveProfilesToDisk (std::list<std::pair<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > >&& profiles)
{
for (auto& it: profiles)
@@ -290,7 +292,7 @@ namespace data
auto ts = i2p::util::GetSecondsSinceEpoch ();
std::list<std::pair<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > > tmp;
{
std::unique_lock<std::mutex> l(g_ProfilesMutex);
std::lock_guard<std::mutex> l(g_ProfilesMutex);
for (auto it = g_Profiles.begin (); it != g_Profiles.end ();)
{
if (ts - it->second->GetLastUpdateTime () > PEER_PROFILE_PERSIST_INTERVAL)
@@ -312,7 +314,7 @@ namespace data
{
std::unordered_map<i2p::data::IdentHash, std::shared_ptr<RouterProfile> > tmp;
{
std::unique_lock<std::mutex> l(g_ProfilesMutex);
std::lock_guard<std::mutex> l(g_ProfilesMutex);
std::swap (tmp, g_Profiles);
}
auto ts = i2p::util::GetSecondsSinceEpoch ();
@@ -347,7 +349,7 @@ namespace data
{
{
auto ts = i2p::util::GetSecondsSinceEpoch ();
std::unique_lock<std::mutex> l(g_ProfilesMutex);
std::lock_guard<std::mutex> l(g_ProfilesMutex);
for (auto it = g_Profiles.begin (); it != g_Profiles.end ();)
{
if (ts - it->second->GetLastUpdateTime () >= PEER_PROFILE_EXPIRATION_TIMEOUT)
@@ -359,5 +361,47 @@ namespace data
return std::async (std::launch::async, DeleteFilesFromDisk);
}
bool UpdateRouterProfile (const IdentHash& identHash, std::function<void (std::shared_ptr<RouterProfile>)> update)
{
if (!update) return true;
std::shared_ptr<RouterProfile> profile;
{
std::lock_guard<std::mutex> l(g_ProfilesMutex);
auto it = g_Profiles.find (identHash);
if (it != g_Profiles.end ())
profile = it->second;
}
if (profile)
{
update (profile);
return true;
}
// postpone
std::lock_guard<std::mutex> l(g_PostponedUpdatesMutex);
g_PostponedUpdates.emplace_back (identHash, update);
return false;
}
static void ApplyPostponedUpdates (std::list<std::pair<i2p::data::IdentHash, std::function<void (std::shared_ptr<RouterProfile>)> > >&& updates)
{
for (const auto& [ident, update] : updates)
{
auto profile = GetRouterProfile (ident);
update (profile);
}
}
std::future<void> FlushPostponedRouterProfileUpdates ()
{
if (g_PostponedUpdates.empty ()) return std::future<void>();
std::list<std::pair<i2p::data::IdentHash, std::function<void (std::shared_ptr<RouterProfile>)> > > updates;
{
std::lock_guard<std::mutex> l(g_PostponedUpdatesMutex);
g_PostponedUpdates.swap (updates);
}
return std::async (std::launch::async, ApplyPostponedUpdates, std::move (updates));
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2024, The PurpleI2P Project
* Copyright (c) 2013-2025, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -11,6 +11,7 @@
#include <memory>
#include <future>
#include <functional>
#include <boost/asio.hpp>
#include "Identity.h"
@@ -44,6 +45,8 @@ namespace data
const int PEER_PROFILE_UNREACHABLE_INTERVAL = 480; // in seconds (8 minutes)
const int PEER_PROFILE_USEFUL_THRESHOLD = 3;
const int PEER_PROFILE_ALWAYS_DECLINING_NUM = 5; // num declines in row to consider always declined
const int PEER_PROFILE_APPLY_POSTPONED_TIMEOUT = 2100; // in milliseconds
const int PEER_PROFILE_APPLY_POSTPONED_TIMEOUT_VARIANCE = 500; // in milliseconds
class RouterProfile
{
@@ -108,6 +111,8 @@ namespace data
std::future<void> DeleteObsoleteProfiles ();
void SaveProfiles ();
std::future<void> PersistProfiles ();
bool UpdateRouterProfile (const IdentHash& identHash, std::function<void (std::shared_ptr<RouterProfile>)> update); // return true if updated immediately, and false if postponed
std::future<void> FlushPostponedRouterProfileUpdates ();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2024, The PurpleI2P Project
* Copyright (c) 2013-2025, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -294,6 +294,7 @@ namespace data
std::shared_ptr<Buffer> GetSharedBuffer () const { return m_Buffer; };
std::shared_ptr<Buffer> CopyBuffer () const;
void ScheduleBufferToDelete () { m_IsBufferScheduledToDelete = true; };
void CancelBufferToDelete () { m_IsBufferScheduledToDelete = false; };
bool IsBufferScheduledToDelete () const { return m_IsBufferScheduledToDelete; };
bool IsUpdated () const { return m_IsUpdated; };

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022-2024, The PurpleI2P Project
* Copyright (c) 2022-2025, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -1527,6 +1527,11 @@ namespace transport
{
return m_Decryptor.Decrypt (msg, msgLen, ad, adLen, key, nonce, buf, len);
}
void SSU2Server::ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out)
{
m_ChaCha20 (msg, msgLen, key, nonce, out);
}
void SSU2Server::SendThroughProxy (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen,
const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to)

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022-2024, The PurpleI2P Project
* Copyright (c) 2022-2025, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -86,6 +86,7 @@ namespace transport
const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len);
bool AEADChaCha20Poly1305Decrypt (const uint8_t * msg, size_t msgLen, const uint8_t * ad, size_t adLen,
const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len);
void ChaCha20 (const uint8_t * msg, size_t msgLen, const uint8_t * key, const uint8_t * nonce, uint8_t * out);
bool IsMaxNumIntroducers (bool v4) const { return (v4 ? m_Introducers.size () : m_IntroducersV6.size ()) >= SSU2_MAX_NUM_INTRODUCERS; }
bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; };
void AdjustTimeOffset (int64_t offset, std::shared_ptr<const i2p::data::IdentityEx> from);
@@ -206,6 +207,7 @@ namespace transport
mutable std::mutex m_ReceivedPacketsQueueMutex;
i2p::crypto::AEADChaCha20Poly1305Encryptor m_Encryptor;
i2p::crypto::AEADChaCha20Poly1305Decryptor m_Decryptor;
i2p::crypto::ChaCha20Context m_ChaCha20;
// proxy
bool m_IsThroughProxy;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024, The PurpleI2P Project
* Copyright (c) 2024-2025, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -46,7 +46,7 @@ namespace transport
}
uint8_t nonce[12] = {0};
uint64_t headerX[2]; // sourceConnID, token
i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX);
GetServer ().ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX);
SetDestConnID (headerX[0]);
// decrypt and handle payload
uint8_t * payload = buf + 32;
@@ -183,7 +183,7 @@ namespace transport
header.ll[0] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 24));
header.ll[1] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 12));
memset (n, 0, 12);
i2p::crypto::ChaCha20 (h + 16, 16, addr->i, n, h + 16);
GetServer ().ChaCha20 (h + 16, 16, addr->i, n, h + 16);
// send
GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, GetRemoteEndpoint ());
UpdateNumSentBytes (payloadSize + 32);
@@ -305,7 +305,7 @@ namespace transport
header.ll[0] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 24));
header.ll[1] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 12));
memset (n, 0, 12);
i2p::crypto::ChaCha20 (h + 16, 16, addr->i, n, h + 16);
GetServer ().ChaCha20 (h + 16, 16, addr->i, n, h + 16);
// send
GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, ep);
UpdateNumSentBytes (payloadSize + 32);

View File

@@ -682,7 +682,7 @@ namespace transport
}
const uint8_t nonce[12] = {0};
uint64_t headerX[2];
i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX);
m_Server.ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX);
LogPrint (eLogWarning, "SSU2: Unexpected PeerTest message SourceConnID=", connID, " DestConnID=", headerX[0]);
break;
}
@@ -748,7 +748,7 @@ namespace transport
payloadSize += 16;
header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 24));
header.ll[1] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 12));
i2p::crypto::ChaCha20 (headerX, 48, m_Address->i, nonce, headerX);
m_Server.ChaCha20 (headerX, 48, m_Address->i, nonce, headerX);
m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || encrypted payload from Session Request) for SessionCreated
m_SentHandshakePacket->payloadSize = payloadSize;
// send
@@ -775,7 +775,7 @@ namespace transport
}
const uint8_t nonce[12] = {0};
uint8_t headerX[48];
i2p::crypto::ChaCha20 (buf + 16, 48, i2p::context.GetSSU2IntroKey (), nonce, headerX);
m_Server.ChaCha20 (buf + 16, 48, i2p::context.GetSSU2IntroKey (), nonce, headerX);
memcpy (&m_DestConnID, headerX, 8);
uint64_t token;
memcpy (&token, headerX + 8, 8);
@@ -874,7 +874,7 @@ namespace transport
m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || encrypted Noise payload from Session Created)
header.ll[0] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), payload + (payloadSize - 24));
header.ll[1] ^= CreateHeaderMask (kh2, payload + (payloadSize - 12));
i2p::crypto::ChaCha20 (headerX, 48, kh2, nonce, headerX);
m_Server.ChaCha20 (headerX, 48, kh2, nonce, headerX);
m_State = eSSU2SessionStateSessionCreatedSent;
m_SentHandshakePacket->payloadSize = payloadSize;
// send
@@ -902,7 +902,7 @@ namespace transport
m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval;
const uint8_t nonce[12] = {0};
uint8_t headerX[48];
i2p::crypto::ChaCha20 (buf + 16, 48, kh2, nonce, headerX);
m_Server.ChaCha20 (buf + 16, 48, kh2, nonce, headerX);
// KDF for SessionCreated
m_NoiseState->MixHash ( { {header.buf, 16}, {headerX, 16} } ); // h = SHA256(h || header)
m_NoiseState->MixHash (headerX + 16, 32); // h = SHA256(h || bepk);
@@ -1206,7 +1206,16 @@ namespace transport
return false;
}
if (!m_Address->published)
ri->GetProfile ()->SetLastEndpoint (m_RemoteEndpoint);
{
if (ri->HasProfile ())
ri->GetProfile ()->SetLastEndpoint (m_RemoteEndpoint);
else
i2p::data::UpdateRouterProfile (ri->GetIdentHash (),
[ep = m_RemoteEndpoint](std::shared_ptr<i2p::data::RouterProfile> profile)
{
if (profile) profile->SetLastEndpoint (ep);
});
}
SetRemoteIdentity (ri->GetRouterIdentity ());
AdjustMaxPayloadSize ();
m_Server.AddSessionByRouterHash (shared_from_this ()); // we know remote router now
@@ -1264,7 +1273,7 @@ namespace transport
header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 24));
header.ll[1] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 12));
memset (nonce, 0, 12);
i2p::crypto::ChaCha20 (h + 16, 16, m_Address->i, nonce, h + 16);
m_Server.ChaCha20 (h + 16, 16, m_Address->i, nonce, h + 16);
// send
if (m_Server.AddPendingOutgoingSession (shared_from_this ()))
m_Server.Send (header.buf, 16, h + 16, 16, payload, payloadSize, m_RemoteEndpoint);
@@ -1286,7 +1295,7 @@ namespace transport
uint8_t nonce[12] = {0};
uint8_t h[32];
memcpy (h, header.buf, 16);
i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, h + 16);
m_Server.ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, h + 16);
memcpy (&m_DestConnID, h + 16, 8);
// decrypt
CreateNonce (be32toh (header.h.packetNum), nonce);
@@ -1338,7 +1347,7 @@ namespace transport
header.ll[0] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), payload + (payloadSize - 24));
header.ll[1] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), payload + (payloadSize - 12));
memset (nonce, 0, 12);
i2p::crypto::ChaCha20 (h + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, h + 16);
m_Server.ChaCha20 (h + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, h + 16);
// send
m_Server.Send (header.buf, 16, h + 16, 16, payload, payloadSize, m_RemoteEndpoint);
}
@@ -1362,7 +1371,7 @@ namespace transport
}
uint8_t nonce[12] = {0};
uint64_t headerX[2]; // sourceConnID, token
i2p::crypto::ChaCha20 (buf + 16, 16, m_Address->i, nonce, (uint8_t *)headerX);
m_Server.ChaCha20 (buf + 16, 16, m_Address->i, nonce, (uint8_t *)headerX);
uint64_t token = headerX[1];
if (token)
m_Server.UpdateOutgoingToken (m_RemoteEndpoint, token, i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT);
@@ -1411,7 +1420,7 @@ namespace transport
}
uint8_t nonce[12] = {0};
uint64_t headerX[2]; // sourceConnID, token
i2p::crypto::ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX);
m_Server.ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX);
m_DestConnID = headerX[0];
// decrypt and handle payload
uint8_t * payload = buf + 32;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2024, The PurpleI2P Project
* Copyright (c) 2013-2025, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -258,9 +258,8 @@ namespace tunnel
void TunnelEndpoint::AddOutOfSequenceFragment (uint32_t msgID, uint8_t fragmentNum,
bool isLastFragment, const uint8_t * fragment, size_t size)
{
std::unique_ptr<Fragment> f(new Fragment (isLastFragment, i2p::util::GetMillisecondsSinceEpoch (), size));
memcpy (f->data.data (), fragment, size);
if (!m_OutOfSequenceFragments.emplace ((uint64_t)msgID << 32 | fragmentNum, std::move (f)).second)
if (!m_OutOfSequenceFragments.try_emplace ((uint64_t)msgID << 32 | fragmentNum,
isLastFragment, i2p::util::GetMillisecondsSinceEpoch (), fragment, size).second)
LogPrint (eLogInfo, "TunnelMessage: Duplicate out-of-sequence fragment ", fragmentNum, " of message ", msgID);
}
@@ -290,7 +289,7 @@ namespace tunnel
if (it != m_OutOfSequenceFragments.end ())
{
LogPrint (eLogDebug, "TunnelMessage: Out-of-sequence fragment ", (int)msg.nextFragmentNum, " of message ", msgID, " found");
size_t size = it->second->data.size ();
size_t size = it->second.data.size ();
if (msg.data->len + size > msg.data->maxLen)
{
LogPrint (eLogWarning, "TunnelMessage: Tunnel endpoint I2NP message size ", msg.data->maxLen, " is not enough");
@@ -298,9 +297,9 @@ namespace tunnel
*newMsg = *(msg.data);
msg.data = newMsg;
}
if (msg.data->Concat (it->second->data.data (), size) < size) // concatenate out-of-sync fragment
if (msg.data->Concat (it->second.data.data (), size) < size) // concatenate out-of-sync fragment
LogPrint (eLogError, "TunnelMessage: Tunnel endpoint I2NP buffer overflow ", msg.data->maxLen);
if (it->second->isLastFragment)
if (it->second.isLastFragment)
// message complete
msg.nextFragmentNum = 0;
else
@@ -349,7 +348,7 @@ namespace tunnel
// out-of-sequence fragments
for (auto it = m_OutOfSequenceFragments.begin (); it != m_OutOfSequenceFragments.end ();)
{
if (ts > it->second->receiveTime + i2p::I2NP_MESSAGE_EXPIRATION_TIMEOUT)
if (ts > it->second.receiveTime + i2p::I2NP_MESSAGE_EXPIRATION_TIMEOUT)
it = m_OutOfSequenceFragments.erase (it);
else
++it;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2024, The PurpleI2P Project
* Copyright (c) 2013-2025, The PurpleI2P Project
*
* This file is part of Purple i2pd project and licensed under BSD3
*
@@ -32,7 +32,8 @@ namespace tunnel
struct Fragment
{
Fragment (bool last, uint64_t t, size_t size): isLastFragment (last), receiveTime (t), data (size) {};
Fragment (bool last, uint64_t t, const uint8_t * buf, size_t size):
isLastFragment (last), receiveTime (t), data (size) { memcpy (data.data(), buf, size); };
bool isLastFragment;
uint64_t receiveTime; // milliseconds since epoch
std::vector<uint8_t> data;
@@ -67,7 +68,7 @@ namespace tunnel
private:
std::unordered_map<uint32_t, TunnelMessageBlockEx> m_IncompleteMessages;
std::unordered_map<uint64_t, std::unique_ptr<Fragment> > m_OutOfSequenceFragments; // ((msgID << 8) + fragment#)->fragment
std::unordered_map<uint64_t, Fragment> m_OutOfSequenceFragments; // ((msgID << 8) + fragment#)->fragment
bool m_IsInbound;
size_t m_NumReceivedBytes;
TunnelMessageBlockEx m_CurrentMessage;