Browse Source

implement SSU2HolPunchSession

pull/2108/head
orignal 1 month ago
parent
commit
97fdedfbe3
  1. 11
      libi2pd/SSU2.cpp
  2. 58
      libi2pd/SSU2OutOfSession.cpp
  3. 15
      libi2pd/SSU2OutOfSession.h
  4. 48
      libi2pd/SSU2Session.cpp
  5. 5
      libi2pd/SSU2Session.h

11
libi2pd/SSU2.cpp

@ -479,9 +479,11 @@ namespace transport
{ {
if (session) if (session)
{ {
m_Sessions.emplace (session->GetConnID (), session); if (m_Sessions.emplace (session->GetConnID (), session).second)
if (session->GetState () != eSSU2SessionStatePeerTest) {
AddSessionByRouterHash (session); if (session->GetState () != eSSU2SessionStatePeerTest)
AddSessionByRouterHash (session);
}
} }
} }
@ -715,6 +717,9 @@ namespace transport
m_LastSession->SetRemoteEndpoint (senderEndpoint); m_LastSession->SetRemoteEndpoint (senderEndpoint);
m_LastSession->ProcessPeerTest (buf, len); m_LastSession->ProcessPeerTest (buf, len);
break; break;
case eSSU2SessionStateHolePunch:
m_LastSession->ProcessFirstIncomingMessage (connID, buf, len); // SessionRequest
break;
case eSSU2SessionStateClosing: case eSSU2SessionStateClosing:
m_LastSession->ProcessData (buf, len, senderEndpoint); // we might receive termintaion block m_LastSession->ProcessData (buf, len, senderEndpoint); // we might receive termintaion block
if (m_LastSession && m_LastSession->GetState () == eSSU2SessionStateClosing) if (m_LastSession && m_LastSession->GetState () == eSSU2SessionStateClosing)

58
libi2pd/SSU2OutOfSession.cpp

@ -224,5 +224,63 @@ namespace transport
m_NumResends++; m_NumResends++;
} }
} }
SSU2HolePunchSession::SSU2HolePunchSession (SSU2Server& server, uint32_t nonce,
const boost::asio::ip::udp::endpoint& remoteEndpoint,
std::shared_ptr<const i2p::data::RouterInfo::Address> localAddr):
SSU2Session (server), // we create full incoming session
m_Nonce (nonce)
{
// we are Charlie
m_Token = GetServer ().GetIncomingToken (remoteEndpoint);
uint64_t destConnID = htobe64 (((uint64_t)nonce << 32) | nonce); // dest id
uint32_t sourceConnID = ~destConnID;
SetSourceConnID (sourceConnID);
SetDestConnID (destConnID);
SetState (eSSU2SessionStateHolePunch);
SetRemoteEndpoint (remoteEndpoint);
SetAddress (localAddr);
SetTerminationTimeout (SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT);
}
void SSU2HolePunchSession::SendHolePunch ()
{
auto addr = GetAddress ();
if (!addr) return;
auto& ep = GetRemoteEndpoint ();
LogPrint (eLogDebug, "SSU2: Sending HolePunch to ", ep);
Header header;
uint8_t h[32], payload[SSU2_MAX_PACKET_SIZE];
// fill packet
header.h.connID = GetDestConnID (); // dest id
RAND_bytes (header.buf + 8, 4); // random packet num
header.h.type = eSSU2HolePunch;
header.h.flags[0] = 2; // ver
header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID
header.h.flags[2] = 0; // flag
memcpy (h, header.buf, 16);
htobuf64 (h + 16, GetSourceConnID ()); // source id
RAND_bytes (h + 24, 8); // header token, to be ignored by Alice
// payload
payload[0] = eSSU2BlkDateTime;
htobe16buf (payload + 1, 4);
htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000);
size_t payloadSize = 7;
payloadSize += CreateAddressBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize, ep);
payloadSize += CreateRelayResponseBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize,
eSSU2RelayResponseCodeAccept, m_Nonce, m_Token, ep.address ().is_v4 ());
payloadSize += CreatePaddingBlock (payload + payloadSize, GetMaxPayloadSize () - payloadSize);
// encrypt
uint8_t n[12];
CreateNonce (be32toh (header.h.packetNum), n);
i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, h, 32, addr->i, n, payload, payloadSize + 16, true);
payloadSize += 16;
header.ll[0] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 24));
header.ll[1] ^= CreateHeaderMask (addr->i, payload + (payloadSize - 12));
memset (n, 0, 12);
i2p::crypto::ChaCha20 (h + 16, 16, addr->i, n, h + 16);
// send
GetServer ().Send (header.buf, 16, h + 16, 16, payload, payloadSize, ep);
}
} }
} }

15
libi2pd/SSU2OutOfSession.h

@ -51,6 +51,21 @@ namespace transport
std::vector<uint8_t> m_SignedData; // for resends std::vector<uint8_t> m_SignedData; // for resends
boost::asio::deadline_timer m_PeerTestResendTimer; boost::asio::deadline_timer m_PeerTestResendTimer;
}; };
class SSU2HolePunchSession: public SSU2Session // Charlie
{
public:
SSU2HolePunchSession (SSU2Server& server, uint32_t nonce, const boost::asio::ip::udp::endpoint& remoteEndpoint,
std::shared_ptr<const i2p::data::RouterInfo::Address> localAddr);
void SendHolePunch ();
private:
uint32_t m_Nonce;
uint64_t m_Token; // for RelayResponse block
};
} }
} }

48
libi2pd/SSU2Session.cpp

@ -1352,46 +1352,6 @@ namespace transport
return true; return true;
} }
void SSU2Session::SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep,
const uint8_t * introKey, uint64_t token)
{
// we are Charlie
LogPrint (eLogDebug, "SSU2: Sending HolePunch to ", ep);
Header header;
uint8_t h[32], payload[SSU2_MAX_PACKET_SIZE];
// fill packet
header.h.connID = htobe64 (((uint64_t)nonce << 32) | nonce); // dest id
RAND_bytes (header.buf + 8, 4); // random packet num
header.h.type = eSSU2HolePunch;
header.h.flags[0] = 2; // ver
header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID
header.h.flags[2] = 0; // flag
memcpy (h, header.buf, 16);
uint64_t c = ~header.h.connID;
memcpy (h + 16, &c, 8); // source id
RAND_bytes (h + 24, 8); // token
// payload
payload[0] = eSSU2BlkDateTime;
htobe16buf (payload + 1, 4);
htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000);
size_t payloadSize = 7;
payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, ep);
payloadSize += CreateRelayResponseBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize,
eSSU2RelayResponseCodeAccept, nonce, token, ep.address ().is_v4 ());
payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
// encrypt
uint8_t n[12];
CreateNonce (be32toh (header.h.packetNum), n);
i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, h, 32, introKey, n, payload, payloadSize + 16, true);
payloadSize += 16;
header.ll[0] ^= CreateHeaderMask (introKey, payload + (payloadSize - 24));
header.ll[1] ^= CreateHeaderMask (introKey, payload + (payloadSize - 12));
memset (n, 0, 12);
i2p::crypto::ChaCha20 (h + 16, 16, introKey, n, h + 16);
// send
m_Server.Send (header.buf, 16, h + 16, 16, payload, payloadSize, ep);
}
bool SSU2Session::ProcessHolePunch (uint8_t * buf, size_t len) bool SSU2Session::ProcessHolePunch (uint8_t * buf, size_t len)
{ {
// we are Alice // we are Alice
@ -1984,7 +1944,6 @@ namespace transport
void SSU2Session::HandleRelayIntro (const uint8_t * buf, size_t len, int attempts) void SSU2Session::HandleRelayIntro (const uint8_t * buf, size_t len, int attempts)
{ {
// we are Charlie // we are Charlie
auto mts = i2p::util::GetMillisecondsSinceEpoch ();
SSU2RelayResponseCode code = eSSU2RelayResponseCodeAccept; SSU2RelayResponseCode code = eSSU2RelayResponseCodeAccept;
uint64_t token = 0; uint64_t token = 0;
bool isV4 = false; bool isV4 = false;
@ -2011,10 +1970,11 @@ namespace transport
{ {
if (m_Server.IsSupported (ep.address ())) if (m_Server.IsSupported (ep.address ()))
{ {
token = m_Server.GetIncomingToken (ep);
isV4 = ep.address ().is_v4 (); isV4 = ep.address ().is_v4 ();
SendHolePunch (bufbe32toh (buf + 33), ep, addr->i, token); auto holePunchSession = std::make_shared<SSU2HolePunchSession>(
m_Server.AddConnectedRecently (ep, mts/1000); m_Server, bufbe32toh (buf + 33), ep, addr);
m_Server.AddSession (holePunchSession);
holePunchSession->SendHolePunch ();
} }
else else
{ {

5
libi2pd/SSU2Session.h

@ -112,6 +112,7 @@ namespace transport
eSSU2SessionStateTerminated, eSSU2SessionStateTerminated,
eSSU2SessionStateFailed, eSSU2SessionStateFailed,
eSSU2SessionStateIntroduced, eSSU2SessionStateIntroduced,
eSSU2SessionStateHolePunch,
eSSU2SessionStatePeerTest, eSSU2SessionStatePeerTest,
eSSU2SessionStateTokenRequestReceived eSSU2SessionStateTokenRequestReceived
}; };
@ -295,6 +296,8 @@ namespace transport
size_t CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep); size_t CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep);
size_t CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize = 0); size_t CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize = 0);
size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code, const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen); size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code, const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen);
size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, uint64_t token, bool v4);
private: private:
@ -320,7 +323,6 @@ namespace transport
uint32_t SendData (const uint8_t * buf, size_t len, uint8_t flags = 0); // returns packet num uint32_t SendData (const uint8_t * buf, size_t len, uint8_t flags = 0); // returns packet num
void SendQuickAck (); void SendQuickAck ();
void SendTermination (); void SendTermination ();
void SendHolePunch (uint32_t nonce, const boost::asio::ip::udp::endpoint& ep, const uint8_t * introKey, uint64_t token);
void SendPathResponse (const uint8_t * data, size_t len); void SendPathResponse (const uint8_t * data, size_t len);
void SendPathChallenge (); void SendPathChallenge ();
@ -352,7 +354,6 @@ namespace transport
size_t CreateFirstFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg); size_t CreateFirstFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg);
size_t CreateFollowOnFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg, uint8_t& fragmentNum, uint32_t msgID); size_t CreateFollowOnFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg, uint8_t& fragmentNum, uint32_t msgID);
size_t CreateRelayIntroBlock (uint8_t * buf, size_t len, const uint8_t * introData, size_t introDataLen); size_t CreateRelayIntroBlock (uint8_t * buf, size_t len, const uint8_t * introData, size_t introDataLen);
size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, uint64_t token, bool v4);
size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint32_t nonce); // Alice size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint32_t nonce); // Alice
size_t CreateTerminationBlock (uint8_t * buf, size_t len); size_t CreateTerminationBlock (uint8_t * buf, size_t len);

Loading…
Cancel
Save