Browse Source

send Ack packet

pull/1748/head
orignal 3 years ago
parent
commit
53148fe58f
  1. 121
      libi2pd/SSU2.cpp
  2. 11
      libi2pd/SSU2.h

121
libi2pd/SSU2.cpp

@ -31,7 +31,7 @@ namespace transport @@ -31,7 +31,7 @@ namespace transport
std::shared_ptr<const i2p::data::RouterInfo::Address> 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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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<const i2p::data::RouterInfo> SSU2Session::ExtractRouterInfo (const uint8_t * buf, size_t size)
{
if (size < 2) return nullptr;
@ -716,6 +757,14 @@ namespace transport @@ -716,6 +757,14 @@ namespace transport
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 ()),
m_TerminationTimer (GetService ())
@ -800,6 +849,7 @@ namespace transport @@ -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 @@ -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<boost::asio::const_buffer> 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 @@ -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<const i2p::data::RouterInfo> router,

11
libi2pd/SSU2.h

@ -103,6 +103,7 @@ namespace transport @@ -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<std::shared_ptr<I2NPMessage> >& msgs) override {};
bool IsEstablished () const { return m_State == eSSU2SessionStateEstablished; };
@ -124,13 +125,18 @@ namespace transport @@ -124,13 +125,18 @@ 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<const i2p::data::RouterInfo> 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:
SSU2Server& m_Server;
@ -141,6 +147,7 @@ namespace transport @@ -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 @@ -164,6 +171,8 @@ namespace transport
void AddSession (uint64_t connID, std::shared_ptr<SSU2Session> session);
void AddPendingOutgoingSession (const boost::asio::ip::udp::endpoint& ep, std::shared_ptr<SSU2Session> 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);

Loading…
Cancel
Save