mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-03-07 06:09:42 +00:00
Compare commits
10 Commits
3f022b252d
...
1145f1feca
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1145f1feca | ||
|
|
c600b834e3 | ||
|
|
b6319d78bf | ||
|
|
e4fc2789fe | ||
|
|
4c5a1e064d | ||
|
|
4bb82110ab | ||
|
|
8c555fe592 | ||
|
|
5f1c599f81 | ||
|
|
f2b5606583 | ||
|
|
32a70562c4 |
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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},
|
||||
|
||||
@@ -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:
|
||||
|
||||
|
||||
@@ -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 ())
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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; };
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user