From 53148fe58f7cc4bc82658cf991beefcc64148235 Mon Sep 17 00:00:00 2001 From: orignal Date: Sat, 26 Mar 2022 16:35:07 -0400 Subject: [PATCH] send Ack packet --- libi2pd/SSU2.cpp | 121 ++++++++++++++++++++++++++++++++++++----------- libi2pd/SSU2.h | 11 ++++- 2 files changed, 104 insertions(+), 28 deletions(-) diff --git a/libi2pd/SSU2.cpp b/libi2pd/SSU2.cpp index 746d5bce..0af896e7 100644 --- a/libi2pd/SSU2.cpp +++ b/libi2pd/SSU2.cpp @@ -31,7 +31,7 @@ namespace transport std::shared_ptr addr, bool peerTest): TransportSession (in_RemoteRouter, SSU2_CONNECT_TIMEOUT), m_Server (server), m_Address (addr), m_DestConnID (0), m_SourceConnID (0), - m_State (eSSU2SessionStateUnknown) + m_State (eSSU2SessionStateUnknown), m_SendPacketNum (0), m_ReceivePacketNum (0) { m_NoiseState.reset (new i2p::crypto::NoiseSymmetricState); if (in_RemoteRouter && m_Address) @@ -62,6 +62,14 @@ namespace transport SendTokenRequest (); } + void SSU2Session::Established () + { + m_State = eSSU2SessionStateEstablished; + m_EphemeralKeys = nullptr; + m_NoiseState.reset (nullptr); + SetTerminationTimeout (SSU2_TERMINATION_TIMEOUT); + } + void SSU2Session::ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len) { // we are Bob @@ -108,6 +116,7 @@ namespace transport uint8_t paddingSize = (rand () & 0x0F) + 1; // 1 - 16 payload[payloadSize] = eSSU2BlkPadding; htobe16buf (payload + payloadSize + 1, paddingSize); + memset (payload + payloadSize + 3, 0, paddingSize); payloadSize += paddingSize + 3; // KDF for session request m_NoiseState->MixHash ({ {header.buf, 16}, {headerX, 16} }); // h = SHA256(h || header) @@ -182,14 +191,8 @@ namespace transport htobe16buf (payload + 1, 4); htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ()); size_t payloadSize = 7; - payloadSize += CreateAddressBlock (m_RemoteEndpoint, payload, 57); - uint8_t paddingSize = rand () & 0x0F; // 0 - 15 - if (paddingSize) - { - payload[payloadSize] = eSSU2BlkPadding; - htobe16buf (payload + payloadSize + 1, paddingSize); - payloadSize += paddingSize + 3; - } + payloadSize += CreateAddressBlock (m_RemoteEndpoint, payload, 64 - payloadSize); + payloadSize += CreatePaddingBlock (payload + payloadSize, 64 - payloadSize); // KDF for SessionCreated m_NoiseState->MixHash ( { {header.buf, 16}, {headerX, 16} } ); // h = SHA256(h || header) m_NoiseState->MixHash (headerX + 16, 32); // h = SHA256(h || bepk); @@ -243,9 +246,9 @@ namespace transport HandlePayload (decryptedPayload.data (), decryptedPayload.size ()); m_Server.AddSession (m_SourceConnID, shared_from_this ()); - m_State = eSSU2SessionStateEstablished; SendSessionConfirmed (headerX + 16); KDFDataPhase (m_KeyDataSend, m_KeyDataReceive); + Established (); return true; } @@ -280,13 +283,7 @@ namespace transport htobe16buf (payload + 1, payloadSize + 2); payload[4] = 1; // frag payloadSize += 5; - uint8_t paddingSize = rand () & 0x0F; // 0 - 15 - if (paddingSize) - { - payload[payloadSize] = eSSU2BlkPadding; - htobe16buf (payload + payloadSize + 1, paddingSize); - payloadSize += paddingSize + 3; - } + payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MTU - payloadSize); // KDF for Session Confirmed part 1 m_NoiseState->MixHash (header.buf, 16); // h = SHA256(h || header) // Encrypt part 1 @@ -309,6 +306,7 @@ namespace transport header.ll[1] ^= CreateHeaderMask (kh2, payload + (payloadSize - 12)); // send m_Server.Send (header.buf, 16, part1, 48, payload, payloadSize, m_RemoteEndpoint); + m_SendPacketNum++; } bool SSU2Session::ProcessSessionConfirmed (uint8_t * buf, size_t len) @@ -380,8 +378,9 @@ namespace transport i2p::data::netdb.PostI2NPMsg (CreateI2NPMessage (eI2NPDummyMsg, ri->GetBuffer (), ri->GetBufferLen ())); // TODO: should insert ri // handle other blocks HandlePayload (decryptedPayload.data () + riSize + 3, decryptedPayload.size () - riSize - 3); - m_State = eSSU2SessionStateEstablished; KDFDataPhase (m_KeyDataReceive, m_KeyDataSend); + Established (); + return true; } @@ -418,6 +417,7 @@ namespace transport uint8_t paddingSize = (rand () & 0x0F) + 1; // 1 - 16 payload[payloadSize] = eSSU2BlkPadding; htobe16buf (payload + payloadSize + 1, paddingSize); + memset (payload + payloadSize + 3, 0, paddingSize); payloadSize += paddingSize + 3; // encrypt const uint8_t nonce[12] = {0}; @@ -473,14 +473,8 @@ namespace transport htobe16buf (payload + 1, 4); htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ()); size_t payloadSize = 7; - payloadSize += CreateAddressBlock (m_RemoteEndpoint, payload, 57); - uint8_t paddingSize = rand () & 0x0F; // 0 - 15 - if (paddingSize) - { - payload[payloadSize] = eSSU2BlkPadding; - htobe16buf (payload + payloadSize + 1, paddingSize); - payloadSize += paddingSize + 3; - } + payloadSize += CreateAddressBlock (m_RemoteEndpoint, payload, 64 - payloadSize); + payloadSize += CreatePaddingBlock (payload + payloadSize, 64 - payloadSize); // encrypt const uint8_t nonce[12] = {0}; i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, h, 32, i2p::context.GetSSU2IntroKey (), nonce, payload, payloadSize + 16, true); @@ -527,6 +521,23 @@ namespace transport return true; } + void SSU2Session::SendData (const uint8_t * buf, size_t len) + { + Header header; + header.h.connID = m_DestConnID; + header.h.packetNum = htobe32 (m_SendPacketNum); + header.h.type = eSSU2Data; + memset (header.h.flags, 0, 3); + uint8_t payload[SSU2_MTU]; + uint8_t nonce[12]; + CreateNonce (m_SendPacketNum, nonce); + i2p::crypto::AEADChaCha20Poly1305 (buf, len, header.buf, 16, m_KeyDataSend, nonce, payload, SSU2_MTU, true); + m_Server.Send (header.buf, 16, payload, len + 16, m_RemoteEndpoint); + m_SendPacketNum++; + m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); + m_NumSentBytes += len + 32; + } + void SSU2Session::ProcessData (uint8_t * buf, size_t len) { Header header; @@ -540,8 +551,9 @@ namespace transport } uint8_t payload[SSU2_MTU]; size_t payloadSize = len - 32; + uint32_t packetNum = be32toh (header.h.packetNum); uint8_t nonce[12]; - CreateNonce (be32toh (header.h.packetNum), nonce); + CreateNonce (packetNum, nonce); if (!i2p::crypto::AEADChaCha20Poly1305 (buf + 16, payloadSize, header.buf, 16, m_KeyDataReceive, nonce, payload, payloadSize, false)) { @@ -549,6 +561,10 @@ namespace transport return; } HandlePayload (payload, payloadSize); + m_LastActivityTimestamp = i2p::util::GetSecondsSinceEpoch (); + m_NumReceivedBytes += len; + if (packetNum > m_ReceivePacketNum) m_ReceivePacketNum = packetNum; + SendQuickAck (); // TODO: don't send too requently } void SSU2Session::HandlePayload (const uint8_t * buf, size_t len) @@ -690,6 +706,31 @@ namespace transport return size + 3; } + size_t SSU2Session::CreateAckBlock (uint8_t * buf, size_t len) + { + if (len < 8) return 0; + buf[0] = eSSU2BlkAck; + htobe16buf (buf + 1, 5); + htobe32buf (buf + 3, m_ReceivePacketNum); // Ack Through + buf[7] = 0; // acnt + return 8; + } + + size_t SSU2Session::CreatePaddingBlock (uint8_t * buf, size_t len) + { + uint8_t paddingSize = rand () & 0x0F; // 0 - 15 + if (paddingSize > len) paddingSize = len; + if (paddingSize) + { + buf[0] = eSSU2BlkPadding; + htobe16buf (buf + 1, paddingSize); + memset (buf + 3, 0, paddingSize); + } + else + return 0; + return paddingSize + 3; + } + std::shared_ptr SSU2Session::ExtractRouterInfo (const uint8_t * buf, size_t size) { if (size < 2) return nullptr; @@ -715,6 +756,14 @@ namespace transport memset (nonce, 0, 4); htole64buf (nonce + 4, seqn); } + + void SSU2Session::SendQuickAck () + { + uint8_t payload[SSU2_MTU]; + size_t payloadSize = CreateAckBlock (payload, SSU2_MTU); + payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MTU - payloadSize); + SendData (payload, payloadSize); + } SSU2Server::SSU2Server (): RunnableServiceWithWork ("SSU2"), m_Socket (GetService ()), m_SocketV6 (GetService ()), @@ -800,6 +849,7 @@ namespace transport { if (!ecode) { + i2p::transport::transports.UpdateReceivedBytes (bytes_transferred); packet->len = bytes_transferred; ProcessNextPacket (packet->buf, packet->len, packet->from); m_PacketsPool.ReleaseMt (packet); @@ -863,6 +913,22 @@ namespace transport } } + void SSU2Server::Send (const uint8_t * header, size_t headerLen, const uint8_t * payload, size_t payloadLen, + const boost::asio::ip::udp::endpoint& to) + { + std::vector bufs + { + boost::asio::buffer (header, headerLen), + boost::asio::buffer (payload, payloadLen) + }; + boost::system::error_code ec; + if (to.address ().is_v6 ()) + m_SocketV6.send_to (bufs, to, 0, ec); + else + m_Socket.send_to (bufs, to, 0, ec); + i2p::transport::transports.UpdateSentBytes (headerLen + payloadLen); + } + void SSU2Server::Send (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen, const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to) { @@ -877,6 +943,7 @@ namespace transport m_SocketV6.send_to (bufs, to, 0, ec); else m_Socket.send_to (bufs, to, 0, ec); + i2p::transport::transports.UpdateSentBytes (headerLen + headerXLen + payloadLen); } bool SSU2Server::CreateSession (std::shared_ptr router, diff --git a/libi2pd/SSU2.h b/libi2pd/SSU2.h index 92e8912d..b4a2eba6 100644 --- a/libi2pd/SSU2.h +++ b/libi2pd/SSU2.h @@ -103,6 +103,7 @@ namespace transport void SetRemoteEndpoint (const boost::asio::ip::udp::endpoint& ep) { m_RemoteEndpoint = ep; }; void Connect (); + void Established (); void Done () override {}; void SendI2NPMessages (const std::vector >& msgs) override {}; bool IsEstablished () const { return m_State == eSSU2SessionStateEstablished; }; @@ -124,12 +125,17 @@ namespace transport void KDFDataPhase (uint8_t * keydata_ab, uint8_t * keydata_ba); void SendTokenRequest (); void SendRetry (); + void SendData (const uint8_t * buf, size_t len); + void SendQuickAck (); void HandlePayload (const uint8_t * buf, size_t len); bool ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep); - size_t CreateAddressBlock (const boost::asio::ip::udp::endpoint& ep, uint8_t * buf, size_t len); std::shared_ptr ExtractRouterInfo (const uint8_t * buf, size_t size); void CreateNonce (uint64_t seqn, uint8_t * nonce); + + size_t CreateAddressBlock (const boost::asio::ip::udp::endpoint& ep, uint8_t * buf, size_t len); + size_t CreateAckBlock (uint8_t * buf, size_t len); + size_t CreatePaddingBlock (uint8_t * buf, size_t len); private: @@ -141,6 +147,7 @@ namespace transport uint64_t m_DestConnID, m_SourceConnID; SSU2SessionState m_State; uint8_t m_KeyDataSend[64], m_KeyDataReceive[64]; + uint32_t m_SendPacketNum, m_ReceivePacketNum; }; class SSU2Server: private i2p::util::RunnableServiceWithWork @@ -164,6 +171,8 @@ namespace transport void AddSession (uint64_t connID, std::shared_ptr session); void AddPendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep, std::shared_ptr session); + void Send (const uint8_t * header, size_t headerLen, const uint8_t * payload, size_t payloadLen, + const boost::asio::ip::udp::endpoint& to); void Send (const uint8_t * header, size_t headerLen, const uint8_t * headerX, size_t headerXLen, const uint8_t * payload, size_t payloadLen, const boost::asio::ip::udp::endpoint& to);