From f20391d4600d41279e2b473470d98239ce7e52f4 Mon Sep 17 00:00:00 2001 From: orignal Date: Tue, 17 Sep 2024 21:49:23 -0400 Subject: [PATCH] check if we connected recently to an endpoint before sending peer test --- libi2pd/SSU2.cpp | 24 ++++++++++++++++++++++++ libi2pd/SSU2.h | 8 ++++++-- libi2pd/SSU2Session.cpp | 28 +++++++++++++++------------- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index b86e3743..ebaeb741 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -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 from) { if (offset) @@ -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 (); diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index fd071e8d..023f072e 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -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 { @@ -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; }; @@ -160,7 +163,7 @@ namespace transport std::map > m_PendingOutgoingSessions; mutable std::mutex m_PendingOutgoingSessionsMutex; std::map > m_IncomingTokens, m_OutgoingTokens; // remote endpoint -> (token, expires in seconds) - std::map > m_Relays; // we are introducer, relay tag -> session + std::unordered_map > m_Relays; // we are introducer, relay tag -> session std::list m_Introducers, m_IntroducersV6; // introducers we are connected to i2p::util::MemoryPoolMt m_PacketsPool; i2p::util::MemoryPool m_SentPacketsPool; @@ -174,7 +177,8 @@ namespace transport int64_t m_PendingTimeOffset; // during peer test std::shared_ptr m_PendingTimeOffsetFrom; std::mt19937 m_Rng; - + std::map m_ConnectedRecently; // endpoint -> last activity time in seconds + // proxy bool m_IsThroughProxy; uint8_t m_UDPRequestHeader[SOCKS5_UDP_IPV6_REQUEST_HEADER_SIZE]; diff --git a/libi2pd/SSU2Session.cpp b/libi2pd/SSU2Session.cpp index eb662716..d98b06c3 100644 --- a/libi2pd/SSU2Session.cpp +++ b/libi2pd/SSU2Session.cpp @@ -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); @@ -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"); - } } } @@ -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; } @@ -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 (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 (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;