diff --git a/libi2pd/NetDb.cpp b/libi2pd/NetDb.cpp index ef36895a..7cb11452 100644 --- a/libi2pd/NetDb.cpp +++ b/libi2pd/NetDb.cpp @@ -1203,6 +1203,16 @@ namespace data }); } + std::shared_ptr NetDb::GetRandomSSU2PeerTestRouter (bool v4, const std::set& excluded) const + { + return GetRandomRouter ( + [v4, &excluded](std::shared_ptr router)->bool + { + return !router->IsHidden () && router->IsECIES () && + router->IsSSU2PeerTesting (v4) && !excluded.count (router->GetIdentHash ()); + }); + } + std::shared_ptr NetDb::GetRandomSSUV6Router () const { return GetRandomRouter ( diff --git a/libi2pd/NetDb.hpp b/libi2pd/NetDb.hpp index ad88274a..22fe693f 100644 --- a/libi2pd/NetDb.hpp +++ b/libi2pd/NetDb.hpp @@ -90,6 +90,7 @@ namespace data std::shared_ptr GetRandomRouter (std::shared_ptr compatibleWith, bool reverse) const; std::shared_ptr GetHighBandwidthRandomRouter (std::shared_ptr compatibleWith, bool reverse) const; std::shared_ptr GetRandomPeerTestRouter (bool v4, const std::set& excluded) const; + std::shared_ptr GetRandomSSU2PeerTestRouter (bool v4, const std::set& excluded) const; std::shared_ptr GetRandomSSUV6Router () const; // TODO: change to v6 peer test later std::shared_ptr GetRandomIntroducer (bool v4, const std::set& excluded) const; std::shared_ptr GetClosestFloodfill (const IdentHash& destination, const std::set& excluded, bool closeThanUsOnly = false) const; diff --git a/libi2pd/RouterInfo.cpp b/libi2pd/RouterInfo.cpp index 34f38919..17469c29 100644 --- a/libi2pd/RouterInfo.cpp +++ b/libi2pd/RouterInfo.cpp @@ -1000,6 +1000,17 @@ namespace data }); } + bool RouterInfo::IsSSU2PeerTesting (bool v4) const + { + if (!(m_SupportedTransports & (v4 ? eSSU2V4 : eSSU2V6))) return false; + return (bool)GetAddress ( + [v4](std::shared_ptr address)->bool + { + return (address->IsSSU2 ()) && address->IsPeerTesting () && + ((v4 && address->IsV4 ()) || (!v4 && address->IsV6 ())) && address->IsReachableSSU (); + }); + } + bool RouterInfo::IsIntroducer (bool v4) const { if (!(m_SupportedTransports & (v4 ? eSSUV4 : eSSUV6))) return false; diff --git a/libi2pd/RouterInfo.h b/libi2pd/RouterInfo.h index a93f2a64..3615006d 100644 --- a/libi2pd/RouterInfo.h +++ b/libi2pd/RouterInfo.h @@ -232,6 +232,7 @@ namespace data bool IsExtraBandwidth () const { return m_Caps & RouterInfo::eExtraBandwidth; }; bool IsEligibleFloodfill () const; bool IsPeerTesting (bool v4) const; + bool IsSSU2PeerTesting (bool v4) const; bool IsIntroducer (bool v4) const; uint8_t GetCaps () const { return m_Caps; }; diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 71af2a90..0041b20a 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -106,12 +106,22 @@ namespace transport return true; } + void SSU2Session::SendPeerTest () + { + // we are Alice + uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; + size_t payloadSize = CreatePeerTestBlock (payload, SSU2_MAX_PAYLOAD_SIZE); + payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); + SendData (payload, payloadSize); + } + void SSU2Session::Terminate () { if (m_State != eSSU2SessionStateTerminated) { m_State = eSSU2SessionStateTerminated; transports.PeerDisconnected (shared_from_this ()); + m_OnEstablished = nullptr; m_Server.RemoveSession (m_SourceConnID); if (m_RelayTag) m_Server.RemoveRelay (m_RelayTag); @@ -134,7 +144,11 @@ namespace transport m_SessionConfirmedFragment1.reset (nullptr); SetTerminationTimeout (SSU2_TERMINATION_TIMEOUT); transports.PeerConnected (shared_from_this ()); - if (m_OnEstablished) m_OnEstablished (); + if (m_OnEstablished) + { + m_OnEstablished (); + m_OnEstablished = nullptr; + } } void SSU2Session::Done () @@ -1279,7 +1293,7 @@ namespace transport uint32_t nonce = bufbe32toh (buf + 37); switch (buf[0]) // msg { - case 1: // Bob for Alice + case 1: // Bob from Alice break; case 2: // Charlie from Bob break; @@ -1293,11 +1307,20 @@ namespace transport if (payloadSize < SSU2_MAX_PAYLOAD_SIZE) payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); it->second.first->SendData (payload, payloadSize); + m_PeerTests.erase (it); } break; } case 4: // Alice from Bob - break; + { + auto it = m_PeerTests.find (nonce); + if (it != m_PeerTests.end ()) + { + // TODO: send to Charlie + m_PeerTests.erase (it); + } + break; + } case 5: // Alice from Chralie 1 break; case 6: // Chralie from Alice @@ -2119,6 +2142,26 @@ namespace transport } } + bool SSU2Server::StartPeerTest (std::shared_ptr router, bool v4) + { + if (!router) return false; + auto addr = v4 ? router->GetSSU2V4Address () : router->GetSSU2V6Address (); + if (!addr) return false; + auto it = m_SessionsByRouterHash.find (router->GetIdentHash ()); + if (it != m_SessionsByRouterHash.end ()) + { + it->second->SendPeerTest (); + return true; + } + auto s = std::make_shared (*this, router, addr); + s->SetOnEstablished ([s]() + { + s->SendPeerTest (); + }); + s->Connect (); + return true; + } + void SSU2Server::ScheduleTermination () { m_TerminationTimer.expires_from_now (boost::posix_time::seconds(SSU2_TERMINATION_CHECK_TIMEOUT)); diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index f9dff1a3..03c72b52 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -150,6 +150,7 @@ namespace transport void Connect (); bool Introduce (std::shared_ptr session, uint32_t relayTag); + void SendPeerTest (); void Terminate (); void TerminateByTimeout (); void CleanUp (uint64_t ts); @@ -289,7 +290,8 @@ namespace transport bool CreateSession (std::shared_ptr router, std::shared_ptr address); - + bool StartPeerTest (std::shared_ptr router, bool v4); + void UpdateOutgoingToken (const boost::asio::ip::udp::endpoint& ep, uint64_t token, uint32_t exp); uint64_t FindOutgoingToken (const boost::asio::ip::udp::endpoint& ep) const; uint64_t GetIncomingToken (const boost::asio::ip::udp::endpoint& ep); diff --git a/libi2pd/Transports.cpp b/libi2pd/Transports.cpp index 8b656561..76cd4514 100644 --- a/libi2pd/Transports.cpp +++ b/libi2pd/Transports.cpp @@ -654,6 +654,16 @@ namespace transport } if (!statusChanged) LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv4"); + + // SSU2 + if (m_SSU2Server) + { + excluded.clear (); + excluded.insert (i2p::context.GetIdentHash ()); + auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (true, excluded); // v4 + if (router) + m_SSU2Server->StartPeerTest (router, true); + } } if (ipv6 && i2p::context.SupportsV6 ()) { @@ -681,6 +691,16 @@ namespace transport } if (!statusChanged) LogPrint (eLogWarning, "Transports: Can't find routers for peer test IPv6"); + + // SSU2 + if (m_SSU2Server) + { + excluded.clear (); + excluded.insert (i2p::context.GetIdentHash ()); + auto router = i2p::data::netdb.GetRandomSSU2PeerTestRouter (false, excluded); // v6 + if (router) + m_SSU2Server->StartPeerTest (router, false); + } } }