/ libi2pd / SSU2Session.cpp
SSU2Session.cpp
   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  #include <string.h>
  10  #include <openssl/rand.h>
  11  #include "Log.h"
  12  #include "Transports.h"
  13  #include "Gzip.h"
  14  #include "NetDb.hpp"
  15  #include "SSU2.h"
  16  #include "SSU2Session.h"
  17  
  18  namespace i2p
  19  {
  20  namespace transport
  21  {
  22  	void SSU2IncompleteMessage::AttachNextFragment (const uint8_t * fragment, size_t fragmentSize)
  23  	{
  24  		if (msg->len + fragmentSize > msg->maxLen)
  25  		{
  26  			LogPrint (eLogInfo, "SSU2: I2NP message size ", msg->maxLen, " is not enough");
  27  			auto newMsg = NewI2NPMessage (msg->len + fragmentSize);
  28  			*newMsg = *msg;
  29  			msg = newMsg;
  30  		}
  31  		if (msg->Concat (fragment, fragmentSize) < fragmentSize)
  32  			LogPrint (eLogError, "SSU2: I2NP buffer overflow ", msg->maxLen);
  33  		nextFragmentNum++;
  34  	}
  35  
  36  	bool SSU2IncompleteMessage::ConcatOutOfSequenceFragments ()
  37  	{
  38  		bool isLast = false;
  39  		while (outOfSequenceFragments)
  40  		{
  41  			if (outOfSequenceFragments->fragmentNum == nextFragmentNum)
  42  			{
  43  				AttachNextFragment (outOfSequenceFragments->buf, outOfSequenceFragments->len);
  44  				isLast = outOfSequenceFragments->isLast;
  45  				if (isLast)
  46  					outOfSequenceFragments = nullptr;
  47  				else
  48  					outOfSequenceFragments = outOfSequenceFragments->next;
  49  			}
  50  			else
  51  				break;
  52  		}
  53  		return isLast;
  54  	}
  55  
  56  	void SSU2IncompleteMessage::AddOutOfSequenceFragment (std::shared_ptr<SSU2IncompleteMessage::Fragment> fragment)
  57  	{
  58  		if (!fragment || !fragment->fragmentNum) return; // fragment 0 not allowed
  59  		if (fragment->fragmentNum < nextFragmentNum) return; // already processed
  60  		if (!outOfSequenceFragments)
  61  			outOfSequenceFragments = fragment;
  62  		else
  63  		{
  64  			auto frag = outOfSequenceFragments;
  65  			std::shared_ptr<Fragment> prev;
  66  			do
  67  			{
  68  				if (fragment->fragmentNum < frag->fragmentNum) break; // found
  69  				if (fragment->fragmentNum == frag->fragmentNum) return; // duplicate
  70  				prev = frag; frag = frag->next;
  71  			}
  72  			while (frag);
  73  			fragment->next = frag;
  74  			if (prev)
  75  				prev->next = fragment;
  76  			else
  77  				outOfSequenceFragments = fragment;
  78  		}
  79  		lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch ();
  80  	}
  81  
  82  	SSU2Session::SSU2Session (SSU2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter,
  83  		std::shared_ptr<const i2p::data::RouterInfo::Address> addr, bool noise):
  84  		TransportSession (in_RemoteRouter, SSU2_CONNECT_TIMEOUT),
  85  		m_Server (server), m_Address (addr), m_RemoteTransports (0), m_RemotePeerTestTransports (0),
  86  		m_RemoteVersion (0), m_DestConnID (0), m_SourceConnID (0), m_State (eSSU2SessionStateUnknown),
  87  		m_SendPacketNum (0), m_ReceivePacketNum (0), m_LastDatetimeSentPacketNum (0),
  88  		m_IsDataReceived (false), m_RTT (SSU2_UNKNOWN_RTT),
  89  		m_MsgLocalExpirationTimeout (I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MAX),
  90  		m_MsgLocalSemiExpirationTimeout (I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MAX / 2),
  91  		m_WindowSize (SSU2_MIN_WINDOW_SIZE),
  92  		m_RTO (SSU2_INITIAL_RTO), m_RelayTag (0),m_ConnectTimer (server.GetService ()),
  93  		m_TerminationReason (eSSU2TerminationReasonNormalClose),
  94  		m_MaxPayloadSize (SSU2_MIN_PACKET_SIZE - IPV6_HEADER_SIZE - UDP_HEADER_SIZE - 32), // min size
  95  		m_LastResendTime (0), m_LastResendAttemptTime (0), m_NumRanges (0)
  96  	{
  97  		if (noise)
  98  			m_NoiseState.reset (new i2p::crypto::NoiseSymmetricState);
  99  		if (in_RemoteRouter && m_Address)
 100  		{
 101  			// outgoing
 102  			if (noise)
 103  				InitNoiseXKState1 (*m_NoiseState, m_Address->s);
 104  			m_RemoteEndpoint = boost::asio::ip::udp::endpoint (m_Address->host, m_Address->port);
 105  			m_RemoteTransports = in_RemoteRouter->GetCompatibleTransports (false);
 106  			m_RemoteVersion = in_RemoteRouter->GetVersion ();
 107  			if (in_RemoteRouter->IsSSU2PeerTesting (true)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V4;
 108  			if (in_RemoteRouter->IsSSU2PeerTesting (false)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V6;
 109  			RAND_bytes ((uint8_t *)&m_DestConnID, 8);
 110  			RAND_bytes ((uint8_t *)&m_SourceConnID, 8);
 111  		}
 112  		else
 113  		{
 114  			// incoming
 115  			if (noise)
 116  				InitNoiseXKState1 (*m_NoiseState, i2p::context.GetSSU2StaticPublicKey ());
 117  		}
 118  	}
 119  
 120  	SSU2Session::~SSU2Session ()
 121  	{
 122  	}
 123  
 124  	void SSU2Session::Connect ()
 125  	{
 126  		if (m_State == eSSU2SessionStateUnknown || m_State == eSSU2SessionStateTokenReceived)
 127  		{
 128  			LogPrint(eLogDebug, "SSU2: Connecting to ", GetRemoteEndpoint (),
 129  				" (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ")");
 130  			ScheduleConnectTimer ();
 131  			auto token = m_Server.FindOutgoingToken (m_RemoteEndpoint);
 132  			if (token)
 133  				SendSessionRequest (token);
 134  			else
 135  			{
 136  				m_State = eSSU2SessionStateUnknown;
 137  				SendTokenRequest ();
 138  			}
 139  		}
 140  	}
 141  
 142  	void SSU2Session::ScheduleConnectTimer ()
 143  	{
 144  		m_ConnectTimer.cancel ();
 145  		m_ConnectTimer.expires_from_now (boost::posix_time::seconds(SSU2_CONNECT_TIMEOUT));
 146  		m_ConnectTimer.async_wait (std::bind (&SSU2Session::HandleConnectTimer,
 147  			shared_from_this (), std::placeholders::_1));
 148  	}
 149  
 150  	void SSU2Session::HandleConnectTimer (const boost::system::error_code& ecode)
 151  	{
 152  		if (!ecode && m_State != eSSU2SessionStateTerminated)
 153  		{
 154  			// timeout expired
 155  			if (m_State == eSSU2SessionStateIntroduced) // WaitForIntroducer
 156  				LogPrint (eLogWarning, "SSU2: Session was not introduced after ", SSU2_CONNECT_TIMEOUT, " seconds");
 157  			else
 158  				LogPrint (eLogWarning, "SSU2: Session with ", m_RemoteEndpoint, " was not established after ", SSU2_CONNECT_TIMEOUT, " seconds");
 159  			Terminate ();
 160  		}
 161  	}
 162  
 163  	bool SSU2Session::Introduce (std::shared_ptr<SSU2Session> session, uint32_t relayTag)
 164  	{
 165  		// we are Alice
 166  		if (!session || !relayTag) return false;
 167  		// find local address to introduce
 168  		auto localAddress = session->FindLocalAddress ();
 169  		if (!localAddress || localAddress->host.is_unspecified () || !localAddress->port)
 170  		{
 171  			// can't introduce invalid endpoint
 172  			LogPrint (eLogWarning, "SSU2: Can't find local address to introduce");
 173  			return false;
 174  		}
 175  		// create nonce
 176  		uint32_t nonce;
 177  		RAND_bytes ((uint8_t *)&nonce, 4);
 178  		auto ts = i2p::util::GetMillisecondsSinceEpoch ();
 179  		// payload
 180  		auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
 181  		uint8_t * payload = packet->payload;
 182  		payload[0] = eSSU2BlkRelayRequest;
 183  		payload[3] = 0; // flag
 184  		htobe32buf (payload + 4, nonce);
 185  		htobe32buf (payload + 8, relayTag);
 186  		htobe32buf (payload + 12, ts/1000);
 187  		payload[16] = 2; // ver
 188  		size_t asz = CreateEndpoint (payload + 18, m_MaxPayloadSize - 18, boost::asio::ip::udp::endpoint (localAddress->host, localAddress->port));
 189  		if (!asz) return false;
 190  		payload[17] = asz;
 191  		packet->payloadSize = asz + 18;
 192  		SignedData<128> s;
 193  		s.Insert ((const uint8_t *)"RelayRequestData", 16); // prologue
 194  		s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash
 195  		s.Insert (session->GetRemoteIdentity ()->GetIdentHash (), 32); // chash
 196  		s.Insert (payload + 4, 14 + asz); // nonce, relay tag, timestamp, ver, asz and Alice's endpoint
 197  		s.Sign (i2p::context.GetPrivateKeys (), payload + packet->payloadSize);
 198  		packet->payloadSize += i2p::context.GetIdentity ()->GetSignatureLen ();
 199  		htobe16buf (payload + 1, packet->payloadSize - 3); // size
 200  		packet->payloadSize += CreatePaddingBlock (payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
 201  		// send
 202  		m_RelaySessions.emplace (nonce, std::make_pair (session, ts/1000));
 203  		session->m_SourceConnID = htobe64 (((uint64_t)nonce << 32) | nonce);
 204  		session->m_DestConnID = ~session->m_SourceConnID;
 205  		m_Server.AddSession (session);
 206  		int32_t packetNum = SendData (packet->payload, packet->payloadSize);
 207  		packet->sendTime = ts;
 208  		m_SentPackets.emplace (packetNum, packet);
 209  
 210  		return true;
 211  	}
 212  
 213  	void SSU2Session::WaitForIntroduction ()
 214  	{
 215  		m_State = eSSU2SessionStateIntroduced;
 216  		ScheduleConnectTimer ();
 217  	}
 218  
 219  	void SSU2Session::ConnectAfterIntroduction ()
 220  	{
 221  		if (m_State == eSSU2SessionStateIntroduced)
 222  		{
 223  			// we are Alice
 224  			//  keep ConnIDs used for introduction, because Charlie waits for SessionRequest from us
 225  			m_State = eSSU2SessionStateTokenReceived;
 226  			// move session to pending outgoing
 227  			if (m_Server.AddPendingOutgoingSession (shared_from_this ()))
 228  			{
 229  				m_Server.RemoveSession (GetConnID ());
 230  				// update endpoint in profile because we know it now
 231  				auto identity = GetRemoteIdentity ();
 232  				if (identity)
 233  				{
 234  					auto profile = i2p::data::GetRouterProfile (identity->GetIdentHash ());
 235  					if (profile) profile->SetLastEndpoint (m_RemoteEndpoint);
 236  				}
 237  				// connect
 238  				LogPrint (eLogDebug, "SSU2: Connecting after introduction to ", GetIdentHashBase64());
 239  				Connect ();
 240  			}
 241  			else
 242  			{
 243  				LogPrint (eLogError, "SSU2: Session ", GetConnID (), " is already pending");
 244  				m_Server.RequestRemoveSession (GetConnID ());
 245  			}
 246  		}
 247  	}
 248  
 249  	void SSU2Session::SendPeerTest ()
 250  	{
 251  		// we are Alice
 252  		uint32_t nonce;
 253  		RAND_bytes ((uint8_t *)&nonce, 4);
 254  		auto ts = i2p::util::GetMillisecondsSinceEpoch ();
 255  		// session for message 5
 256  		auto session = std::make_shared<SSU2PeerTestSession> (m_Server,
 257  			htobe64 (((uint64_t)nonce << 32) | nonce), 0);
 258  		m_Server.AddRequestedPeerTest (nonce, session, ts/1000);
 259  		m_Server.AddSession (session);
 260  		// peer test block
 261  		auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
 262  		packet->payloadSize = CreatePeerTestBlock (packet->payload, m_MaxPayloadSize, nonce);
 263  		if (packet->payloadSize > 0)
 264  		{
 265  			packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
 266  			uint32_t packetNum = SendData (packet->payload, packet->payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED);
 267  			packet->sendTime = ts;
 268  			m_SentPackets.emplace (packetNum, packet);
 269  			LogPrint (eLogDebug, "SSU2: PeerTest msg=1 sent to ", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()));
 270  		}
 271  	}
 272  
 273  	void SSU2Session::SendKeepAlive ()
 274  	{
 275  		if (IsEstablished ())
 276  		{
 277  			uint8_t payload[20];
 278  			size_t payloadSize = CreatePaddingBlock (payload, 20, 8);
 279  			SendData (payload, payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED);
 280  		}
 281  	}
 282  
 283  	void SSU2Session::Terminate ()
 284  	{
 285  		if (m_State != eSSU2SessionStateTerminated)
 286  		{
 287  			m_State = eSSU2SessionStateTerminated;
 288  			m_ConnectTimer.cancel ();
 289  			m_OnEstablished = nullptr;
 290  			if (m_RelayTag)
 291  				m_Server.RemoveRelay (m_RelayTag);
 292  			m_Server.AddConnectedRecently (m_RemoteEndpoint, GetLastActivityTimestamp ());
 293  			m_SentHandshakePacket.reset (nullptr);
 294  			m_SessionConfirmedFragment.reset (nullptr);
 295  			m_PathChallenge.reset (nullptr);
 296  			if (!m_IntermediateQueue.empty ())
 297  				m_SendQueue.splice (m_SendQueue.end (), m_IntermediateQueue);
 298  			for (auto& it: m_SendQueue)
 299  				it->Drop ();
 300  			m_SendQueue.clear ();
 301  			SetSendQueueSize (0);
 302  			m_SentPackets.clear ();
 303  			m_IncompleteMessages.clear ();
 304  			m_RelaySessions.clear ();
 305  			m_ReceivedI2NPMsgIDs.clear ();
 306  			m_Server.RemoveSession (m_SourceConnID);
 307  			transports.PeerDisconnected (shared_from_this ());
 308  			auto remoteIdentity = GetRemoteIdentity ();
 309  			if (remoteIdentity)
 310  				LogPrint (eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (),
 311  					" (", i2p::data::GetIdentHashAbbreviation (remoteIdentity->GetIdentHash ()), ") terminated");
 312  			else
 313  				LogPrint (eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (), " terminated");
 314  		}
 315  	}
 316  
 317  	void SSU2Session::RequestTermination (SSU2TerminationReason reason)
 318  	{
 319  		if (m_State == eSSU2SessionStateEstablished || m_State == eSSU2SessionStateClosing)
 320  		{
 321  			m_TerminationReason = reason;
 322  			SendTermination ();
 323  			m_State = eSSU2SessionStateClosing;
 324  		}
 325  		else
 326  			Done ();
 327  	}
 328  
 329  	void SSU2Session::Established ()
 330  	{
 331  		m_State = eSSU2SessionStateEstablished;
 332  		m_EphemeralKeys = nullptr;
 333  		m_NoiseState.reset (nullptr);
 334  		m_SessionConfirmedFragment.reset (nullptr);
 335  		m_SentHandshakePacket.reset (nullptr);
 336  		m_ConnectTimer.cancel ();
 337  		SetTerminationTimeout (SSU2_TERMINATION_TIMEOUT);
 338  		SendQueue ();
 339  		transports.PeerConnected (shared_from_this ());
 340  
 341  		LogPrint(eLogDebug, "SSU2: Session with ", GetRemoteEndpoint (),
 342  			" (", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()), ") established");
 343  		if (m_OnEstablished)
 344  		{
 345  			m_OnEstablished ();
 346  			m_OnEstablished = nullptr;
 347  		}
 348  	}
 349  
 350  	void SSU2Session::Done ()
 351  	{
 352  		boost::asio::post (m_Server.GetService (), std::bind (&SSU2Session::Terminate, shared_from_this ()));
 353  	}
 354  
 355  	void SSU2Session::SendLocalRouterInfo (bool update)
 356  	{
 357  		if (update || !IsOutgoing ())
 358  		{
 359  			auto s = shared_from_this ();
 360  			boost::asio::post (m_Server.GetService (), [s]()
 361  				{
 362  					if (!s->IsEstablished ()) return;
 363  					uint8_t payload[SSU2_MAX_PACKET_SIZE];
 364  					size_t payloadSize = s->CreateRouterInfoBlock (payload, s->m_MaxPayloadSize - 32, i2p::context.CopyRouterInfoBuffer ());
 365  					if (payloadSize)
 366  					{
 367  						if (payloadSize < s->m_MaxPayloadSize)
 368  							payloadSize += s->CreatePaddingBlock (payload + payloadSize, s->m_MaxPayloadSize - payloadSize);
 369  						s->SendData (payload, payloadSize);
 370  					}
 371  					else
 372  						s->SendFragmentedMessage (CreateDatabaseStoreMsg ());
 373  				});
 374  		}
 375  
 376  	}
 377  
 378  	void SSU2Session::SendI2NPMessages (std::list<std::shared_ptr<I2NPMessage> >& msgs)
 379  	{
 380  		if (m_State == eSSU2SessionStateTerminated || msgs.empty ())
 381  		{
 382  			msgs.clear ();
 383  			return;
 384  		}
 385  		bool empty = false;
 386  		{
 387  			std::lock_guard<std::mutex> l(m_IntermediateQueueMutex);
 388  			empty = m_IntermediateQueue.empty ();
 389  			m_IntermediateQueue.splice (m_IntermediateQueue.end (), msgs);
 390  		}
 391  		if (empty)
 392  			boost::asio::post (m_Server.GetService (), std::bind (&SSU2Session::PostI2NPMessages, shared_from_this ()));
 393  	}
 394  
 395  	void SSU2Session::PostI2NPMessages ()
 396  	{
 397  		if (m_State == eSSU2SessionStateTerminated) return;
 398  		std::list<std::shared_ptr<I2NPMessage> > msgs;
 399  		{
 400  			std::lock_guard<std::mutex> l(m_IntermediateQueueMutex);
 401  			m_IntermediateQueue.swap (msgs);
 402  		}
 403  		uint64_t mts = i2p::util::GetMonotonicMicroseconds ();
 404  		bool isSemiFull = false;
 405  		if (m_SendQueue.size ())
 406  		{
 407  			int64_t queueLag = (int64_t)mts - (int64_t)m_SendQueue.front ()->GetEnqueueTime ();
 408  			isSemiFull = queueLag > m_MsgLocalSemiExpirationTimeout;
 409  			if (isSemiFull)
 410  			{
 411  				LogPrint (eLogWarning, "SSU2: Outgoing messages queue to ",
 412  					i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()),
 413  					" is semi-full (size = ", m_SendQueue.size (), ", lag = ", queueLag / 1000, ", rtt = ", (int)m_RTT, ")");
 414  			}
 415  		}
 416  		if (isSemiFull)
 417  		{
 418  			for (auto it: msgs)
 419  			{
 420  				if (it->onDrop)
 421  					it->Drop (); // drop earlier because we can handle it
 422  				else
 423  				{
 424  					it->SetEnqueueTime (mts);
 425  					m_SendQueue.push_back (std::move (it));
 426  				}
 427  			}
 428  		}
 429  		else
 430  		{
 431  			for (auto& it: msgs) it->SetEnqueueTime (mts);
 432  			m_SendQueue.splice (m_SendQueue.end (), msgs);
 433  		}
 434  		if (IsEstablished ())
 435  		{
 436  			SendQueue ();
 437  			if (m_SendQueue.size () > 0) // windows is full
 438  				Resend (i2p::util::GetMillisecondsSinceEpoch ());
 439  		}
 440  		SetSendQueueSize (m_SendQueue.size ());
 441  	}
 442  
 443  	void SSU2Session::MoveSendQueue (std::shared_ptr<SSU2Session> other)
 444  	{
 445  		if (!other || m_SendQueue.empty ()) return;
 446  		std::list<std::shared_ptr<I2NPMessage> > msgs;
 447  		auto ts = i2p::util::GetMillisecondsSinceEpoch ();
 448  		for (auto it: m_SendQueue)
 449  			if (!it->IsExpired (ts))
 450  				msgs.push_back (it);
 451  			else
 452  				it->Drop ();
 453  		m_SendQueue.clear ();
 454  		if (!msgs.empty ())
 455  			other->SendI2NPMessages (msgs);
 456  	}
 457  
 458  	bool SSU2Session::SendQueue ()
 459  	{
 460  		if (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize && IsEstablished ())
 461  		{
 462  			auto ts = i2p::util::GetMillisecondsSinceEpoch ();
 463  			uint64_t mts = i2p::util::GetMonotonicMicroseconds ();
 464  			auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
 465  			size_t ackBlockSize = CreateAckBlock (packet->payload, m_MaxPayloadSize);
 466  			bool ackBlockSent = false;
 467  			packet->payloadSize += ackBlockSize;
 468  			while (!m_SendQueue.empty () && m_SentPackets.size () <= m_WindowSize)
 469  			{
 470  				auto msg = m_SendQueue.front ();
 471  				if (!msg || msg->IsExpired (ts) || msg->GetEnqueueTime() + I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_TRANSIT < mts)
 472  				{
 473  					// drop null or expired message
 474  					if (msg) msg->Drop ();
 475  					m_SendQueue.pop_front ();
 476  					continue;
 477  				}
 478  				size_t len = msg->GetNTCP2Length () + 3;
 479  				if (len > m_MaxPayloadSize) // message too long
 480  				{
 481  					m_SendQueue.pop_front ();
 482  					if (SendFragmentedMessage (msg))
 483  						ackBlockSent = true;
 484  				}
 485  				else if (packet->payloadSize + len <= m_MaxPayloadSize)
 486  				{
 487  					m_SendQueue.pop_front ();
 488  					packet->payloadSize += CreateI2NPBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, std::move (msg));
 489  				}
 490  				else
 491  				{
 492  					// create new packet and copy ack block
 493  					auto newPacket = m_Server.GetSentPacketsPool ().AcquireShared ();
 494  					memcpy (newPacket->payload, packet->payload, ackBlockSize);
 495  					newPacket->payloadSize = ackBlockSize;
 496  					// complete current packet
 497  					if (packet->payloadSize > ackBlockSize) // more than just ack block
 498  					{
 499  						ackBlockSent = true;
 500  						// try to add padding
 501  						if (packet->payloadSize + 16 < m_MaxPayloadSize)
 502  							packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
 503  					}
 504  					else
 505  					{
 506  						// reduce ack block
 507  						if (len + 8 < m_MaxPayloadSize)
 508  						{
 509  							// keep Ack block and drop some ranges
 510  							ackBlockSent = true;
 511  							packet->payloadSize = m_MaxPayloadSize - len;
 512  							if (packet->payloadSize & 0x01) packet->payloadSize--; // make it even
 513  							htobe16buf (packet->payload + 1, packet->payloadSize - 3); // new block size
 514  						}
 515  						else // drop Ack block completely
 516  							packet->payloadSize = 0;
 517  						// msg fits single packet
 518  						m_SendQueue.pop_front ();
 519  						packet->payloadSize += CreateI2NPBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, std::move (msg));
 520  					}
 521  					// send right a way
 522  					uint32_t packetNum = SendData (packet->payload, packet->payloadSize);
 523  					packet->sendTime = ts;
 524  					m_SentPackets.emplace (packetNum, packet);
 525  					packet = newPacket; // just ack block
 526  				}
 527  			};
 528  			if (packet->payloadSize > ackBlockSize)
 529  			{
 530  				// last
 531  				ackBlockSent = true;
 532  				if (packet->payloadSize + 16 < m_MaxPayloadSize)
 533  					packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
 534  				uint32_t packetNum = SendData (packet->payload, packet->payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED);
 535  				packet->sendTime = ts;
 536  				m_SentPackets.emplace (packetNum, packet);
 537  			}
 538  			return ackBlockSent;
 539  		}
 540  		return false;
 541  	}
 542  
 543  	bool SSU2Session::SendFragmentedMessage (std::shared_ptr<I2NPMessage> msg)
 544  	{
 545  		if (!msg) return false;
 546  		size_t lastFragmentSize = (msg->GetNTCP2Length () + 3 - m_MaxPayloadSize) % (m_MaxPayloadSize - 8);
 547  		size_t extraSize = m_MaxPayloadSize - lastFragmentSize;
 548  		bool ackBlockSent = false;
 549  		uint32_t msgID;
 550  		memcpy (&msgID, msg->GetHeader () + I2NP_HEADER_MSGID_OFFSET, 4);
 551  		auto ts = i2p::util::GetMillisecondsSinceEpoch ();
 552  		auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
 553  		if (extraSize >= 8)
 554  		{
 555  			packet->payloadSize = CreateAckBlock (packet->payload, extraSize);
 556  			ackBlockSent = true;
 557  			if (packet->payloadSize + 12 < m_MaxPayloadSize)
 558  			{
 559  				uint32_t packetNum = SendData (packet->payload, packet->payloadSize);
 560  				packet->sendTime = ts;
 561  				m_SentPackets.emplace (packetNum, packet);
 562  				packet = m_Server.GetSentPacketsPool ().AcquireShared ();
 563  			}
 564  			else
 565  				extraSize -= packet->payloadSize;
 566  		}
 567  		size_t offset = extraSize > 0 ? (m_Server.GetRng ()() % extraSize) : 0;
 568  		if (offset + packet->payloadSize >= m_MaxPayloadSize) offset = 0;
 569  		auto size = CreateFirstFragmentBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - offset - packet->payloadSize, msg);
 570  		if (!size) return false;
 571  		extraSize -= offset;
 572  		packet->payloadSize += size;
 573  		uint32_t firstPacketNum = SendData (packet->payload, packet->payloadSize);
 574  		packet->sendTime = ts;
 575  		m_SentPackets.emplace (firstPacketNum, packet);
 576  		uint8_t fragmentNum = 0;
 577  		while (msg->offset < msg->len)
 578  		{
 579  			offset = extraSize > 0 ? (m_Server.GetRng ()() % extraSize) : 0;
 580  			packet = m_Server.GetSentPacketsPool ().AcquireShared ();
 581  			packet->payloadSize = CreateFollowOnFragmentBlock (packet->payload, m_MaxPayloadSize - offset, msg, fragmentNum, msgID);
 582  			extraSize -= offset;
 583  			uint8_t flags = 0;
 584  			if (msg->offset >= msg->len && packet->payloadSize + 16 < m_MaxPayloadSize) // last fragment
 585  			{
 586  				packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
 587  				if (fragmentNum > 2) // 3 or more fragments
 588  					flags |= SSU2_FLAG_IMMEDIATE_ACK_REQUESTED;
 589  			}
 590  			uint32_t followonPacketNum = SendData (packet->payload, packet->payloadSize, flags);
 591  			packet->sendTime = ts;
 592  			m_SentPackets.emplace (followonPacketNum, packet);
 593  		}
 594  		return ackBlockSent;
 595  	}
 596  
 597  	size_t SSU2Session::Resend (uint64_t ts)
 598  	{
 599  		if (ts + SSU2_RESEND_ATTEMPT_MIN_INTERVAL < m_LastResendAttemptTime) return 0;
 600  		m_LastResendAttemptTime = ts;
 601  		// resend handshake packet
 602  		if (m_SentHandshakePacket && ts >= m_SentHandshakePacket->sendTime + SSU2_HANDSHAKE_RESEND_INTERVAL)
 603  		{
 604  			LogPrint (eLogDebug, "SSU2: Resending ", (int)m_State);
 605  			ResendHandshakePacket ();
 606  			m_SentHandshakePacket->sendTime = ts;
 607  			return 0;
 608  		}
 609  		// resend data packets
 610  		if (m_SentPackets.empty ()) return 0;
 611  		std::map<uint32_t, std::shared_ptr<SSU2SentPacket> > resentPackets;
 612  		for (auto it = m_SentPackets.begin (); it != m_SentPackets.end (); )
 613  			if (ts >= it->second->sendTime + (it->second->numResends + 1) * m_RTO)
 614  			{
 615  				if (it->second->numResends > SSU2_MAX_NUM_RESENDS)
 616  				{
 617  					LogPrint (eLogInfo, "SSU2: Packet was not Acked after ", it->second->numResends, " attempts. Terminate session");
 618  					m_SentPackets.clear ();
 619  					m_SendQueue.clear ();
 620  					SetSendQueueSize (0);
 621  					RequestTermination (eSSU2TerminationReasonTimeout);
 622  					return resentPackets.size ();
 623  				}
 624  				else
 625  				{
 626  					uint32_t packetNum = SendData (it->second->payload, it->second->payloadSize,
 627  						it->second->numResends > 1 ? SSU2_FLAG_IMMEDIATE_ACK_REQUESTED : 0);
 628  					it->second->numResends++;
 629  					it->second->sendTime = ts;
 630  					resentPackets.emplace (packetNum, it->second);
 631  					it = m_SentPackets.erase (it);
 632  				}
 633  			}
 634  			else
 635  				it++;
 636  		if (!resentPackets.empty ())
 637  		{
 638  			m_LastResendTime = ts;
 639  			m_SentPackets.merge (resentPackets);
 640  			m_WindowSize >>= 1; // /2
 641  			if (m_WindowSize < SSU2_MIN_WINDOW_SIZE) m_WindowSize = SSU2_MIN_WINDOW_SIZE;
 642  			return resentPackets.size ();
 643  		}
 644  		return 0;
 645  	}
 646  
 647  	void SSU2Session::ResendHandshakePacket ()
 648  	{
 649  		if (m_SentHandshakePacket)
 650  		{
 651  			m_Server.Send (m_SentHandshakePacket->header.buf, 16, m_SentHandshakePacket->headerX, 48,
 652  				m_SentHandshakePacket->payload, m_SentHandshakePacket->payloadSize, m_RemoteEndpoint);
 653  			if (m_SessionConfirmedFragment && m_State == eSSU2SessionStateSessionConfirmedSent)
 654  				// resend second fragment of SessionConfirmed
 655  				m_Server.Send (m_SessionConfirmedFragment->header.buf, 16,
 656  					m_SessionConfirmedFragment->payload, m_SessionConfirmedFragment->payloadSize, m_RemoteEndpoint);
 657  		}
 658  	}
 659  
 660  	bool SSU2Session::ProcessFirstIncomingMessage (uint64_t connID, uint8_t * buf, size_t len)
 661  	{
 662  		// we are Bob
 663  		m_SourceConnID = connID;
 664  		Header header;
 665  		header.h.connID = connID;
 666  		memcpy (header.buf + 8, buf + 8, 8);
 667  		header.ll[1] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 12));
 668  		switch (header.h.type)
 669  		{
 670  			case eSSU2SessionRequest:
 671  				ProcessSessionRequest (header, buf, len);
 672  			break;
 673  			case eSSU2TokenRequest:
 674  				ProcessTokenRequest (header, buf, len);
 675  			break;
 676  			case eSSU2PeerTest:
 677  			{
 678  				// TODO: remove later
 679  				if (len < 32)
 680  				{
 681  					LogPrint (eLogWarning, "SSU2: PeerTest message too short ", len);
 682  					break;
 683  				}
 684  				const uint8_t nonce[12] = {0};
 685  				uint64_t headerX[2];
 686  				m_Server.ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX);
 687  				LogPrint (eLogWarning, "SSU2: Unexpected PeerTest message SourceConnID=", connID, " DestConnID=", headerX[0]);
 688  				break;
 689  			}
 690  			case eSSU2HolePunch:
 691  				LogPrint (eLogDebug, "SSU2: Late HolePunch for ", connID);
 692  			break;
 693  			default:
 694  			{
 695  				LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " from ", m_RemoteEndpoint, " of ", len, " bytes");
 696  				return false;
 697  			}
 698  		}
 699  		return true;
 700  	}
 701  
 702  	void SSU2Session::SendSessionRequest (uint64_t token)
 703  	{
 704  		// we are Alice
 705  		m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair ();
 706  		m_SentHandshakePacket.reset (new HandshakePacket);
 707  		auto ts = i2p::util::GetMillisecondsSinceEpoch ();
 708  		m_SentHandshakePacket->sendTime = ts;
 709  
 710  		Header& header = m_SentHandshakePacket->header;
 711  		uint8_t * headerX = m_SentHandshakePacket->headerX,
 712  				* payload = m_SentHandshakePacket->payload;
 713  		// fill packet
 714  		header.h.connID = m_DestConnID; // dest id
 715  		RAND_bytes (header.buf + 8, 4); // random packet num
 716  		header.h.type = eSSU2SessionRequest;
 717  		header.h.flags[0] = 2; // ver
 718  		header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID
 719  		header.h.flags[2] = 0; // flag
 720  		memcpy (headerX, &m_SourceConnID, 8); // source id
 721  		memcpy (headerX + 8, &token, 8); // token
 722  		memcpy (headerX + 16, m_EphemeralKeys->GetPublicKey (), 32); // X
 723  		// payload
 724  		payload[0] = eSSU2BlkDateTime;
 725  		htobe16buf (payload + 1, 4);
 726  		htobe32buf (payload + 3, (ts + 500)/1000);
 727  		size_t payloadSize = 7;
 728  		if (GetRouterStatus () == eRouterStatusFirewalled && m_Address->IsIntroducer ())
 729  		{
 730  			if (!m_Server.IsMaxNumIntroducers (m_RemoteEndpoint.address ().is_v4 ()) ||
 731  			    m_Server.GetRng ()() & 0x01) // request tag with probability 1/2 if we have enough introducers
 732  			{
 733  				// relay tag request
 734  				payload[payloadSize] = eSSU2BlkRelayTagRequest;
 735  				memset (payload + payloadSize + 1, 0, 2); // size = 0
 736  				payloadSize += 3;
 737  			}
 738  		}
 739  		payloadSize += CreatePaddingBlock (payload + payloadSize, 40 - payloadSize, 1);
 740  		// KDF for session request
 741  		m_NoiseState->MixHash ({ {header.buf, 16}, {headerX, 16} }); // h = SHA256(h || header)
 742  		m_NoiseState->MixHash (m_EphemeralKeys->GetPublicKey (), 32); // h = SHA256(h || aepk);
 743  		uint8_t sharedSecret[32];
 744  		m_EphemeralKeys->Agree (m_Address->s, sharedSecret);
 745  		m_NoiseState->MixKey (sharedSecret);
 746  		// encrypt
 747  		const uint8_t nonce[12] = {0}; // always 0
 748  		i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true);
 749  		payloadSize += 16;
 750  		header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 24));
 751  		header.ll[1] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 12));
 752  		m_Server.ChaCha20 (headerX, 48, m_Address->i, nonce, headerX);
 753  		m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || encrypted payload from Session Request) for SessionCreated
 754  		m_SentHandshakePacket->payloadSize = payloadSize;
 755  		// send
 756  		if (m_State == eSSU2SessionStateTokenReceived || m_Server.AddPendingOutgoingSession (shared_from_this ()))
 757  		{
 758  			m_State = eSSU2SessionStateSessionRequestSent;
 759  			m_HandshakeInterval = ts;
 760  			m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint);
 761  		}
 762  		else
 763  		{
 764  			LogPrint (eLogWarning, "SSU2: SessionRequest request to ", m_RemoteEndpoint, " already pending");
 765  			Terminate ();
 766  		}
 767  	}
 768  
 769  	void SSU2Session::ProcessSessionRequest (Header& header, uint8_t * buf, size_t len)
 770  	{
 771  		// we are Bob
 772  		if (len < 88)
 773  		{
 774  			LogPrint (eLogWarning, "SSU2: SessionRequest message too short ", len);
 775  			return;
 776  		}
 777  		if (header.h.flags[0] != 2) // ver
 778  		{
 779              LogPrint (eLogInfo, "SSU2: SessionRequest protocol version ", header.h.flags[0], " is not supported");
 780              return;
 781  		}
 782  		const uint8_t nonce[12] = {0};
 783  		uint8_t headerX[48];
 784  		m_Server.ChaCha20 (buf + 16, 48, i2p::context.GetSSU2IntroKey (), nonce, headerX);
 785  		memcpy (&m_DestConnID, headerX, 8);
 786  		uint64_t token;
 787  		memcpy (&token, headerX + 8, 8);
 788  		if (!token || token != m_Server.GetIncomingToken (m_RemoteEndpoint))
 789  		{
 790  			LogPrint (eLogDebug, "SSU2: SessionRequest token mismatch. Retry");
 791  			SendRetry ();
 792  			return;
 793  		}
 794  		// KDF for session request
 795  		m_NoiseState->MixHash ( { {header.buf, 16}, {headerX, 16} } ); // h = SHA256(h || header)
 796  		m_NoiseState->MixHash (headerX + 16, 32); // h = SHA256(h || aepk);
 797  		uint8_t sharedSecret[32];
 798  		i2p::context.GetSSU2StaticKeys ().Agree (headerX + 16, sharedSecret);
 799  		m_NoiseState->MixKey (sharedSecret);
 800  		// decrypt
 801  		uint8_t * payload = buf + 64;
 802  		std::vector<uint8_t> decryptedPayload(len - 80);
 803  		if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 80, m_NoiseState->m_H, 32,
 804  			m_NoiseState->m_CK + 32, nonce, decryptedPayload.data (), decryptedPayload.size (), false))
 805  		{
 806  			LogPrint (eLogWarning, "SSU2: SessionRequest AEAD verification failed ");
 807  			return;
 808  		}
 809  		m_NoiseState->MixHash (payload, len - 64); // h = SHA256(h || encrypted payload from Session Request) for SessionCreated
 810  		// payload
 811  		m_State = eSSU2SessionStateSessionRequestReceived;
 812  		HandlePayload (decryptedPayload.data (), decryptedPayload.size ());
 813  
 814  		if (m_TerminationReason == eSSU2TerminationReasonNormalClose)
 815  		{
 816  			m_Server.AddSession (shared_from_this ());
 817  			SendSessionCreated (headerX + 16);
 818  		}
 819  		else
 820  			SendRetry ();
 821  	}
 822  
 823  	void SSU2Session::SendSessionCreated (const uint8_t * X)
 824  	{
 825  		// we are Bob
 826  		m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair ();
 827  		m_SentHandshakePacket.reset (new HandshakePacket);
 828  		auto ts = i2p::util::GetMillisecondsSinceEpoch ();
 829  		m_SentHandshakePacket->sendTime = ts;
 830  
 831  		uint8_t kh2[32];
 832  		i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "SessCreateHeader", kh2, 32); // k_header_2 = HKDF(chainKey, ZEROLEN, "SessCreateHeader", 32)
 833  		// fill packet
 834  		Header& header = m_SentHandshakePacket->header;
 835  		uint8_t * headerX = m_SentHandshakePacket->headerX,
 836  				* payload = m_SentHandshakePacket->payload;
 837  		header.h.connID = m_DestConnID; // dest id
 838  		RAND_bytes (header.buf + 8, 4); // random packet num
 839  		header.h.type = eSSU2SessionCreated;
 840  		header.h.flags[0] = 2; // ver
 841  		header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID
 842  		header.h.flags[2] = 0; // flag
 843  		memcpy (headerX, &m_SourceConnID, 8); // source id
 844  		memset (headerX + 8, 0, 8); // token = 0
 845  		memcpy (headerX + 16, m_EphemeralKeys->GetPublicKey (), 32); // Y
 846  		// payload
 847  		size_t maxPayloadSize = m_MaxPayloadSize - 48;
 848  		payload[0] = eSSU2BlkDateTime;
 849  		htobe16buf (payload + 1, 4);
 850  		htobe32buf (payload + 3, (ts + 500)/1000);
 851  		size_t payloadSize = 7;
 852  		payloadSize += CreateAddressBlock (payload + payloadSize, maxPayloadSize - payloadSize, m_RemoteEndpoint);
 853  		if (m_RelayTag)
 854  		{
 855  			payload[payloadSize] = eSSU2BlkRelayTag;
 856  			htobe16buf (payload + payloadSize + 1, 4);
 857  			htobe32buf (payload + payloadSize + 3, m_RelayTag);
 858  			payloadSize += 7;
 859  		}
 860  		auto token = m_Server.NewIncomingToken (m_RemoteEndpoint);
 861  		if (ts + SSU2_TOKEN_EXPIRATION_THRESHOLD > token.second) // not expired?
 862  		{
 863  			payload[payloadSize] = eSSU2BlkNewToken;
 864  			htobe16buf (payload + payloadSize + 1, 12);
 865  			htobe32buf (payload + payloadSize + 3, token.second - SSU2_TOKEN_EXPIRATION_THRESHOLD); // expires
 866  			memcpy (payload + payloadSize + 7, &token.first, 8); // token
 867  			payloadSize += 15;
 868  		}
 869  		payloadSize += CreatePaddingBlock (payload + payloadSize, maxPayloadSize - payloadSize);
 870  		// KDF for SessionCreated
 871  		m_NoiseState->MixHash ( { {header.buf, 16}, {headerX, 16} } ); // h = SHA256(h || header)
 872  		m_NoiseState->MixHash (headerX + 16, 32); // h = SHA256(h || bepk);
 873  		uint8_t sharedSecret[32];
 874  		m_EphemeralKeys->Agree (X, sharedSecret);
 875  		m_NoiseState->MixKey (sharedSecret);
 876  		// encrypt
 877  		const uint8_t nonce[12] = {0}; // always zero
 878  		i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true);
 879  		payloadSize += 16;
 880  		m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || encrypted Noise payload from Session Created)
 881  		header.ll[0] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), payload + (payloadSize - 24));
 882  		header.ll[1] ^= CreateHeaderMask (kh2, payload + (payloadSize - 12));
 883  		m_Server.ChaCha20 (headerX, 48, kh2, nonce, headerX);
 884  		m_State = eSSU2SessionStateSessionCreatedSent;
 885  		m_SentHandshakePacket->payloadSize = payloadSize;
 886  		// send
 887  		m_HandshakeInterval = ts;
 888  		m_Server.Send (header.buf, 16, headerX, 48, payload, payloadSize, m_RemoteEndpoint);
 889  	}
 890  
 891  	bool SSU2Session::ProcessSessionCreated (uint8_t * buf, size_t len)
 892  	{
 893  		// we are Alice
 894  		Header header;
 895  		memcpy (header.buf, buf, 16);
 896  		header.ll[0] ^= CreateHeaderMask (m_Address->i, buf + (len - 24));
 897  		uint8_t kh2[32];
 898  		i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "SessCreateHeader", kh2, 32); // k_header_2 = HKDF(chainKey, ZEROLEN, "SessCreateHeader", 32)
 899  		header.ll[1] ^= CreateHeaderMask (kh2, buf + (len - 12));
 900  		if (header.h.type != eSSU2SessionCreated)
 901  		// this situation is valid, because it might be Retry with different encryption
 902  			return false;
 903  		if (len < 80)
 904  		{
 905  			LogPrint (eLogWarning, "SSU2: SessionCreated message too short ", len);
 906  			return false;
 907  		}
 908  		m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval;
 909  		const uint8_t nonce[12] = {0};
 910  		uint8_t headerX[48];
 911  		m_Server.ChaCha20 (buf + 16, 48, kh2, nonce, headerX);
 912  		// KDF for SessionCreated
 913  		m_NoiseState->MixHash ( { {header.buf, 16}, {headerX, 16} } ); // h = SHA256(h || header)
 914  		m_NoiseState->MixHash (headerX + 16, 32); // h = SHA256(h || bepk);
 915  		uint8_t sharedSecret[32];
 916  		m_EphemeralKeys->Agree (headerX + 16, sharedSecret);
 917  		m_NoiseState->MixKey (sharedSecret);
 918  		// decrypt
 919  		uint8_t * payload = buf + 64;
 920  		std::vector<uint8_t> decryptedPayload(len - 80);
 921  		if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 80, m_NoiseState->m_H, 32,
 922  			m_NoiseState->m_CK + 32, nonce, decryptedPayload.data (), decryptedPayload.size (), false))
 923  		{
 924  			LogPrint (eLogWarning, "SSU2: SessionCreated AEAD verification failed ");
 925  			if (GetRemoteIdentity ())
 926  				i2p::data::netdb.SetUnreachable (GetRemoteIdentity ()->GetIdentHash (), true);  // assume wrong s key
 927  			return false;
 928  		}
 929  		m_NoiseState->MixHash (payload, len - 64); // h = SHA256(h || encrypted payload from SessionCreated) for SessionConfirmed
 930  		// payload
 931  		m_State = eSSU2SessionStateSessionCreatedReceived;
 932  		HandlePayload (decryptedPayload.data (), decryptedPayload.size ());
 933  
 934  		m_Server.AddSession (shared_from_this ());
 935  		AdjustMaxPayloadSize ();
 936  		SendSessionConfirmed (headerX + 16);
 937  		KDFDataPhase (m_KeyDataSend, m_KeyDataReceive);
 938  
 939  		return true;
 940  	}
 941  
 942  	void SSU2Session::SendSessionConfirmed (const uint8_t * Y)
 943  	{
 944  		// we are Alice
 945  		m_SentHandshakePacket.reset (new HandshakePacket);
 946  		m_SentHandshakePacket->sendTime = i2p::util::GetMillisecondsSinceEpoch ();
 947  
 948  		uint8_t kh2[32];
 949  		i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "SessionConfirmed", kh2, 32); // k_header_2 = HKDF(chainKey, ZEROLEN, "SessionConfirmed", 32)
 950  		// fill packet
 951  		Header& header = m_SentHandshakePacket->header;
 952  		header.h.connID = m_DestConnID; // dest id
 953  		header.h.packetNum = 0; // always zero
 954  		header.h.type = eSSU2SessionConfirmed;
 955  		memset (header.h.flags, 0, 3);
 956  		header.h.flags[0] = 1; // frag, total fragments always 1
 957  		// payload
 958  		size_t maxPayloadSize = m_MaxPayloadSize - 48; // for part 2, 48 is part1
 959  		uint8_t * payload = m_SentHandshakePacket->payload;
 960  		size_t payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.CopyRouterInfoBuffer ());
 961  		if (!payloadSize)
 962  		{
 963  			// split by two fragments
 964  			maxPayloadSize += m_MaxPayloadSize;
 965  			payloadSize = CreateRouterInfoBlock (payload, maxPayloadSize, i2p::context.CopyRouterInfoBuffer ());
 966  			header.h.flags[0] = 0x02; // frag 0, total fragments 2
 967  			// TODO: check if we need more fragments
 968  		}
 969  		if (payloadSize < maxPayloadSize)
 970  			payloadSize += CreatePaddingBlock (payload + payloadSize, maxPayloadSize - payloadSize);
 971  		// KDF for Session Confirmed part 1
 972  		m_NoiseState->MixHash (header.buf, 16); // h = SHA256(h || header)
 973  		// Encrypt part 1
 974  		uint8_t * part1 = m_SentHandshakePacket->headerX;
 975  		uint8_t nonce[12];
 976  		CreateNonce (1, nonce); // always one
 977  		i2p::crypto::AEADChaCha20Poly1305 (i2p::context.GetSSU2StaticPublicKey (), 32, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, part1, 48, true);
 978  		m_NoiseState->MixHash (part1, 48); // h = SHA256(h || ciphertext);
 979  		// KDF for Session Confirmed part 2
 980  		uint8_t sharedSecret[32];
 981  		i2p::context.GetSSU2StaticKeys ().Agree (Y, sharedSecret);
 982  		m_NoiseState->MixKey (sharedSecret);
 983  		// Encrypt part2
 984  		memset (nonce, 0, 12); // always zero
 985  		i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, m_NoiseState->m_H, 32, m_NoiseState->m_CK + 32, nonce, payload, payloadSize + 16, true);
 986  		payloadSize += 16;
 987  		m_NoiseState->MixHash (payload, payloadSize); // h = SHA256(h || ciphertext);
 988  		m_SentHandshakePacket->payloadSize = payloadSize;
 989  		if (header.h.flags[0] > 1)
 990  		{
 991  			if (payloadSize > m_MaxPayloadSize - 48)
 992  			{
 993  				payloadSize = m_MaxPayloadSize - 48 - (m_Server.GetRng ()() % 16);
 994  				if (m_SentHandshakePacket->payloadSize - payloadSize < 24)
 995  					payloadSize -= 24;
 996  			}
 997  			else
 998  				header.h.flags[0] = 1;
 999  		}
1000  		// Encrypt header
1001  		header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 24));
1002  		header.ll[1] ^= CreateHeaderMask (kh2, payload + (payloadSize - 12));
1003  		m_State = eSSU2SessionStateSessionConfirmedSent;
1004  		// send
1005  		m_Server.Send (header.buf, 16, part1, 48, payload, payloadSize, m_RemoteEndpoint);
1006  		m_SendPacketNum++;
1007  		if (m_SentHandshakePacket->payloadSize > payloadSize)
1008  		{
1009  			// send second fragment
1010  			m_SessionConfirmedFragment.reset (new HandshakePacket);
1011  			Header& header = m_SessionConfirmedFragment->header;
1012  			header.h.connID = m_DestConnID; // dest id
1013  			header.h.packetNum = 0;
1014  			header.h.type = eSSU2SessionConfirmed;
1015  			memset (header.h.flags, 0, 3);
1016  			header.h.flags[0] = 0x12; // frag 1, total fragments 2
1017  			m_SessionConfirmedFragment->payloadSize = m_SentHandshakePacket->payloadSize - payloadSize;
1018  			memcpy (m_SessionConfirmedFragment->payload, m_SentHandshakePacket->payload + payloadSize, m_SessionConfirmedFragment->payloadSize);
1019  			m_SentHandshakePacket->payloadSize = payloadSize;
1020  			header.ll[0] ^= CreateHeaderMask (m_Address->i, m_SessionConfirmedFragment->payload + (m_SessionConfirmedFragment->payloadSize - 24));
1021  			header.ll[1] ^= CreateHeaderMask (kh2, m_SessionConfirmedFragment->payload + (m_SessionConfirmedFragment->payloadSize - 12));
1022  			m_Server.Send (header.buf, 16, m_SessionConfirmedFragment->payload, m_SessionConfirmedFragment->payloadSize, m_RemoteEndpoint);
1023  		}
1024  	}
1025  
1026  	bool SSU2Session::ProcessSessionConfirmed (uint8_t * buf, size_t len)
1027  	{
1028  		// we are Bob
1029  		Header header;
1030  		memcpy (header.buf, buf, 16);
1031  		header.ll[0] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 24));
1032  		uint8_t kh2[32];
1033  		i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "SessionConfirmed", kh2, 32); // k_header_2 = HKDF(chainKey, ZEROLEN, "SessionConfirmed", 32)
1034  		header.ll[1] ^= CreateHeaderMask (kh2, buf + (len - 12));
1035  		if (header.h.type != eSSU2SessionConfirmed)
1036  		{
1037  			LogPrint (eLogInfo, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2SessionConfirmed);
1038  			// TODO: queue up
1039  			return true;
1040  		}
1041  		// packet num must be always zero
1042  		if (header.h.packetNum)
1043  		{
1044  			LogPrint (eLogError, "SSU2: Non zero packet number in SessionConfirmed");
1045  			return false;
1046  		}
1047  		// check if fragmented
1048  		uint8_t numFragments = header.h.flags[0] & 0x0F;
1049  		if (numFragments > 1)
1050  		{
1051  			// fragmented
1052  			if (numFragments > 2)
1053  			{
1054  				LogPrint (eLogError, "SSU2: Too many fragments ", (int)numFragments, " in SessionConfirmed from ", m_RemoteEndpoint);
1055  				return false;
1056  			}
1057  			if (len < 32)
1058  			{
1059  				LogPrint (eLogWarning, "SSU2: SessionConfirmed fragment too short ", len);
1060  				if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr);
1061  				return false;
1062  			}
1063  			if (!(header.h.flags[0] & 0xF0))
1064  			{
1065  				// first fragment
1066  				if (!m_SessionConfirmedFragment)
1067  				{
1068  					m_SessionConfirmedFragment.reset (new HandshakePacket);
1069  					m_SessionConfirmedFragment->header = header;
1070  					memcpy (m_SessionConfirmedFragment->payload, buf + 16, len - 16);
1071  					m_SessionConfirmedFragment->payloadSize = len - 16;
1072  					return true; // wait for second fragment
1073  				}
1074  				else if (m_SessionConfirmedFragment->isSecondFragment)
1075  				{
1076  					// we have second fragment
1077  					m_SessionConfirmedFragment->header = header;
1078  					memmove (m_SessionConfirmedFragment->payload + (len - 16), m_SessionConfirmedFragment->payload, m_SessionConfirmedFragment->payloadSize);
1079  					memcpy (m_SessionConfirmedFragment->payload, buf + 16, len - 16);
1080  					m_SessionConfirmedFragment->payloadSize += (len - 16);
1081  					m_SessionConfirmedFragment->isSecondFragment = false;
1082  					buf = m_SessionConfirmedFragment->payload - 16;
1083  					len = m_SessionConfirmedFragment->payloadSize + 16;
1084  				}
1085  				else
1086  					return true;
1087  			}
1088  			else
1089  			{
1090  				// second fragment
1091  				if (!m_SessionConfirmedFragment)
1092  				{
1093  					// out of sequence, save it
1094  					m_SessionConfirmedFragment.reset (new HandshakePacket);
1095  					memcpy (m_SessionConfirmedFragment->payload, buf + 16, len - 16);
1096  					m_SessionConfirmedFragment->payloadSize = len - 16;
1097  					m_SessionConfirmedFragment->isSecondFragment = true;
1098  					return true;
1099  				}
1100  				header = m_SessionConfirmedFragment->header;
1101  				if (m_SessionConfirmedFragment->payloadSize + (len - 16) <= SSU2_MAX_PACKET_SIZE*2)
1102  				{
1103  					memcpy (m_SessionConfirmedFragment->payload + m_SessionConfirmedFragment->payloadSize, buf + 16, len - 16);
1104  					m_SessionConfirmedFragment->payloadSize += (len - 16);
1105  				}
1106  				buf = m_SessionConfirmedFragment->payload - 16;
1107  				len = m_SessionConfirmedFragment->payloadSize + 16;
1108  			}
1109  		}
1110  		if (len < 80)
1111  		{
1112  			LogPrint (eLogWarning, "SSU2: SessionConfirmed message too short ", len);
1113  			if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr);
1114  			return false;
1115  		}
1116  		m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval;
1117  		// KDF for Session Confirmed part 1
1118  		m_NoiseState->MixHash (header.buf, 16); // h = SHA256(h || header)
1119  		// decrypt part1
1120  		uint8_t nonce[12];
1121  		CreateNonce (1, nonce);
1122  		uint8_t S[32];
1123  		if (!i2p::crypto::AEADChaCha20Poly1305 (buf + 16, 32, m_NoiseState->m_H, 32,
1124  			m_NoiseState->m_CK + 32, nonce, S, 32, false))
1125  		{
1126  			LogPrint (eLogWarning, "SSU2: SessionConfirmed part 1 AEAD verification failed ");
1127  			if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr);
1128  			return false;
1129  		}
1130  		m_NoiseState->MixHash (buf + 16, 48); // h = SHA256(h || ciphertext);
1131  		// KDF for Session Confirmed part 2 and data phase
1132  		uint8_t sharedSecret[32];
1133  		m_EphemeralKeys->Agree (S, sharedSecret);
1134  		m_NoiseState->MixKey (sharedSecret);
1135  		KDFDataPhase (m_KeyDataReceive, m_KeyDataSend);
1136  		// decrypt part2
1137  		memset (nonce, 0, 12);
1138  		uint8_t * payload = buf + 64;
1139  		std::vector<uint8_t> decryptedPayload(len - 80);
1140  		if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 80, m_NoiseState->m_H, 32,
1141  			m_NoiseState->m_CK + 32, nonce, decryptedPayload.data (), decryptedPayload.size (), false))
1142  		{
1143  			LogPrint (eLogWarning, "SSU2: SessionConfirmed part 2 AEAD verification failed ");
1144  			if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr);
1145  			return false;
1146  		}
1147  		m_NoiseState->MixHash (payload, len - 64); // h = SHA256(h || ciphertext);
1148  		if (m_SessionConfirmedFragment) m_SessionConfirmedFragment.reset (nullptr);
1149  		// payload
1150  		// handle RouterInfo block that must be first
1151  		if (decryptedPayload[0] != eSSU2BlkRouterInfo)
1152  		{
1153  			LogPrint (eLogError, "SSU2: SessionConfirmed unexpected first block type ", (int)decryptedPayload[0]);
1154  			return false;
1155  		}
1156  		size_t riSize = bufbe16toh (decryptedPayload.data () + 1);
1157  		if (riSize + 3 > decryptedPayload.size ())
1158  		{
1159  			LogPrint (eLogError, "SSU2: SessionConfirmed RouterInfo block is too long ", riSize);
1160  			return false;
1161  		}
1162  		LogPrint (eLogDebug, "SSU2: RouterInfo in SessionConfirmed");
1163  		auto ri = ExtractRouterInfo (decryptedPayload.data () + 3, riSize);
1164  		if (!ri)
1165  		{
1166  			LogPrint (eLogError, "SSU2: SessionConfirmed malformed RouterInfo block");
1167  			return false;
1168  		}
1169  		auto ts = i2p::util::GetMillisecondsSinceEpoch();
1170  		if (ts > ri->GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes
1171  		{
1172  			LogPrint (eLogError, "SSU2: RouterInfo in SessionConfirmed is too old for ", (ts - ri->GetTimestamp ())/1000LL, " seconds");
1173  			return false;
1174  		}
1175  		if (ts + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri->GetTimestamp ()) // 2 minutes
1176  		{
1177  			LogPrint (eLogError, "SSU2: RouterInfo in SessionConfirmed is from future for ", (ri->GetTimestamp () - ts)/1000LL, " seconds");
1178  			return false;
1179  		}
1180  		if (ri->GetVersion () < i2p::data::NETDB_MIN_ALLOWED_VERSION && !ri->IsHighBandwidth ())
1181  		{
1182  			LogPrint (eLogInfo, "SSU2: Router version ", ri->GetVersion (), " is too old in SessionConfirmed");
1183  			return false;
1184  		}
1185  		// update RouterInfo in netdb
1186  		auto ri1 = i2p::data::netdb.AddRouterInfo (ri->GetBuffer (), ri->GetBufferLen ()); // ri points to one from netdb now
1187  		if (!ri1)
1188  		{
1189  			LogPrint (eLogError, "SSU2: Couldn't update RouterInfo from SessionConfirmed in netdb");
1190  			return false;
1191  		}
1192  
1193  		bool isOlder = false;
1194  		if (ri->GetTimestamp () + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri1->GetTimestamp ())
1195  		{
1196  			// received RouterInfo is older than one in netdb
1197  			isOlder = true;
1198  			if (ri->HasProfile ())
1199  			{
1200  				auto profile = i2p::data::GetRouterProfile (ri->GetIdentHash ()); // retrieve profile
1201  				if (profile && profile->IsDuplicated ())
1202  					return false;
1203  			}
1204  		}
1205  		ri = ri1;
1206  
1207  		m_Address = m_RemoteEndpoint.address ().is_v6 () ? ri->GetSSU2V6Address () : ri->GetSSU2V4Address ();
1208  		if (!m_Address)
1209  		{
1210  			LogPrint (eLogError, "SSU2: Address not found in SessionConfirmed from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
1211  			return false;
1212  		}
1213  		if (m_Address->published && m_RemoteEndpoint.address () != m_Address->host &&
1214  		    (!m_RemoteEndpoint.address ().is_v6 () ||
1215  			 memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), m_Address->host.to_v6 ().to_bytes ().data (), 8))) // temporary address
1216  		{
1217  			if (isOlder) // older router?
1218  				i2p::data::UpdateRouterProfile (ri->GetIdentHash (),
1219  					[](std::shared_ptr<i2p::data::RouterProfile> profile)
1220  					{
1221  						if (profile) profile->Duplicated (); // mark router as duplicated in profile
1222  					});
1223  			else
1224  				LogPrint (eLogInfo, "SSU2: Host mismatch between published address ", m_Address->host,
1225  					" and actual endpoint ", m_RemoteEndpoint.address (), " from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
1226  			return false;
1227  		}
1228  		if (memcmp (S, m_Address->s, 32))
1229  		{
1230  			LogPrint (eLogError, "SSU2: Wrong static key in SessionConfirmed from ", i2p::data::GetIdentHashAbbreviation (ri->GetIdentHash ()));
1231  			if (m_Address->published)
1232  				i2p::transport::transports.AddBan (m_RemoteEndpoint.address ());
1233  			return false;
1234  		}
1235  		if (!m_Address->published)
1236  		{
1237  			if (ri->HasProfile ())
1238  				ri->GetProfile ()->SetLastEndpoint (m_RemoteEndpoint);
1239  			else
1240  				i2p::data::UpdateRouterProfile (ri->GetIdentHash (),
1241  					[ep = m_RemoteEndpoint](std::shared_ptr<i2p::data::RouterProfile> profile)
1242  				    {
1243  						if (profile) profile->SetLastEndpoint (ep);
1244  					});
1245  		}
1246  		SetRemoteIdentity (ri->GetRouterIdentity ());
1247  		AdjustMaxPayloadSize ();
1248  		m_Server.AddSessionByRouterHash (shared_from_this ()); // we know remote router now
1249  		m_RemoteTransports = ri->GetCompatibleTransports (false);
1250  		m_RemotePeerTestTransports = 0;
1251  		if (ri->IsSSU2PeerTesting (true)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V4;
1252  		if (ri->IsSSU2PeerTesting (false)) m_RemotePeerTestTransports |= i2p::data::RouterInfo::eSSU2V6;
1253  		m_RemoteVersion = ri->GetVersion ();
1254  
1255  		// handle other blocks
1256  		HandlePayload (decryptedPayload.data () + riSize + 3, decryptedPayload.size () - riSize - 3);
1257  
1258  		Established ();
1259  		if (ri->GetCongestion () == i2p::data::RouterInfo::eRejectAll)
1260  		{
1261  			auto terminationTimeout = GetTerminationTimeout ()/2;
1262  			if (terminationTimeout < SSU2_CONNECT_TIMEOUT) terminationTimeout = SSU2_CONNECT_TIMEOUT;
1263  			SetTerminationTimeout (terminationTimeout);
1264  		}
1265  		SendQuickAck ();
1266  
1267  		return true;
1268  	}
1269  
1270  	void SSU2Session::KDFDataPhase (uint8_t * keydata_ab, uint8_t * keydata_ba)
1271  	{
1272  		uint8_t keydata[64];
1273  		i2p::crypto::HKDF (m_NoiseState->m_CK, nullptr, 0, "", keydata); // keydata = HKDF(chainKey, ZEROLEN, "", 64)
1274  		// ab
1275  		i2p::crypto::HKDF (keydata, nullptr, 0, "HKDFSSU2DataKeys", keydata_ab); // keydata_ab = HKDF(keydata, ZEROLEN, "HKDFSSU2DataKeys", 64)
1276  		// ba
1277  		i2p::crypto::HKDF (keydata + 32, nullptr, 0, "HKDFSSU2DataKeys", keydata_ba); // keydata_ba = HKDF(keydata + 32, ZEROLEN, "HKDFSSU2DataKeys", 64)
1278  	}
1279  
1280  	void SSU2Session::SendTokenRequest ()
1281  	{
1282  		// we are Alice
1283  		Header header;
1284  		uint8_t h[32], payload[41];
1285  		// fill packet
1286  		header.h.connID = m_DestConnID; // dest id
1287  		RAND_bytes (header.buf + 8, 4); // random packet num
1288  		header.h.type = eSSU2TokenRequest;
1289  		header.h.flags[0] = 2; // ver
1290  		header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID
1291  		header.h.flags[2] = 0; // flag
1292  		memcpy (h, header.buf, 16);
1293  		memcpy (h + 16, &m_SourceConnID, 8); // source id
1294  		memset (h + 24, 0, 8); // zero token
1295  		// payload
1296  		payload[0] = eSSU2BlkDateTime;
1297  		htobe16buf (payload + 1, 4);
1298  		htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000);
1299  		size_t payloadSize = 7;
1300  		payloadSize += CreatePaddingBlock (payload + payloadSize, 25 - payloadSize, 1);
1301  		// encrypt
1302  		uint8_t nonce[12];
1303  		CreateNonce (be32toh (header.h.packetNum), nonce);
1304  		i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, h, 32, m_Address->i, nonce, payload, payloadSize + 16, true);
1305  		payloadSize += 16;
1306  		header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 24));
1307  		header.ll[1] ^= CreateHeaderMask (m_Address->i, payload + (payloadSize - 12));
1308  		memset (nonce, 0, 12);
1309  		m_Server.ChaCha20 (h + 16, 16, m_Address->i, nonce, h + 16);
1310  		// send
1311  		if (m_Server.AddPendingOutgoingSession (shared_from_this ()))
1312  			m_Server.Send (header.buf, 16, h + 16, 16, payload, payloadSize, m_RemoteEndpoint);
1313  		else
1314  		{
1315  			LogPrint (eLogWarning, "SSU2: TokenRequest request to ", m_RemoteEndpoint, " already pending");
1316  			Terminate ();
1317  		}
1318  	}
1319  
1320  	void SSU2Session::ProcessTokenRequest (Header& header, uint8_t * buf, size_t len)
1321  	{
1322  		// we are Bob
1323  		if (len < 48)
1324  		{
1325  			LogPrint (eLogWarning, "SSU2: Incorrect TokenRequest len ", len);
1326  			return;
1327  		}
1328  		uint8_t nonce[12] = {0};
1329  		uint8_t h[32];
1330  		memcpy (h, header.buf, 16);
1331  		m_Server.ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, h + 16);
1332  		memcpy (&m_DestConnID, h + 16, 8);
1333  		// decrypt
1334  		CreateNonce (be32toh (header.h.packetNum), nonce);
1335  		uint8_t * payload = buf + 32;
1336  		if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 48, h, 32,
1337  			i2p::context.GetSSU2IntroKey (), nonce, payload, len - 48, false))
1338  		{
1339  			LogPrint (eLogWarning, "SSU2: TokenRequest AEAD verification failed ");
1340  			return;
1341  		}
1342  		// payload
1343  		m_State = eSSU2SessionStateTokenRequestReceived;
1344  		HandlePayload (payload, len - 48);
1345  		SendRetry ();
1346  	}
1347  
1348  	void SSU2Session::SendRetry ()
1349  	{
1350  		// we are Bob
1351  		Header header;
1352  		uint8_t h[32], payload[72];
1353  		// fill packet
1354  		header.h.connID = m_DestConnID; // dest id
1355  		RAND_bytes (header.buf + 8, 4); // random packet num
1356  		header.h.type = eSSU2Retry;
1357  		header.h.flags[0] = 2; // ver
1358  		header.h.flags[1] = (uint8_t)i2p::context.GetNetID (); // netID
1359  		header.h.flags[2] = 0; // flag
1360  		memcpy (h, header.buf, 16);
1361  		memcpy (h + 16, &m_SourceConnID, 8); // source id
1362  		uint64_t token = 0;
1363  		if (m_TerminationReason == eSSU2TerminationReasonNormalClose)
1364  			token = m_Server.GetIncomingToken (m_RemoteEndpoint);
1365  		memcpy (h + 24, &token, 8); // token
1366  		// payload
1367  		payload[0] = eSSU2BlkDateTime;
1368  		htobe16buf (payload + 1, 4);
1369  		htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000);
1370  		size_t payloadSize = 7;
1371  		payloadSize += CreateAddressBlock (payload + payloadSize, 56 - payloadSize, m_RemoteEndpoint);
1372  		if (m_TerminationReason != eSSU2TerminationReasonNormalClose)
1373  			payloadSize += CreateTerminationBlock (payload + payloadSize, 56 - payloadSize);
1374  		payloadSize += CreatePaddingBlock (payload + payloadSize, 56 - payloadSize);
1375  		// encrypt
1376  		uint8_t nonce[12];
1377  		CreateNonce (be32toh (header.h.packetNum), nonce);
1378  		i2p::crypto::AEADChaCha20Poly1305 (payload, payloadSize, h, 32, i2p::context.GetSSU2IntroKey (), nonce, payload, payloadSize + 16, true);
1379  		payloadSize += 16;
1380  		header.ll[0] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), payload + (payloadSize - 24));
1381  		header.ll[1] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), payload + (payloadSize - 12));
1382  		memset (nonce, 0, 12);
1383  		m_Server.ChaCha20 (h + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, h + 16);
1384  		// send
1385  		m_Server.Send (header.buf, 16, h + 16, 16, payload, payloadSize, m_RemoteEndpoint);
1386  	}
1387  
1388  	bool SSU2Session::ProcessRetry (uint8_t * buf, size_t len)
1389  	{
1390  		// we are Alice
1391  		Header header;
1392  		memcpy (header.buf, buf, 16);
1393  		header.ll[0] ^= CreateHeaderMask (m_Address->i, buf + (len - 24));
1394  		header.ll[1] ^= CreateHeaderMask (m_Address->i, buf + (len - 12));
1395  		if (header.h.type != eSSU2Retry)
1396  		{
1397  			LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2Retry);
1398  			return false;
1399  		}
1400  		if (len < 48)
1401  		{
1402  			LogPrint (eLogWarning, "SSU2: Retry message too short ", len);
1403  			return false;
1404  		}
1405  		uint8_t nonce[12] = {0};
1406  		uint64_t headerX[2]; // sourceConnID, token
1407  		m_Server.ChaCha20 (buf + 16, 16, m_Address->i, nonce, (uint8_t *)headerX);
1408  		uint64_t token = headerX[1];
1409  		if (token)
1410  			m_Server.UpdateOutgoingToken (m_RemoteEndpoint, token, i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT);
1411  		// decrypt and handle payload
1412  		uint8_t * payload = buf + 32;
1413  		CreateNonce (be32toh (header.h.packetNum), nonce);
1414  		uint8_t h[32];
1415  		memcpy (h, header.buf, 16);
1416  		memcpy (h + 16, &headerX, 16);
1417  		if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 48, h, 32,
1418  			m_Address->i, nonce, payload, len - 48, false))
1419  		{
1420  			LogPrint (eLogWarning, "SSU2: Retry AEAD verification failed");
1421  			return false;
1422  		}
1423  		m_State = eSSU2SessionStateTokenReceived;
1424  		HandlePayload (payload, len - 48);
1425  		if (!token)
1426  		{
1427  			// we should handle payload even for zero token to handle Datetime block and adjust clock in case of clock skew
1428  			LogPrint (eLogWarning, "SSU2: Retry token is zero");
1429  			return false;
1430  		}
1431  		InitNoiseXKState1 (*m_NoiseState, m_Address->s); // reset Noise TODO: check state
1432  		SendSessionRequest (token);
1433  		return true;
1434  	}
1435  
1436  	bool SSU2Session::ProcessHolePunch (uint8_t * buf, size_t len)
1437  	{
1438  		// we are Alice
1439  		LogPrint (eLogDebug, "SSU2: HolePunch");
1440  		Header header;
1441  		memcpy (header.buf, buf, 16);
1442  		header.ll[0] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 24));
1443  		header.ll[1] ^= CreateHeaderMask (i2p::context.GetSSU2IntroKey (), buf + (len - 12));
1444  		if (header.h.type != eSSU2HolePunch)
1445  		{
1446  			LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2HolePunch);
1447  			return false;
1448  		}
1449  		if (len < 48)
1450  		{
1451  			LogPrint (eLogWarning, "SSU2: HolePunch message too short ", len);
1452  			return false;
1453  		}
1454  		uint8_t nonce[12] = {0};
1455  		uint64_t headerX[2]; // sourceConnID, token
1456  		m_Server.ChaCha20 (buf + 16, 16, i2p::context.GetSSU2IntroKey (), nonce, (uint8_t *)headerX);
1457  		m_DestConnID = headerX[0];
1458  		// decrypt and handle payload
1459  		uint8_t * payload = buf + 32;
1460  		CreateNonce (be32toh (header.h.packetNum), nonce);
1461  		uint8_t h[32];
1462  		memcpy (h, header.buf, 16);
1463  		memcpy (h + 16, &headerX, 16);
1464  		if (!i2p::crypto::AEADChaCha20Poly1305 (payload, len - 48, h, 32,
1465  			i2p::context.GetSSU2IntroKey (), nonce, payload, len - 48, false))
1466  		{
1467  			LogPrint (eLogWarning, "SSU2: HolePunch AEAD verification failed ");
1468  			return false;
1469  		}
1470  		HandlePayload (payload, len - 48);
1471  		m_IsDataReceived = false;
1472  		// connect to Charlie
1473  		ConnectAfterIntroduction ();
1474  
1475  		return true;
1476  	}
1477  
1478  	bool SSU2Session::ProcessPeerTest (uint8_t * buf, size_t len)
1479  	{
1480  		LogPrint (eLogWarning, "SSU2:  Unexpected peer test message for this session type");
1481  		return false;
1482  	}
1483  
1484  	uint32_t SSU2Session::SendData (const uint8_t * buf, size_t len, uint8_t flags)
1485  	{
1486  		if (len < 8)
1487  		{
1488  			LogPrint (eLogWarning, "SSU2: Data message payload is too short ", (int)len);
1489  			return 0;
1490  		}
1491  		Header header;
1492  		header.h.connID = m_DestConnID;
1493  		header.h.packetNum = htobe32 (m_SendPacketNum);
1494  		header.h.type = eSSU2Data;
1495  		memset (header.h.flags, 0, 3);
1496  		if (flags) header.h.flags[0] = flags;
1497  		uint8_t nonce[12];
1498  		CreateNonce (m_SendPacketNum, nonce);
1499  		uint8_t payload[SSU2_MAX_PACKET_SIZE];
1500  		m_Server.AEADChaCha20Poly1305Encrypt (buf, len, header.buf, 16, m_KeyDataSend, nonce, payload, SSU2_MAX_PACKET_SIZE);
1501  		header.ll[0] ^= CreateHeaderMask (m_Address->i, payload + (len - 8));
1502  		header.ll[1] ^= CreateHeaderMask (m_KeyDataSend + 32, payload + (len + 4));
1503  		m_Server.Send (header.buf, 16, payload, len + 16, m_RemoteEndpoint);
1504  		m_SendPacketNum++;
1505  		UpdateNumSentBytes (len + 32);
1506  		return m_SendPacketNum - 1;
1507  	}
1508  
1509  	void SSU2Session::ProcessData (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& from)
1510  	{
1511  		Header header;
1512  		header.ll[0] = m_SourceConnID;
1513  		memcpy (header.buf + 8, buf + 8, 8);
1514  		header.ll[1] ^= CreateHeaderMask (m_KeyDataReceive + 32, buf + (len - 12));
1515  		if (header.h.type != eSSU2Data)
1516  		{
1517  			LogPrint (eLogWarning, "SSU2: Unexpected message type ", (int)header.h.type, " instead ", (int)eSSU2Data);
1518  			if (IsEstablished ())
1519  				SendQuickAck (); // in case it was SessionConfirmed
1520  			else
1521  				ResendHandshakePacket (); // assume we receive
1522  			return;
1523  		}
1524  		if (from != m_RemoteEndpoint && !i2p::transport::transports.IsInReservedRange (from.address ()) &&
1525  		    (!m_PathChallenge || from != m_PathChallenge->second)) // path challenge was not sent to this endpoint yet
1526  		{
1527  			LogPrint (eLogInfo, "SSU2: Remote endpoint update ", m_RemoteEndpoint, "->", from);
1528  			SendPathChallenge (from);
1529  		}
1530  		if (len < 32)
1531  		{
1532  			LogPrint (eLogWarning, "SSU2: Data message too short ", len);
1533  			return;
1534  		}
1535  		uint8_t payload[SSU2_MAX_PACKET_SIZE];
1536  		size_t payloadSize = len - 32;
1537  		uint32_t packetNum = be32toh (header.h.packetNum);
1538  		uint8_t nonce[12];
1539  		CreateNonce (packetNum, nonce);
1540  		if (!m_Server.AEADChaCha20Poly1305Decrypt (buf + 16, payloadSize, header.buf, 16,
1541  			m_KeyDataReceive, nonce, payload, payloadSize))
1542  		{
1543  			LogPrint (eLogWarning, "SSU2: Data AEAD verification failed ");
1544  			return;
1545  		}
1546  		UpdateNumReceivedBytes (len);
1547  		if (header.h.flags[0] & SSU2_FLAG_IMMEDIATE_ACK_REQUESTED) m_IsDataReceived = true;
1548  		if (!packetNum || UpdateReceivePacketNum (packetNum))
1549  			HandlePayload (payload, payloadSize);
1550  	}
1551  
1552  	void SSU2Session::HandlePayload (const uint8_t * buf, size_t len)
1553  	{
1554  		size_t offset = 0;
1555  		while (offset < len)
1556  		{
1557  			uint8_t blk = buf[offset];
1558  			offset++;
1559  			auto size = bufbe16toh (buf + offset);
1560  			offset += 2;
1561  			LogPrint (eLogDebug, "SSU2: Block type ", (int)blk, " of size ", size);
1562  			if (offset + size > len)
1563  			{
1564  				LogPrint (eLogError, "SSU2: Unexpected block length ", size);
1565  				break;
1566  			}
1567  			switch (blk)
1568  			{
1569  				case eSSU2BlkDateTime:
1570  					LogPrint (eLogDebug, "SSU2: Datetime");
1571  					HandleDateTime (buf + offset, size);
1572  				break;
1573  				case eSSU2BlkOptions:
1574  					LogPrint (eLogDebug, "SSU2: Options");
1575  				break;
1576  				case eSSU2BlkRouterInfo:
1577  					LogPrint (eLogDebug, "SSU2: RouterInfo");
1578  					HandleRouterInfo (buf + offset, size);
1579  				break;
1580  				case eSSU2BlkI2NPMessage:
1581  				{
1582  					LogPrint (eLogDebug, "SSU2: I2NP message");
1583  					auto nextMsg = (buf[offset] == eI2NPTunnelData) ? NewI2NPTunnelMessage (true) : NewI2NPShortMessage ();
1584  					nextMsg->len = nextMsg->offset + size + 7; // 7 more bytes for full I2NP header
1585  					memcpy (nextMsg->GetNTCP2Header (), buf + offset, size);
1586  					nextMsg->FromNTCP2 (); // SSU2 has the same format as NTCP2
1587  					HandleI2NPMsg (std::move (nextMsg));
1588  					m_IsDataReceived = true;
1589  					break;
1590  				}
1591  				case eSSU2BlkFirstFragment:
1592  					LogPrint (eLogDebug, "SSU2: First fragment");
1593  					HandleFirstFragment (buf + offset, size);
1594  					m_IsDataReceived = true;
1595  				break;
1596  				case eSSU2BlkFollowOnFragment:
1597  					LogPrint (eLogDebug, "SSU2: Follow-on fragment");
1598  					HandleFollowOnFragment (buf + offset, size);
1599  					m_IsDataReceived = true;
1600  				break;
1601  				case eSSU2BlkTermination:
1602  				{
1603  					if (size >= 9)
1604  					{
1605  						uint8_t rsn = buf[offset + 8]; // reason
1606  						LogPrint (eLogDebug, "SSU2: Termination reason=", (int)rsn);
1607  						if (IsEstablished () && rsn != eSSU2TerminationReasonTerminationReceived)
1608  							RequestTermination (eSSU2TerminationReasonTerminationReceived);
1609  						else if (m_State != eSSU2SessionStateTerminated)
1610  						{
1611  							if (m_State == eSSU2SessionStateClosing && rsn == eSSU2TerminationReasonTerminationReceived)
1612  								m_State = eSSU2SessionStateClosingConfirmed;
1613  							Done ();
1614  						}
1615  					}
1616  					else
1617  						LogPrint(eLogWarning, "SSU2: Unexpected termination block size ", size);
1618  					break;
1619  				}
1620  				case eSSU2BlkRelayRequest:
1621  					LogPrint (eLogDebug, "SSU2: RelayRequest");
1622  					HandleRelayRequest (buf + offset, size);
1623  					m_IsDataReceived = true;
1624  				break;
1625  				case eSSU2BlkRelayResponse:
1626  					LogPrint (eLogDebug, "SSU2: RelayResponse");
1627  					HandleRelayResponse (buf + offset, size);
1628  					m_IsDataReceived = true;
1629  				break;
1630  				case eSSU2BlkRelayIntro:
1631  					LogPrint (eLogDebug, "SSU2: RelayIntro");
1632  					HandleRelayIntro (buf + offset, size);
1633  					m_IsDataReceived = true;
1634  				break;
1635  				case eSSU2BlkPeerTest:
1636  					LogPrint (eLogDebug, "SSU2: PeerTest msg=", (int)buf[offset], " code=", (int)buf[offset+1]);
1637  					HandlePeerTest (buf + offset, size);
1638  					if (buf[offset] < 5)
1639  						m_IsDataReceived = true;
1640  				break;
1641  				case eSSU2BlkNextNonce:
1642  				break;
1643  				case eSSU2BlkAck:
1644  					LogPrint (eLogDebug, "SSU2: Ack");
1645  					HandleAck (buf + offset, size);
1646  				break;
1647  				case eSSU2BlkAddress:
1648  					LogPrint (eLogDebug, "SSU2: Address");
1649  					HandleAddress (buf + offset, size);
1650  				break;
1651  				case eSSU2BlkIntroKey:
1652  				break;
1653  				case eSSU2BlkRelayTagRequest:
1654  					LogPrint (eLogDebug, "SSU2: RelayTagRequest");
1655  					if (!m_RelayTag)
1656  					{
1657  						if (i2p::context.AcceptsTunnels())
1658  						{
1659  							auto addr = FindLocalAddress ();
1660  							if (addr && addr->IsIntroducer ())
1661  							{
1662  								RAND_bytes ((uint8_t *)&m_RelayTag, 4);
1663  								m_Server.AddRelay (m_RelayTag, shared_from_this ());
1664  							}
1665  						}
1666  					}
1667  				break;
1668  				case eSSU2BlkRelayTag:
1669  					LogPrint (eLogDebug, "SSU2: RelayTag");
1670  					m_RelayTag = bufbe32toh (buf + offset);
1671  				break;
1672  				case eSSU2BlkNewToken:
1673  				{
1674  					LogPrint (eLogDebug, "SSU2: New token");
1675  					uint64_t token;
1676  					memcpy (&token, buf + offset + 4, 8);
1677  					m_Server.UpdateOutgoingToken (m_RemoteEndpoint, token, bufbe32toh (buf + offset));
1678  					break;
1679  				}
1680  				case eSSU2BlkPathChallenge:
1681  					LogPrint (eLogDebug, "SSU2: Path challenge");
1682  					SendPathResponse (buf + offset, size);
1683  				break;
1684  				case eSSU2BlkPathResponse:
1685  				{
1686  					LogPrint (eLogDebug, "SSU2: Path response");
1687  					if (m_PathChallenge)
1688  					{
1689  						if (buf64toh (buf + offset) == m_PathChallenge->first)
1690  						{
1691  							m_RemoteEndpoint = m_PathChallenge->second;
1692  							m_PathChallenge.reset (nullptr);
1693  						}
1694  					}
1695  					break;
1696  				}
1697  				case eSSU2BlkFirstPacketNumber:
1698  				break;
1699  				case eSSU2BlkPadding:
1700  					LogPrint (eLogDebug, "SSU2: Padding");
1701  				break;
1702  				default:
1703  					LogPrint (eLogWarning, "SSU2: Unknown block type ", (int)blk);
1704  			}
1705  			offset += size;
1706  		}
1707  	}
1708  
1709  	void SSU2Session::HandleDateTime (const uint8_t * buf, size_t len)
1710  	{
1711  		int64_t offset = (int64_t)i2p::util::GetSecondsSinceEpoch () - (int64_t)bufbe32toh (buf);
1712  		switch (m_State)
1713  		{
1714  			case eSSU2SessionStateSessionRequestReceived:
1715  			case eSSU2SessionStateTokenRequestReceived:
1716  			case eSSU2SessionStateEstablished:
1717  				if (std::abs (offset) > SSU2_CLOCK_SKEW)
1718  					m_TerminationReason = eSSU2TerminationReasonClockSkew;
1719  			break;
1720  			case eSSU2SessionStateSessionCreatedReceived:
1721  			case eSSU2SessionStateTokenReceived:
1722  				if ((m_RemoteEndpoint.address ().is_v4 () && i2p::context.GetTesting ()) ||
1723  				    (m_RemoteEndpoint.address ().is_v6 () && i2p::context.GetTestingV6 ()))
1724  				{
1725  					if (m_Server.IsSyncClockFromPeers ())
1726  					{
1727  						if (std::abs (offset) > SSU2_CLOCK_THRESHOLD)
1728  						{
1729  							LogPrint (eLogWarning, "SSU2: Time offset ", offset, " from ", m_RemoteEndpoint);
1730  							m_Server.AdjustTimeOffset (-offset, GetRemoteIdentity ());
1731  						}
1732  						else
1733  							m_Server.AdjustTimeOffset (0, nullptr);
1734  					}
1735  					else if (std::abs (offset) > SSU2_CLOCK_SKEW)
1736  					{
1737  						LogPrint (eLogError, "SSU2: Clock skew detected ", offset, ". Check your clock");
1738  						i2p::context.SetError (eRouterErrorClockSkew);
1739  					}
1740  				}
1741  			break;
1742  			default: ;
1743  		};
1744  	}
1745  
1746  	void SSU2Session::HandleRouterInfo (const uint8_t * buf, size_t len)
1747  	{
1748  		if (len < 2) return;
1749  		// not from SessionConfirmed, we must add it instantly to use in next block
1750  		std::shared_ptr<const i2p::data::RouterInfo> newRi;
1751  		if (buf[0] & SSU2_ROUTER_INFO_FLAG_GZIP) // compressed?
1752  		{
1753  			auto ri = ExtractRouterInfo (buf, len);
1754  			if (ri)
1755  				newRi = i2p::data::netdb.AddRouterInfo (ri->GetBuffer (), ri->GetBufferLen ());
1756  		}
1757  		else // use buffer directly. TODO: handle frag
1758  			newRi = i2p::data::netdb.AddRouterInfo (buf + 2, len - 2);
1759  
1760  		if (newRi)
1761  		{
1762  			auto remoteIdentity = GetRemoteIdentity ();
1763  			if (remoteIdentity && remoteIdentity->GetIdentHash () == newRi->GetIdentHash ())
1764  			{
1765  				// peer's RouterInfo update
1766  				SetRemoteIdentity (newRi->GetIdentity ());
1767  				auto address = m_RemoteEndpoint.address ().is_v6 () ? newRi->GetSSU2V6Address () : newRi->GetSSU2V4Address ();
1768  				if (address)
1769  				{
1770  					m_Address = address;
1771  					if (IsOutgoing () && m_RelayTag && !address->IsIntroducer ())
1772  						m_RelayTag = 0; // not longer introducer
1773  				}
1774  			}
1775  			i2p::transport::transports.UpdatePeerParams (newRi);
1776  		}
1777  	}
1778  
1779  	void SSU2Session::HandleAck (const uint8_t * buf, size_t len)
1780  	{
1781  		if (m_State == eSSU2SessionStateSessionConfirmedSent)
1782  		{
1783  			Established ();
1784  			return;
1785  		}
1786  		if (m_SentPackets.empty ()) return;
1787  		if (len < 5) return;
1788  		// acnt
1789  		uint32_t ackThrough = bufbe32toh (buf);
1790  		uint32_t firstPacketNum = ackThrough > buf[4] ? ackThrough - buf[4] : 0;
1791  		HandleAckRange (firstPacketNum, ackThrough, i2p::util::GetMillisecondsSinceEpoch ()); // acnt
1792  		// ranges
1793  		len -= 5;
1794  		if (!len || m_SentPackets.empty ()) return; // don't handle ranges if nothing to acknowledge
1795  		const uint8_t * ranges = buf + 5;
1796  		while (len > 0 && firstPacketNum && ackThrough - firstPacketNum < SSU2_MAX_NUM_ACK_PACKETS)
1797  		{
1798  			uint32_t lastPacketNum = firstPacketNum - 1;
1799  			if (*ranges > lastPacketNum) break;
1800  			lastPacketNum -= *ranges; ranges++; // nacks
1801  			if (*ranges > lastPacketNum + 1) break;
1802  			firstPacketNum = lastPacketNum - *ranges + 1; ranges++; // acks
1803  			len -= 2;
1804  			HandleAckRange (firstPacketNum, lastPacketNum, 0);
1805  		}
1806  	}
1807  
1808  	void SSU2Session::HandleAckRange (uint32_t firstPacketNum, uint32_t lastPacketNum, uint64_t ts)
1809  	{
1810  		if (firstPacketNum > lastPacketNum) return;
1811  		auto it = m_SentPackets.begin ();
1812  		while (it != m_SentPackets.end () && it->first < firstPacketNum) it++; // find first acked packet
1813  		if (it == m_SentPackets.end () || it->first > lastPacketNum) return; // not found
1814  		auto it1 = it;
1815  		int numPackets = 0;
1816  		while (it1 != m_SentPackets.end () && it1->first <= lastPacketNum)
1817  		{
1818  			if (ts && !it1->second->numResends)
1819  			{
1820  				if (ts > it1->second->sendTime)
1821  				{
1822  					auto rtt = ts - it1->second->sendTime;
1823  					if (m_RTT != SSU2_UNKNOWN_RTT)
1824  						m_RTT = SSU2_RTT_EWMA_ALPHA * rtt + (1.0 - SSU2_RTT_EWMA_ALPHA) * m_RTT;
1825  					else
1826  						m_RTT = rtt;
1827  					m_RTO = m_RTT*SSU2_kAPPA;
1828  					m_MsgLocalExpirationTimeout = std::max (I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MIN,
1829  						std::min (I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_MAX,
1830  						(unsigned int)(m_RTT * 1000 * I2NP_MESSAGE_LOCAL_EXPIRATION_TIMEOUT_FACTOR)));
1831  					m_MsgLocalSemiExpirationTimeout = m_MsgLocalExpirationTimeout / 2;
1832  					if (m_RTO < SSU2_MIN_RTO) m_RTO = SSU2_MIN_RTO;
1833  					if (m_RTO > SSU2_MAX_RTO) m_RTO = SSU2_MAX_RTO;
1834  				}
1835  				ts = 0; // update RTT one time per range
1836  			}
1837  			it1++;
1838  			numPackets++;
1839  		}
1840  		m_SentPackets.erase (it, it1);
1841  		if (numPackets > 0)
1842  		{
1843  			m_WindowSize += numPackets;
1844  			if (m_WindowSize > SSU2_MAX_WINDOW_SIZE) m_WindowSize = SSU2_MAX_WINDOW_SIZE;
1845  		}
1846  	}
1847  
1848  	void SSU2Session::HandleAddress (const uint8_t * buf, size_t len)
1849  	{
1850  		boost::asio::ip::udp::endpoint ep;
1851  		if (ExtractEndpoint (buf, len, ep))
1852  		{
1853  			LogPrint (eLogInfo, "SSU2: Our external address is ", ep);
1854  			if (!i2p::transport::transports.IsInReservedRange (ep.address ()))
1855  			{
1856  				i2p::context.UpdateAddress (ep.address ());
1857  				// check our port
1858  				bool isV4 = ep.address ().is_v4 ();
1859  				if (ep.port () != m_Server.GetPort (isV4))
1860  				{
1861  					LogPrint (eLogInfo, "SSU2: Our port ", ep.port (), " received from ", m_RemoteEndpoint, " is different from ", m_Server.GetPort (isV4));
1862  					if (isV4)
1863  					{
1864  						if (i2p::context.GetTesting ())
1865  							i2p::context.SetError (eRouterErrorSymmetricNAT);
1866  						else if (m_State == eSSU2SessionStatePeerTest)
1867  						{
1868  							i2p::context.SetError (eRouterErrorFullConeNAT); // TODO: Full-Cone NAT detection isn't working.
1869  							// i2p::context.PublishNTCP2Address (TCP_PORT, true, true, false, false); // TODO: TCP_PORT to be filled similar to ep.port()
1870  							i2p::context.PublishSSU2Address (ep.port(), true, true, false);
1871  						}
1872  					}
1873  					else
1874  					{
1875  						if (i2p::context.GetTestingV6 ())
1876  							i2p::context.SetErrorV6 (eRouterErrorSymmetricNAT);
1877  						else if (m_State == eSSU2SessionStatePeerTest)
1878  						{
1879  							i2p::context.SetErrorV6 (eRouterErrorFullConeNAT);
1880  							// i2p::context.PublishNTCP2Address (TCP_PORT, true, false, true, false); // TODO: TCP_PORT to be filled similar to ep.port()
1881  							i2p::context.PublishSSU2Address (ep.port(), true, false, true);
1882  						}
1883  					}
1884  				}
1885  				else
1886  				{
1887  					if (isV4)
1888  					{
1889  						if (i2p::context.GetError () == eRouterErrorSymmetricNAT)
1890  						{
1891  							if (m_State == eSSU2SessionStatePeerTest)
1892  								i2p::context.SetStatus (eRouterStatusOK);
1893  							i2p::context.SetError (eRouterErrorNone);
1894  						}
1895  						else if (i2p::context.GetError () == eRouterErrorFullConeNAT)
1896  							i2p::context.SetError (eRouterErrorNone);
1897  					}
1898  					else
1899  					{
1900  						if (i2p::context.GetErrorV6 () == eRouterErrorSymmetricNAT)
1901  						{
1902  							if (m_State == eSSU2SessionStatePeerTest)
1903  								i2p::context.SetStatusV6 (eRouterStatusOK);
1904  							i2p::context.SetErrorV6 (eRouterErrorNone);
1905  						}
1906  						else if (i2p::context.GetErrorV6 () == eRouterErrorFullConeNAT)
1907  							i2p::context.SetErrorV6 (eRouterErrorNone);
1908  					}
1909  				}
1910  			}
1911  		}
1912  	}
1913  
1914  	void SSU2Session::HandleFirstFragment (const uint8_t * buf, size_t len)
1915  	{
1916  		auto msg = (buf[0] == eI2NPTunnelData) ? NewI2NPTunnelMessage (true) : NewI2NPShortMessage ();
1917  		uint32_t msgID; memcpy (&msgID, buf + 1, 4);
1918  		// same format as I2NP message block
1919  		msg->len = msg->offset + len + 7;
1920  		memcpy (msg->GetNTCP2Header (), buf, len);
1921  		std::shared_ptr<SSU2IncompleteMessage> m;
1922  		bool found = false;
1923  		auto it = m_IncompleteMessages.find (msgID);
1924  		if (it != m_IncompleteMessages.end ())
1925  		{
1926  			found = true;
1927  			m = it->second;
1928  		}
1929  		else
1930  		{
1931  			m = m_Server.GetIncompleteMessagesPool ().AcquireShared ();
1932  			m_IncompleteMessages.emplace (msgID, m);
1933  		}
1934  		m->msg = msg;
1935  		m->nextFragmentNum = 1;
1936  		m->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch ();
1937  		if (found && m->ConcatOutOfSequenceFragments ())
1938  		{
1939  			// we have all follow-on fragments already
1940  			m->msg->FromNTCP2 ();
1941  			HandleI2NPMsg (std::move (m->msg));
1942  			m_IncompleteMessages.erase (it);
1943  		}
1944  	}
1945  
1946  	void SSU2Session::HandleFollowOnFragment (const uint8_t * buf, size_t len)
1947  	{
1948  		if (len < 5) return;
1949  		uint8_t fragmentNum = buf[0] >> 1;
1950  		if (!fragmentNum || fragmentNum >= SSU2_MAX_NUM_FRAGMENTS)
1951  		{
1952  			LogPrint (eLogWarning, "SSU2: Invalid follow-on fragment num ", fragmentNum);
1953  			return;
1954  		}
1955  		bool isLast = buf[0] & 0x01;
1956  		uint32_t msgID; memcpy (&msgID, buf + 1, 4);
1957  		auto it = m_IncompleteMessages.find (msgID);
1958  		if (it != m_IncompleteMessages.end ())
1959  		{
1960  			if (fragmentNum < it->second->nextFragmentNum) return; // duplicate
1961  			if (it->second->nextFragmentNum == fragmentNum && fragmentNum < SSU2_MAX_NUM_FRAGMENTS &&
1962  			    it->second->msg)
1963  			{
1964  				// in sequence
1965  				it->second->AttachNextFragment (buf + 5, len - 5);
1966  				if (isLast)
1967  				{
1968  					it->second->msg->FromNTCP2 ();
1969  					HandleI2NPMsg (std::move (it->second->msg));
1970  					m_IncompleteMessages.erase (it);
1971  				}
1972  				else
1973  				{
1974  					if (it->second->ConcatOutOfSequenceFragments ())
1975  					{
1976  						HandleI2NPMsg (std::move (it->second->msg));
1977  						m_IncompleteMessages.erase (it);
1978  					}
1979  					else
1980  						it->second->lastFragmentInsertTime = i2p::util::GetSecondsSinceEpoch ();
1981  				}
1982  				return;
1983  			}
1984  		}
1985  		else
1986  		{
1987  			// follow-on fragment before first fragment
1988  			auto msg = m_Server.GetIncompleteMessagesPool ().AcquireShared ();
1989  			msg->nextFragmentNum = 0;
1990  			it = m_IncompleteMessages.emplace (msgID, msg).first;
1991  		}
1992  		// insert out of sequence fragment
1993  		auto fragment = m_Server.GetFragmentsPool ().AcquireShared ();
1994  		memcpy (fragment->buf, buf + 5, len -5);
1995  		fragment->len = len - 5;
1996  		fragment->fragmentNum = fragmentNum;
1997  		fragment->isLast = isLast;
1998  		it->second->AddOutOfSequenceFragment (fragment);
1999  	}
2000  
2001  	void SSU2Session::HandleRelayRequest (const uint8_t * buf, size_t len)
2002  	{
2003  		// we are Bob
2004  		if (len < 9) return;
2005  		auto mts = i2p::util::GetMillisecondsSinceEpoch ();
2006  		uint32_t nonce = bufbe32toh (buf + 1); // nonce
2007  		uint32_t relayTag = bufbe32toh (buf + 5); // relay tag
2008  		auto session = m_Server.FindRelaySession (relayTag);
2009  		if (!session)
2010  		{
2011  			LogPrint (eLogWarning, "SSU2: RelayRequest session with relay tag ", relayTag, " not found");
2012  			// send relay response back to Alice
2013  			auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
2014  			packet->payloadSize = CreateAckBlock (packet->payload, m_MaxPayloadSize);
2015  			packet->payloadSize += CreateRelayResponseBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize,
2016  				eSSU2RelayResponseCodeBobRelayTagNotFound, nonce, 0, false);
2017  			packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
2018  			uint32_t packetNum = SendData (packet->payload, packet->payloadSize);
2019  			if (m_RemoteVersion >= SSU2_MIN_RELAY_RESPONSE_RESEND_VERSION)
2020  			{
2021  				// sometimes Alice doesn't ack this RelayResponse in older versions
2022  				packet->sendTime = mts;
2023  				m_SentPackets.emplace (packetNum, packet);
2024  			}
2025  			return;
2026  		}
2027  		if (session->m_RelaySessions.emplace (nonce, std::make_pair (shared_from_this (), mts/1000)).second)
2028  		{
2029  			// send relay intro to Charlie
2030  			auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ()); // Alice's RI
2031  			if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr;
2032  			if (!r) LogPrint (eLogWarning, "SSU2: RelayRequest Alice's router info not found");
2033  
2034  			auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
2035  			packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0;
2036  			if (!packet->payloadSize && r)
2037  				session->SendFragmentedMessage (CreateDatabaseStoreMsg (r));
2038  			packet->payloadSize += CreateRelayIntroBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, buf + 1, len - 1);
2039  			if (packet->payloadSize < m_MaxPayloadSize)
2040  				packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
2041  			uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize);
2042  			packet->sendTime = mts;
2043  			// Charlie always responds with RelayResponse
2044  			session->m_SentPackets.emplace (packetNum, packet);
2045  		}
2046  		else
2047  			LogPrint (eLogInfo, "SSU2: Relay request nonce ", nonce, " already exists. Ignore");
2048  	}
2049  
2050  	void SSU2Session::HandleRelayIntro (const uint8_t * buf, size_t len, int attempts)
2051  	{
2052  		// we are Charlie
2053  		if (len < 47) return;
2054  		SSU2RelayResponseCode code = eSSU2RelayResponseCodeAccept;
2055  		boost::asio::ip::udp::endpoint ep;
2056  		std::shared_ptr<const i2p::data::RouterInfo::Address> addr;
2057  		auto r = i2p::data::netdb.FindRouter (buf + 1); // Alice
2058  		if (r)
2059  		{
2060  			SignedData<128> s;
2061  			s.Insert ((const uint8_t *)"RelayRequestData", 16); // prologue
2062  			s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash
2063  			s.Insert (i2p::context.GetIdentHash (), 32); // chash
2064  			s.Insert (buf + 33, 14); // nonce, relay tag, timestamp, ver, asz
2065  			uint8_t asz = buf[46];
2066  			if (asz + 47 + r->GetIdentity ()->GetSignatureLen () > len)
2067  			{
2068  				LogPrint (eLogWarning, "SSU2: Malformed RelayIntro len=", len);
2069  				return;
2070  			}
2071  			s.Insert (buf + 47, asz); // Alice Port, Alice IP
2072  			if (s.Verify (r->GetIdentity (), buf + 47 + asz))
2073  			{
2074  				// obtain and check endpoint and address for HolePunch
2075  				if (ExtractEndpoint (buf + 47, asz, ep))
2076  				{
2077  					if (!ep.address ().is_unspecified () && ep.port ())
2078  					{
2079  						if (m_Server.IsSupported (ep.address ()))
2080  						{
2081  							addr = ep.address ().is_v6 () ? r->GetSSU2V6Address () : r->GetSSU2V4Address ();
2082  							if (!addr)
2083  							{
2084  								LogPrint (eLogWarning, "SSU2: RelayIntro address for endpoint not found");
2085  								code = eSSU2RelayResponseCodeCharlieAliceIsUnknown;
2086  							}
2087  						}
2088  						else
2089  						{
2090  							LogPrint (eLogWarning, "SSU2: RelayIntro unsupported address");
2091  							code = eSSU2RelayResponseCodeCharlieUnsupportedAddress;
2092  						}
2093  					}
2094  					else
2095  					{
2096  						LogPrint (eLogWarning, "SSU2: RelayIntro invalid endpoint");
2097  						code = eSSU2RelayResponseCodeCharlieAliceIsUnknown;
2098  					}
2099  				}
2100  				else
2101  				{
2102  					LogPrint (eLogWarning, "SSU2: RelayIntro can't extract endpoint");
2103  					code = eSSU2RelayResponseCodeCharlieAliceIsUnknown;
2104  				}
2105  			}
2106  			else
2107  			{
2108  				LogPrint (eLogWarning, "SSU2: RelayIntro signature verification failed");
2109  				code = eSSU2RelayResponseCodeCharlieSignatureFailure;
2110  			}
2111  		}
2112  		else if (!attempts)
2113  		{
2114  			// RouterInfo might come in the next packet, try again
2115  			auto vec = std::make_shared<std::vector<uint8_t> >(len);
2116  			memcpy (vec->data (), buf, len);
2117  			auto s = shared_from_this ();
2118  			boost::asio::post (m_Server.GetService (), [s, vec, attempts]()
2119  				{
2120  					LogPrint (eLogDebug, "SSU2: RelayIntro attempt ", attempts + 1);
2121  					s->HandleRelayIntro (vec->data (), vec->size (), attempts + 1);
2122  				});
2123  			return;
2124  		}
2125  		else
2126  		{
2127  			LogPrint (eLogWarning, "SSU2: RelayIntro unknown router to introduce");
2128  			code = eSSU2RelayResponseCodeCharlieAliceIsUnknown;
2129  		}
2130  		// send relay response to Bob
2131  		auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
2132  		uint32_t nonce = bufbe32toh (buf + 33);
2133  		packet->payloadSize = CreateRelayResponseBlock (packet->payload, m_MaxPayloadSize,
2134  			code, nonce, m_Server.GetIncomingToken (ep), ep.address ().is_v4 ());
2135  		if (code == eSSU2RelayResponseCodeAccept && addr)
2136  		{
2137  			// send HolePunch
2138  			auto holePunchSession = std::make_shared<SSU2HolePunchSession>(m_Server, nonce, ep, addr);
2139  			if (m_Server.AddSession (holePunchSession))
2140  				holePunchSession->SendHolePunch (packet->payload, packet->payloadSize); // relay response block
2141  			else
2142  			{
2143  				LogPrint (eLogInfo, "SSU2: Relay intro nonce ", nonce, " already exists. Ignore");
2144  				return;
2145  			}
2146  		}
2147  		packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
2148  		uint32_t packetNum = SendData (packet->payload, packet->payloadSize);
2149  		if (m_RemoteVersion >= SSU2_MIN_RELAY_RESPONSE_RESEND_VERSION)
2150  		{
2151  			// sometimes Bob doesn't ack this RelayResponse in older versions
2152  			packet->sendTime = i2p::util::GetMillisecondsSinceEpoch ();
2153  			m_SentPackets.emplace (packetNum, packet);
2154  		}
2155  	}
2156  
2157  	void SSU2Session::HandleRelayResponse (const uint8_t * buf, size_t len)
2158  	{
2159  		if (len < 6) return;
2160  		uint32_t nonce = bufbe32toh (buf + 2);
2161  		if (m_State == eSSU2SessionStateIntroduced)
2162  		{
2163  			// HolePunch from Charlie
2164  			// TODO: verify address and signature
2165  			// verify nonce
2166  			if (~htobe64 (((uint64_t)nonce << 32) | nonce) != m_DestConnID)
2167  				LogPrint (eLogWarning, "SSU2: Relay response nonce mismatch ", nonce, " connID=", m_DestConnID);
2168  			if (len >= 8)
2169  			{
2170  				// new token
2171  				uint64_t token;
2172  				memcpy (&token, buf + len - 8, 8);
2173  				m_Server.UpdateOutgoingToken (m_RemoteEndpoint, token, i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT);
2174  			}
2175  			return;
2176  		}
2177  		auto it = m_RelaySessions.find (nonce);
2178  		if (it != m_RelaySessions.end ())
2179  		{
2180  			auto relaySession = it->second.first;
2181  			m_RelaySessions.erase (it);
2182  			if (relaySession && relaySession->IsEstablished ())
2183  			{
2184  				// we are Bob, message from Charlie
2185  				auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
2186  				uint8_t * payload = packet->payload;
2187  				payload[0] = eSSU2BlkRelayResponse;
2188  				htobe16buf (payload + 1, len);
2189  				memcpy (payload + 3, buf, len); // forward to Alice as is
2190  				packet->payloadSize = len + 3;
2191  				packet->payloadSize += CreatePaddingBlock (payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
2192  				uint32_t packetNum = relaySession->SendData (packet->payload, packet->payloadSize);
2193  				if (m_RemoteVersion >= SSU2_MIN_RELAY_RESPONSE_RESEND_VERSION)
2194  				{
2195  					// sometimes Alice doesn't ack this RelayResponse in older versions
2196  					packet->sendTime = i2p::util::GetMillisecondsSinceEpoch ();
2197  					relaySession->m_SentPackets.emplace (packetNum, packet);
2198  				}
2199  			}
2200  			else
2201  			{
2202  				// we are Alice, message from Bob
2203  				if (!buf[1]) // status code accepted?
2204  				{
2205  					// verify signature
2206  					uint8_t csz = (len >= 12) ? buf[11] : 0;
2207  					if (csz + 12 + relaySession->GetRemoteIdentity ()->GetSignatureLen () > len)
2208  					{
2209  						LogPrint (eLogWarning, "SSU2: Malformed RelayResponse len=", len);
2210  						relaySession->Done ();
2211  						return;
2212  					}
2213  					SignedData<128> s;
2214  					s.Insert ((const uint8_t *)"RelayAgreementOK", 16); // prologue
2215  					s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash
2216  					s.Insert (buf + 2, 10 + csz); // nonce, timestamp, ver, csz and Charlie's endpoint
2217  					if (s.Verify (relaySession->GetRemoteIdentity (), buf + 12 + csz))
2218  					{
2219  						if (relaySession->m_State == eSSU2SessionStateIntroduced) // HolePunch not received yet
2220  						{
2221  							// update Charlie's endpoint
2222  							if (ExtractEndpoint (buf + 12, csz, relaySession->m_RemoteEndpoint))
2223  							{
2224  								// update token
2225  								uint64_t token;
2226  								memcpy (&token, buf + len - 8, 8);
2227  								m_Server.UpdateOutgoingToken (relaySession->m_RemoteEndpoint,
2228  									token, i2p::util::GetSecondsSinceEpoch () + SSU2_TOKEN_EXPIRATION_TIMEOUT);
2229  								// connect to Charlie, HolePunch will be ignored
2230  								relaySession->ConnectAfterIntroduction ();
2231  							}
2232  							else
2233  								LogPrint (eLogWarning, "SSU2: RelayResponse can't extract endpoint");
2234  						}
2235  					}
2236  					else
2237  					{
2238  						LogPrint (eLogWarning, "SSU2: RelayResponse signature verification failed");
2239  						relaySession->Done ();
2240  					}
2241  				}
2242  				else
2243  				{
2244  					LogPrint (eLogInfo, "SSU2: RelayResponse status code=", (int)buf[1], " nonce=", bufbe32toh (buf + 2));
2245  					relaySession->Done ();
2246  				}
2247  			}
2248  		}
2249  		else
2250  			LogPrint (eLogDebug, "SSU2: RelayResponse unknown nonce ", bufbe32toh (buf + 2));
2251  	}
2252  
2253  	void SSU2Session::HandlePeerTest (const uint8_t * buf, size_t len)
2254  	{
2255  		// msgs 1-4
2256  		if (len < 3) return;
2257  		uint8_t msg = buf[0];
2258  		size_t offset = 3; // points to signed data
2259  		if (msg == 2 || msg == 4) offset += 32; // hash is presented for msg 2 and 4 only
2260  		if (len < offset + 5) return;
2261  		auto ts = i2p::util::GetMillisecondsSinceEpoch ();
2262  		uint32_t nonce = bufbe32toh (buf + offset + 1);
2263  		switch (msg) // msg
2264  		{
2265  			case 1: // Bob from Alice
2266  			{
2267  				auto session = m_Server.GetRandomPeerTestSession ((buf[12] == 6) ? i2p::data::RouterInfo::eSSU2V4 : i2p::data::RouterInfo::eSSU2V6,
2268  					GetRemoteIdentity ()->GetIdentHash ());
2269  				if (session) // session with Charlie
2270  				{
2271  					if (m_Server.AddPeerTest (nonce, shared_from_this (), ts/1000))
2272  					{
2273  						auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
2274  						// Alice's RouterInfo
2275  						auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ());
2276  						if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr;
2277  						packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0;
2278  						if (!packet->payloadSize && r)
2279  							session->SendFragmentedMessage (CreateDatabaseStoreMsg (r));
2280  						if (packet->payloadSize + len + 48 > m_MaxPayloadSize)
2281  						{
2282  							// doesn't fit one message, send RouterInfo in separate message
2283  							uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED);
2284  							packet->sendTime = ts;
2285  							session->m_SentPackets.emplace (packetNum, packet);
2286  							packet = m_Server.GetSentPacketsPool ().AcquireShared (); // new packet
2287  						}
2288  						// PeerTest to Charlie
2289  						packet->payloadSize += CreatePeerTestBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize, 2,
2290  							eSSU2PeerTestCodeAccept, GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset);
2291  						packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
2292  						uint32_t packetNum = session->SendData (packet->payload, packet->payloadSize, SSU2_FLAG_IMMEDIATE_ACK_REQUESTED);
2293  						packet->sendTime = ts;
2294  						session->m_SentPackets.emplace (packetNum, packet);
2295  					}
2296  					else
2297  						LogPrint (eLogInfo, "SSU2: Peer test 1 nonce ", nonce, " already exists. Ignored");
2298  				}
2299  				else
2300  				{
2301  					// Charlie not found, send error back to Alice
2302  					auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
2303  					uint8_t zeroHash[32] = {0};
2304  					packet->payloadSize = CreatePeerTestBlock (packet->payload, m_MaxPayloadSize, 4,
2305  						eSSU2PeerTestCodeBobNoCharlieAvailable, zeroHash, buf + offset, len - offset);
2306  					packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
2307  					uint32_t packetNum = SendData (packet->payload, packet->payloadSize);
2308  					packet->sendTime = ts;
2309  					m_SentPackets.emplace (packetNum, packet);
2310  				}
2311  				break;
2312  			}
2313  			case 2: // Charlie from Bob
2314  			{
2315  				// sign with Charlie's key
2316  				if (len < offset + 9) return;
2317  				uint8_t asz = buf[offset + 9];
2318  				size_t l = asz + 10 + i2p::context.GetIdentity ()->GetSignatureLen ();
2319  				if (len < offset + l) return;
2320  				std::vector<uint8_t> newSignedData (l);
2321  				memcpy (newSignedData.data (), buf + offset, asz + 10);
2322  				SignedData<128> s;
2323  				s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue
2324  				s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash
2325  				s.Insert (buf + 3, 32); // ahash
2326  				s.Insert (newSignedData.data (), asz + 10); // ver, nonce, ts, asz, Alice's endpoint
2327  				s.Sign (i2p::context.GetPrivateKeys (), newSignedData.data () + 10 + asz);
2328  				// send response (msg 3) back and msg 5 if accepted
2329  				SSU2PeerTestCode code = eSSU2PeerTestCodeAccept;
2330  				auto r = i2p::data::netdb.FindRouter (buf + 3); // find Alice
2331  				if (r)
2332  				{
2333  					size_t signatureLen = r->GetIdentity ()->GetSignatureLen ();
2334  					if (len >= offset + asz + 10 + signatureLen)
2335  					{
2336  						s.Reset ();
2337  						s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue
2338  						s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash
2339  						s.Insert (buf + offset, asz + 10); // signed data
2340  						if (s.Verify (r->GetIdentity (), buf + offset + asz + 10))
2341  						{
2342  							if (!m_Server.FindSession (r->GetIdentity ()->GetIdentHash ()))
2343  							{
2344  								boost::asio::ip::udp::endpoint ep;
2345  								std::shared_ptr<const i2p::data::RouterInfo::Address> addr;
2346  								if (ExtractEndpoint (buf + offset + 10, asz, ep) && !ep.address ().is_unspecified () && ep.port ())
2347  									addr = r->GetSSU2Address (ep.address ().is_v4 ());
2348  								if (addr && m_Server.IsSupported (ep.address ()) &&
2349  								    i2p::context.GetRouterInfo ().IsSSU2PeerTesting (ep.address ().is_v4 ()))
2350  								{
2351  									if (!m_Server.IsConnectedRecently (ep)) // no alive hole punch
2352  									{
2353  										// send msg 5 to Alice
2354  										auto session = std::make_shared<SSU2PeerTestSession> (m_Server,
2355  											0, htobe64 (((uint64_t)nonce << 32) | nonce));
2356  										session->m_RemoteEndpoint = ep; // might be different
2357  										m_Server.AddSession (session);
2358  										session->SendPeerTest (5, newSignedData.data (), newSignedData.size (), addr);
2359  									}
2360  									else
2361  										code = eSSU2PeerTestCodeCharlieAliceIsAlreadyConnected;
2362  								}
2363  								else
2364  									code = eSSU2PeerTestCodeCharlieUnsupportedAddress;
2365  							}
2366  							else
2367  								code = eSSU2PeerTestCodeCharlieAliceIsAlreadyConnected;
2368  						}
2369  						else
2370  							code = eSSU2PeerTestCodeCharlieSignatureFailure;
2371  					}
2372  					else // maformed message
2373  						code = eSSU2PeerTestCodeCharlieReasonUnspecified;
2374  				}
2375  				else
2376  					code = eSSU2PeerTestCodeCharlieAliceIsUnknown;
2377  				// send msg 3 back to Bob
2378  				auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
2379  				packet->payloadSize = CreatePeerTestBlock (packet->payload, m_MaxPayloadSize, 3,
2380  					code, nullptr, newSignedData.data (), newSignedData.size ());
2381  				packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
2382  				uint32_t packetNum = SendData (packet->payload, packet->payloadSize);
2383  				packet->sendTime = ts;
2384  				m_SentPackets.emplace (packetNum, packet);
2385  				break;
2386  			}
2387  			case 3: // Bob from Charlie
2388  			{
2389  				auto aliceSession = m_Server.GetPeerTest (nonce);
2390  				if (aliceSession && aliceSession->IsEstablished ())
2391  				{
2392  					auto packet = m_Server.GetSentPacketsPool ().AcquireShared ();
2393  					// Charlie's RouterInfo
2394  					auto r = i2p::data::netdb.FindRouter (GetRemoteIdentity ()->GetIdentHash ());
2395  					if (r && (r->IsUnreachable () || !i2p::data::netdb.PopulateRouterInfoBuffer (r))) r = nullptr;
2396  					packet->payloadSize = r ? CreateRouterInfoBlock (packet->payload, m_MaxPayloadSize - len - 32, r) : 0;
2397  					if (!packet->payloadSize && r)
2398  						aliceSession->SendFragmentedMessage (CreateDatabaseStoreMsg (r));
2399  					if (packet->payloadSize + len + 16 > m_MaxPayloadSize)
2400  					{
2401  						// doesn't fit one message, send RouterInfo in separate message
2402  						uint32_t packetNum = aliceSession->SendData (packet->payload, packet->payloadSize);
2403  						packet->sendTime = ts;
2404  						aliceSession->m_SentPackets.emplace (packetNum, packet);
2405  						packet = m_Server.GetSentPacketsPool ().AcquireShared ();
2406  					}
2407  					// PeerTest to Alice
2408  					packet->payloadSize += CreatePeerTestBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize, 4,
2409  						(SSU2PeerTestCode)buf[1], GetRemoteIdentity ()->GetIdentHash (), buf + offset, len - offset);
2410  					if (packet->payloadSize < m_MaxPayloadSize)
2411  						packet->payloadSize += CreatePaddingBlock (packet->payload + packet->payloadSize, m_MaxPayloadSize - packet->payloadSize);
2412  					uint32_t packetNum = aliceSession->SendData (packet->payload, packet->payloadSize);
2413  					packet->sendTime = ts;
2414  					aliceSession->m_SentPackets.emplace (packetNum, packet);
2415  				}
2416  				else
2417  					LogPrint (eLogDebug, "SSU2: Unknown peer test 3 nonce ", nonce);
2418  				break;
2419  			}
2420  			case 4: // Alice from Bob
2421  			{
2422  				auto session = m_Server.GetRequestedPeerTest (nonce);
2423  				if (session)
2424  				{
2425  					if (buf[1] == eSSU2PeerTestCodeAccept)
2426  					{
2427  						if (GetRouterStatus () == eRouterStatusUnknown)
2428  							SetTestingState (true);
2429  						auto r = i2p::data::netdb.FindRouter (buf + 3); // find Charlie
2430  						if (r && len >= offset + 9)
2431  						{
2432  							uint8_t asz = buf[offset + 9];
2433  							if (len < offset + asz + 10 + r->GetIdentity ()->GetSignatureLen ())
2434  							{
2435  								LogPrint (eLogWarning, "Malformed PeerTest 4 len=", len);
2436  								session->Done ();
2437  								return;
2438  							}
2439  							SignedData<128> s;
2440  							s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue
2441  							s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash
2442  							s.Insert (i2p::context.GetIdentity ()->GetIdentHash (), 32); // ahash
2443  							s.Insert (buf + offset, asz + 10); // ver, nonce, ts, asz, Alice's endpoint
2444  							if (s.Verify (r->GetIdentity (), buf + offset + asz + 10))
2445  							{
2446  								session->SetRemoteIdentity (r->GetIdentity ());
2447  								auto addr = r->GetSSU2Address (m_Address->IsV4 ());
2448  								if (addr && addr->IsPeerTesting ())
2449  								{
2450  									if (session->GetMsgNumReceived () >= 5)
2451  									{
2452  										// msg 5 already received and we know remote endpoint
2453  										if (session->GetMsgNumReceived () == 5)
2454  										{
2455  											if (!session->IsConnectedRecently ())
2456  												SetRouterStatus (eRouterStatusOK);
2457  										 	// send msg 6 immeditely
2458  											session->SendPeerTest (6, buf + offset, len - offset, addr);
2459  										}
2460  										else
2461  											LogPrint (eLogWarning, "SSU2: PeerTest 4 received, but msg ", session->GetMsgNumReceived (), " already received");
2462  									}
2463  									else
2464  									{
2465  										session->m_Address = addr;
2466  										if (GetTestingState ())
2467  										{
2468  											// schedule msg 6 with delay
2469  											if (!addr->host.is_unspecified () && addr->port)
2470  											{
2471  												session->SetRemoteEndpoint (boost::asio::ip::udp::endpoint (addr->host, addr->port));
2472  												session->SendPeerTest (6, buf + offset, len - offset, addr, true);
2473  											}
2474  											SetTestingState (false);
2475  											if (i2p::context.GetError () == eRouterErrorFullConeNAT)
2476  												SetRouterStatus (eRouterStatusOK);
2477  											else if (GetRouterStatus () != eRouterStatusFirewalled && addr->IsPeerTesting ())
2478  											{
2479  												SetRouterStatus (eRouterStatusFirewalled);
2480  												session->SetStatusChanged ();
2481  												if (m_Address->IsV4 ())
2482  													m_Server.RescheduleIntroducersUpdateTimer ();
2483  												else
2484  													m_Server.RescheduleIntroducersUpdateTimerV6 ();
2485  											}
2486  										}
2487  									}
2488  									LogPrint (eLogDebug, "SSU2: Peer test 4 received from ", i2p::data::GetIdentHashAbbreviation (GetRemoteIdentity ()->GetIdentHash ()),
2489  										" with information about ", i2p::data::GetIdentHashAbbreviation (i2p::data::IdentHash (buf + 3)));
2490  								}
2491  								else
2492  								{
2493  									LogPrint (eLogWarning, "SSU2: Peer test 4 address not found or not supported");
2494  									session->Done ();
2495  								}
2496  							}
2497  							else
2498  							{
2499  								LogPrint (eLogWarning, "SSU2: Peer test 4 signature verification failed");
2500  								session->Done ();
2501  							}
2502  						}
2503  						else
2504  						{
2505  							LogPrint (eLogWarning, "SSU2: Peer test 4 router not found");
2506  							session->Done ();
2507  						}
2508  					}
2509  					else
2510  					{
2511  						LogPrint (eLogInfo, "SSU2: Peer test 4 error code ", (int)buf[1], " from ",
2512  							i2p::data::GetIdentHashAbbreviation (buf[1] < 64 ? GetRemoteIdentity ()->GetIdentHash () : i2p::data::IdentHash (buf + 3)));
2513  						if (GetTestingState () && GetRouterStatus () != eRouterStatusFirewalled)
2514  							SetRouterStatus (eRouterStatusUnknown);
2515  						session->Done ();
2516  					}
2517  				}
2518  				else
2519  					LogPrint (eLogDebug, "SSU2: Unknown peer test 4 nonce ", nonce);
2520  				break;
2521  			}
2522  			default:
2523  				LogPrint (eLogWarning, "SSU2: PeerTest unexpected msg num ", buf[0]);
2524  		}
2525  	}
2526  
2527  	void SSU2Session::HandleI2NPMsg (std::shared_ptr<I2NPMessage>&& msg)
2528  	{
2529  		if (!msg) return;
2530  		uint32_t msgID = msg->GetMsgID ();
2531  		if (!msg->IsExpired ())
2532  		{
2533  			// m_LastActivityTimestamp is updated in ProcessData before
2534  			if (m_ReceivedI2NPMsgIDs.emplace (msgID, (uint32_t)GetLastActivityTimestamp ()).second)
2535  				m_Handler.PutNextMessage (std::move (msg));
2536  			else
2537  				LogPrint (eLogDebug, "SSU2: Message ", msgID, " already received");
2538  		}
2539  		else
2540  			LogPrint (eLogDebug, "SSU2: Message ", msgID, " expired");
2541  	}
2542  
2543  	bool SSU2Session::ExtractEndpoint (const uint8_t * buf, size_t size, boost::asio::ip::udp::endpoint& ep)
2544  	{
2545  		if (size < 2) return false;
2546  		int port = bufbe16toh (buf);
2547  		if (size == 6)
2548  		{
2549  			boost::asio::ip::address_v4::bytes_type bytes;
2550  			memcpy (bytes.data (), buf + 2, 4);
2551  			ep = boost::asio::ip::udp::endpoint (boost::asio::ip::address_v4 (bytes), port);
2552  		}
2553  		else if (size == 18)
2554  		{
2555  			boost::asio::ip::address_v6::bytes_type bytes;
2556  			memcpy (bytes.data (), buf + 2, 16);
2557  			ep = boost::asio::ip::udp::endpoint (boost::asio::ip::address_v6 (bytes), port);
2558  		}
2559  		else
2560  		{
2561  			LogPrint (eLogWarning, "SSU2: Address size ", int(size), " is not supported");
2562  			return false;
2563  		}
2564  		return true;
2565  	}
2566  
2567  	size_t SSU2Session::CreateEndpoint (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep)
2568  	{
2569  		if (len < 6) return 0;
2570  		htobe16buf (buf, ep.port ());
2571  		size_t size = 0;
2572  		if (ep.address ().is_v4 ())
2573  		{
2574  			memcpy (buf + 2, ep.address ().to_v4 ().to_bytes ().data (), 4);
2575  			size = 6;
2576  		}
2577  		else if (ep.address ().is_v6 ())
2578  		{
2579  			if (len < 18) return 0;
2580  			memcpy (buf + 2, ep.address ().to_v6 ().to_bytes ().data (), 16);
2581  			size = 18;
2582  		}
2583  		else
2584  		{
2585  			LogPrint (eLogWarning, "SSU2: Wrong address type ", ep.address ().to_string ());
2586  			return 0;
2587  		}
2588  		return size;
2589  	}
2590  
2591  	std::shared_ptr<const i2p::data::RouterInfo::Address> SSU2Session::FindLocalAddress () const
2592  	{
2593  		if (m_Address)
2594  			return i2p::context.GetRouterInfo ().GetSSU2Address (m_Address->IsV4 ());
2595  		else if (!m_RemoteEndpoint.address ().is_unspecified ())
2596  			return i2p::context.GetRouterInfo ().GetSSU2Address (m_RemoteEndpoint.address ().is_v4 ());
2597  		return nullptr;
2598  	}
2599  
2600  	void SSU2Session::AdjustMaxPayloadSize (size_t maxMtu)
2601  	{
2602  		auto addr = FindLocalAddress ();
2603  		if (addr && addr->ssu)
2604  		{
2605  			int mtu = addr->ssu->mtu;
2606  			if (!mtu && addr->IsV4 ()) mtu = SSU2_MAX_PACKET_SIZE;
2607  			if (mtu > (int)maxMtu) mtu = maxMtu;
2608  			if (m_Address && m_Address->ssu && (!mtu || m_Address->ssu->mtu < mtu))
2609  				mtu = m_Address->ssu->mtu;
2610  			if (mtu)
2611  			{
2612  				if (mtu > (int)SSU2_MAX_PACKET_SIZE) mtu = SSU2_MAX_PACKET_SIZE;
2613  				if (mtu < (int)SSU2_MIN_PACKET_SIZE) mtu = SSU2_MIN_PACKET_SIZE;
2614  				m_MaxPayloadSize = mtu - (addr->IsV6 () ? IPV6_HEADER_SIZE: IPV4_HEADER_SIZE) - UDP_HEADER_SIZE - 32;
2615  				LogPrint (eLogDebug, "SSU2: Session MTU=", mtu, ", max payload size=", m_MaxPayloadSize);
2616  			}
2617  		}
2618  	}
2619  
2620  	RouterStatus SSU2Session::GetRouterStatus () const
2621  	{
2622  		if (m_Address)
2623  		{
2624  			if (m_Address->IsV4 ())
2625  				return i2p::context.GetStatus ();
2626  			if (m_Address->IsV6 ())
2627  				return i2p::context.GetStatusV6 ();
2628  		}
2629  		return eRouterStatusUnknown;
2630  	}
2631  
2632  	void SSU2Session::SetRouterStatus (RouterStatus status) const
2633  	{
2634  		if (m_Address)
2635  		{
2636  			if (m_Address->IsV4 ())
2637  				i2p::context.SetStatus (status);
2638  			else if (m_Address->IsV6 ())
2639  				i2p::context.SetStatusV6 (status);
2640  		}
2641  	}
2642  
2643  	bool SSU2Session::GetTestingState () const
2644  	{
2645  		if (m_Address)
2646  		{
2647  			if (m_Address->IsV4 ())
2648  				return i2p::context.GetTesting ();
2649  			if (m_Address->IsV6 ())
2650  				return i2p::context.GetTestingV6 ();
2651  		}
2652  		return false;
2653  	}
2654  
2655  	void SSU2Session::SetTestingState (bool testing) const
2656  	{
2657  		if (m_Address)
2658  		{
2659  			if (m_Address->IsV4 ())
2660  				i2p::context.SetTesting (testing);
2661  			else if (m_Address->IsV6 ())
2662  				i2p::context.SetTestingV6 (testing);
2663  		}
2664  		if (!testing)
2665  			m_Server.AdjustTimeOffset (0, nullptr); // reset time offset when testing is over
2666  	}
2667  
2668  	size_t SSU2Session::CreateAddressBlock (uint8_t * buf, size_t len, const boost::asio::ip::udp::endpoint& ep)
2669  	{
2670  		if (len < 9) return 0;
2671  		buf[0] = eSSU2BlkAddress;
2672  		size_t size = CreateEndpoint (buf + 3, len - 3, ep);
2673  		if (!size) return 0;
2674  		htobe16buf (buf + 1, size);
2675  		return size + 3;
2676  	}
2677  
2678  	size_t SSU2Session::CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo> r)
2679  	{
2680  		if (!r || len < 5) return 0;
2681  		return CreateRouterInfoBlock (buf, len, r->GetSharedBuffer ());
2682  	}
2683  
2684  	size_t SSU2Session::CreateRouterInfoBlock (uint8_t * buf, size_t len, std::shared_ptr<const i2p::data::RouterInfo::Buffer> riBuffer)
2685  	{
2686  		if (!riBuffer || len < 5) return 0;
2687  		buf[0] = eSSU2BlkRouterInfo;
2688  		size_t size = riBuffer->GetBufferLen ();
2689  		if (size + 5 < len)
2690  		{
2691  			memcpy (buf + 5, riBuffer->data (), size);
2692  			buf[3] = 0; // flag
2693  		}
2694  		else
2695  		{
2696  			i2p::data::GzipDeflator deflator;
2697  			deflator.SetCompressionLevel (9);
2698  			size = deflator.Deflate (riBuffer->data (), riBuffer->GetBufferLen (), buf + 5, len - 5);
2699  			if (!size) return 0; // doesn't fit
2700  			buf[3] = SSU2_ROUTER_INFO_FLAG_GZIP; // flag
2701  		}
2702  		htobe16buf (buf + 1, size + 2); // size
2703  		buf[4] = 1; // frag
2704  		return size + 5;
2705  	}
2706  
2707  
2708  	size_t SSU2Session::CreateAckBlock (uint8_t * buf, size_t len)
2709  	{
2710  		if (len < 8) return 0;
2711  		buf[0] = eSSU2BlkAck;
2712  		uint32_t ackThrough = m_OutOfSequencePackets.empty () ? m_ReceivePacketNum : *m_OutOfSequencePackets.rbegin ();
2713  		htobe32buf (buf + 3, ackThrough); // Ack Through
2714  		uint16_t acnt = 0;
2715  		if (ackThrough)
2716  		{
2717  			if (m_OutOfSequencePackets.empty ())
2718  			{
2719  				acnt = std::min ((int)ackThrough, SSU2_MAX_NUM_ACNT); // no gaps
2720  				m_NumRanges = 0;
2721  			}
2722  			else
2723  			{
2724  				auto it = m_OutOfSequencePackets.rbegin (); it++; // prev packet num
2725  				while (it != m_OutOfSequencePackets.rend () && *it == ackThrough - acnt	- 1)
2726  				{
2727  					acnt++;
2728  					if (acnt >= SSU2_MAX_NUM_ACK_PACKETS)
2729  						break;
2730  					else
2731  						it++;
2732  				}
2733  				// ranges
2734  				if (!m_NumRanges)
2735  				{
2736  					int maxNumRanges = (len - 8) >> 1;
2737  					if (maxNumRanges > SSU2_MAX_NUM_ACK_RANGES) maxNumRanges = SSU2_MAX_NUM_ACK_RANGES;
2738  					int numRanges = 0;
2739  					uint32_t lastNum = ackThrough - acnt;
2740  					if (acnt > SSU2_MAX_NUM_ACNT)
2741  					{
2742  						auto d = std::div (acnt - SSU2_MAX_NUM_ACNT, SSU2_MAX_NUM_ACNT);
2743  						acnt = SSU2_MAX_NUM_ACNT;
2744  						if (d.quot > maxNumRanges)
2745  						{
2746  							d.quot = maxNumRanges;
2747  							d.rem = 0;
2748  						}
2749  						// Acks only ranges for acnt
2750  						for (int i = 0; i < d.quot; i++)
2751  						{
2752  							m_Ranges[numRanges*2] = 0; m_Ranges[numRanges*2 + 1] = SSU2_MAX_NUM_ACNT; // NACKs 0, Acks 255
2753  							numRanges++;
2754  						}
2755  						if (d.rem > 0)
2756  						{
2757  							m_Ranges[numRanges*2] = 0; m_Ranges[numRanges*2 + 1] = d.rem;
2758  							numRanges++;
2759  						}
2760  					}
2761  					int numPackets = acnt + numRanges*SSU2_MAX_NUM_ACNT;
2762  					while (it != m_OutOfSequencePackets.rend () &&
2763  						numRanges < maxNumRanges && numPackets < SSU2_MAX_NUM_ACK_PACKETS)
2764  					{
2765  						if (lastNum - (*it) > SSU2_MAX_NUM_ACNT)
2766  						{
2767  							// NACKs only ranges
2768  							if (lastNum > (*it) + SSU2_MAX_NUM_ACNT*(maxNumRanges - numRanges)) break; // too many NACKs
2769  							while (lastNum - (*it) > SSU2_MAX_NUM_ACNT)
2770  							{
2771  								m_Ranges[numRanges*2] = SSU2_MAX_NUM_ACNT; m_Ranges[numRanges*2 + 1] = 0; // NACKs 255, Acks 0
2772  								lastNum -= SSU2_MAX_NUM_ACNT;
2773  								numRanges++;
2774  								numPackets += SSU2_MAX_NUM_ACNT;
2775  							}
2776  						}
2777  						// NACKs and Acks ranges
2778  						m_Ranges[numRanges*2] = lastNum - (*it) - 1; // NACKs
2779  						numPackets += m_Ranges[numRanges*2];
2780  						lastNum = *it; it++;
2781  						int numAcks = 1;
2782  						while (it != m_OutOfSequencePackets.rend () && lastNum > 0 && *it == lastNum - 1)
2783  						{
2784  							numAcks++; lastNum--;
2785  							it++;
2786  						}
2787  						while (numAcks > SSU2_MAX_NUM_ACNT)
2788  						{
2789  							// Acks only ranges
2790  							m_Ranges[numRanges*2 + 1] = SSU2_MAX_NUM_ACNT; // Acks 255
2791  							numAcks -= SSU2_MAX_NUM_ACNT;
2792  							numRanges++;
2793  							numPackets += SSU2_MAX_NUM_ACNT;
2794  							m_Ranges[numRanges*2] = 0; // NACKs 0
2795  							if (numRanges >= maxNumRanges || numPackets >= SSU2_MAX_NUM_ACK_PACKETS) break;
2796  						}
2797  						if (numAcks > SSU2_MAX_NUM_ACNT) numAcks = SSU2_MAX_NUM_ACNT;
2798  						m_Ranges[numRanges*2 + 1] = (uint8_t)numAcks; // Acks
2799  						numPackets += numAcks;
2800  						numRanges++;
2801  					}
2802  					if (it == m_OutOfSequencePackets.rend () &&
2803  						numRanges < maxNumRanges && numPackets < SSU2_MAX_NUM_ACK_PACKETS)
2804  					{
2805  						// add range between out-of-sequence and received
2806  						int nacks = *m_OutOfSequencePackets.begin () - m_ReceivePacketNum - 1;
2807  						if (nacks > 0)
2808  						{
2809  							if (nacks > SSU2_MAX_NUM_ACNT) nacks = SSU2_MAX_NUM_ACNT;
2810  							m_Ranges[numRanges*2] = nacks;
2811  							m_Ranges[numRanges*2 + 1] = std::min ((int)m_ReceivePacketNum + 1, SSU2_MAX_NUM_ACNT);
2812  							numRanges++;
2813  						}
2814  					}
2815  					m_NumRanges = numRanges;
2816  				}
2817  				if (m_NumRanges)
2818  					memcpy (buf + 8, m_Ranges, m_NumRanges*2);
2819  			}
2820  		}
2821  		buf[7] = (uint8_t)acnt; // acnt
2822  		htobe16buf (buf + 1, 5 + m_NumRanges*2);
2823  		return 8 + m_NumRanges*2;
2824  	}
2825  
2826  	size_t SSU2Session::CreatePaddingBlock (uint8_t * buf, size_t len, size_t minSize)
2827  	{
2828  		if (len < 3 || len < minSize) return 0;
2829  		size_t paddingSize = m_Server.GetRng ()() & 0x1F; // 0 - 31
2830  		if (paddingSize + 3 > len) paddingSize = len - 3;
2831  		else if (paddingSize + 3 < minSize) paddingSize = minSize - 3;
2832  		buf[0] = eSSU2BlkPadding;
2833  		htobe16buf (buf + 1, paddingSize);
2834  		memset (buf + 3, 0, paddingSize);
2835  		return paddingSize + 3;
2836  	}
2837  
2838  	size_t SSU2Session::CreateI2NPBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage>&& msg)
2839  	{
2840  		msg->ToNTCP2 ();
2841  		auto msgBuf = msg->GetNTCP2Header ();
2842  		auto msgLen = msg->GetNTCP2Length ();
2843  		if (msgLen + 3 > len) msgLen = len - 3;
2844  		buf[0] = eSSU2BlkI2NPMessage;
2845  		htobe16buf (buf + 1, msgLen); // size
2846  		memcpy (buf + 3, msgBuf, msgLen);
2847  		return msgLen + 3;
2848  	}
2849  
2850  	size_t SSU2Session::CreateFirstFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg)
2851  	{
2852  		if (len < 12) return 0;
2853  		msg->ToNTCP2 ();
2854  		auto msgBuf = msg->GetNTCP2Header ();
2855  		auto msgLen = msg->GetNTCP2Length ();
2856  		if (msgLen + 3 <= len) return 0;
2857  		msgLen = len - 3;
2858  		buf[0] = eSSU2BlkFirstFragment;
2859  		htobe16buf (buf + 1, msgLen); // size
2860  		memcpy (buf + 3, msgBuf, msgLen);
2861  		msg->offset = (msgBuf - msg->buf) + msgLen;
2862  		return msgLen + 3;
2863  	}
2864  
2865  	size_t SSU2Session::CreateFollowOnFragmentBlock (uint8_t * buf, size_t len, std::shared_ptr<I2NPMessage> msg, uint8_t& fragmentNum, uint32_t msgID)
2866  	{
2867  		if (len < 8) return 0;
2868  		bool isLast = true;
2869  		auto msgLen = msg->len - msg->offset;
2870  		if (msgLen + 8 > len)
2871  		{
2872  			msgLen = len - 8;
2873  			isLast = false;
2874  		}
2875  		buf[0] = eSSU2BlkFollowOnFragment;
2876  		htobe16buf (buf + 1, msgLen + 5); // size
2877  		fragmentNum++;
2878  		buf[3] = fragmentNum << 1;
2879  		if (isLast) buf[3] |= 0x01;
2880  		memcpy (buf + 4, &msgID, 4);
2881  		memcpy (buf + 8, msg->buf + msg->offset, msgLen);
2882  		msg->offset += msgLen;
2883  		return msgLen + 8;
2884  	}
2885  
2886  	size_t SSU2Session::CreateRelayIntroBlock (uint8_t * buf, size_t len, const uint8_t * introData, size_t introDataLen)
2887  	{
2888  		buf[0] = eSSU2BlkRelayIntro;
2889  		size_t payloadSize = 1/* flag */ + 32/* Alice router hash */ + introDataLen;
2890  		if (payloadSize + 3 > len) return 0;
2891  		htobe16buf (buf + 1, payloadSize); // size
2892  		buf[3] = 0; // flag
2893  		memcpy (buf + 4, GetRemoteIdentity ()->GetIdentHash (), 32); // Alice router hash
2894  		memcpy (buf + 36, introData, introDataLen);
2895  		return payloadSize + 3;
2896  	}
2897  
2898  	size_t SSU2Session::CreateRelayResponseBlock (uint8_t * buf, size_t len,
2899  		SSU2RelayResponseCode code, uint32_t nonce, uint64_t token, bool v4)
2900  	{
2901  		buf[0] = eSSU2BlkRelayResponse;
2902  		buf[3] = 0; // flag
2903  		buf[4] = code; // code
2904  		htobe32buf (buf + 5, nonce); // nonce
2905  		htobe32buf (buf + 9, i2p::util::GetSecondsSinceEpoch ()); // timestamp
2906  		buf[13] = 2; // ver
2907  		size_t csz = 0;
2908  		if (code == eSSU2RelayResponseCodeAccept)
2909  		{
2910  			auto addr = i2p::context.GetRouterInfo ().GetSSU2Address (v4);
2911  			if (!addr)
2912  			{
2913  				LogPrint (eLogError, "SSU2: Can't find local address for RelayResponse");
2914  				return 0;
2915  			}
2916  			csz = CreateEndpoint (buf + 15, len - 15, boost::asio::ip::udp::endpoint (addr->host, addr->port));
2917  			if (!csz)
2918  			{
2919  				LogPrint (eLogError, "SSU2: Can't create local endpoint for RelayResponse");
2920  				return 0;
2921  			}
2922  		}
2923  		buf[14] = csz; // csz
2924  		// signature
2925  		size_t signatureLen = i2p::context.GetIdentity ()->GetSignatureLen ();
2926  		if (15 + csz + signatureLen > len)
2927  		{
2928  			LogPrint (eLogError, "SSU2: Buffer for RelayResponse signature is too small ", len);
2929  			return 0;
2930  		}
2931  		SignedData<128> s;
2932  		s.Insert ((const uint8_t *)"RelayAgreementOK", 16); // prologue
2933  		if (code == eSSU2RelayResponseCodeAccept || code >= 64) // Charlie
2934  			s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash
2935  		else // Bob's reject
2936  			s.Insert (i2p::context.GetIdentity ()->GetIdentHash (), 32); // bhash
2937  		s.Insert (buf + 5, 10 + csz); // nonce, timestamp, ver, csz and Charlie's endpoint
2938  		s.Sign (i2p::context.GetPrivateKeys (), buf + 15 + csz);
2939  		size_t payloadSize = 12 + csz + signatureLen;
2940  		if (!code)
2941  		{
2942  			if (payloadSize + 11 > len)
2943  			{
2944  				LogPrint (eLogError, "SSU2: Buffer for RelayResponse token is too small ", len);
2945  				return 0;
2946  			}
2947  			memcpy (buf + 3 + payloadSize, &token, 8);
2948  			payloadSize += 8;
2949  		}
2950  		htobe16buf (buf + 1, payloadSize); // size
2951  		return payloadSize + 3;
2952  	}
2953  
2954  	size_t SSU2Session::CreatePeerTestBlock (uint8_t * buf, size_t len, uint8_t msg, SSU2PeerTestCode code,
2955  		const uint8_t * routerHash, const uint8_t * signedData, size_t signedDataLen)
2956  	{
2957  		buf[0] = eSSU2BlkPeerTest;
2958  		size_t payloadSize = 3/* msg, code, flag */ + signedDataLen;
2959  		if (routerHash) payloadSize += 32; // router hash
2960  		if (payloadSize + 3 > len) return 0;
2961  		htobe16buf (buf + 1, payloadSize); // size
2962  		buf[3] = msg; // msg
2963  		buf[4] = (uint8_t)code; // code
2964  		buf[5] = 0; //flag
2965  		size_t offset = 6;
2966  		if (routerHash)
2967  		{
2968  			memcpy (buf + offset, routerHash, 32); // router hash
2969  			offset += 32;
2970  		}
2971  		memcpy (buf + offset, signedData, signedDataLen);
2972  		return payloadSize + 3;
2973  	}
2974  
2975  	size_t SSU2Session::CreatePeerTestBlock (uint8_t * buf, size_t len, uint32_t nonce)
2976  	{
2977  		auto localAddress = FindLocalAddress ();
2978  		if (!localAddress || !localAddress->port || localAddress->host.is_unspecified () ||
2979  		    localAddress->host.is_v4 () != m_RemoteEndpoint.address ().is_v4 ())
2980  		{
2981  			LogPrint (eLogWarning, "SSU2: Can't find local address for peer test");
2982  			return 0;
2983  		}
2984  		// signed data
2985  		auto ts = i2p::util::GetSecondsSinceEpoch ();
2986  		uint8_t signedData[96];
2987  		signedData[0] = 2; // ver
2988  		htobe32buf (signedData + 1, nonce);
2989  		htobe32buf (signedData + 5, ts);
2990  		size_t asz = CreateEndpoint (signedData + 10, 86, boost::asio::ip::udp::endpoint (localAddress->host, localAddress->port));
2991  		signedData[9] = asz;
2992  		// signature
2993  		SignedData<128> s;
2994  		s.Insert ((const uint8_t *)"PeerTestValidate", 16); // prologue
2995  		s.Insert (GetRemoteIdentity ()->GetIdentHash (), 32); // bhash
2996  		s.Insert (signedData, 10 + asz); // ver, nonce, ts, asz, Alice's endpoint
2997  		s.Sign (i2p::context.GetPrivateKeys (), signedData + 10 + asz);
2998  		return CreatePeerTestBlock (buf, len, 1, eSSU2PeerTestCodeAccept, nullptr,
2999  			signedData, 10 + asz + i2p::context.GetIdentity ()->GetSignatureLen ());
3000  	}
3001  
3002  	size_t SSU2Session::CreateTerminationBlock (uint8_t * buf, size_t len)
3003  	{
3004  		buf[0] = eSSU2BlkTermination;
3005  		htobe16buf (buf + 1, 9);
3006  		htobe64buf (buf + 3, m_ReceivePacketNum);
3007  		buf[11] = (uint8_t)m_TerminationReason;
3008  		return 12;
3009  	}
3010  
3011  	std::shared_ptr<const i2p::data::RouterInfo> SSU2Session::ExtractRouterInfo (const uint8_t * buf, size_t size)
3012  	{
3013  		if (size < 2) return nullptr;
3014  		// TODO: handle frag
3015  		std::shared_ptr<const i2p::data::RouterInfo> ri;
3016  		if (buf[0] & SSU2_ROUTER_INFO_FLAG_GZIP)
3017  		{
3018  			i2p::data::GzipInflator inflator;
3019  			uint8_t uncompressed[i2p::data::MAX_RI_BUFFER_SIZE];
3020  			size_t uncompressedSize = inflator.Inflate (buf + 2, size - 2, uncompressed, i2p::data::MAX_RI_BUFFER_SIZE);
3021  			if (uncompressedSize && uncompressedSize <= i2p::data::MAX_RI_BUFFER_SIZE)
3022  				ri = std::make_shared<i2p::data::RouterInfo>(uncompressed, uncompressedSize);
3023  			else
3024  				LogPrint (eLogInfo, "SSU2: RouterInfo decompression failed ", uncompressedSize);
3025  		}
3026  		else if (size <= i2p::data::MAX_RI_BUFFER_SIZE + 2)
3027  			ri = std::make_shared<i2p::data::RouterInfo>(buf + 2, size - 2);
3028  		else
3029  			LogPrint (eLogInfo, "SSU2: RouterInfo is too long ", size);
3030  		return ri;
3031  	}
3032  
3033  	bool SSU2Session::UpdateReceivePacketNum (uint32_t packetNum)
3034  	{
3035  		if (packetNum <= m_ReceivePacketNum) return false; // duplicate
3036  		if (packetNum == m_ReceivePacketNum + 1)
3037  		{
3038  			if (!m_OutOfSequencePackets.empty ())
3039  			{
3040  				auto it = m_OutOfSequencePackets.begin ();
3041  				if (*it == packetNum + 1)
3042  				{
3043  					// first out of sequence packet is in sequence now
3044  					packetNum++; it++;
3045  					while (it != m_OutOfSequencePackets.end ())
3046  					{
3047  						if (*it == packetNum + 1)
3048  						{
3049  							packetNum++;
3050  							it++;
3051  						}
3052  						else // next out of sequence
3053  							break;
3054  					}
3055  					m_OutOfSequencePackets.erase (m_OutOfSequencePackets.begin (), it);
3056  				}
3057  				m_NumRanges = 0; // recalculate ranges when create next Ack
3058  			}
3059  			m_ReceivePacketNum = packetNum;
3060  		}
3061  		else
3062  		{
3063  			if (m_NumRanges && (m_OutOfSequencePackets.empty () ||
3064  				packetNum != (*m_OutOfSequencePackets.rbegin ()) + 1))
3065  				m_NumRanges = 0; // reset ranges if received packet is not next
3066  			m_OutOfSequencePackets.insert (packetNum);
3067  		}
3068  		return true;
3069  	}
3070  
3071  	void SSU2Session::SendQuickAck ()
3072  	{
3073  		uint8_t payload[SSU2_MAX_PACKET_SIZE];
3074  		size_t payloadSize = 0;
3075  		if (m_SendPacketNum > m_LastDatetimeSentPacketNum + SSU2_SEND_DATETIME_NUM_PACKETS)
3076  		{
3077  			payload[0] = eSSU2BlkDateTime;
3078  			htobe16buf (payload + 1, 4);
3079  			htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000);
3080  			payloadSize += 7;
3081  			m_LastDatetimeSentPacketNum = m_SendPacketNum;
3082  		}
3083  		payloadSize += CreateAckBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
3084  		payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
3085  		SendData (payload, payloadSize);
3086  	}
3087  
3088  	void SSU2Session::SendTermination ()
3089  	{
3090  		uint8_t payload[32];
3091  		size_t payloadSize = CreateTerminationBlock (payload, 32);
3092  		payloadSize += CreatePaddingBlock (payload + payloadSize, 32 - payloadSize);
3093  		SendData (payload, payloadSize);
3094  	}
3095  
3096  	void SSU2Session::SendPathResponse (const uint8_t * data, size_t len)
3097  	{
3098  		uint8_t payload[SSU2_MAX_PACKET_SIZE];
3099  		size_t payloadSize = 0;
3100  		// datetime block
3101  		payload[0] = eSSU2BlkDateTime;
3102  		htobe16buf (payload + 1, 4);
3103  		htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000);
3104  		payloadSize += 7;
3105  		// address block
3106  		payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize  - payloadSize, m_RemoteEndpoint);
3107  		// path response
3108  		if (payloadSize + len > m_MaxPayloadSize)
3109  		{
3110  			LogPrint (eLogWarning, "SSU2: Incorrect data size for path response ", len);
3111  			return;
3112  		}
3113  		payload[payloadSize] = eSSU2BlkPathResponse;
3114  		htobe16buf (payload + payloadSize + 1, len);
3115  		memcpy (payload + payloadSize + 3, data, len);
3116  		payloadSize += len + 3;
3117  		// ack block
3118  		if (payloadSize < m_MaxPayloadSize)
3119  			payloadSize += CreateAckBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
3120  		// padding
3121  		if (payloadSize < m_MaxPayloadSize)
3122  			payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
3123  		SendData (payload, payloadSize);
3124  	}
3125  
3126  	void SSU2Session::SendPathChallenge (const boost::asio::ip::udp::endpoint& to)
3127  	{
3128  		AdjustMaxPayloadSize (SSU2_MIN_PACKET_SIZE); // reduce to minimum
3129  		m_WindowSize = SSU2_MIN_WINDOW_SIZE; // reduce window to minimum
3130  
3131  		uint8_t payload[SSU2_MAX_PACKET_SIZE];
3132  		size_t payloadSize = 0;
3133  		// datetime block
3134  		payload[0] = eSSU2BlkDateTime;
3135  		htobe16buf (payload + 1, 4);
3136  		htobe32buf (payload + 3, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000);
3137  		payloadSize += 7;
3138  		// address block with new address
3139  		payloadSize += CreateAddressBlock (payload + payloadSize, m_MaxPayloadSize  - payloadSize, to);
3140  		// path challenge block
3141  		payload[payloadSize] = eSSU2BlkPathChallenge;
3142  		uint64_t challenge;
3143  		RAND_bytes ((uint8_t *)&challenge, 8);
3144  		htobe16buf (payload + payloadSize + 1, 8); // always 8 bytes
3145  		htobuf64 (payload + payloadSize + 3, challenge);
3146  		payloadSize += 11;
3147  		m_PathChallenge = std::make_unique<std::pair<uint64_t, boost::asio::ip::udp::endpoint> >(challenge, to);
3148  		// ack block
3149  		if (payloadSize < m_MaxPayloadSize)
3150  			payloadSize += CreateAckBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
3151  		// padding block
3152  		if (payloadSize < m_MaxPayloadSize)
3153  			payloadSize += CreatePaddingBlock (payload + payloadSize, m_MaxPayloadSize - payloadSize);
3154  		// send to new endpoint
3155  		auto existing = m_RemoteEndpoint;
3156  		m_RemoteEndpoint = to; // send path challenge to new endpoint
3157  		SendData (payload, payloadSize);
3158  		m_RemoteEndpoint = existing; // restore endpoint back until path response received
3159  	}
3160  
3161  	void SSU2Session::CleanUp (uint64_t ts)
3162  	{
3163  		for (auto it = m_IncompleteMessages.begin (); it != m_IncompleteMessages.end ();)
3164  		{
3165  			if (ts > it->second->lastFragmentInsertTime + SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT)
3166  			{
3167  				LogPrint (eLogWarning, "SSU2: message ", it->first, " was not completed in ", SSU2_INCOMPLETE_MESSAGES_CLEANUP_TIMEOUT, " seconds, deleted");
3168  				it = m_IncompleteMessages.erase (it);
3169  			}
3170  			else
3171  				++it;
3172  		}
3173  		if (m_ReceivedI2NPMsgIDs.size () > SSU2_MAX_NUM_RECEIVED_I2NP_MSGIDS || ts > GetLastActivityTimestamp () + SSU2_DECAY_INTERVAL)
3174  			// decay
3175  			m_ReceivedI2NPMsgIDs.clear ();
3176  		else
3177  		{
3178  			// delete old received msgIDs
3179  			for (auto it = m_ReceivedI2NPMsgIDs.begin (); it != m_ReceivedI2NPMsgIDs.end ();)
3180  			{
3181  				if (ts > it->second + SSU2_RECEIVED_I2NP_MSGIDS_CLEANUP_TIMEOUT)
3182  					it = m_ReceivedI2NPMsgIDs.erase (it);
3183  				else
3184  					++it;
3185  			}
3186  		}
3187  		if (!m_OutOfSequencePackets.empty ())
3188  		{
3189  			int ranges = 0;
3190  			while (ranges < 8 && !m_OutOfSequencePackets.empty () &&
3191  				(m_OutOfSequencePackets.size () > 2*SSU2_MAX_NUM_ACK_RANGES ||
3192  			    *m_OutOfSequencePackets.rbegin () > m_ReceivePacketNum + SSU2_MAX_NUM_ACK_PACKETS))
3193  			{
3194  				uint32_t packet = *m_OutOfSequencePackets.begin ();
3195  				if (packet > m_ReceivePacketNum + 1)
3196  				{
3197  					// like we've just received all packets before first
3198  					packet--;
3199  					m_ReceivePacketNum = packet - 1;
3200  					UpdateReceivePacketNum (packet);
3201  					ranges++;
3202  				}
3203  				else
3204  				{
3205  					LogPrint (eLogError, "SSU2: Out of sequence packet ", packet, " is less than last received ", m_ReceivePacketNum);
3206  					break;
3207  				}
3208  			}
3209  			if (m_OutOfSequencePackets.size () > 255*4)
3210  			{
3211  				// seems we have a serious network issue
3212  				m_ReceivePacketNum = *m_OutOfSequencePackets.rbegin ();
3213  				m_OutOfSequencePackets.clear ();
3214  			}
3215  		}
3216  
3217  		for (auto it = m_RelaySessions.begin (); it != m_RelaySessions.end ();)
3218  		{
3219  			if (ts > it->second.second + SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT)
3220  			{
3221  				LogPrint (eLogInfo, "SSU2: Relay nonce ", it->first, " was not responded in ", SSU2_RELAY_NONCE_EXPIRATION_TIMEOUT, " seconds, deleted");
3222  				it = m_RelaySessions.erase (it);
3223  			}
3224  			else
3225  				++it;
3226  		}
3227  		if (m_PathChallenge)
3228  			RequestTermination (eSSU2TerminationReasonNormalClose);
3229  	}
3230  
3231  	void SSU2Session::FlushData ()
3232  	{
3233  		bool sent = SendQueue (); // if we have something to send
3234  		if (sent)
3235  			SetSendQueueSize (m_SendQueue.size ());
3236  		if (m_IsDataReceived)
3237  		{
3238  			if (!sent) SendQuickAck ();
3239  			m_Handler.Flush ();
3240  			m_IsDataReceived = false;
3241  		}
3242  		else if (!sent && !m_SentPackets.empty ()) // if only acks received, nothing sent and we still have something to resend
3243  			Resend (i2p::util::GetMillisecondsSinceEpoch ()); // than right time to resend
3244  	}
3245  
3246  	i2p::data::RouterInfo::SupportedTransports SSU2Session::GetTransportType () const
3247  	{
3248  		return m_RemoteEndpoint.address ().is_v4 () ? i2p::data::RouterInfo::eSSU2V4 : i2p::data::RouterInfo::eSSU2V6;
3249  	}
3250  }
3251  }