select first hop from connected peers based on peer ordering key

This commit is contained in:
orignal
2026-05-25 21:08:37 -04:00
parent d4471cbb0f
commit b37e0572d8
6 changed files with 68 additions and 31 deletions
+19 -1
View File
@@ -16,6 +16,7 @@
#include "I2PEndian.h"
#include "Base.h"
#include "Crypto.h"
#include "Siphash.h"
#include "Log.h"
#include "Timestamp.h"
#include "I2NPProtocol.h"
@@ -26,8 +27,8 @@
#include "Garlic.h"
#include "ECIESX25519AEADRatchetSession.h"
#include "Config.h"
#include "NetDb.hpp"
#include "util.h"
#include "NetDb.hpp"
using namespace i2p::transport;
@@ -1406,5 +1407,22 @@ namespace data
if (r->GetBuffer ()) return true;
return r->LoadBuffer (m_Storage.Path (r->GetIdentHashBase64 ()));
}
int CalculatePeerOrderingGroup (i2p::data::Tag<16> key, const i2p::data::IdentHash& routerIdent)
{
uint8_t hash[16];
#if OPENSSL_SIPHASH
EVP_PKEY * sipKey = EVP_PKEY_new_raw_private_key (EVP_PKEY_SIPHASH, nullptr, key, 16);
EVP_MD_CTX * ctx = EVP_MD_CTX_create ();
EVP_DigestSignInit (ctx, nullptr, nullptr, nullptr, sipKey);
size_t l = 16;
EVP_DigestSign (ctx, hash, &l, routerIdent, 32);
EVP_MD_CTX_destroy (ctx);
EVP_PKEY_free (sipKey);
#else
i2p::crypto::Siphash<16> (hash, routerIdent, 32, key);
#endif
return hash[0] & 0x03;
}
}
}
+2
View File
@@ -205,6 +205,8 @@ namespace data
};
extern NetDb netdb;
int CalculatePeerOrderingGroup (i2p::data::Tag<16> key, const i2p::data::IdentHash& routerIdent);
}
}
+40 -26
View File
@@ -1183,7 +1183,7 @@ namespace transport
}
template<typename Filter>
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer (Filter filter) const
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer (Filter filter, i2p::data::Tag<16> * peerOrderingKey) const
{
std::vector<std::pair<i2p::data::IdentHash, std::shared_ptr<Peer>>> peers;
{
@@ -1203,13 +1203,17 @@ namespace transport
inds[0] %= count;
auto& [ident, peer] = peers[inds[0]];
// try random peer
if (filter (peer))
if (ts > peer->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL)
{
foundIdent = ident;
peer->lastSelectionTime = ts;
found = true;
int peerOrderingGroup = peerOrderingKey ? i2p::data::CalculatePeerOrderingGroup (*peerOrderingKey, ident) : 0;
if (!peerOrderingGroup && filter (peer))
{
foundIdent = ident;
peer->lastSelectionTime = ts;
found = true;
}
}
else
if (!found)
{
// try some peers around
if (inds[0])
@@ -1233,13 +1237,16 @@ namespace transport
for (auto i = inds[1]; i < inds[2]; i++)
{
auto& [ident, peer] = peers[i];
if (ts > peer->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL &&
filter (peer))
if (ts > peer->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL)
{
foundIdent = ident;
peer->lastSelectionTime = ts;
found = true;
break;
int peerOrderingGroup = peerOrderingKey ? i2p::data::CalculatePeerOrderingGroup (*peerOrderingKey, ident) : 0;
if (!peerOrderingGroup && filter (peer))
{
foundIdent = ident;
peer->lastSelectionTime = ts;
found = true;
break;
}
}
}
@@ -1249,13 +1256,16 @@ namespace transport
for (auto i = 0; i < inds[1]; i++)
{
auto& [ident, peer] = peers[i];
if (ts > peer->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL &&
filter (peer))
if (ts > peer->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL)
{
foundIdent = ident;
peer->lastSelectionTime = ts;
found = true;
break;
int peerOrderingGroup = peerOrderingKey ? i2p::data::CalculatePeerOrderingGroup (*peerOrderingKey, ident) : 0;
if (!peerOrderingGroup && filter (peer))
{
foundIdent = ident;
peer->lastSelectionTime = ts;
found = true;
break;
}
}
}
@@ -1265,13 +1275,16 @@ namespace transport
for (auto i = inds[2]; i < peers.size (); i++)
{
auto& [ident, peer] = peers[i];
if (ts > peer->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL &&
filter (peer))
if (ts > peer->lastSelectionTime + PEER_SELECTION_MIN_INTERVAL)
{
foundIdent = ident;
peer->lastSelectionTime = ts;
found = true;
break;
int peerOrderingGroup = peerOrderingKey ? i2p::data::CalculatePeerOrderingGroup (*peerOrderingKey, ident) : 0;
if (!peerOrderingGroup && filter (peer))
{
foundIdent = ident;
peer->lastSelectionTime = ts;
found = true;
break;
}
}
}
}
@@ -1280,7 +1293,7 @@ namespace transport
return found ? i2p::data::netdb.FindRouter (foundIdent) : nullptr;
}
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer (bool isHighBandwidth) const
std::shared_ptr<const i2p::data::RouterInfo> Transports::GetRandomPeer (bool isHighBandwidth, i2p::data::Tag<16> * peerOrderingKey) const
{
return GetRandomPeer (
[isHighBandwidth, this](std::shared_ptr<const Peer> peer)->bool
@@ -1304,7 +1317,8 @@ namespace transport
}
}
return true;
});
},
i2p::context.IsLimitedConnectivity () ? nullptr : peerOrderingKey);
}
void Transports::RestrictRoutesToFamilies(const std::vector<std::string_view>& families)
+2 -2
View File
@@ -173,7 +173,7 @@ namespace transport
uint32_t GetTransitBandwidth15s () const { return m_TransitBandwidth15s; };
int GetCongestionLevel (bool longTerm) const;
size_t GetNumPeers () const { return m_Peers.size (); };
std::shared_ptr<const i2p::data::RouterInfo> GetRandomPeer (bool isHighBandwidth) const;
std::shared_ptr<const i2p::data::RouterInfo> GetRandomPeer (bool isHighBandwidth, i2p::data::Tag<16> * peerOrderingKey = nullptr) const;
/** get a trusted first hop for restricted routes */
std::shared_ptr<const i2p::data::RouterInfo> GetRestrictedPeer();
@@ -215,7 +215,7 @@ namespace transport
void DetectExternalIP ();
template<typename Filter>
std::shared_ptr<const i2p::data::RouterInfo> GetRandomPeer (Filter filter) const;
std::shared_ptr<const i2p::data::RouterInfo> GetRandomPeer (Filter filter, i2p::data::Tag<16> * peerOrderingKey) const;
boost::asio::ip::address GetNetworkAddress (std::shared_ptr<TransportSession> session) const;
boost::asio::ip::address GetNetworkAddress (const boost::asio::ip::address& addr) const;
+4 -2
View File
@@ -61,6 +61,7 @@ namespace tunnel
if (m_OutboundVariance > 0 && m_NumOutboundHops + m_OutboundVariance > STANDARD_NUM_RECORDS)
m_OutboundVariance = (m_NumOutboundHops < STANDARD_NUM_RECORDS) ? STANDARD_NUM_RECORDS - m_NumOutboundHops : 0;
m_NextManageTime = i2p::util::GetSecondsSinceEpoch () + m_Rng () % TUNNEL_POOL_MANAGE_INTERVAL;
RAND_bytes (m_PeerOrderingKey, 16);
}
TunnelPool::~TunnelPool ()
@@ -611,7 +612,8 @@ namespace tunnel
(inbound && (i2p::transport::transports.GetNumPeers () > 25 ||
(i2p::context.IsLimitedConnectivity () && i2p::transport::transports.GetNumPeers () > 0))))
{
auto r = i2p::transport::transports.GetRandomPeer (m_IsHighBandwidth && !i2p::context.IsLimitedConnectivity ());
auto r = i2p::transport::transports.GetRandomPeer (m_IsHighBandwidth && !i2p::context.IsLimitedConnectivity (),
&m_PeerOrderingKey);
if (r && r->IsECIES () && (!r->HasProfile () || !r->GetProfile ()->IsBad ()) &&
(numHops > 1 || (r->IsV4 () && (!inbound || r->IsPublished (true))))) // first inbound must be published ipv4
{
@@ -627,7 +629,7 @@ namespace tunnel
if (!hop && !i) // if no suitable peer found for first hop, try already connected
{
LogPrint (eLogInfo, "Tunnels: Can't select first hop for a tunnel. Trying already connected");
hop = i2p::transport::transports.GetRandomPeer (false);
hop = i2p::transport::transports.GetRandomPeer (false, &m_PeerOrderingKey);
if (hop && !hop->IsECIES ()) hop = nullptr;
}
if (!hop)
+1
View File
@@ -153,6 +153,7 @@ namespace tunnel
std::mutex m_CustomPeerSelectorMutex;
ITunnelPeerSelector * m_CustomPeerSelector;
std::mt19937 m_Rng; // for tunnel selection
i2p::data::Tag<16> m_PeerOrderingKey;
int m_MinLatency = 0; // if > 0 this tunnel pool will try building tunnels with minimum latency by ms
int m_MaxLatency = 0; // if > 0 this tunnel pool will try building tunnels with maximum latency by ms