Browse Source

calculate SSU2 session MTU and max payload size

pull/1776/head
orignal 2 years ago
parent
commit
3394bb4b8d
  1. 155
      libi2pd/SSU2Session.cpp
  2. 6
      libi2pd/SSU2Session.h
  3. 5
      libi2pd/SSUData.h
  4. 6
      libi2pd/TransportSession.h

155
libi2pd/SSU2Session.cpp

@ -25,7 +25,8 @@ namespace transport
m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown), m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown),
m_SendPacketNum (0), m_ReceivePacketNum (0), m_IsDataReceived (false), m_SendPacketNum (0), m_ReceivePacketNum (0), m_IsDataReceived (false),
m_WindowSize (SSU2_MAX_WINDOW_SIZE), m_RelayTag (0), m_WindowSize (SSU2_MAX_WINDOW_SIZE), m_RelayTag (0),
m_ConnectTimer (server.GetService ()), m_TerminationReason (eSSU2TerminationReasonNormalClose) m_ConnectTimer (server.GetService ()), m_TerminationReason (eSSU2TerminationReasonNormalClose),
m_MaxPayloadSize (SSU2_MAX_PAYLOAD_SIZE)
{ {
m_NoiseState.reset (new i2p::crypto::NoiseSymmetricState); m_NoiseState.reset (new i2p::crypto::NoiseSymmetricState);
if (in_RemoteRouter && m_Address) if (in_RemoteRouter && m_Address)
@ -94,7 +95,7 @@ namespace transport
RAND_bytes ((uint8_t *)&nonce, 4); RAND_bytes ((uint8_t *)&nonce, 4);
auto ts = i2p::util::GetSecondsSinceEpoch (); auto ts = i2p::util::GetSecondsSinceEpoch ();
// payload // payload
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; uint8_t payload[SSU2_MAX_PACKET_SIZE];
size_t payloadSize = 0; size_t payloadSize = 0;
payload[0] = eSSU2BlkRelayRequest; payload[0] = eSSU2BlkRelayRequest;
payload[3] = 0; // flag payload[3] = 0; // flag
@ -102,7 +103,7 @@ namespace transport
htobe32buf (payload + 8, relayTag); htobe32buf (payload + 8, relayTag);
htobe32buf (payload + 12, ts); htobe32buf (payload + 12, ts);
payload[16] = 2; // ver payload[16] = 2; // ver
size_t asz = CreateEndpoint (payload + 18, SSU2_MAX_PAYLOAD_SIZE - 18, boost::asio::ip::udp::endpoint (localAddress->host, localAddress->port)); size_t asz = CreateEndpoint (payload + 18, m_MaxPayloadSize - 18, boost::asio::ip::udp::endpoint (localAddress->host, localAddress->port));
if (!asz) return false; if (!asz) return false;
payload[17] = asz; payload[17] = asz;
payloadSize += asz + 18; payloadSize += asz + 18;
@ -114,7 +115,7 @@ namespace transport
s.Sign (i2p::context.GetPrivateKeys (), payload + payloadSize); s.Sign (i2p::context.GetPrivateKeys (), payload + payloadSize);
payloadSize += i2p::context.GetIdentity ()->GetSignatureLen (); payloadSize += i2p::context.GetIdentity ()->GetSignatureLen ();
htobe16buf (payload + 1, payloadSize - 3); // size htobe16buf (payload + 1, payloadSize - 3); // size
payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
// send // send
m_RelaySessions.emplace (nonce, std::make_pair (session, ts)); m_RelaySessions.emplace (nonce, std::make_pair (session, ts));
session->m_SourceConnID = htobe64 (((uint64_t)nonce << 32) | nonce); session->m_SourceConnID = htobe64 (((uint64_t)nonce << 32) | nonce);
@ -145,9 +146,9 @@ namespace transport
session->m_DestConnID = ~session->m_SourceConnID; session->m_DestConnID = ~session->m_SourceConnID;
m_Server.AddSession (session); m_Server.AddSession (session);
// peer test block // peer test block
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; uint8_t payload[SSU2_MAX_PACKET_SIZE];
size_t payloadSize = CreatePeerTestBlock (payload, SSU2_MAX_PAYLOAD_SIZE, nonce); size_t payloadSize = CreatePeerTestBlock (payload, m_MaxPayloadSize, nonce);
payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
SendData (payload, payloadSize); SendData (payload, payloadSize);
} }
@ -218,12 +219,12 @@ namespace transport
m_Server.GetService ().post ([s]() m_Server.GetService ().post ([s]()
{ {
if (!s->IsEstablished ()) return; if (!s->IsEstablished ()) return;
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; uint8_t payload[SSU2_MAX_PACKET_SIZE];
size_t payloadSize = s->CreateRouterInfoBlock (payload, SSU2_MAX_PAYLOAD_SIZE - 32, i2p::context.GetSharedRouterInfo ()); size_t payloadSize = s->CreateRouterInfoBlock (payload, s->m_MaxPayloadSize - 32, i2p::context.GetSharedRouterInfo ());
if (payloadSize) if (payloadSize)
{ {
if (payloadSize < SSU2_MAX_PAYLOAD_SIZE) if (payloadSize < s->m_MaxPayloadSize)
payloadSize += s->CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); payloadSize += s->CreatePaddingBlock (payload + payloadSize, s->m_MaxPayloadSize - payloadSize);
s->SendData (payload, payloadSize); s->SendData (payload, payloadSize);
} }
else else
@ -251,17 +252,17 @@ namespace transport
{ {
auto nextResend = i2p::util::GetSecondsSinceEpoch () + SSU2_RESEND_INTERVAL; auto nextResend = i2p::util::GetSecondsSinceEpoch () + SSU2_RESEND_INTERVAL;
auto packet = std::make_shared<SentPacket>(); auto packet = std::make_shared<SentPacket>();
packet->payloadSize += CreateAckBlock (packet->payload + packet->payloadSize, SSU2_MAX_PAYLOAD_SIZE - packet->payloadSize); packet->payloadSize += CreateAckBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
while (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize) while (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize)
{ {
auto msg = m_SendQueue.front (); auto msg = m_SendQueue.front ();
size_t len = msg->GetNTCP2Length (); size_t len = msg->GetNTCP2Length ();
if (len + 3 < SSU2_MAX_PAYLOAD_SIZE - packet->payloadSize) if (len + 3 < m_MaxPayloadSize - packet->payloadSize)
{ {
m_SendQueue.pop_front (); m_SendQueue.pop_front ();
packet->payloadSize += CreateI2NPBlock (packet->payload + packet->payloadSize, SSU2_MAX_PAYLOAD_SIZE - packet->payloadSize, std::move (msg)); packet->payloadSize += CreateI2NPBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, std::move (msg));
} }
else if (len > SSU2_MAX_PAYLOAD_SIZE) // message too long else if (len > m_MaxPayloadSize) // message too long
{ {
m_SendQueue.pop_front (); m_SendQueue.pop_front ();
SendFragmentedMessage (msg); SendFragmentedMessage (msg);
@ -269,19 +270,19 @@ namespace transport
else else
{ {
// send right a way // send right a way
if (packet->payloadSize + 16 < SSU2_MAX_PAYLOAD_SIZE) if (packet->payloadSize + 16 < m_MaxPayloadSize)
packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, SSU2_MAX_PAYLOAD_SIZE - packet->payloadSize); packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
uint32_t packetNum = SendData (packet->payload, packet->payloadSize); uint32_t packetNum = SendData (packet->payload, packet->payloadSize);
packet->nextResendTime = nextResend; packet->nextResendTime = nextResend;
m_SentPackets.emplace (packetNum, packet); m_SentPackets.emplace (packetNum, packet);
packet = std::make_shared<SentPacket>(); packet = std::make_shared<SentPacket>();
packet->payloadSize += CreateAckBlock (packet->payload + packet->payloadSize, SSU2_MAX_PAYLOAD_SIZE - packet->payloadSize); packet->payloadSize += CreateAckBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
} }
}; };
if (packet->payloadSize) if (packet->payloadSize)
{ {
if (packet->payloadSize + 16 < SSU2_MAX_PAYLOAD_SIZE) if (packet->payloadSize + 16 < m_MaxPayloadSize)
packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, SSU2_MAX_PAYLOAD_SIZE - packet->payloadSize); packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
uint32_t packetNum = SendData (packet->payload, packet->payloadSize); uint32_t packetNum = SendData (packet->payload, packet->payloadSize);
packet->nextResendTime = nextResend; packet->nextResendTime = nextResend;
m_SentPackets.emplace (packetNum, packet); m_SentPackets.emplace (packetNum, packet);
@ -297,11 +298,11 @@ namespace transport
memcpy (&msgID, msg->GetHeader () + I2NP_HEADER_MSGID_OFFSET, 4); memcpy (&msgID, msg->GetHeader () + I2NP_HEADER_MSGID_OFFSET, 4);
auto nextResend = i2p::util::GetSecondsSinceEpoch () + SSU2_RESEND_INTERVAL; auto nextResend = i2p::util::GetSecondsSinceEpoch () + SSU2_RESEND_INTERVAL;
auto packet = std::make_shared<SentPacket>(); auto packet = std::make_shared<SentPacket>();
packet->payloadSize = CreateAckBlock (packet->payload, SSU2_MAX_PAYLOAD_SIZE); packet->payloadSize = CreateAckBlock (packet->payload, m_MaxPayloadSize);
auto size = CreateFirstFragmentBlock (packet->payload + packet->payloadSize, SSU2_MAX_PAYLOAD_SIZE - 16 - packet->payloadSize, msg); auto size = CreateFirstFragmentBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - 16 - packet->payloadSize, msg);
if (!size) return; if (!size) return;
packet->payloadSize += size; packet->payloadSize += size;
packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, SSU2_MAX_PAYLOAD_SIZE - 16 - packet->payloadSize); packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - 16 - packet->payloadSize);
uint32_t firstPacketNum = SendData (packet->payload, packet->payloadSize); uint32_t firstPacketNum = SendData (packet->payload, packet->payloadSize);
packet->nextResendTime = nextResend; packet->nextResendTime = nextResend;
m_SentPackets.emplace (firstPacketNum, packet); m_SentPackets.emplace (firstPacketNum, packet);
@ -309,8 +310,8 @@ namespace transport
while (msg->offset < msg->len) while (msg->offset < msg->len)
{ {
packet = std::make_shared<SentPacket>(); packet = std::make_shared<SentPacket>();
packet->payloadSize = CreateFollowOnFragmentBlock (packet->payload, SSU2_MAX_PAYLOAD_SIZE - 16, msg, fragmentNum, msgID); packet->payloadSize = CreateFollowOnFragmentBlock (packet->payload, m_MaxPayloadSize - 16, msg, fragmentNum, msgID);
packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, SSU2_MAX_PAYLOAD_SIZE - 16 - packet->payloadSize); packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - 16 - packet->payloadSize);
uint32_t followonPacketNum = SendData (packet->payload, packet->payloadSize); uint32_t followonPacketNum = SendData (packet->payload, packet->payloadSize);
packet->nextResendTime = nextResend; packet->nextResendTime = nextResend;
m_SentPackets.emplace (followonPacketNum, packet); m_SentPackets.emplace (followonPacketNum, packet);
@ -528,7 +529,7 @@ namespace transport
memset (headerX + 8, 0, 8); // token = 0 memset (headerX + 8, 0, 8); // token = 0
memcpy (headerX + 16, m_EphemeralKeys->GetPublicKey (), 32); // Y memcpy (headerX + 16, m_EphemeralKeys->GetPublicKey (), 32); // Y
// payload // payload
const size_t maxPayloadSize = SSU2_MAX_PAYLOAD_SIZE - 48; size_t maxPayloadSize = m_MaxPayloadSize - 48;
payload[0] = eSSU2BlkDateTime; payload[0] = eSSU2BlkDateTime;
htobe16buf (payload + 1, 4); htobe16buf (payload + 1, 4);
htobe32buf (payload + 3, ts); htobe32buf (payload + 3, ts);
@ -611,6 +612,7 @@ namespace transport
HandlePayload (decryptedPayload.data (), decryptedPayload.size ()); HandlePayload (decryptedPayload.data (), decryptedPayload.size ());
m_Server.AddSession (shared_from_this ()); m_Server.AddSession (shared_from_this ());
AdjustMaxPayloadSize ();
SendSessionConfirmed (headerX + 16); SendSessionConfirmed (headerX + 16);
KDFDataPhase (m_KeyDataSend, m_KeyDataReceive); KDFDataPhase (m_KeyDataSend, m_KeyDataReceive);
@ -634,13 +636,13 @@ namespace transport
memset (header.h.flags, 0, 3); memset (header.h.flags, 0, 3);
header.h.flags[0] = 1; // frag, total fragments always 1 header.h.flags[0] = 1; // frag, total fragments always 1
// payload // payload
size_t maxPayloadSize = SSU2_MAX_PAYLOAD_SIZE - 64; // part 2 size_t maxPayloadSize = m_MaxPayloadSize - 48; // for part 2, 48 is part1
uint8_t * payload = m_SentHandshakePacket->payload; uint8_t * payload = m_SentHandshakePacket->payload;
size_t payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.GetSharedRouterInfo ()); size_t payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.GetSharedRouterInfo ());
if (!payloadSize) if (!payloadSize)
{ {
// split by two fragments // split by two fragments
maxPayloadSize += SSU2_MAX_PAYLOAD_SIZE; maxPayloadSize += m_MaxPayloadSize;
payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.GetSharedRouterInfo ()); payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.GetSharedRouterInfo ());
header.h.flags[0] = 0x02; // frag 0, total fragments 2 header.h.flags[0] = 0x02; // frag 0, total fragments 2
// TODO: check if we need more fragments // TODO: check if we need more fragments
@ -798,6 +800,7 @@ namespace transport
LogPrint (eLogError, "SSU2: No SSU2 address with static key found in SessionConfirmed"); LogPrint (eLogError, "SSU2: No SSU2 address with static key found in SessionConfirmed");
return false; return false;
} }
AdjustMaxPayloadSize ();
m_Server.AddSessionByRouterHash (shared_from_this ()); // we know remote router now m_Server.AddSessionByRouterHash (shared_from_this ()); // we know remote router now
m_RemoteTransports = ri->GetCompatibleTransports (false); m_RemoteTransports = ri->GetCompatibleTransports (false);
i2p::data::netdb.PostI2NPMsg (CreateDatabaseStoreMsg (ri)); // TODO: should insert ri i2p::data::netdb.PostI2NPMsg (CreateDatabaseStoreMsg (ri)); // TODO: should insert ri
@ -965,7 +968,7 @@ namespace transport
{ {
// we are Charlie // we are Charlie
Header header; Header header;
uint8_t h[32], payload[SSU2_MAX_PAYLOAD_SIZE]; uint8_t h[32], payload[SSU2_MAX_PACKET_SIZE];
// fill packet // fill packet
header.h.connID = htobe64 (((uint64_t)nonce << 32) | nonce); // dest id header.h.connID = htobe64 (((uint64_t)nonce << 32) | nonce); // dest id
RAND_bytes (header.buf + 8, 4); // random packet num RAND_bytes (header.buf + 8, 4); // random packet num
@ -982,10 +985,10 @@ namespace transport
htobe16buf (payload + 1, 4); htobe16buf (payload + 1, 4);
htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ()); htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ());
size_t payloadSize = 7; size_t payloadSize = 7;
payloadSize += CreateAddressBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize, ep); payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, ep);
payloadSize += CreateRelayResponseBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize, payloadSize += CreateRelayResponseBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize,
eSSU2RelayResponseCodeAccept, nonce, true, token); eSSU2RelayResponseCodeAccept, nonce, true, token);
payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
// encrypt // encrypt
uint8_t n[12]; uint8_t n[12];
CreateNonce (be32toh (header.h.packetNum), n); CreateNonce (be32toh (header.h.packetNum), n);
@ -1049,7 +1052,7 @@ namespace transport
void SSU2Session::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, const uint8_t * introKey) void SSU2Session::SendPeerTest (uint8_t msg, const uint8_t * signedData, size_t signedDataLen, const uint8_t * introKey)
{ {
Header header; Header header;
uint8_t h[32], payload[SSU2_MAX_PAYLOAD_SIZE]; uint8_t h[32], payload[SSU2_MAX_PACKET_SIZE];
// fill packet // fill packet
header.h.connID = m_DestConnID; // dest id header.h.connID = m_DestConnID; // dest id
RAND_bytes (header.buf + 8, 4); // random packet num RAND_bytes (header.buf + 8, 4); // random packet num
@ -1065,10 +1068,10 @@ namespace transport
htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ()); htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ());
size_t payloadSize = 7; size_t payloadSize = 7;
if (msg == 6 || msg == 7) if (msg == 6 || msg == 7)
payloadSize += CreateAddressBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize, m_RemoteEndpoint); payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, m_RemoteEndpoint);
payloadSize += CreatePeerTestBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize, payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize,
msg, eSSU2PeerTestCodeAccept, nullptr, signedData, signedDataLen); msg, eSSU2PeerTestCodeAccept, nullptr, signedData, signedDataLen);
payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
// encrypt // encrypt
uint8_t n[12]; uint8_t n[12];
CreateNonce (be32toh (header.h.packetNum), n); CreateNonce (be32toh (header.h.packetNum), n);
@ -1449,10 +1452,10 @@ namespace transport
{ {
LogPrint (eLogWarning, "SSU2: RelayRequest session with relay tag ", relayTag, " not found"); LogPrint (eLogWarning, "SSU2: RelayRequest session with relay tag ", relayTag, " not found");
// send relay response back to Alice // send relay response back to Alice
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; uint8_t payload[SSU2_MAX_PACKET_SIZE];
size_t payloadSize = CreateRelayResponseBlock (payload, SSU2_MAX_PAYLOAD_SIZE, size_t payloadSize = CreateRelayResponseBlock (payload, m_MaxPayloadSize,
eSSU2RelayResponseCodeBobRelayTagNotFound, bufbe32toh (buf + 1), false, 0); eSSU2RelayResponseCodeBobRelayTagNotFound, bufbe32toh (buf + 1), false, 0);
payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
SendData (payload, payloadSize); SendData (payload, payloadSize);
return; return;
} }
@ -1466,12 +1469,12 @@ namespace transport
else else
LogPrint (eLogWarning, "SSU2: RelayRequest Alice's router info not found"); LogPrint (eLogWarning, "SSU2: RelayRequest Alice's router info not found");
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; uint8_t payload[SSU2_MAX_PAYLOAD_SIZE];
size_t payloadSize = r ? CreateRouterInfoBlock (payload, SSU2_MAX_PAYLOAD_SIZE - len - 32, r) : 0; size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0;
if (!payloadSize && r) if (!payloadSize && r)
session->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); session->SendFragmentedMessage (CreateDatabaseStoreMsg (r));
payloadSize += CreateRelayIntroBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize, buf + 1, len -1); payloadSize += CreateRelayIntroBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, buf + 1, len -1);
if (payloadSize < SSU2_MAX_PAYLOAD_SIZE) if (payloadSize < SSU2_MAX_PAYLOAD_SIZE)
payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
session->SendData (payload, payloadSize); session->SendData (payload, payloadSize);
} }
@ -1526,10 +1529,10 @@ namespace transport
code = eSSU2RelayResponseCodeCharlieAliceIsUnknown; code = eSSU2RelayResponseCodeCharlieAliceIsUnknown;
} }
// send relay response to Bob // send relay response to Bob
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; uint8_t payload[SSU2_MAX_PACKET_SIZE];
size_t payloadSize = CreateRelayResponseBlock (payload, SSU2_MAX_PAYLOAD_SIZE, size_t payloadSize = CreateRelayResponseBlock (payload, m_MaxPayloadSize,
code, bufbe32toh (buf + 33), true, token); code, bufbe32toh (buf + 33), true, token);
payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
SendData (payload, payloadSize); SendData (payload, payloadSize);
} }
@ -1558,12 +1561,12 @@ namespace transport
if (it->second.first && it->second.first->IsEstablished ()) if (it->second.first && it->second.first->IsEstablished ())
{ {
// we are Bob, message from Charlie // we are Bob, message from Charlie
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; uint8_t payload[SSU2_MAX_PACKET_SIZE];
payload[0] = eSSU2BlkRelayResponse; payload[0] = eSSU2BlkRelayResponse;
htobe16buf (payload + 1, len); htobe16buf (payload + 1, len);
memcpy (payload + 3, buf, len); // forward to Alice as is memcpy (payload + 3, buf, len); // forward to Alice as is
size_t payloadSize = len + 3; size_t payloadSize = len + 3;
payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
it->second.first->SendData (payload, payloadSize); it->second.first->SendData (payload, payloadSize);
} }
else else
@ -1618,32 +1621,32 @@ namespace transport
if (session) // session with Charlie if (session) // session with Charlie
{ {
session->m_PeerTests.emplace (nonce, std::make_pair (shared_from_this (), i2p::util::GetSecondsSinceEpoch ())); session->m_PeerTests.emplace (nonce, std::make_pair (shared_from_this (), i2p::util::GetSecondsSinceEpoch ()));
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; uint8_t payload[SSU2_MAX_PACKET_SIZE];
// Alice's RouterInfo // Alice's RouterInfo
auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ());
if (r) i2p::data::netdb.PopulateRouterInfoBuffer (r); if (r) i2p::data::netdb.PopulateRouterInfoBuffer (r);
size_t payloadSize = r ? CreateRouterInfoBlock (payload, SSU2_MAX_PAYLOAD_SIZE - len - 32, r) : 0; size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0;
if (!payloadSize && r) if (!payloadSize && r)
session->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); session->SendFragmentedMessage (CreateDatabaseStoreMsg (r));
if (payloadSize + len + 48 > SSU2_MAX_PAYLOAD_SIZE) if (payloadSize + len + 48 > m_MaxPayloadSize)
{ {
// doesn't fit one message, send RouterInfo in separate message // doesn't fit one message, send RouterInfo in separate message
session->SendData (payload, payloadSize); session->SendData (payload, payloadSize);
payloadSize = 0; payloadSize = 0;
} }
// PeerTest to Charlie // PeerTest to Charlie
payloadSize += CreatePeerTestBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize, 2, payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize, 2,
eSSU2PeerTestCodeAccept, GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset); eSSU2PeerTestCodeAccept, GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset);
payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
session->SendData (payload, payloadSize); session->SendData (payload, payloadSize);
} }
else else
{ {
// Charlie not found, send error back to Alice // Charlie not found, send error back to Alice
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE], zeroHash[32] = {0}; uint8_t payload[SSU2_MAX_PACKET_SIZE], zeroHash[32] = {0};
size_t payloadSize = CreatePeerTestBlock (payload, SSU2_MAX_PAYLOAD_SIZE, 4, size_t payloadSize = CreatePeerTestBlock (payload, m_MaxPayloadSize, 4,
eSSU2PeerTestCodeBobNoCharlieAvailable, zeroHash, buf + offset, len - offset); eSSU2PeerTestCodeBobNoCharlieAvailable, zeroHash, buf + offset, len - offset);
payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
SendData (payload, payloadSize); SendData (payload, payloadSize);
} }
break; break;
@ -1706,10 +1709,10 @@ namespace transport
else else
code = eSSU2PeerTestCodeCharlieAliceIsUnknown; code = eSSU2PeerTestCodeCharlieAliceIsUnknown;
// send msg 3 back to Bob // send msg 3 back to Bob
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; uint8_t payload[SSU2_MAX_PACKET_SIZE];
size_t payloadSize = CreatePeerTestBlock (payload, SSU2_MAX_PAYLOAD_SIZE, 3, size_t payloadSize = CreatePeerTestBlock (payload, m_MaxPayloadSize, 3,
code, nullptr, newSignedData.data (), newSignedData.size ()); code, nullptr, newSignedData.data (), newSignedData.size ());
payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
SendData (payload, payloadSize); SendData (payload, payloadSize);
break; break;
} }
@ -1718,24 +1721,24 @@ namespace transport
auto it = m_PeerTests.find (nonce); auto it = m_PeerTests.find (nonce);
if (it != m_PeerTests.end () && it->second.first) if (it != m_PeerTests.end () && it->second.first)
{ {
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; uint8_t payload[SSU2_MAX_PACKET_SIZE];
// Charlie's RouterInfo // Charlie's RouterInfo
auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ());
if (r) i2p::data::netdb.PopulateRouterInfoBuffer (r); if (r) i2p::data::netdb.PopulateRouterInfoBuffer (r);
size_t payloadSize = r ? CreateRouterInfoBlock (payload, SSU2_MAX_PAYLOAD_SIZE - len - 32, r) : 0; size_t payloadSize = r ? CreateRouterInfoBlock (payload, m_MaxPayloadSize - len - 32, r) : 0;
if (!payloadSize && r) if (!payloadSize && r)
it->second.first->SendFragmentedMessage (CreateDatabaseStoreMsg (r)); it->second.first->SendFragmentedMessage (CreateDatabaseStoreMsg (r));
if (payloadSize + len + 16 > SSU2_MAX_PAYLOAD_SIZE) if (payloadSize + len + 16 > m_MaxPayloadSize)
{ {
// doesn't fit one message, send RouterInfo in separate message // doesn't fit one message, send RouterInfo in separate message
it->second.first->SendData (payload, payloadSize); it->second.first->SendData (payload, payloadSize);
payloadSize = 0; payloadSize = 0;
} }
// PeerTest to Alice // PeerTest to Alice
payloadSize += CreatePeerTestBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE, 4, payloadSize += CreatePeerTestBlock (payload + payloadSize, m_MaxPayloadSize, 4,
(SSU2PeerTestCode)buf[1], GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset); (SSU2PeerTestCode)buf[1], GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset);
if (payloadSize < SSU2_MAX_PAYLOAD_SIZE) if (payloadSize < m_MaxPayloadSize)
payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MAX_PAYLOAD_SIZE - payloadSize); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
it->second.first->SendData (payload, payloadSize); it->second.first->SendData (payload, payloadSize);
m_PeerTests.erase (it); m_PeerTests.erase (it);
} }
@ -1893,6 +1896,22 @@ namespace transport
return nullptr; return nullptr;
} }
void SSU2Session::AdjustMaxPayloadSize ()
{
auto addr = FindLocalAddress ();
if (addr && addr->ssu)
{
int mtu = addr->ssu->mtu;
if (m_Address && m_Address->ssu && (!mtu || m_Address->ssu->mtu < mtu))
mtu = m_Address->ssu->mtu;
if (mtu)
{
m_MaxPayloadSize = mtu - (addr->IsV6 () ? IPV6_HEADER_SIZE: IPV4_HEADER_SIZE) - UDP_HEADER_SIZE - 32;
LogPrint (eLogDebug, "SSU2: Session MTU=", mtu, ", max payload size=", m_MaxPayloadSize);
}
}
}
RouterStatus SSU2Session::GetRouterStatus () const RouterStatus SSU2Session::GetRouterStatus () const
{ {
if (m_Address) if (m_Address)
@ -2240,9 +2259,9 @@ namespace transport
void SSU2Session::SendQuickAck () void SSU2Session::SendQuickAck ()
{ {
uint8_t payload[SSU2_MTU]; uint8_t payload[SSU2_MAX_PACKET_SIZE];
size_t payloadSize = CreateAckBlock (payload, SSU2_MTU); size_t payloadSize = CreateAckBlock (payload, m_MaxPayloadSize);
payloadSize += CreatePaddingBlock (payload + payloadSize, SSU2_MTU - payloadSize); payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
SendData (payload, payloadSize); SendData (payload, payloadSize);
} }
@ -2253,7 +2272,7 @@ namespace transport
payloadSize += CreatePaddingBlock (payload + payloadSize, 32 - payloadSize); payloadSize += CreatePaddingBlock (payload + payloadSize, 32 - payloadSize);
SendData (payload, payloadSize); SendData (payload, payloadSize);
} }
void SSU2Session::CleanUp (uint64_t ts) void SSU2Session::CleanUp (uint64_t ts)
{ {
for (auto it = m_IncompleteMessages.begin (); it != m_IncompleteMessages.end ();) for (auto it = m_IncompleteMessages.begin (); it != m_IncompleteMessages.end ();)

6
libi2pd/SSU2Session.h

@ -33,7 +33,7 @@ namespace transport
const int SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT = 10; // in seconds const int SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT = 10; // in seconds
const int SSU2_PEER_TEST_EXPIRATION_TIMEOUT = 60; // 60 seconds const int SSU2_PEER_TEST_EXPIRATION_TIMEOUT = 60; // 60 seconds
const size_t SSU2_MAX_PACKET_SIZE = 1500; const size_t SSU2_MAX_PACKET_SIZE = 1500;
const size_t SSU2_MTU = 1440; // TODO: should be 1456 for ipv4 const size_t SSU2_MTU = SSU2_MAX_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; // TODO: ipv4
const size_t SSU2_MAX_PAYLOAD_SIZE = SSU2_MTU - 32; const size_t SSU2_MAX_PAYLOAD_SIZE = SSU2_MTU - 32;
const int SSU2_HANDSHAKE_RESEND_INTERVAL = 1; // in seconds const int SSU2_HANDSHAKE_RESEND_INTERVAL = 1; // in seconds
const int SSU2_RESEND_INTERVAL = 3; // in seconds const int SSU2_RESEND_INTERVAL = 3; // in seconds
@ -186,7 +186,7 @@ namespace transport
struct SentPacket struct SentPacket
{ {
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; uint8_t payload[SSU2_MAX_PACKET_SIZE];
size_t payloadSize = 0; size_t payloadSize = 0;
uint32_t nextResendTime; // in seconds uint32_t nextResendTime; // in seconds
int numResends = 0; int numResends = 0;
@ -273,6 +273,7 @@ namespace transport
bool ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep); bool ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep);
size_t CreateEndpoint (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep); size_t CreateEndpoint (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep);
std::shared_ptr<const i2p::data::RouterInfo::Address> FindLocalAddress () const; std::shared_ptr<const i2p::data::RouterInfo::Address> FindLocalAddress () const;
void AdjustMaxPayloadSize ();
RouterStatus GetRouterStatus () const; RouterStatus GetRouterStatus () const;
void SetRouterStatus (RouterStatus status) const; void SetRouterStatus (RouterStatus status) const;
std::shared_ptr<const i2p::data::RouterInfo> ExtractRouterInfo (const uint8_t * buf, size_t size); std::shared_ptr<const i2p::data::RouterInfo> ExtractRouterInfo (const uint8_t * buf, size_t size);
@ -326,6 +327,7 @@ namespace transport
OnEstablished m_OnEstablished; // callback from Established OnEstablished m_OnEstablished; // callback from Established
boost::asio::deadline_timer m_ConnectTimer; boost::asio::deadline_timer m_ConnectTimer;
SSU2TerminationReason m_TerminationReason; SSU2TerminationReason m_TerminationReason;
size_t m_MaxPayloadSize;
}; };
inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce) inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce)

5
libi2pd/SSUData.h

@ -19,17 +19,14 @@
#include "I2NPProtocol.h" #include "I2NPProtocol.h"
#include "Identity.h" #include "Identity.h"
#include "RouterInfo.h" #include "RouterInfo.h"
#include "TransportSession.h"
namespace i2p namespace i2p
{ {
namespace transport namespace transport
{ {
const size_t SSU_MTU_V4 = 1484; const size_t SSU_MTU_V4 = 1484;
const size_t SSU_MTU_V6 = 1488; const size_t SSU_MTU_V6 = 1488;
const size_t IPV4_HEADER_SIZE = 20;
const size_t IPV6_HEADER_SIZE = 40;
const size_t UDP_HEADER_SIZE = 8;
const size_t SSU_V4_MAX_PACKET_SIZE = SSU_MTU_V4 - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; // 1456 const size_t SSU_V4_MAX_PACKET_SIZE = SSU_MTU_V4 - IPV4_HEADER_SIZE - UDP_HEADER_SIZE; // 1456
const size_t SSU_V6_MAX_PACKET_SIZE = SSU_MTU_V6 - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; // 1440 const size_t SSU_V6_MAX_PACKET_SIZE = SSU_MTU_V6 - IPV6_HEADER_SIZE - UDP_HEADER_SIZE; // 1440
const int RESEND_INTERVAL = 3; // in seconds const int RESEND_INTERVAL = 3; // in seconds

6
libi2pd/TransportSession.h

@ -24,6 +24,10 @@ namespace i2p
{ {
namespace transport namespace transport
{ {
const size_t IPV4_HEADER_SIZE = 20;
const size_t IPV6_HEADER_SIZE = 40;
const size_t UDP_HEADER_SIZE = 8;
class SignedData class SignedData
{ {
public: public:
@ -64,7 +68,7 @@ namespace transport
std::stringstream m_Stream; std::stringstream m_Stream;
}; };
class TransportSession class TransportSession
{ {
public: public:

Loading…
Cancel
Save