diff --git a/libi2pd/SSU2OutOfSession.cpp b/libi2pd/SSU2OutOfSession.cpp index dc626b16..bed3dabe 100644 --- a/libi2pd/SSU2OutOfSession.cpp +++ b/libi2pd/SSU2OutOfSession.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2024-2025, The PurpleI2P Project +* Copyright (c) 2024-2026, The PurpleI2P Project * * This file is part of Purple i2pd project and licensed under BSD3 * @@ -14,18 +14,18 @@ namespace i2p { namespace transport { - SSU2PeerTestSession::SSU2PeerTestSession (SSU2Server& server, uint64_t sourceConnID, uint64_t destConnID): - SSU2Session (server, nullptr, nullptr, false), + SSU2PeerTestSession::SSU2PeerTestSession (SSU2Server& server, uint64_t sourceConnID, uint64_t destConnID): + SSU2Session (server, nullptr, nullptr, false), m_MsgNumReceived (0), m_NumResends (0),m_IsConnectedRecently (false), m_IsStatusChanged (false), m_PeerTestResendTimer (server.GetService ()) { if (!sourceConnID) sourceConnID = ~destConnID; if (!destConnID) destConnID = ~sourceConnID; SetSourceConnID (sourceConnID); - SetDestConnID (destConnID); - SetState (eSSU2SessionStatePeerTest); + SetDestConnID (destConnID); + SetState (eSSU2SessionStatePeerTest); SetTerminationTimeout (SSU2_PEER_TEST_EXPIRATION_TIMEOUT); - } + } bool SSU2PeerTestSession::ProcessPeerTest (uint8_t * buf, size_t len) { @@ -63,14 +63,14 @@ namespace transport HandlePayload (payload, len - 48); SetIsDataReceived (false); return true; - } + } void SSU2PeerTestSession::HandleAddress (const uint8_t * buf, size_t len) { if (!ExtractEndpoint (buf, len, m_OurEndpoint)) LogPrint (eLogWarning, "SSU2: Can't handle address block from peer test message"); - } - + } + void SSU2PeerTestSession::HandlePeerTest (const uint8_t * buf, size_t len) { // msgs 5-7 @@ -80,19 +80,19 @@ namespace transport { LogPrint (eLogDebug, "SSU2: PeerTest msg num ", msg, " received after ", m_MsgNumReceived, ". Ignored"); return; - } + } size_t offset = 3; // points to signed data after msg + code + flag uint32_t nonce = bufbe32toh (buf + offset + 1); // 1 - ver switch (msg) // msg { case 5: // Alice from Charlie 1 - { + { if (htobe64 (((uint64_t)nonce << 32) | nonce) == GetSourceConnID ()) { m_PeerTestResendTimer.cancel (); // cancel delayed msg 6 if any - if (GetServer ().IsForcedFirewalled (GetRemoteEndpoint ().address().is_v4())) + if (GetServer ().IsForcedFirewalled (GetRemoteEndpoint ().address().is_v4())) // we assume that msg 5 was not received if forced firewalled - return; + return; m_IsConnectedRecently = GetServer ().IsConnectedRecently (GetRemoteEndpoint ()); if (GetAddress ()) { @@ -108,49 +108,51 @@ namespace transport break; } case 6: // Charlie from Alice - { + { m_PeerTestResendTimer.cancel (); // no more msg 5 resends if (GetAddress ()) SendPeerTest (7, buf + offset, len - offset); else LogPrint (eLogWarning, "SSU2: Unknown address for peer test 6"); + GetServer ().AddConnectedRecently (GetRemoteEndpoint (), i2p::util::GetSecondsSinceEpoch ()); GetServer ().RequestRemoveSession (GetConnID ()); break; - } + } case 7: // Alice from Charlie 2 - { + { m_PeerTestResendTimer.cancel (); // no more msg 6 resends if (m_MsgNumReceived < 5 && m_OurEndpoint.port ()) // msg 5 was not received { if (m_OurEndpoint.address ().is_v4 ()) // ipv4 { if (i2p::context.GetStatus () == eRouterStatusFirewalled) - { + { if (m_OurEndpoint.port () != GetServer ().GetPort (true)) i2p::context.SetError (eRouterErrorSymmetricNAT); else if (i2p::context.GetError () == eRouterErrorSymmetricNAT) i2p::context.SetError (eRouterErrorNone); } - } + } else { if (i2p::context.GetStatusV6 () == eRouterStatusFirewalled) - { + { if (m_OurEndpoint.port () != GetServer ().GetPort (false)) i2p::context.SetErrorV6 (eRouterErrorSymmetricNAT); else if (i2p::context.GetErrorV6 () == eRouterErrorSymmetricNAT) i2p::context.SetErrorV6 (eRouterErrorNone); } - } - } - GetServer ().RequestRemoveSession (GetConnID ()); + } + } + GetServer ().AddConnectedRecently (GetRemoteEndpoint (), i2p::util::GetSecondsSinceEpoch ()); + GetServer ().RequestRemoveSession (GetConnID ()); break; - } - default: + } + default: LogPrint (eLogWarning, "SSU2: PeerTest unexpected msg num ", msg); return; - } - m_MsgNumReceived = msg; + } + m_MsgNumReceived = msg; } void SSU2PeerTestSession::SendPeerTest (uint8_t msg) @@ -190,7 +192,7 @@ namespace transport // send GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, GetRemoteEndpoint ()); UpdateNumSentBytes (payloadSize + 32); - } + } void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, bool delayed) { @@ -200,26 +202,26 @@ namespace transport // schedule resend for msgs 5 or 6 if (msg == 5 || msg == 6) ScheduleResend (msg); - } - - void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, + } + + void SSU2PeerTestSession::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, std::shared_ptr addr, bool delayed) { if (!addr) return; SetAddress (addr); - SendPeerTest (msg, signedData, signedDataLen, delayed); - } + SendPeerTest (msg, signedData, signedDataLen, delayed); + } void SSU2PeerTestSession::Connect () { LogPrint (eLogError, "SSU2: Can't connect peer test session"); - } + } bool SSU2PeerTestSession::ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len) { LogPrint (eLogError, "SSU2: Can't handle incoming message in peer test session"); return false; - } + } void SSU2PeerTestSession::ScheduleResend (uint8_t msg) { @@ -233,19 +235,19 @@ namespace transport if (ecode != boost::asio::error::operation_aborted) { auto s1 = s.lock (); - if (s1) + if (s1) { - if (msg > s1->m_MsgNumReceived) - { + if (msg > s1->m_MsgNumReceived) + { s1->SendPeerTest (msg); s1->m_NumResends++; s1->ScheduleResend (msg); - } - } - } + } + } + } }); - } - } + } + } SSU2HolePunchSession::SSU2HolePunchSession (SSU2Server& server, uint32_t nonce, const boost::asio::ip::udp::endpoint& remoteEndpoint, @@ -257,12 +259,12 @@ namespace transport uint64_t destConnID = htobe64 (((uint64_t)nonce << 32) | nonce); // dest id uint64_t sourceConnID = ~destConnID; SetSourceConnID (sourceConnID); - SetDestConnID (destConnID); + SetDestConnID (destConnID); SetState (eSSU2SessionStateHolePunch); SetRemoteEndpoint (remoteEndpoint); SetAddress (addr); - SetTerminationTimeout (SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT); - } + SetTerminationTimeout (SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT); + } void SSU2HolePunchSession::SendHolePunch () { @@ -288,12 +290,12 @@ namespace transport htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); size_t payloadSize = 7; payloadSize += CreateAddressBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize, ep); - // relay response block + // relay response block if (payloadSize + m_RelayResponseBlock.size () < GetMaxPayloadSize ()) - { + { memcpy (payload + payloadSize, m_RelayResponseBlock.data (), m_RelayResponseBlock.size ()); payloadSize += m_RelayResponseBlock.size (); - } + } payloadSize += CreatePaddingBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize); // encrypt uint8_t n[12]; @@ -307,14 +309,14 @@ namespace transport // send GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, ep); UpdateNumSentBytes (payloadSize + 32); - } + } void SSU2HolePunchSession::SendHolePunch (const uint8_t * relayResponseBlock, size_t relayResponseBlockLen) { m_RelayResponseBlock.assign (relayResponseBlock, relayResponseBlock + relayResponseBlockLen); SendHolePunch (); ScheduleResend (); - } + } void SSU2HolePunchSession::ScheduleResend () { @@ -328,21 +330,21 @@ namespace transport if (ecode != boost::asio::error::operation_aborted) { auto s1 = s.lock (); - if (s1 && s1->GetState () == eSSU2SessionStateHolePunch) + if (s1 && s1->GetState () == eSSU2SessionStateHolePunch) { s1->SendHolePunch (); s1->m_NumResends++; - s1->ScheduleResend (); - } - } + s1->ScheduleResend (); + } + } }); - } + } } bool SSU2HolePunchSession::ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len) { m_HolePunchResendTimer.cancel (); return SSU2Session::ProcessFirstIncomingMessage (connID, buf, len); - } + } } }