diff --git a/SSU.cpp b/SSU.cpp index 39197293..c735d912 100644 --- a/SSU.cpp +++ b/SSU.cpp @@ -463,12 +463,28 @@ namespace transport } } - void SSUServer::NewPeerTest (uint32_t nonce) + void SSUServer::NewPeerTest (uint32_t nonce, PeerTestParticipant role) { - m_PeerTests[nonce] = i2p::util::GetMillisecondsSinceEpoch (); + m_PeerTests[nonce] = { i2p::util::GetMillisecondsSinceEpoch (), role }; } - void SSUServer::PeerTestComplete (uint32_t nonce) + PeerTestParticipant SSUServer::GetPeerTestParticipant (uint32_t nonce) + { + auto it = m_PeerTests.find (nonce); + if (it != m_PeerTests.end ()) + return it->second.role; + else + return ePeerTestParticipantUnknown; + } + + void SSUServer::UpdatePeerTest (uint32_t nonce, PeerTestParticipant role) + { + auto it = m_PeerTests.find (nonce); + if (it != m_PeerTests.end ()) + it->second.role = role; + } + + void SSUServer::RemovePeerTest (uint32_t nonce) { m_PeerTests.erase (nonce); } diff --git a/SSU.h b/SSU.h index 12cbb775..f5f3cc87 100644 --- a/SSU.h +++ b/SSU.h @@ -53,8 +53,10 @@ namespace transport void AddRelay (uint32_t tag, const boost::asio::ip::udp::endpoint& relay); std::shared_ptr FindRelaySession (uint32_t tag); - void NewPeerTest (uint32_t nonce); - void PeerTestComplete (uint32_t nonce); + void NewPeerTest (uint32_t nonce, PeerTestParticipant role); + PeerTestParticipant GetPeerTestParticipant (uint32_t nonce); + void UpdatePeerTest (uint32_t nonce, PeerTestParticipant role); + void RemovePeerTest (uint32_t nonce); private: @@ -76,6 +78,12 @@ namespace transport private: + struct PeerTest + { + uint64_t creationTime; + PeerTestParticipant role; + }; + bool m_IsRunning; std::thread * m_Thread, * m_ThreadV6, * m_ReceiversThread; boost::asio::io_service m_Service, m_ServiceV6, m_ReceiversService; @@ -87,7 +95,7 @@ namespace transport std::mutex m_SessionsMutex; std::map > m_Sessions; std::map m_Relays; // we are introducer - std::map m_PeerTests; // nonce -> creation time in milliseconds + std::map m_PeerTests; // nonce -> creation time in milliseconds public: // for HTTP only diff --git a/SSUSession.cpp b/SSUSession.cpp index 42c6a17f..4e6f85f5 100644 --- a/SSUSession.cpp +++ b/SSUSession.cpp @@ -896,62 +896,80 @@ namespace transport LogPrint (eLogWarning, "Address of ", size, " bytes not supported"); return; } - if (m_PeerTestNonces.count (nonce) > 0) - { + switch (m_Server.GetPeerTestParticipant (nonce)) + { // existing test - if (m_PeerTest) // Alice - { + case ePeerTestParticipantAlice1: + { if (m_State == eSessionStateEstablished) LogPrint (eLogDebug, "SSU peer test from Bob. We are Alice"); else { LogPrint (eLogDebug, "SSU first peer test from Charlie. We are Alice"); - m_PeerTest = false; - m_PeerTestNonces.erase (nonce); - m_Server.PeerTestComplete (nonce); + m_Server.UpdatePeerTest (nonce, ePeerTestParticipantAlice2); SendPeerTest (nonce, senderEndpoint.address ().to_v4 ().to_ulong (), senderEndpoint.port (), introKey, true, false); // to Charlie } - } - else if (port) // Bob + break; + } + case ePeerTestParticipantAlice2: + { + if (m_State == eSessionStateEstablished) + LogPrint (eLogDebug, "SSU peer test from Bob. We are Alice"); + else + { + // peer test successive + LogPrint (eLogDebug, "SSU second peer test from Charlie. We are Alice"); + m_Server.RemovePeerTest (nonce); + } + break; + } + case ePeerTestParticipantBob: { LogPrint (eLogDebug, "SSU peer test from Charlie. We are Bob"); - m_PeerTestNonces.erase (nonce); // nonce has been used + m_Server.RemovePeerTest (nonce); // nonce has been used boost::asio::ip::udp::endpoint ep (boost::asio::ip::address_v4 (be32toh (address)), be16toh (port)); // Alice's address/port auto session = m_Server.FindSession (ep); // find session with Alice if (session) session->Send (PAYLOAD_TYPE_PEER_TEST, buf1, len); // back to Alice + break; } - else // Charlie - { + case ePeerTestParticipantCharlie: + { LogPrint (eLogDebug, "SSU peer test from Alice. We are Charlie"); + m_Server.RemovePeerTest (nonce); // nonce has been used SendPeerTest (nonce, senderEndpoint.address ().to_v4 ().to_ulong (), senderEndpoint.port (), introKey); // to Alice with her actual address + break; } - } - else - { - if (m_State == eSessionStateEstablished) + // test not found + case ePeerTestParticipantUnknown: { - // new test - m_PeerTestNonces.insert (nonce); - if (port) + if (m_State == eSessionStateEstablished) { - LogPrint (eLogDebug, "SSU peer test from Bob. We are Charlie"); - Send (PAYLOAD_TYPE_PEER_TEST, buf1, len); // back to Bob - SendPeerTest (nonce, be32toh (address), be16toh (port), introKey); // to Alice with her address received from Bob + // new test + if (port) + { + LogPrint (eLogDebug, "SSU peer test from Bob. We are Charlie"); + m_Server.NewPeerTest (nonce, ePeerTestParticipantCharlie); + Send (PAYLOAD_TYPE_PEER_TEST, buf1, len); // back to Bob + SendPeerTest (nonce, be32toh (address), be16toh (port), introKey); // to Alice with her address received from Bob + } + else + { + LogPrint (eLogDebug, "SSU peer test from Alice. We are Bob"); + auto session = m_Server.GetRandomEstablishedSession (shared_from_this ()); // Charlie + if (session) + { + m_Server.NewPeerTest (nonce, ePeerTestParticipantBob); + session->SendPeerTest (nonce, senderEndpoint.address ().to_v4 ().to_ulong (), + senderEndpoint.port (), introKey, false); // to Charlie with Alice's actual address + } + } } else - { - LogPrint (eLogDebug, "SSU peer test from Alice. We are Bob"); - auto session = m_Server.GetRandomEstablishedSession (shared_from_this ()); // Charlie - if (session) - session->SendPeerTest (nonce, senderEndpoint.address ().to_v4 ().to_ulong (), - senderEndpoint.port (), introKey, false); // to Charlie with Alice's actual address - } + LogPrint (eLogError, "SSU unexpected peer test"); } - else - LogPrint (eLogDebug, "SSU second peer test from Charlie. We are Alice"); } } @@ -1023,8 +1041,8 @@ namespace transport } uint32_t nonce = i2p::context.GetRandomNumberGenerator ().GenerateWord32 (); if (!nonce) nonce = 1; - m_PeerTestNonces.insert (nonce); - m_Server.NewPeerTest (nonce); + m_PeerTest = false; + m_Server.NewPeerTest (nonce, ePeerTestParticipantAlice1); SendPeerTest (nonce, 0, 0, address->key, false, false); // address and port always zero for Alice } diff --git a/SSUSession.h b/SSUSession.h index a8e5c54a..0889f416 100644 --- a/SSUSession.h +++ b/SSUSession.h @@ -49,6 +49,15 @@ namespace transport eSessionStateFailed }; + enum PeerTestParticipant + { + ePeerTestParticipantUnknown = 0, + ePeerTestParticipantAlice1, + ePeerTestParticipantAlice2, + ePeerTestParticipantBob, + ePeerTestParticipantCharlie + }; + class SSUServer; class SSUSession: public TransportSession, public std::enable_shared_from_this { @@ -133,7 +142,6 @@ namespace transport SessionState m_State; bool m_IsSessionKey; uint32_t m_RelayTag; - std::set m_PeerTestNonces; i2p::crypto::CBCEncryption m_SessionKeyEncryption; i2p::crypto::CBCDecryption m_SessionKeyDecryption; i2p::crypto::AESKey m_SessionKey;