Skip to content

Commit

Permalink
check if we connected recently to an endpoint before sending peer test
Browse files Browse the repository at this point in the history
  • Loading branch information
orignal committed Sep 18, 2024
1 parent ca4db7a commit f20391d
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 15 deletions.
24 changes: 24 additions & 0 deletions libi2pd/SSU2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,22 @@ namespace transport
return ep.port ();
}

bool SSU2Server::IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep) const
{
if (!ep.port () || ep.address ().is_unspecified ()) return false;
auto it = m_ConnectedRecently.find (ep);
if (it != m_ConnectedRecently.end ())
return i2p::util::GetSecondsSinceEpoch () <= it->second + SSU2_HOLE_PUNCH_EXPIRATION;
return false;
}

void SSU2Server::AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts)
{
if (!ep.port () || ep.address ().is_unspecified () ||
i2p::util::GetSecondsSinceEpoch () > ts + SSU2_HOLE_PUNCH_EXPIRATION) return;
m_ConnectedRecently.try_emplace (ep, ts);
}

void SSU2Server::AdjustTimeOffset (int64_t offset, std::shared_ptr<const i2p::data::IdentityEx> from)
{
if (offset)
Expand Down Expand Up @@ -1001,6 +1017,14 @@ namespace transport
it++;
}

for (auto it = m_ConnectedRecently.begin (); it != m_ConnectedRecently.end (); )
{
if (ts > it->second + SSU2_HOLE_PUNCH_EXPIRATION)
it = m_ConnectedRecently.erase (it);
else
it++;
}

m_PacketsPool.CleanUpMt ();
m_SentPacketsPool.CleanUp ();
m_IncompleteMessagesPool.CleanUp ();
Expand Down
8 changes: 6 additions & 2 deletions libi2pd/SSU2.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ namespace transport
const int SSU2_KEEP_ALIVE_INTERVAL = 15; // in seconds
const int SSU2_KEEP_ALIVE_INTERVAL_VARIANCE = 4; // in seconds
const int SSU2_PROXY_CONNECT_RETRY_TIMEOUT = 30; // in seconds
const int SSU2_HOLE_PUNCH_EXPIRATION = 20; // in seconds

class SSU2Server: private i2p::util::RunnableServiceWithWork
{
Expand Down Expand Up @@ -72,6 +73,8 @@ namespace transport
bool UsesProxy () const { return m_IsThroughProxy; };
bool IsSupported (const boost::asio::ip::address& addr) const;
uint16_t GetPort (bool v4) const;
bool IsConnectedRecently (const boost::asio::ip::udp::endpoint& ep) const;
void AddConnectedRecently (const boost::asio::ip::udp::endpoint& ep, uint64_t ts);
std::mt19937& GetRng () { return m_Rng; }
bool IsMaxNumIntroducers (bool v4) const { return (v4 ? m_Introducers.size () : m_IntroducersV6.size ()) >= SSU2_MAX_NUM_INTRODUCERS; }
bool IsSyncClockFromPeers () const { return m_IsSyncClockFromPeers; };
Expand Down Expand Up @@ -160,7 +163,7 @@ namespace transport
std::map<boost::asio::ip::udp::endpoint, std::shared_ptr<SSU2Session> > m_PendingOutgoingSessions;
mutable std::mutex m_PendingOutgoingSessionsMutex;
std::map<boost::asio::ip::udp::endpoint, std::pair<uint64_t, uint32_t> > m_IncomingTokens, m_OutgoingTokens; // remote endpoint -> (token, expires in seconds)
std::map<uint32_t, std::shared_ptr<SSU2Session> > m_Relays; // we are introducer, relay tag -> session
std::unordered_map<uint32_t, std::shared_ptr<SSU2Session> > m_Relays; // we are introducer, relay tag -> session
std::list<i2p::data::IdentHash> m_Introducers, m_IntroducersV6; // introducers we are connected to
i2p::util::MemoryPoolMt<Packet> m_PacketsPool;
i2p::util::MemoryPool<SSU2SentPacket> m_SentPacketsPool;
Expand All @@ -174,7 +177,8 @@ namespace transport
int64_t m_PendingTimeOffset; // during peer test
std::shared_ptr<const i2p::data::IdentityEx> m_PendingTimeOffsetFrom;
std::mt19937 m_Rng;

std::map<boost::asio::ip::udp::endpoint, uint64_t> m_ConnectedRecently; // endpoint -> last activity time in seconds

// proxy
bool m_IsThroughProxy;
uint8_t m_UDPRequestHeader[SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE];
Expand Down
28 changes: 15 additions & 13 deletions libi2pd/SSU2Session.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ namespace transport
m_OnEstablished = nullptr;
if (m_RelayTag)
m_Server.RemoveRelay (m_RelayTag);
m_Server.AddConnectedRecently (m_RemoteEndpoint, GetLastActivityTimestamp ());
m_SentHandshakePacket.reset (nullptr);
m_SessionConfirmedFragment.reset (nullptr);
m_PathChallenge.reset (nullptr);
Expand All @@ -281,14 +282,10 @@ namespace transport
transports.PeerDisconnected (shared_from_this ());
auto remoteIdentity = GetRemoteIdentity ();
if (remoteIdentity)
{
LogPrint (eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (),
" (", i2p::data::GetIdentHashAbbreviation (remoteIdentity->GetIdentHash ()), ") terminated");
}
else
{
LogPrint (eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (), " terminated");
}
}
}

Expand Down Expand Up @@ -1153,7 +1150,7 @@ namespace transport
if (profile) // older router?
profile->Duplicated (); // mark router as duplicated in profile
else
LogPrint (eLogError, "SSU2: Host mismatch between published address ", m_Address->host,
LogPrint (eLogInfo, "SSU2: Host mismatch between published address ", m_Address->host,
" and actual endpoint ", m_RemoteEndpoint.address (), " from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
return false;
}
Expand Down Expand Up @@ -2276,14 +2273,19 @@ namespace transport
if (addr && m_Server.IsSupported (ep.address ()) &&
i2p::context.GetRouterInfo ().IsSSU2PeerTesting (ep.address ().is_v4 ()))
{
// send msg 5 to Alice
auto session = std::make_shared<SSU2Session> (m_Server, r, addr);
session->SetState (eSSU2SessionStatePeerTest);
session->m_RemoteEndpoint = ep; // might be different
session->m_DestConnID = htobe64 (((uint64_t)nonce << 32) | nonce);
session->m_SourceConnID = ~session->m_DestConnID;
m_Server.AddSession (session);
session->SendPeerTest (5, newSignedData.data (), newSignedData.size (), addr->i);
if (!m_Server.IsConnectedRecently (ep)) // no alive hole punch
{
// send msg 5 to Alice
auto session = std::make_shared<SSU2Session> (m_Server, r, addr);
session->SetState (eSSU2SessionStatePeerTest);
session->m_RemoteEndpoint = ep; // might be different
session->m_DestConnID = htobe64 (((uint64_t)nonce << 32) | nonce);
session->m_SourceConnID = ~session->m_DestConnID;
m_Server.AddSession (session);
session->SendPeerTest (5, newSignedData.data (), newSignedData.size (), addr->i);
}
else
code = eSSU2PeerTestCodeCharlieAliceIsAlreadyConnected;
}
else
code = eSSU2PeerTestCodeCharlieUnsupportedAddress;
Expand Down

0 comments on commit f20391d

Please sign in to comment.