/ libi2pd / SSU2Session.h
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