Browse Source

resend SessionRequest and SessionCreated

pull/1771/head
orignal 3 years ago
parent
commit
ed04747b9d
  1. 4
      libi2pd/SSU2.cpp
  2. 42
      libi2pd/SSU2Session.cpp
  3. 11
      libi2pd/SSU2Session.h

4
libi2pd/SSU2.cpp

@ -361,7 +361,7 @@ namespace transport
case eSSU2SessionStateEstablished: case eSSU2SessionStateEstablished:
m_LastSession->ProcessData (buf, len); m_LastSession->ProcessData (buf, len);
break; break;
case eSSU2SessionStateUnknown: case eSSU2SessionStateSessionCreatedSent:
m_LastSession->ProcessSessionConfirmed (buf, len); m_LastSession->ProcessSessionConfirmed (buf, len);
break; break;
case eSSU2SessionStateIntroduced: case eSSU2SessionStateIntroduced:
@ -650,6 +650,8 @@ namespace transport
auto ts = i2p::util::GetSecondsSinceEpoch (); auto ts = i2p::util::GetSecondsSinceEpoch ();
for (auto it: m_Sessions) for (auto it: m_Sessions)
it.second->Resend (ts); it.second->Resend (ts);
for (auto it: m_PendingOutgoingSessions)
it.second->Resend (ts);
ScheduleResend (); ScheduleResend ();
} }
} }

42
libi2pd/SSU2Session.cpp

@ -160,6 +160,7 @@ namespace transport
m_Server.RemoveSession (m_SourceConnID); m_Server.RemoveSession (m_SourceConnID);
if (m_RelayTag) if (m_RelayTag)
m_Server.RemoveRelay (m_RelayTag); m_Server.RemoveRelay (m_RelayTag);
m_SentHandshakePacket.reset (nullptr);
m_SendQueue.clear (); m_SendQueue.clear ();
LogPrint (eLogDebug, "SSU2: Session terminated"); LogPrint (eLogDebug, "SSU2: Session terminated");
} }
@ -177,6 +178,7 @@ namespace transport
m_EphemeralKeys = nullptr; m_EphemeralKeys = nullptr;
m_NoiseState.reset (nullptr); m_NoiseState.reset (nullptr);
m_SessionConfirmedFragment1.reset (nullptr); m_SessionConfirmedFragment1.reset (nullptr);
m_SentHandshakePacket.reset (nullptr);
m_ConnectTimer.cancel (); m_ConnectTimer.cancel ();
SetTerminationTimeout (SSU2_TERMINATION_TIMEOUT); SetTerminationTimeout (SSU2_TERMINATION_TIMEOUT);
transports.PeerConnected (shared_from_this ()); transports.PeerConnected (shared_from_this ());
@ -301,10 +303,22 @@ namespace transport
void SSU2Session::Resend (uint64_t ts) void SSU2Session::Resend (uint64_t ts)
{ {
// resend handshake packet
if (m_SentHandshakePacket && ts >= m_SentHandshakePacket->nextResendTime)
{
// TODO: implement SessionConfirmed
LogPrint (eLogDebug, "SSU2: Resending ", (m_State == eSSU2SessionStateSessionRequestSent) ? "SessionRequest" : "SessionCreated");
m_Server.Send (m_SentHandshakePacket->header.buf, 16, m_SentHandshakePacket->headerX, 48,
m_SentHandshakePacket->payload, m_SentHandshakePacket->payloadSize, m_RemoteEndpoint);
m_SentHandshakePacket->numResends++;
m_SentHandshakePacket->nextResendTime = ts + SSU2_HANDSHAKE_RESEND_INTERVAL;
return;
}
// resend data packets
if (m_SentPackets.empty ()) return; if (m_SentPackets.empty ()) return;
std::map<uint32_t, std::shared_ptr<SentPacket> > resentPackets; std::map<uint32_t, std::shared_ptr<SentPacket> > resentPackets;
for (auto it = m_SentPackets.begin (); it != m_SentPackets.end (); ) for (auto it = m_SentPackets.begin (); it != m_SentPackets.end (); )
if (ts > it->second->nextResendTime) if (ts >= it->second->nextResendTime)
{ {
if (it->second->numResends > SSU2_MAX_NUM_RESENDS) if (it->second->numResends > SSU2_MAX_NUM_RESENDS)
it = m_SentPackets.erase (it); it = m_SentPackets.erase (it);
@ -369,9 +383,13 @@ namespace transport
{ {
// we are Alice // we are Alice
m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair (); m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair ();
m_SentHandshakePacket.reset (new HandshakePacket);
auto ts = i2p::util::GetSecondsSinceEpoch ();
m_SentHandshakePacket->nextResendTime = ts + SSU2_HANDSHAKE_RESEND_INTERVAL;
Header header; Header& header = m_SentHandshakePacket->header;
uint8_t headerX[48], payload[40]; uint8_t * headerX = m_SentHandshakePacket->headerX,
* payload = m_SentHandshakePacket->payload;
// fill packet // fill packet
header.h.connID = m_DestConnID; // dest id header.h.connID = m_DestConnID; // dest id
header.h.packetNum = 0; header.h.packetNum = 0;
@ -385,7 +403,7 @@ namespace transport
// payload // payload
payload[0] = eSSU2BlkDateTime; payload[0] = eSSU2BlkDateTime;
htobe16buf (payload + 1, 4); htobe16buf (payload + 1, 4);
htobe32buf (payload + 3, i2p::util::GetSecondsSinceEpoch ()); htobe32buf (payload + 3, ts);
size_t payloadSize = 7; size_t payloadSize = 7;
payloadSize += CreatePaddingBlock (payload + payloadSize, 40 - payloadSize, 1); payloadSize += CreatePaddingBlock (payload + payloadSize, 40 - payloadSize, 1);
// KDF for session request // KDF for session request
@ -402,6 +420,8 @@ namespace transport
header.ll[1] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 12)); header.ll[1] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 12));
i2p::crypto::ChaCha20 (headerX, 48, m_Address->i, nonce, headerX); i2p::crypto::ChaCha20 (headerX, 48, m_Address->i, nonce, headerX);
m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || encrypted payload from Session Request) for SessionCreated m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || encrypted payload from Session Request) for SessionCreated
m_State = eSSU2SessionStateSessionRequestSent;
m_SentHandshakePacket->payloadSize = payloadSize;
// send // send
if (m_State == eSSU2SessionStateTokenReceived || m_Server.AddPendingOutgoingSession (shared_from_this ())) if (m_State == eSSU2SessionStateTokenReceived || m_Server.AddPendingOutgoingSession (shared_from_this ()))
m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint); m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint);
@ -454,11 +474,16 @@ namespace transport
{ {
// we are Bob // we are Bob
m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair (); m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair ();
m_SentHandshakePacket.reset (new HandshakePacket);
auto ts = i2p::util::GetSecondsSinceEpoch ();
m_SentHandshakePacket->nextResendTime = ts + SSU2_HANDSHAKE_RESEND_INTERVAL;
uint8_t kh2[32]; uint8_t kh2[32];
i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "SessCreateHeader", kh2, 32); // k_header_2 = HKDF(chainKey, ZEROLEN, "SessCreateHeader", 32) i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "SessCreateHeader", kh2, 32); // k_header_2 = HKDF(chainKey, ZEROLEN, "SessCreateHeader", 32)
// fill packet // fill packet
Header header; Header& header = m_SentHandshakePacket->header;
uint8_t headerX[48], payload[80]; uint8_t * headerX = m_SentHandshakePacket->headerX,
* payload = m_SentHandshakePacket->payload;
header.h.connID = m_DestConnID; // dest id header.h.connID = m_DestConnID; // dest id
header.h.packetNum = 0; header.h.packetNum = 0;
header.h.type = eSSU2SessionCreated; header.h.type = eSSU2SessionCreated;
@ -469,7 +494,6 @@ 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
auto ts = i2p::util::GetSecondsSinceEpoch ();
payload[0] = eSSU2BlkDateTime; payload[0] = eSSU2BlkDateTime;
htobe16buf (payload + 1, 4); htobe16buf (payload + 1, 4);
htobe32buf (payload + 3, ts); htobe32buf (payload + 3, ts);
@ -506,6 +530,8 @@ namespace transport
header.ll[0] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), payload + (payloadSize - 24)); header.ll[0] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), payload + (payloadSize - 24));
header.ll[1] ^= CreateHeaderMask (kh2, payload + (payloadSize - 12)); header.ll[1] ^= CreateHeaderMask (kh2, payload + (payloadSize - 12));
i2p::crypto::ChaCha20 (headerX, 48, kh2, nonce, headerX); i2p::crypto::ChaCha20 (headerX, 48, kh2, nonce, headerX);
m_State = eSSU2SessionStateSessionCreatedSent;
m_SentHandshakePacket->payloadSize = payloadSize;
// send // send
m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint); m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint);
} }
@ -617,7 +643,7 @@ namespace transport
if (!(header.h.flags[0] & 0xF0)) if (!(header.h.flags[0] & 0xF0))
{ {
// first fragment // first fragment
m_SessionConfirmedFragment1.reset (new SessionConfirmedFragment); m_SessionConfirmedFragment1.reset (new HandshakePacket);
m_SessionConfirmedFragment1->header = header; m_SessionConfirmedFragment1->header = header;
memcpy (m_SessionConfirmedFragment1->payload, buf + 16, len - 16); memcpy (m_SessionConfirmedFragment1->payload, buf + 16, len - 16);
m_SessionConfirmedFragment1->payloadSize = len - 16; m_SessionConfirmedFragment1->payloadSize = len - 16;

11
libi2pd/SSU2Session.h

@ -32,6 +32,7 @@ namespace transport
const int SSU2_PEER_TEST_EXPIRATION_TIMEOUT = 60; // 60 seconds const int SSU2_PEER_TEST_EXPIRATION_TIMEOUT = 60; // 60 seconds
const size_t SSU2_MTU = 1488; const size_t SSU2_MTU = 1488;
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_RESEND_INTERVAL = 3; // in seconds const int SSU2_RESEND_INTERVAL = 3; // in seconds
const int SSU2_MAX_NUM_RESENDS = 5; const int SSU2_MAX_NUM_RESENDS = 5;
const int SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds const int SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds
@ -80,6 +81,8 @@ namespace transport
{ {
eSSU2SessionStateUnknown, eSSU2SessionStateUnknown,
eSSU2SessionStateTokenReceived, eSSU2SessionStateTokenReceived,
eSSU2SessionStateSessionRequestSent,
eSSU2SessionStateSessionCreatedSent,
eSSU2SessionStateEstablished, eSSU2SessionStateEstablished,
eSSU2SessionStateTerminated, eSSU2SessionStateTerminated,
eSSU2SessionStateFailed, eSSU2SessionStateFailed,
@ -157,11 +160,10 @@ namespace transport
int numResends = 0; int numResends = 0;
}; };
struct SessionConfirmedFragment struct HandshakePacket: public SentPacket
{ {
Header header; Header header;
uint8_t payload[SSU2_MAX_PAYLOAD_SIZE]; uint8_t headerX[48]; // not used in SessionConfirmed
size_t payloadSize;
}; };
typedef std::function<void ()> OnEstablished; typedef std::function<void ()> OnEstablished;
@ -263,7 +265,8 @@ namespace transport
SSU2Server& m_Server; SSU2Server& m_Server;
std::shared_ptr<i2p::crypto::X25519Keys> m_EphemeralKeys; std::shared_ptr<i2p::crypto::X25519Keys> m_EphemeralKeys;
std::unique_ptr<i2p::crypto::NoiseSymmetricState> m_NoiseState; std::unique_ptr<i2p::crypto::NoiseSymmetricState> m_NoiseState;
std::unique_ptr<SessionConfirmedFragment> m_SessionConfirmedFragment1; // for Bob if applicable std::unique_ptr<HandshakePacket> m_SessionConfirmedFragment1; // for Bob if applicable
std::unique_ptr<HandshakePacket> m_SentHandshakePacket; // SessionRequest or SessionCreated
std::shared_ptr<const i2p::data::RouterInfo::Address> m_Address; std::shared_ptr<const i2p::data::RouterInfo::Address> m_Address;
boost::asio::ip::udp::endpoint m_RemoteEndpoint; boost::asio::ip::udp::endpoint m_RemoteEndpoint;
i2p::data::RouterInfo::CompatibleTransports m_RemoteTransports; // for peer tests i2p::data::RouterInfo::CompatibleTransports m_RemoteTransports; // for peer tests

Loading…
Cancel
Save