SSU2Session.h
1 /* 2 * Copyright (c) 2022-2026, The PurpleI2P Project 3 * 4 * This file is part of Purple i2pd project and licensed under BSD3 5 * 6 * See full license text in LICENSE file at top of project tree 7 */ 8 9 #ifndef SSU2_SESSION_H__ 10 #define SSU2_SESSION_H__ 11 12 #include <memory> 13 #include <functional> 14 #include <map> 15 #include <set> 16 #include <list> 17 #include <boost/asio.hpp> 18 #include "version.h" 19 #include "Crypto.h" 20 #include "RouterInfo.h" 21 #include "RouterContext.h" 22 #include "TransportSession.h" 23 24 namespace i2p 25 { 26 namespace transport 27 { 28 const int SSU2_CONNECT_TIMEOUT = 5; // 5 seconds 29 const int SSU2_TERMINATION_TIMEOUT = 165; // in seconds 30 const int SSU2_CLOCK_SKEW = 60; // in seconds 31 const int SSU2_CLOCK_THRESHOLD = 15; // in seconds, if more we should adjust 32 const int SSU2_TOKEN_EXPIRATION_TIMEOUT = 9; // for Retry message, in seconds 33 const int SSU2_NEXT_TOKEN_EXPIRATION_TIMEOUT = 52*60; // for next token block, in seconds 34 const int SSU2_TOKEN_EXPIRATION_THRESHOLD = 2; // in seconds 35 const int SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT = 10; // in seconds 36 const int SSU2_PEER_TEST_EXPIRATION_TIMEOUT = 60; // 60 seconds 37 const size_t SSU2_MAX_PACKET_SIZE = 1500; 38 const size_t SSU2_MIN_PACKET_SIZE = 1280; 39 const int SSU2_HANDSHAKE_RESEND_INTERVAL = 1000; // in milliseconds 40 const int SSU2_MAX_NUM_RESENDS = 5; 41 const int SSU2_RESEND_ATTEMPT_MIN_INTERVAL = 3; // in milliseconds 42 const int SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT = 30; // in seconds 43 const int SSU2_MAX_NUM_RECEIVED_I2NP_MSGIDS = 5000; // how many msgID we store for duplicates check 44 const int SSU2_RECEIVED_I2NP_MSGIDS_CLEANUP_TIMEOUT = 10; // in seconds 45 const int SSU2_DECAY_INTERVAL = 20; // in seconds 46 const size_t SSU2_MIN_WINDOW_SIZE = 16; // in packets 47 const size_t SSU2_MAX_WINDOW_SIZE = 256; // in packets 48 const size_t SSU2_MIN_RTO = 100; // in milliseconds 49 const size_t SSU2_INITIAL_RTO = 540; // in milliseconds 50 const size_t SSU2_MAX_RTO = 2500; // in milliseconds 51 const double SSU2_UNKNOWN_RTT = -1; 52 const double SSU2_RTT_EWMA_ALPHA = 0.125; 53 const float SSU2_kAPPA = 1.8; 54 const int SSU2_MAX_NUM_ACNT = 255; // acnt, acks or nacks 55 const int SSU2_MAX_NUM_ACK_PACKETS = 511; // ackthrough + acnt + 1 range 56 const int SSU2_MAX_NUM_ACK_RANGES = 32; // to send 57 const uint8_t SSU2_MAX_NUM_FRAGMENTS = 64; 58 const int SSU2_SEND_DATETIME_NUM_PACKETS = 256; 59 const int SSU2_MIN_RELAY_RESPONSE_RESEND_VERSION = MAKE_VERSION_NUMBER(0, 9, 64); // 0.9.64 60 61 // flags 62 const uint8_t SSU2_FLAG_IMMEDIATE_ACK_REQUESTED = 0x01; 63 64 enum SSU2MessageType 65 { 66 eSSU2SessionRequest = 0, 67 eSSU2SessionCreated = 1, 68 eSSU2SessionConfirmed = 2, 69 eSSU2Data = 6, 70 eSSU2PeerTest = 7, 71 eSSU2Retry = 9, 72 eSSU2TokenRequest = 10, 73 eSSU2HolePunch = 11 74 }; 75 76 enum SSU2BlockType 77 { 78 eSSU2BlkDateTime = 0, 79 eSSU2BlkOptions, // 1 80 eSSU2BlkRouterInfo, // 2 81 eSSU2BlkI2NPMessage, // 3 82 eSSU2BlkFirstFragment, // 4 83 eSSU2BlkFollowOnFragment, // 5 84 eSSU2BlkTermination, // 6 85 eSSU2BlkRelayRequest, // 7 86 eSSU2BlkRelayResponse, // 8 87 eSSU2BlkRelayIntro, // 9 88 eSSU2BlkPeerTest, // 10 89 eSSU2BlkNextNonce, // 11 90 eSSU2BlkAck, // 12 91 eSSU2BlkAddress, // 13 92 eSSU2BlkIntroKey, // 14 93 eSSU2BlkRelayTagRequest, // 15 94 eSSU2BlkRelayTag, // 16 95 eSSU2BlkNewToken, // 17 96 eSSU2BlkPathChallenge, // 18 97 eSSU2BlkPathResponse, // 19 98 eSSU2BlkFirstPacketNumber, // 20 99 eSSU2BlkPadding = 254 100 }; 101 102 enum SSU2SessionState 103 { 104 eSSU2SessionStateUnknown, 105 eSSU2SessionStateTokenReceived, 106 eSSU2SessionStateSessionRequestSent, 107 eSSU2SessionStateSessionRequestReceived, 108 eSSU2SessionStateSessionCreatedSent, 109 eSSU2SessionStateSessionCreatedReceived, 110 eSSU2SessionStateSessionConfirmedSent, 111 eSSU2SessionStateEstablished, 112 eSSU2SessionStateClosing, 113 eSSU2SessionStateClosingConfirmed, 114 eSSU2SessionStateTerminated, 115 eSSU2SessionStateFailed, 116 eSSU2SessionStateIntroduced, 117 eSSU2SessionStateHolePunch, 118 eSSU2SessionStatePeerTest, 119 eSSU2SessionStateTokenRequestReceived 120 }; 121 122 enum SSU2PeerTestCode 123 { 124 eSSU2PeerTestCodeAccept = 0, 125 eSSU2PeerTestCodeBobReasonUnspecified = 1, 126 eSSU2PeerTestCodeBobNoCharlieAvailable = 2, 127 eSSU2PeerTestCodeBobLimitExceeded = 3, 128 eSSU2PeerTestCodeBobSignatureFailure = 4, 129 eSSU2PeerTestCodeCharlieReasonUnspecified = 64, 130 eSSU2PeerTestCodeCharlieUnsupportedAddress = 65, 131 eSSU2PeerTestCodeCharlieLimitExceeded = 66, 132 eSSU2PeerTestCodeCharlieSignatureFailure = 67, 133 eSSU2PeerTestCodeCharlieAliceIsAlreadyConnected = 68, 134 eSSU2PeerTestCodeCharlieAliceIsBanned = 69, 135 eSSU2PeerTestCodeCharlieAliceIsUnknown = 70, 136 eSSU2PeerTestCodeUnspecified = 128 137 }; 138 139 enum SSU2RelayResponseCode 140 { 141 eSSU2RelayResponseCodeAccept = 0, 142 eSSU2RelayResponseCodeBobRelayTagNotFound = 5, 143 eSSU2RelayResponseCodeCharlieUnsupportedAddress = 65, 144 eSSU2RelayResponseCodeCharlieSignatureFailure = 67, 145 eSSU2RelayResponseCodeCharlieAliceIsUnknown = 70 146 }; 147 148 enum SSU2TerminationReason 149 { 150 eSSU2TerminationReasonNormalClose = 0, 151 eSSU2TerminationReasonTerminationReceived = 1, 152 eSSU2TerminationReasonIdleTimeout = 2, 153 eSSU2TerminationReasonRouterShutdown = 3, 154 eSSU2TerminationReasonDataPhaseAEADFailure= 4, 155 eSSU2TerminationReasonIncompatibleOptions = 5, 156 eSSU2TerminationReasonTncompatibleSignatureType = 6, 157 eSSU2TerminationReasonClockSkew = 7, 158 eSSU2TerminationPaddingViolation = 8, 159 eSSU2TerminationReasonAEADFramingError = 9, 160 eSSU2TerminationReasonPayloadFormatError = 10, 161 eSSU2TerminationReasonSessionRequestError = 11, 162 eSSU2TerminationReasonSessionCreatedError = 12, 163 eSSU2TerminationReasonSessionConfirmedError = 13, 164 eSSU2TerminationReasonTimeout = 14, 165 eSSU2TerminationReasonRouterInfoSignatureVerificationFail = 15, 166 eSSU2TerminationReasonInvalidS = 16, 167 eSSU2TerminationReasonBanned = 17, 168 eSSU2TerminationReasonBadToken = 18, 169 eSSU2TerminationReasonConnectionLimits = 19, 170 eSSU2TerminationReasonIncompatibleVersion = 20, 171 eSSU2TerminationReasonWrongNetID = 21, 172 eSSU2TerminationReasonReplacedByNewSession = 22 173 }; 174 175 struct SSU2IncompleteMessage 176 { 177 struct Fragment 178 { 179 uint8_t buf[SSU2_MAX_PACKET_SIZE]; 180 size_t len; 181 int fragmentNum; 182 bool isLast; 183 std::shared_ptr<Fragment> next; 184 }; 185 186 std::shared_ptr<I2NPMessage> msg; 187 int nextFragmentNum; 188 uint32_t lastFragmentInsertTime; // in seconds 189 std::shared_ptr<Fragment> outOfSequenceFragments; // #1 and more 190 191 void AttachNextFragment (const uint8_t * fragment, size_t fragmentSize); 192 bool ConcatOutOfSequenceFragments (); // true if message complete 193 void AddOutOfSequenceFragment (std::shared_ptr<Fragment> fragment); 194 }; 195 196 struct SSU2SentPacket 197 { 198 uint8_t payload[SSU2_MAX_PACKET_SIZE]; 199 size_t payloadSize = 0; 200 uint64_t sendTime; // in milliseconds 201 int numResends = 0; 202 }; 203 204 // RouterInfo flags 205 const uint8_t SSU2_ROUTER_INFO_FLAG_REQUEST_FLOOD = 0x01; 206 const uint8_t SSU2_ROUTER_INFO_FLAG_GZIP = 0x02; 207 208 class SSU2Server; 209 class SSU2Session: public TransportSession, public std::enable_shared_from_this<SSU2Session> 210 { 211 protected: 212 213 union Header 214 { 215 uint64_t ll[2]; 216 uint8_t buf[16]; 217 struct 218 { 219 uint64_t connID; 220 uint32_t packetNum; 221 uint8_t type; 222 uint8_t flags[3]; 223 } h; 224 }; 225 226 private: 227 228 struct HandshakePacket 229 { 230 Header header; 231 uint8_t headerX[48]; // part1 for SessionConfirmed 232 uint8_t payload[SSU2_MAX_PACKET_SIZE*2]; 233 size_t payloadSize = 0; 234 uint64_t sendTime = 0; // in milliseconds 235 bool isSecondFragment = false; // for SessionConfirmed 236 }; 237 238 typedef std::function<void ()> OnEstablished; 239 240 public: 241 242 SSU2Session (SSU2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter = nullptr, 243 std::shared_ptr<const i2p::data::RouterInfo::Address> addr = nullptr, bool noise = true); 244 virtual ~SSU2Session (); 245 246 void SetRemoteEndpoint (const boost::asio::ip::udp::endpoint& ep) { m_RemoteEndpoint = ep; }; 247 const boost::asio::ip::udp::endpoint& GetRemoteEndpoint () const { return m_RemoteEndpoint; }; 248 i2p::data::RouterInfo::CompatibleTransports GetRemoteTransports () const { return m_RemoteTransports; }; 249 i2p::data::RouterInfo::CompatibleTransports GetRemotePeerTestTransports () const { return m_RemotePeerTestTransports; }; 250 int GetRemoteVersion () const { return m_RemoteVersion; }; 251 std::shared_ptr<const i2p::data::RouterInfo::Address> GetAddress () const { return m_Address; }; 252 void SetOnEstablished (OnEstablished e) { m_OnEstablished = e; }; 253 OnEstablished GetOnEstablished () const { return m_OnEstablished; }; 254 255 virtual void Connect (); 256 bool Introduce (std::shared_ptr<SSU2Session> session, uint32_t relayTag); 257 void WaitForIntroduction (); 258 void SendPeerTest (); // Alice, Data message 259 void SendKeepAlive (); 260 void RequestTermination (SSU2TerminationReason reason); 261 void CleanUp (uint64_t ts); 262 void FlushData (); 263 void Done () override; 264 void SendLocalRouterInfo (bool update) override; 265 void SendI2NPMessages (std::list<std::shared_ptr<I2NPMessage> >& msgs) override; 266 void MoveSendQueue (std::shared_ptr<SSU2Session> other); 267 uint32_t GetRelayTag () const override { return m_RelayTag; }; 268 size_t Resend (uint64_t ts); // return number of resent packets 269 uint64_t GetLastResendTime () const { return m_LastResendTime; }; 270 bool IsEstablished () const override { return m_State == eSSU2SessionStateEstablished; }; 271 i2p::data::RouterInfo::SupportedTransports GetTransportType () const override; 272 uint64_t GetConnID () const { return m_SourceConnID; }; 273 SSU2SessionState GetState () const { return m_State; }; 274 void SetState (SSU2SessionState state) { m_State = state; }; 275 276 virtual bool ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len); 277 bool ProcessSessionCreated (uint8_t * buf, size_t len); 278 bool ProcessSessionConfirmed (uint8_t * buf, size_t len); 279 bool ProcessRetry (uint8_t * buf, size_t len); 280 bool ProcessHolePunch (uint8_t * buf, size_t len); 281 virtual bool ProcessPeerTest (uint8_t * buf, size_t len); 282 void ProcessData (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from); 283 284 protected: 285 286 SSU2Server& GetServer () { return m_Server; } 287 RouterStatus GetRouterStatus () const; 288 void SetRouterStatus (RouterStatus status) const; 289 size_t GetMaxPayloadSize () const { return m_MaxPayloadSize; } 290 void SetIsDataReceived (bool dataReceived) { m_IsDataReceived = dataReceived; }; 291 292 uint64_t GetSourceConnID () const { return m_SourceConnID; } 293 void SetSourceConnID (uint64_t sourceConnID) { m_SourceConnID = sourceConnID; } 294 uint64_t GetDestConnID () const { return m_DestConnID; } 295 void SetDestConnID (uint64_t destConnID) { m_DestConnID = destConnID; } 296 297 void SetAddress (std::shared_ptr<const i2p::data::RouterInfo::Address> addr) { m_Address = addr; } 298 void HandlePayload (const uint8_t * buf, size_t len); 299 300 size_t CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep); 301 size_t CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize = 0); 302 size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code, const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen); 303 304 bool ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep); 305 306 private: 307 308 void Terminate (); 309 void Established (); 310 void ScheduleConnectTimer (); 311 void HandleConnectTimer (const boost::system::error_code& ecode); 312 void PostI2NPMessages (); 313 bool SendQueue (); // returns true if ack block was sent 314 bool SendFragmentedMessage (std::shared_ptr<I2NPMessage> msg); 315 void ResendHandshakePacket (); 316 void ConnectAfterIntroduction (); 317 318 void ProcessSessionRequest (Header& header, uint8_t * buf, size_t len); 319 void ProcessTokenRequest (Header& header, uint8_t * buf, size_t len); 320 321 void SendSessionRequest (uint64_t token = 0); 322 void SendSessionCreated (const uint8_t * X); 323 void SendSessionConfirmed (const uint8_t * Y); 324 void KDFDataPhase (uint8_t * keydata_ab, uint8_t * keydata_ba); 325 void SendTokenRequest (); 326 void SendRetry (); 327 uint32_t SendData (const uint8_t * buf, size_t len, uint8_t flags = 0); // returns packet num 328 void SendQuickAck (); 329 void SendTermination (); 330 void SendPathResponse (const uint8_t * data, size_t len); 331 void SendPathChallenge (const boost::asio::ip::udp::endpoint& to); 332 333 void HandleDateTime (const uint8_t * buf, size_t len); 334 void HandleRouterInfo (const uint8_t * buf, size_t len); 335 void HandleAck (const uint8_t * buf, size_t len); 336 void HandleAckRange (uint32_t firstPacketNum, uint32_t lastPacketNum, uint64_t ts); 337 virtual void HandleAddress (const uint8_t * buf, size_t len); 338 size_t CreateEndpoint (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep); 339 std::shared_ptr<const i2p::data::RouterInfo::Address> FindLocalAddress () const; 340 void AdjustMaxPayloadSize (size_t maxMtu = SSU2_MAX_PACKET_SIZE); 341 bool GetTestingState () const; 342 void SetTestingState(bool testing) const; 343 std::shared_ptr<const i2p::data::RouterInfo> ExtractRouterInfo (const uint8_t * buf, size_t size); 344 bool UpdateReceivePacketNum (uint32_t packetNum); // for Ack, returns false if duplicate 345 void HandleFirstFragment (const uint8_t * buf, size_t len); 346 void HandleFollowOnFragment (const uint8_t * buf, size_t len); 347 void HandleRelayRequest (const uint8_t * buf, size_t len); 348 void HandleRelayIntro (const uint8_t * buf, size_t len, int attempts = 0); 349 void HandleRelayResponse (const uint8_t * buf, size_t len); 350 virtual void HandlePeerTest (const uint8_t * buf, size_t len); 351 void HandleI2NPMsg (std::shared_ptr<I2NPMessage>&& msg); 352 353 size_t CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo> r); 354 size_t CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo::Buffer> riBuffer); 355 size_t CreateAckBlock (uint8_t * buf, size_t len); 356 size_t CreateI2NPBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage>&& msg); 357 size_t CreateFirstFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg); 358 size_t CreateFollowOnFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg, uint8_t& fragmentNum, uint32_t msgID); 359 size_t CreateRelayIntroBlock (uint8_t * buf, size_t len, const uint8_t * introData, size_t introDataLen); 360 size_t CreateRelayResponseBlock (uint8_t * buf, size_t len, SSU2RelayResponseCode code, uint32_t nonce, uint64_t token, bool v4); 361 362 size_t CreatePeerTestBlock (uint8_t * buf, size_t len, uint32_t nonce); // Alice 363 size_t CreateTerminationBlock (uint8_t * buf, size_t len); 364 365 private: 366 367 SSU2Server& m_Server; 368 std::shared_ptr<i2p::crypto::X25519Keys> m_EphemeralKeys; 369 std::unique_ptr<i2p::crypto::NoiseSymmetricState> m_NoiseState; 370 std::unique_ptr<HandshakePacket> m_SessionConfirmedFragment; // for Bob if applicable or second fragment for Alice 371 std::unique_ptr<HandshakePacket> m_SentHandshakePacket; // SessionRequest, SessionCreated or SessionConfirmed 372 std::shared_ptr<const i2p::data::RouterInfo::Address> m_Address; 373 boost::asio::ip::udp::endpoint m_RemoteEndpoint; 374 i2p::data::RouterInfo::CompatibleTransports m_RemoteTransports, m_RemotePeerTestTransports; 375 int m_RemoteVersion; 376 uint64_t m_DestConnID, m_SourceConnID; 377 SSU2SessionState m_State; 378 uint8_t m_KeyDataSend[64], m_KeyDataReceive[64]; 379 uint32_t m_SendPacketNum, m_ReceivePacketNum, m_LastDatetimeSentPacketNum; 380 std::set<uint32_t> m_OutOfSequencePackets; // packet nums > receive packet num 381 std::map<uint32_t, std::shared_ptr<SSU2SentPacket> > m_SentPackets; // packetNum -> packet 382 std::unordered_map<uint32_t, std::shared_ptr<SSU2IncompleteMessage> > m_IncompleteMessages; // msgID -> I2NP 383 std::unordered_map<uint32_t, std::pair <std::shared_ptr<SSU2Session>, uint64_t > > m_RelaySessions; // nonce->(Alice, timestamp) for Bob or nonce->(Charlie, timestamp) for Alice 384 std::list<std::shared_ptr<I2NPMessage> > m_SendQueue; 385 i2p::I2NPMessagesHandler m_Handler; 386 std::list<std::shared_ptr<I2NPMessage> > m_IntermediateQueue; // from transports 387 mutable std::mutex m_IntermediateQueueMutex; 388 bool m_IsDataReceived; 389 double m_RTT; 390 int m_MsgLocalExpirationTimeout; 391 int m_MsgLocalSemiExpirationTimeout; 392 size_t m_WindowSize, m_RTO; 393 uint32_t m_RelayTag; // between Bob and Charlie 394 OnEstablished m_OnEstablished; // callback from Established 395 boost::asio::deadline_timer m_ConnectTimer; 396 SSU2TerminationReason m_TerminationReason; 397 size_t m_MaxPayloadSize; 398 std::unique_ptr<std::pair<uint64_t, boost::asio::ip::udp::endpoint> > m_PathChallenge; 399 std::unordered_map<uint32_t, uint32_t> m_ReceivedI2NPMsgIDs; // msgID -> timestamp in seconds 400 uint64_t m_LastResendTime, m_LastResendAttemptTime; // in milliseconds 401 int m_NumRanges; 402 uint8_t m_Ranges[SSU2_MAX_NUM_ACK_RANGES*2]; // ranges sent with previous Ack if any 403 }; 404 405 inline uint64_t CreateHeaderMask (const uint8_t * kh, const uint8_t * nonce) 406 { 407 uint64_t data = 0; 408 i2p::crypto::ChaCha20 ((uint8_t *)&data, 8, kh, nonce, (uint8_t *)&data); 409 return data; 410 } 411 412 inline void CreateNonce (uint64_t seqn, uint8_t * nonce) 413 { 414 memset (nonce, 0, 4); 415 htole64buf (nonce + 4, seqn); 416 } 417 } 418 } 419 420 #endif