Browse Source

Send fragmented SessionConfirmed

pull/1776/head
orignal 2 years ago
parent
commit
90981f628e
  1. 70
      libi2pd/SSU2Session.cpp
  2. 4
      libi2pd/SSU2Session.h

70
libi2pd/SSU2Session.cpp

@ -193,7 +193,7 @@ namespace transport @@ -193,7 +193,7 @@ namespace transport
m_State = eSSU2SessionStateEstablished;
m_EphemeralKeys = nullptr;
m_NoiseState.reset (nullptr);
m_SessionConfirmedFragment1.reset (nullptr);
m_SessionConfirmedFragment.reset (nullptr);
m_SentHandshakePacket.reset (nullptr);
m_ConnectTimer.cancel ();
SetTerminationTimeout (SSU2_TERMINATION_TIMEOUT);
@ -326,6 +326,10 @@ namespace transport @@ -326,6 +326,10 @@ namespace transport
m_Server.Send (m_SentHandshakePacket->header.buf, 16, m_SentHandshakePacket->headerX, 48,
m_SentHandshakePacket->payload, m_SentHandshakePacket->payloadSize, m_RemoteEndpoint);
m_SentHandshakePacket->nextResendTime = ts + SSU2_HANDSHAKE_RESEND_INTERVAL;
if (m_SessionConfirmedFragment && m_State == eSSU2SessionStateSessionConfirmedSent)
// resend second fragment of SessionConfirmed
m_Server.Send (m_SessionConfirmedFragment->header.buf, 16,
m_SessionConfirmedFragment->payload, m_SessionConfirmedFragment->payloadSize, m_RemoteEndpoint);
return;
}
// resend data packets
@ -623,10 +627,17 @@ namespace transport @@ -623,10 +627,17 @@ namespace transport
memset (header.h.flags, 0, 3);
header.h.flags[0] = 1; // frag, total fragments always 1
// payload
const size_t maxPayloadSize = SSU2_MAX_PAYLOAD_SIZE - 48; // part 2
size_t maxPayloadSize = SSU2_MAX_PAYLOAD_SIZE - 64; // part 2
uint8_t * payload = m_SentHandshakePacket->payload;
size_t payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.GetSharedRouterInfo ());
// TODO: check is RouterInfo doesn't fit and split by two fragments
if (!payloadSize)
{
// split by two fragments
maxPayloadSize += SSU2_MAX_PAYLOAD_SIZE;
payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.GetSharedRouterInfo ());
header.h.flags[0] = 0x02; // frag 0, total fragments 2
// TODO: check if we need more fragments
}
if (payloadSize < maxPayloadSize)
payloadSize += CreatePaddingBlock (payload + payloadSize, maxPayloadSize - payloadSize);
// KDF for Session Confirmed part 1
@ -646,14 +657,42 @@ namespace transport @@ -646,14 +657,42 @@ namespace transport
i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true);
payloadSize += 16;
m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || ciphertext);
m_SentHandshakePacket->payloadSize = payloadSize;
if (header.h.flags[0] > 1)
{
if (payloadSize > SSU2_MAX_PAYLOAD_SIZE - 64)
{
payloadSize = SSU2_MAX_PAYLOAD_SIZE - 64 - (rand () % 16);
if (m_SentHandshakePacket->payloadSize - payloadSize < 24)
payloadSize -= 24;
}
else
header.h.flags[0] = 1;
}
// Encrypt header
header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 24));
header.ll[1] ^= CreateHeaderMask (kh2, payload + (payloadSize - 12));
m_State = eSSU2SessionStateSessionConfirmedSent;
m_SentHandshakePacket->payloadSize = payloadSize;
// send
m_Server.Send (header.buf, 16, part1, 48, payload, payloadSize, m_RemoteEndpoint);
m_SendPacketNum++;
if (m_SentHandshakePacket->payloadSize > payloadSize)
{
// send second fragment
m_SessionConfirmedFragment.reset (new HandshakePacket);
Header& header = m_SessionConfirmedFragment->header;
header.h.connID = m_DestConnID; // dest id
header.h.packetNum = 0;
header.h.type = eSSU2SessionConfirmed;
memset (header.h.flags, 0, 3);
header.h.flags[0] = 0x12; // frag 1, total fragments 2
m_SessionConfirmedFragment->payloadSize = m_SentHandshakePacket->payloadSize - payloadSize;
memcpy (m_SessionConfirmedFragment->payload, m_SentHandshakePacket->payload + payloadSize, m_SessionConfirmedFragment->payloadSize);
m_SentHandshakePacket->payloadSize = payloadSize;
header.ll[0] ^= CreateHeaderMask (m_Address->i, m_SessionConfirmedFragment->payload + (m_SessionConfirmedFragment->payloadSize - 24));
header.ll[1] ^= CreateHeaderMask (kh2, m_SessionConfirmedFragment->payload + (m_SessionConfirmedFragment->payloadSize - 12));
m_Server.Send (header.buf, 16, m_SessionConfirmedFragment->payload, m_SessionConfirmedFragment->payloadSize, m_RemoteEndpoint);
}
}
bool SSU2Session::ProcessSessionConfirmed (uint8_t * buf, size_t len)
@ -677,24 +716,24 @@ namespace transport @@ -677,24 +716,24 @@ namespace transport
if (!(header.h.flags[0] & 0xF0))
{
// first fragment
if (!m_SessionConfirmedFragment1)
if (!m_SessionConfirmedFragment)
{
m_SessionConfirmedFragment1.reset (new HandshakePacket);
m_SessionConfirmedFragment1->header = header;
memcpy (m_SessionConfirmedFragment1->payload, buf + 16, len - 16);
m_SessionConfirmedFragment1->payloadSize = len - 16;
m_SessionConfirmedFragment.reset (new HandshakePacket);
m_SessionConfirmedFragment->header = header;
memcpy (m_SessionConfirmedFragment->payload, buf + 16, len - 16);
m_SessionConfirmedFragment->payloadSize = len - 16;
}
return true; // wait for second fragment
}
else
{
// second fragment
if (!m_SessionConfirmedFragment1) return false; // out of sequence
header = m_SessionConfirmedFragment1->header;
memcpy (m_SessionConfirmedFragment1->payload + m_SessionConfirmedFragment1->payloadSize, buf + 16, len - 16);
m_SessionConfirmedFragment1->payloadSize += (len - 16);
buf = m_SessionConfirmedFragment1->payload - 16;
len = m_SessionConfirmedFragment1->payloadSize + 16;
if (!m_SessionConfirmedFragment) return false; // out of sequence
header = m_SessionConfirmedFragment->header;
memcpy (m_SessionConfirmedFragment->payload + m_SessionConfirmedFragment->payloadSize, buf + 16, len - 16);
m_SessionConfirmedFragment->payloadSize += (len - 16);
buf = m_SessionConfirmedFragment->payload - 16;
len = m_SessionConfirmedFragment->payloadSize + 16;
}
}
// KDF for Session Confirmed part 1
@ -725,7 +764,6 @@ namespace transport @@ -725,7 +764,6 @@ namespace transport
return false;
}
m_NoiseState->MixHash (payload, len - 64); // h = SHA256(h || ciphertext);
if (m_SessionConfirmedFragment1) m_SessionConfirmedFragment1.reset (nullptr);
// payload
// handle RouterInfo block that must be first
if (decryptedPayload[0] != eSSU2BlkRouterInfo)

4
libi2pd/SSU2Session.h

@ -302,8 +302,8 @@ namespace transport @@ -302,8 +302,8 @@ namespace transport
SSU2Server& m_Server;
std::shared_ptr<i2p::crypto::X25519Keys> m_EphemeralKeys;
std::unique_ptr<i2p::crypto::NoiseSymmetricState> m_NoiseState;
std::unique_ptr<HandshakePacket> m_SessionConfirmedFragment1; // for Bob if applicable
std::unique_ptr<HandshakePacket> m_SentHandshakePacket; // SessionRequest or SessionCreated
std::unique_ptr<HandshakePacket> m_SessionConfirmedFragment; // for Bob if applicable or second fragment for Alice
std::unique_ptr<HandshakePacket> m_SentHandshakePacket; // SessionRequest, SessionCreated or SessionConfirmed
std::shared_ptr<const i2p::data::RouterInfo::Address> m_Address;
boost::asio::ip::udp::endpoint m_RemoteEndpoint;
i2p::data::RouterInfo::CompatibleTransports m_RemoteTransports; // for peer tests

Loading…
Cancel
Save