/ libi2pd / NTCP2.cpp
NTCP2.cpp
   1  /*
   2  * Copyright (c) 2013-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  
  10  #include <openssl/rand.h>
  11  #include <openssl/sha.h>
  12  #include <openssl/hmac.h>
  13  #include <stdlib.h>
  14  #include <vector>
  15  #include <chrono>
  16  #include "Log.h"
  17  #include "I2PEndian.h"
  18  #include "Crypto.h"
  19  #include "Siphash.h"
  20  #include "RouterContext.h"
  21  #include "Transports.h"
  22  #include "NetDb.hpp"
  23  #include "HTTP.h"
  24  #include "util.h"
  25  #include "Socks5.h"
  26  #include "NTCP2.h"
  27  
  28  #if defined(__linux__) && !defined(_NETINET_IN_H)
  29  	#include <linux/in6.h>
  30  #endif
  31  
  32  namespace i2p
  33  {
  34  namespace transport
  35  {
  36  	NTCP2Establisher::NTCP2Establisher ():
  37  		m_SessionConfirmedBuffer (nullptr), m_BufferLen (0)
  38  	{
  39          SetVersion (2);
  40  	}
  41  
  42  	NTCP2Establisher::~NTCP2Establisher ()
  43  	{
  44  		delete[] m_SessionConfirmedBuffer;
  45  	}
  46  
  47  	void NTCP2Establisher::SetVersion (int version)
  48  	{
  49  #if OPENSSL_PQ
  50          switch (version)
  51          {
  52              case 3:
  53                   m_CryptoType = i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM512_X25519_AEAD;
  54              break;
  55              case 4:
  56                   m_CryptoType = i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM768_X25519_AEAD;
  57              break;
  58              case 5:
  59                   m_CryptoType = i2p::data::CRYPTO_KEY_TYPE_ECIES_MLKEM1024_X25519_AEAD;
  60              break;
  61              default:
  62                  m_CryptoType = i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD;
  63          }
  64  #else
  65          m_CryptoType = i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD;
  66  #endif
  67  	}
  68  
  69  	bool NTCP2Establisher::KeyDerivationFunction1 (const uint8_t * pub, i2p::crypto::X25519Keys& priv, const uint8_t * rs, const uint8_t * epub)
  70  	{
  71  #if OPENSSL_PQ
  72          if (m_CryptoType == i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
  73              i2p::crypto::InitNoiseXKState (*this, rs);
  74          else
  75              i2p::crypto::InitNoiseXKStateMLKEM (*this, m_CryptoType, rs);
  76  #else
  77  		i2p::crypto::InitNoiseXKState (*this, rs);
  78  #endif
  79  		// h = SHA256(h || epub)
  80  		MixHash (epub, 32);
  81  		// x25519 between pub and priv
  82  		uint8_t inputKeyMaterial[32];
  83  		if (!priv.Agree (pub, inputKeyMaterial)) return false;
  84  		MixKey (inputKeyMaterial);
  85  		return true;
  86  	}
  87  
  88  	bool NTCP2Establisher::KDF1Alice ()
  89  	{
  90  		return KeyDerivationFunction1 (m_RemoteStaticKey, *m_EphemeralKeys, m_RemoteStaticKey, GetPub ());
  91  	}
  92  
  93  	bool NTCP2Establisher::KDF1Bob ()
  94  	{
  95  		return KeyDerivationFunction1 (GetRemotePub (), i2p::context.GetNTCP2StaticKeys (), i2p::context.GetNTCP2StaticPublicKey (), GetRemotePub ());
  96  	}
  97  
  98  	bool NTCP2Establisher::KeyDerivationFunction2 (const uint8_t * epub)
  99  	{
 100  		MixHash (epub, 32);
 101  
 102  		// x25519 between remote pub and ephemaral priv
 103  		uint8_t inputKeyMaterial[32];
 104  		if (!m_EphemeralKeys->Agree (GetRemotePub (), inputKeyMaterial)) return false;
 105  		MixKey (inputKeyMaterial);
 106  		return true;
 107  	}
 108  
 109  	bool NTCP2Establisher::KDF2Alice ()
 110  	{
 111  		return KeyDerivationFunction2 (GetRemotePub ());
 112  	}
 113  
 114  	bool NTCP2Establisher::KDF2Bob ()
 115  	{
 116  		return KeyDerivationFunction2 (GetPub ());
 117  	}
 118  
 119  	bool NTCP2Establisher::KDF3Alice ()
 120  	{
 121  		uint8_t inputKeyMaterial[32];
 122  		if (!i2p::context.GetNTCP2StaticKeys ().Agree (GetRemotePub (), inputKeyMaterial)) return false;
 123  		MixKey (inputKeyMaterial);
 124  		return true;
 125  	}
 126  
 127  	bool NTCP2Establisher::KDF3Bob ()
 128  	{
 129  		uint8_t inputKeyMaterial[32];
 130  		if (!m_EphemeralKeys->Agree (m_RemoteStaticKey, inputKeyMaterial)) return false;
 131  		MixKey (inputKeyMaterial);
 132  		return true;
 133  	}
 134  
 135  	void NTCP2Establisher::CreateEphemeralKey ()
 136  	{
 137  		m_EphemeralKeys = i2p::transport::transports.GetNextX25519KeysPair ();
 138  	}
 139  
 140  	void NTCP2Establisher::ApplyPadding (uint8_t * padding, size_t paddingLength)
 141  	{
 142          MixHash (padding, paddingLength);
 143  	}
 144  
 145  	bool NTCP2Establisher::CreateSessionRequestMessage (std::mt19937& rng)
 146  	{
 147  		size_t offset  = 0;
 148  		// encrypt X
 149  		i2p::crypto::CBCEncryption encryption;
 150  		encryption.SetKey (m_RemoteIdentHash);
 151  #if OPENSSL_PQ
 152          if (m_CryptoType > i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
 153          {
 154              uint8_t pub[32];
 155              memcpy (pub, GetPub (), 32);
 156              pub[31] |= 0x80; // set highest bit
 157              encryption.Encrypt (pub, 32, m_IV, m_Buffer); // X
 158              //  ML-KEM encap_key
 159              m_PQKeys = i2p::crypto::CreateMLKEMKeys (m_CryptoType);
 160              m_PQKeys->GenerateKeys ();
 161          }
 162          else
 163              encryption.Encrypt (GetPub (), 32, m_IV, m_Buffer); // X
 164  #else
 165  		encryption.Encrypt (GetPub (), 32, m_IV, m_Buffer); // X
 166  #endif
 167  		memcpy (m_IV, m_Buffer + 16, 16); // save last block as IV for SessionCreated
 168  		offset += 32;
 169  		// encryption key for next block
 170  		if (!KDF1Alice ()) return false;
 171  		size_t maxMsgLength = NTCP2_SESSION_REQUEST_MAX_SIZE;
 172  #if OPENSSL_PQ
 173          if (m_PQKeys)
 174          {
 175              // ML-KEM frame
 176              auto keyLen = i2p::crypto::GetMLKEMPublicKeyLen (m_CryptoType);
 177  			std::vector<uint8_t> encapsKey(keyLen);
 178  			m_PQKeys->GetPublicKey (encapsKey.data ());
 179  			// encrypt encapsKey
 180  			if (!Encrypt (encapsKey.data (), m_Buffer + offset, keyLen))
 181  			{
 182  				LogPrint (eLogWarning, "NTCP2: SessionRequest ML-KEM encap_key frame AEAD encryption failed ");
 183  				return false;
 184  			}
 185  			MixHash (m_Buffer + offset, keyLen + 16); // h = SHA256(h || ciphertext)
 186  			offset += keyLen + 16;
 187  			maxMsgLength += keyLen + 16;
 188          }
 189  #endif
 190          // calculate padding length
 191  		auto paddingLength = (offset + 32 < maxMsgLength) ? (rng () % (maxMsgLength - offset - 32)) : 0; // 32 bytes following options block size
 192  		// fill options
 193  		uint8_t options[32]; // actual options size is 16 bytes
 194  		memset (options, 0, 16);
 195  		options[0] = i2p::context.GetNetID (); // network ID
 196  		options[1] = 2; // ver, always 2 regradless actual version
 197  		htobe16buf (options + 2, paddingLength); // padLen
 198  		// calculate m3p2Len
 199  		auto riBuffer = i2p::context.CopyRouterInfoBuffer ();
 200  		auto bufLen = riBuffer->GetBufferLen ();
 201  		m3p2Len = bufLen + 4 + 16; // (RI header + RI + MAC for now) TODO: implement options
 202  		htobe16buf (options + 4, m3p2Len);
 203  		// 2 bytes reserved
 204  		htobe32buf (options + 8, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); // tsA, rounded to seconds
 205  		// 4 bytes reserved
 206  		// encrypt options
 207  		if (!Encrypt (options, m_Buffer + offset, 16))
 208  		{
 209  			LogPrint (eLogWarning, "NTCP2: SessionRequest options frame AEAD encryption failed");
 210  			return false;
 211  		}
 212  		MixHash (m_Buffer + offset, 32);
 213  		offset += 32;
 214          // padding
 215          if (paddingLength)
 216          {
 217              RAND_bytes (m_Buffer + offset, paddingLength);
 218              MixHash (m_Buffer + offset, paddingLength);
 219  		}
 220  		m_BufferLen = offset + paddingLength;
 221  		// create m3p2 payload (RouterInfo block) for SessionConfirmed
 222  		m_SessionConfirmedBuffer = new uint8_t[m3p2Len + 48]; // m3p1 is 48 bytes
 223  		uint8_t * m3p2 = m_SessionConfirmedBuffer + 48;
 224  		m3p2[0] = eNTCP2BlkRouterInfo; // block
 225  		htobe16buf (m3p2 + 1, bufLen + 1); // flag + RI
 226  		m3p2[3] = 0; // flag
 227  		memcpy (m3p2 + 4, riBuffer->data (), bufLen); // TODO: eliminate extra copy
 228  
 229  		return true;
 230  	}
 231  
 232  	bool NTCP2Establisher::CreateSessionCreatedMessage (std::mt19937& rng)
 233  	{
 234  		size_t offset = 0;
 235  		// encrypt Y
 236  		i2p::crypto::CBCEncryption encryption;
 237  		encryption.SetKey (i2p::context.GetIdentHash ());
 238  		encryption.Encrypt (GetPub (), 32, m_IV, m_Buffer); // Y
 239  		offset += 32;
 240  		// encryption key for next block (m_K)
 241  		if (!KDF2Bob ()) return false;
 242  		size_t maxMsgLength = NTCP2_SESSION_CREATED_MAX_SIZE;
 243  #if OPENSSL_PQ
 244          if (m_PQKeys)
 245          {
 246              size_t cipherTextLen = i2p::crypto::GetMLKEMCipherTextLen (m_CryptoType);
 247  			std::vector<uint8_t> kemCiphertext(cipherTextLen);
 248  			uint8_t sharedSecret[32];
 249  			m_PQKeys->Encaps (kemCiphertext.data (), sharedSecret);
 250  			if (!Encrypt (kemCiphertext.data (), m_Buffer + offset, cipherTextLen))
 251  			{
 252  				LogPrint (eLogWarning, "NTCP2: SessionCreated ML-KEM ciphertext section AEAD encryption failed");
 253  				return false;
 254  			}
 255  			MixHash (m_Buffer + offset, cipherTextLen + 16); // encrypt ML-KEM frame
 256  			MixKey (sharedSecret);
 257              offset += cipherTextLen + 16;
 258          }
 259  #endif
 260           // calculate padding length
 261  		auto paddingLen = (offset + 32 < maxMsgLength) ? (rng () % (maxMsgLength - offset - 32)) : 0; // 32 bytes following options block size
 262  		uint8_t options[16];
 263  		memset (options, 0, 16);
 264  		htobe16buf (options + 2, paddingLen); // padLen
 265  		htobe32buf (options + 8, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000); // tsB, rounded to seconds
 266  		// encrypt options
 267  		if (!Encrypt (options, m_Buffer + offset, 16))
 268  		{
 269  			LogPrint (eLogWarning, "NTCP2: SessionCreated failed to encrypt options");
 270  			return false;
 271  		}
 272  		MixHash (m_Buffer + offset, 32);	// encrypted options
 273  		offset += 32;
 274          // padding
 275          if (paddingLen)
 276          {
 277              RAND_bytes (m_Buffer + offset, paddingLen);
 278              MixHash (m_Buffer + offset, paddingLen);
 279          }
 280          m_BufferLen = offset + paddingLen;
 281  		return true;
 282  	}
 283  
 284  	bool NTCP2Establisher::CreateSessionConfirmedMessagePart1 ()
 285  	{
 286  		// part1 48 bytes, n = 1
 287  		if (!Encrypt (i2p::context.GetNTCP2StaticPublicKey (), m_SessionConfirmedBuffer, 32))
 288  		{
 289  			LogPrint (eLogWarning, "NTCP2: SessionConfirmed failed to encrypt part1");
 290  			return false;
 291  		}
 292  		return true;
 293  	}
 294  
 295  	bool NTCP2Establisher::CreateSessionConfirmedMessagePart2 ()
 296  	{
 297  		// part 2
 298  		// update AD again
 299  		MixHash (m_SessionConfirmedBuffer, 48);
 300  		// encrypt m3p2, it must be filled in SessionRequest
 301  		if (!KDF3Alice ()) return false; // MixKey, n = 0
 302  		uint8_t * m3p2 = m_SessionConfirmedBuffer + 48;
 303  		if (!Encrypt (m3p2, m3p2, m3p2Len - 16))
 304  		{
 305  			LogPrint (eLogWarning, "NTCP2: SessionConfirmed failed to encrypt part2");
 306  			return false;
 307  		}
 308  		// update h again
 309  		MixHash (m3p2, m3p2Len); //h = SHA256(h || ciphertext)
 310  		return true;
 311  	}
 312  
 313  	bool NTCP2Establisher::ProcessSessionRequestMessage (uint16_t& paddingLen, bool& clockSkew, bool& pq, bool decryptX)
 314  	{
 315  		clockSkew = false;
 316  		pq = false;
 317  		size_t offset = 0;
 318  		if (decryptX)
 319  		{
 320              // decrypt X
 321              auto x = GetRemotePub ();
 322              i2p::crypto::CBCDecryption decryption;
 323              decryption.SetKey (i2p::context.GetIdentHash ());
 324              decryption.Decrypt (m_Buffer, 32, i2p::context.GetNTCP2IV (), x);
 325              memcpy (m_IV, m_Buffer + 16, 16); // save last block as IV for SessionCreated
 326              if (x[31] & 0x80)
 327              {
 328  #if OPENSSL_PQ
 329                  if (m_CryptoType > i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
 330                  {
 331                      pq = true;
 332                      x[31] &= 0x7F;
 333                  }
 334  #endif
 335                  if (!pq)
 336                  {
 337                      LogPrint (eLogWarning, "NTCP2: SessionRequest ML-KEM requested but not supported");
 338                      return false;
 339                  }
 340              }
 341              else
 342                  SetVersion (2); // regular x25519 requested
 343              // decryption key for next block
 344              if (!KDF1Bob ())
 345              {
 346                  LogPrint (eLogWarning, "NTCP2: SessionRequest KDF failed");
 347                  return false;
 348              }
 349  		}
 350  		offset += 32;
 351  #if OPENSSL_PQ
 352          if (pq) return true; // we need to read extra ML-KEM block first
 353          if (m_CryptoType > i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
 354          {
 355              auto keyLen = i2p::crypto::GetMLKEMPublicKeyLen (m_CryptoType);
 356              std::vector<uint8_t> encapsKey(keyLen);
 357              if (Decrypt (m_Buffer + offset, encapsKey.data (), keyLen))
 358              {
 359                  MixHash (m_Buffer + offset, keyLen + 16);
 360                  offset += keyLen + 16;
 361                  m_PQKeys = i2p::crypto::CreateMLKEMKeys (m_CryptoType);
 362                  m_PQKeys->SetPublicKey (encapsKey.data ());
 363              }
 364          }
 365  #endif
 366  		// verify MAC and decrypt options block (32 bytes)
 367  		uint8_t options[16];
 368  		if (Decrypt (m_Buffer + offset, options, 16))
 369  		{
 370              MixHash (m_Buffer + offset, 32);
 371              offset += 32;
 372  			// options
 373  			if (options[0] && options[0] != i2p::context.GetNetID ())
 374  			{
 375  				LogPrint (eLogWarning, "NTCP2: SessionRequest networkID ", (int)options[0], " mismatch. Expected ", i2p::context.GetNetID ());
 376  				return false;
 377  			}
 378  			if (options[1] == 2) // ver is always 2
 379  			{
 380  				paddingLen = bufbe16toh (options + 2);
 381  				m_BufferLen = paddingLen + offset;
 382  				// actual padding is not known yet, apply MixHash later
 383  				m3p2Len = bufbe16toh (options + 4);
 384  				if (m3p2Len < 16)
 385  				{
 386  					LogPrint (eLogWarning, "NTCP2: SessionRequest m3p2len=", m3p2Len, " is too short");
 387  					return false;
 388  				}
 389  				// check timestamp
 390  				auto ts = i2p::util::GetSecondsSinceEpoch ();
 391  				uint32_t tsA = bufbe32toh (options + 8);
 392  				if (tsA < ts - NTCP2_CLOCK_SKEW || tsA > ts + NTCP2_CLOCK_SKEW)
 393  				{
 394  					LogPrint (eLogWarning, "NTCP2: SessionRequest time difference ", (int)(ts - tsA), " exceeds clock skew");
 395  					clockSkew = true;
 396  					// we send SessionCreate to let Alice know our time and then close session
 397  				}
 398  			}
 399  			else
 400  			{
 401  				LogPrint (eLogWarning, "NTCP2: SessionRequest version mismatch ", (int)options[1]);
 402  				return false;
 403  			}
 404  		}
 405  		else
 406  		{
 407  			LogPrint (eLogWarning, "NTCP2: SessionRequest AEAD verification failed ");
 408  			return false;
 409  		}
 410  		return true;
 411  	}
 412  
 413  	bool NTCP2Establisher::ProcessSessionCreatedMessage (uint16_t& paddingLen)
 414  	{
 415  		size_t offset = 0;
 416  		// decrypt Y
 417  		i2p::crypto::CBCDecryption decryption;
 418  		decryption.SetKey (m_RemoteIdentHash);
 419  		decryption.Decrypt (m_Buffer + offset, 32, m_IV, GetRemotePub ());
 420  		offset = 32;
 421  		// decryption key for next block (m_K)
 422  		if (!KDF2Alice ())
 423  		{
 424  			LogPrint (eLogWarning, "NTCP2: SessionCreated KDF failed");
 425  			return false;
 426  		}
 427  #if OPENSSL_PQ
 428          if (m_CryptoType > i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD && m_PQKeys)
 429  		{
 430  			// decrypt kem_ciphertext  frame
 431  			size_t cipherTextLen = i2p::crypto::GetMLKEMCipherTextLen (m_CryptoType);
 432  			std::vector<uint8_t> kemCiphertext(cipherTextLen);
 433  			if (!Decrypt (m_Buffer + offset, kemCiphertext.data (), cipherTextLen))
 434  			{
 435  				LogPrint (eLogWarning, "NTCP2: SessionCreated ML-KEM ciphertext section AEAD decryption failed");
 436  				return false;
 437  			}
 438  
 439  			MixHash (m_Buffer + offset, cipherTextLen + 16);
 440  			offset += cipherTextLen + 16;
 441  			// decaps
 442  			uint8_t sharedSecret[32];
 443  			m_PQKeys->Decaps (kemCiphertext.data (), sharedSecret);
 444  			MixKey (sharedSecret);
 445  		}
 446  #endif
 447  		// decrypt options and verify MAC
 448  		uint8_t options[16];
 449  		if (Decrypt (m_Buffer + offset, options, 16))
 450  		{
 451              MixHash (m_Buffer + offset, 32); // encrypted options
 452  			// options
 453  			paddingLen = bufbe16toh(options + 2);
 454  			// actual padding is not known yet, apply MixHash later
 455  			// check timestamp
 456  			auto ts = i2p::util::GetSecondsSinceEpoch ();
 457  			uint32_t tsB = bufbe32toh (options + 8);
 458  			if (tsB < ts - NTCP2_CLOCK_SKEW || tsB > ts + NTCP2_CLOCK_SKEW)
 459  			{
 460  				LogPrint (eLogWarning, "NTCP2: SessionCreated time difference ", (int)(ts - tsB), " exceeds clock skew");
 461  				return false;
 462  			}
 463  			offset += 32;
 464  		}
 465  		else
 466  		{
 467  			LogPrint (eLogWarning, "NTCP2: SessionCreated AEAD verification failed ");
 468  			return false;
 469  		}
 470  		m_BufferLen = offset;
 471  		return true;
 472  	}
 473  
 474  	bool NTCP2Establisher::ProcessSessionConfirmedMessagePart1 ()
 475  	{
 476  		// decrypt S, n = 1
 477  		if (!Decrypt (m_SessionConfirmedBuffer, m_RemoteStaticKey, 32))
 478  		{
 479  			LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part1 AEAD verification failed ");
 480  			return false;
 481  		}
 482  		MixHash (m_SessionConfirmedBuffer, 48);
 483  		return true;
 484  	}
 485  
 486  	bool NTCP2Establisher::ProcessSessionConfirmedMessagePart2 (uint8_t * m3p2Buf)
 487  	{
 488  		if (!KDF3Bob ()) // MixKey, n = 0
 489  		{
 490  			LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 KDF failed");
 491  			return false;
 492  		}
 493  		if (Decrypt (m_SessionConfirmedBuffer + 48, m3p2Buf, m3p2Len - 16))
 494  			// calculate new h again for KDF data
 495  			MixHash (m_SessionConfirmedBuffer + 48, m3p2Len); // h = SHA256(h || ciphertext)
 496  		else
 497  		{
 498  			LogPrint (eLogWarning, "NTCP2: SessionConfirmed Part2 AEAD verification failed ");
 499  			return false;
 500  		}
 501  		return true;
 502  	}
 503  
 504  	NTCP2Session::NTCP2Session (NTCP2Server& server, std::shared_ptr<const i2p::data::RouterInfo> in_RemoteRouter,
 505  		std::shared_ptr<const i2p::data::RouterInfo::Address> addr):
 506  		TransportSession (in_RemoteRouter, NTCP2_ESTABLISH_TIMEOUT),
 507  		m_Server (server), m_Socket (m_Server.GetService ()),
 508  		m_IsEstablished (false), m_IsTerminated (false),
 509  		m_Establisher (new NTCP2Establisher),
 510  		m_SendKey (nullptr), m_ReceiveKey (nullptr),
 511  #if OPENSSL_SIPHASH
 512  		m_SendMDCtx(nullptr), m_ReceiveMDCtx (nullptr),
 513  #else
 514  		m_SendSipKey (nullptr), m_ReceiveSipKey (nullptr),
 515  #endif
 516  		m_NextReceivedLen (0), m_NextReceivedBuffer (nullptr), m_NextSendBuffer (nullptr),
 517  		m_NextReceivedBufferSize (0), m_ReceiveSequenceNumber (0), m_SendSequenceNumber (0),
 518  		m_IsSending (false), m_IsReceiving (false), m_NextPaddingSize (16)
 519  	{
 520  		if (in_RemoteRouter) // Alice
 521  		{
 522  			m_Establisher->m_RemoteIdentHash = GetRemoteIdentity ()->GetIdentHash ();
 523  			if (addr)
 524  			{
 525  				memcpy (m_Establisher->m_RemoteStaticKey, addr->s, 32);
 526  				memcpy (m_Establisher->m_IV, addr->i, 16);
 527  				m_RemoteEndpoint = boost::asio::ip::tcp::endpoint (addr->host, addr->port);
 528  #if OPENSSL_PQ
 529                  if (m_Server.GetVersion () > 2) // we support post quantum in config
 530                      m_Establisher->SetVersion (addr->v);
 531  #endif
 532  			}
 533  			else
 534  				LogPrint (eLogWarning, "NTCP2: Missing NTCP2 address");
 535  		}
 536  		m_NextRouterInfoResendTime = i2p::util::GetSecondsSinceEpoch () + NTCP2_ROUTERINFO_RESEND_INTERVAL +
 537  			m_Server.GetRng ()() % NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD;
 538  	}
 539  
 540  	NTCP2Session::~NTCP2Session ()
 541  	{
 542  		delete[] m_NextReceivedBuffer;
 543  		delete[] m_NextSendBuffer;
 544  #if OPENSSL_SIPHASH
 545  		if (m_SendMDCtx) EVP_MD_CTX_destroy (m_SendMDCtx);
 546  		if (m_ReceiveMDCtx) EVP_MD_CTX_destroy (m_ReceiveMDCtx);
 547  #endif
 548  	}
 549  
 550  	void NTCP2Session::Terminate ()
 551  	{
 552  		if (!m_IsTerminated)
 553  		{
 554  			m_IsTerminated = true;
 555  			m_IsEstablished = false;
 556  			boost::system::error_code ec;
 557  			m_Socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
 558  			if (ec)
 559  				LogPrint (eLogDebug, "NTCP2: Couldn't shutdown socket: ", ec.message ());
 560  			m_Socket.close ();
 561  			transports.PeerDisconnected (shared_from_this ());
 562  			m_Server.RemoveNTCP2Session (shared_from_this ());
 563  			if (!m_IntermediateQueue.empty ())
 564  				m_SendQueue.splice (m_SendQueue.end (), m_IntermediateQueue);
 565  			for (auto& it: m_SendQueue)
 566  				it->Drop ();
 567  			m_SendQueue.clear ();
 568  			SetSendQueueSize (0);
 569  			auto remoteIdentity = GetRemoteIdentity ();
 570  			if (remoteIdentity)
 571  			{
 572  				LogPrint (eLogDebug, "NTCP2: Session with ", GetRemoteEndpoint (),
 573  					" (", i2p::data::GetIdentHashAbbreviation (remoteIdentity->GetIdentHash ()), ") terminated");
 574  			}
 575  			else
 576  			{
 577  				LogPrint (eLogDebug, "NTCP2: Session with ", GetRemoteEndpoint (), " terminated");
 578  			}
 579  		}
 580  	}
 581  
 582  	void NTCP2Session::Close ()
 583  	{
 584  		m_Socket.close ();
 585  	}
 586  
 587  	void NTCP2Session::TerminateByTimeout ()
 588  	{
 589  		SendTerminationAndTerminate (eNTCP2IdleTimeout);
 590  	}
 591  
 592  	void NTCP2Session::Done ()
 593  	{
 594  		boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
 595  	}
 596  
 597  	void NTCP2Session::Established ()
 598  	{
 599  		m_IsEstablished = true;
 600  		m_Establisher.reset (nullptr);
 601  		SetTerminationTimeout (NTCP2_TERMINATION_TIMEOUT + m_Server.GetRng ()() % NTCP2_TERMINATION_TIMEOUT_VARIANCE);
 602  		SendQueue ();
 603  		transports.PeerConnected (shared_from_this ());
 604  	}
 605  
 606  	void NTCP2Session::CreateNonce (uint64_t seqn, uint8_t * nonce)
 607  	{
 608  		memset (nonce, 0, 4);
 609  		htole64buf (nonce + 4, seqn);
 610  	}
 611  
 612  	void NTCP2Session::CreateNextReceivedBuffer (size_t size)
 613  	{
 614  		if (m_NextReceivedBuffer)
 615  		{
 616  			if (size <= m_NextReceivedBufferSize)
 617  				return; // buffer is good, do nothing
 618  			else
 619  				delete[] m_NextReceivedBuffer;
 620  		}
 621  		m_NextReceivedBuffer = new uint8_t[size];
 622  		m_NextReceivedBufferSize = size;
 623  	}
 624  
 625  	void NTCP2Session::DeleteNextReceiveBuffer (uint64_t ts)
 626  	{
 627  		if (m_NextReceivedBuffer && !m_IsReceiving &&
 628  			ts > GetLastActivityTimestamp () + NTCP2_RECEIVE_BUFFER_DELETION_TIMEOUT)
 629  		{
 630  			delete[] m_NextReceivedBuffer;
 631  			m_NextReceivedBuffer = nullptr;
 632  			m_NextReceivedBufferSize = 0;
 633  		}
 634  	}
 635  
 636  	void NTCP2Session::KeyDerivationFunctionDataPhase ()
 637  	{
 638  		uint8_t k[64];
 639  		i2p::crypto::HKDF (m_Establisher->GetCK (), nullptr, 0, "", k); // k_ab, k_ba = HKDF(ck, zerolen)
 640  		memcpy (m_Kab, k, 32); memcpy (m_Kba, k + 32, 32);
 641  		uint8_t master[32];
 642  		i2p::crypto::HKDF (m_Establisher->GetCK (), nullptr, 0, "ask", master, 32); // ask_master = HKDF(ck, zerolen, info="ask")
 643  		uint8_t h[39];
 644  		memcpy (h, m_Establisher->GetH (), 32);
 645  		memcpy (h + 32, "siphash", 7);
 646  		i2p::crypto::HKDF (master, h, 39, "", master, 32); // sip_master = HKDF(ask_master, h || "siphash")
 647  		i2p::crypto::HKDF (master, nullptr, 0, "", k); // sipkeys_ab, sipkeys_ba = HKDF(sip_master, zerolen)
 648  		memcpy (m_Sipkeysab, k, 32); memcpy (m_Sipkeysba, k + 32, 32);
 649  	}
 650  
 651  
 652  	void NTCP2Session::SendSessionRequest ()
 653  	{
 654  		if (!m_Establisher->CreateSessionRequestMessage (m_Server.GetRng ()))
 655  		{
 656  			LogPrint (eLogWarning, "NTCP2: Send SessionRequest KDF failed");
 657  			boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
 658  			return;
 659  		}
 660  		// send message
 661  		m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch ();
 662  		boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_Buffer, m_Establisher->m_BufferLen), boost::asio::transfer_all (),
 663  			std::bind(&NTCP2Session::HandleSessionRequestSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
 664  	}
 665  
 666  	void NTCP2Session::HandleSessionRequestSent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
 667  	{
 668  		(void) bytes_transferred;
 669  		if (ecode)
 670  		{
 671  			LogPrint (eLogWarning, "NTCP2: Couldn't send SessionRequest message: ", ecode.message ());
 672  			Terminate ();
 673  		}
 674  		else
 675  		{
 676  			// we receive first 64 bytes (32 Y, and 32 ChaCha/Poly frame) first and ML-KEM frame if post quantum
 677  			size_t len = 64;
 678  #if OPENSSL_PQ
 679  			if (m_Establisher->m_CryptoType > i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)
 680                  len += i2p::crypto::GetMLKEMCipherTextLen (m_Establisher->m_CryptoType) + 16;
 681  #endif
 682  			boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_Buffer, len), boost::asio::transfer_all (),
 683  				std::bind(&NTCP2Session::HandleSessionCreatedReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
 684  		}
 685  	}
 686  
 687  	void NTCP2Session::HandleSessionRequestReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
 688  	{
 689  		if (ecode)
 690  		{
 691  			LogPrint (eLogWarning, "NTCP2: SessionRequest read error: ", ecode.message ());
 692  			Terminate ();
 693  		}
 694  		else
 695  		{
 696  			m_Establisher->CreateEphemeralKey ();
 697  			boost::asio::post (m_Server.GetEstablisherService (),
 698  				[s = shared_from_this (), bytes_transferred] ()
 699  				{
 700  					s->ProcessSessionRequest (bytes_transferred);;
 701  				});
 702  		}
 703  	}
 704  
 705  	void NTCP2Session::ProcessSessionRequest (size_t len, bool first)
 706  	{
 707  		LogPrint (eLogDebug, "NTCP2: SessionRequest ", first ? "received " : "updated ", len);
 708  		uint16_t paddingLen = 0;
 709  		bool clockSkew = false, pq = false;
 710  		if (m_Establisher->ProcessSessionRequestMessage (paddingLen, clockSkew, pq, first))
 711  		{
 712  			if (clockSkew)
 713  			{
 714  				// we don't care about padding, send SessionCreated and close session
 715  				SendSessionCreated ();
 716  				boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
 717  			}
 718  #if OPENSSL_PQ
 719  			else if (pq)
 720  			{
 721                  auto keyLen = i2p::crypto::GetMLKEMPublicKeyLen (m_Establisher->m_CryptoType);
 722                  boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_Buffer + 64, keyLen + 16), boost::asio::transfer_all (),
 723  						std::bind(&NTCP2Session::HandleSessionRequestMLKEMReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
 724  			}
 725  #endif
 726  			else if (paddingLen > 0)
 727  			{
 728  #if OPENSSL_PQ
 729                  if (len + paddingLen <= NTCP2_SESSION_REQUEST_MAX_SIZE + i2p::crypto::MLKEM1024_KEY_LENGTH + 16)
 730  #else
 731  				if (len + paddingLen <= NTCP2_SESSION_REQUEST_MAX_SIZE) // session request is 287 bytes max
 732  #endif
 733  				{
 734  					boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_Buffer + len, paddingLen), boost::asio::transfer_all (),
 735  						std::bind(&NTCP2Session::HandleSessionRequestPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
 736  				}
 737  				else
 738  				{
 739  					LogPrint (eLogWarning, "NTCP2: SessionRequest padding length ", (int)paddingLen, " is too long");
 740  					boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
 741  				}
 742  			}
 743  			else
 744  				SendSessionCreated ();
 745  		}
 746  		else
 747  			ReadSomethingAndTerminate (); // probing resistance
 748  	}
 749  
 750  	void NTCP2Session::HandleSessionRequestPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
 751  	{
 752  		if (ecode)
 753  		{
 754  			LogPrint (eLogWarning, "NTCP2: SessionRequest padding read error: ", ecode.message ());
 755  			Terminate ();
 756  		}
 757  		else
 758  		{
 759              boost::asio::post (m_Server.GetEstablisherService (),
 760  				[s = shared_from_this (), paddingLength = bytes_transferred] ()
 761  				{
 762                      if (paddingLength < s->m_Establisher->m_BufferLen)
 763                          s->m_Establisher->ApplyPadding (s->m_Establisher->m_Buffer + s->m_Establisher->m_BufferLen - paddingLength, paddingLength);
 764  					s->SendSessionCreated ();
 765  				});
 766  		}
 767  	}
 768  
 769  #if OPENSSL_PQ
 770      void NTCP2Session::HandleSessionRequestMLKEMReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
 771      {
 772          if (ecode)
 773  		{
 774  			LogPrint (eLogWarning, "NTCP2: SessionRequest ML-KEM read error: ", ecode.message ());
 775  			Terminate ();
 776  		}
 777  		else
 778  		{
 779               boost::asio::post (m_Server.GetEstablisherService (),
 780  				[s = shared_from_this (), bytes_transferred] ()
 781  				{
 782                      s->ProcessSessionRequest (bytes_transferred + 64, false);
 783                  });
 784  		}
 785      }
 786  #endif
 787  
 788  	void NTCP2Session::SendSessionCreated ()
 789  	{
 790  		if (!m_Establisher->CreateSessionCreatedMessage (m_Server.GetRng ()))
 791  		{
 792  			LogPrint (eLogWarning, "NTCP2: Send SessionCreated KDF failed");
 793  			boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
 794  			return;
 795  		}
 796  		// send message
 797  		m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch ();
 798  		boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_Buffer, m_Establisher->m_BufferLen), boost::asio::transfer_all (),
 799  			std::bind(&NTCP2Session::HandleSessionCreatedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
 800  	}
 801  
 802  	void NTCP2Session::HandleSessionCreatedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
 803  	{
 804  		if (ecode)
 805  		{
 806  			LogPrint (eLogWarning, "NTCP2: SessionCreated read error: ", ecode.message ());
 807  			Terminate ();
 808  		}
 809  		else
 810  		{
 811  			m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval;
 812  			boost::asio::post (m_Server.GetEstablisherService (),
 813  				[s = shared_from_this (), bytes_transferred] ()
 814  				{
 815  					s->ProcessSessionCreated (bytes_transferred);
 816  				});
 817  		}
 818  	}
 819  
 820  	void NTCP2Session::ProcessSessionCreated (size_t len)
 821  	{
 822  		LogPrint (eLogDebug, "NTCP2: SessionCreated received ", len);
 823  		uint16_t paddingLen = 0;
 824  		if (m_Establisher->ProcessSessionCreatedMessage (paddingLen))
 825  		{
 826  			if (paddingLen > 0)
 827  			{
 828  				if (paddingLen <= NTCP2_SESSION_CREATED_MAX_SIZE - 64) // session created is 287 bytes max
 829  				{
 830  					boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_Buffer + m_Establisher->m_BufferLen, paddingLen), boost::asio::transfer_all (),
 831  						std::bind(&NTCP2Session::HandleSessionCreatedPaddingReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
 832  				}
 833  				else
 834  				{
 835  					LogPrint (eLogWarning, "NTCP2: SessionCreated padding length ", (int)paddingLen, " is too long");
 836  					boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
 837  				}
 838  			}
 839  			else
 840  				SendSessionConfirmed ();
 841  		}
 842  		else
 843  		{
 844  			if (GetRemoteIdentity ())
 845  				i2p::data::netdb.SetUnreachable (GetRemoteIdentity ()->GetIdentHash (), true);  // assume wrong s key
 846  			boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
 847  		}
 848  	}
 849  
 850  	void NTCP2Session::HandleSessionCreatedPaddingReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
 851  	{
 852  		if (ecode)
 853  		{
 854  			LogPrint (eLogWarning, "NTCP2: SessionCreated padding read error: ", ecode.message ());
 855  			Terminate ();
 856  		}
 857  		else
 858  		{
 859  			boost::asio::post (m_Server.GetEstablisherService (),
 860  				[s = shared_from_this (), paddingLength = bytes_transferred] ()
 861  				{
 862                      s->m_Establisher->ApplyPadding (s->m_Establisher->m_Buffer + s->m_Establisher->m_BufferLen, paddingLength);
 863                      s->m_Establisher->m_BufferLen += paddingLength;
 864  					s->SendSessionConfirmed ();
 865  				});
 866  		}
 867  	}
 868  
 869  	void NTCP2Session::SendSessionConfirmed ()
 870  	{
 871  		if (!m_Establisher->CreateSessionConfirmedMessagePart1 ())
 872  		{
 873  			boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
 874  			return;
 875  		}
 876  		if (!m_Establisher->CreateSessionConfirmedMessagePart2 ())
 877  		{
 878  			LogPrint (eLogWarning, "NTCP2: Send SessionConfirmed Part2 KDF failed");
 879  			boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
 880  			return;
 881  		}
 882  		// send message
 883  		boost::asio::async_write (m_Socket, boost::asio::buffer (m_Establisher->m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (),
 884  			std::bind(&NTCP2Session::HandleSessionConfirmedSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
 885  	}
 886  
 887  	void NTCP2Session::HandleSessionConfirmedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
 888  	{
 889  		(void) bytes_transferred;
 890  		if (ecode)
 891  		{
 892  			LogPrint (eLogWarning, "NTCP2: Couldn't send SessionConfirmed message: ", ecode.message ());
 893  			Terminate ();
 894  		}
 895  		else
 896  		{
 897  			LogPrint (eLogDebug, "NTCP2: SessionConfirmed sent");
 898  			KeyDerivationFunctionDataPhase ();
 899  			// Alice data phase keys
 900  			m_SendKey = m_Kab;
 901  			m_ReceiveKey = m_Kba;
 902  			SetSipKeys (m_Sipkeysab, m_Sipkeysba);
 903  			memcpy (m_ReceiveIV.buf, m_Sipkeysba + 16, 8);
 904  			memcpy (m_SendIV.buf, m_Sipkeysab + 16, 8);
 905  			Established ();
 906  			ReceiveLength ();
 907  
 908  			// TODO: remove
 909  			// m_SendQueue.push_back (CreateDeliveryStatusMsg (1));
 910  			// SendQueue ();
 911  		}
 912  	}
 913  
 914  	void NTCP2Session::HandleSessionCreatedSent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
 915  	{
 916  		(void) bytes_transferred;
 917  		if (ecode)
 918  		{
 919  			LogPrint (eLogWarning, "NTCP2: Couldn't send SessionCreated message: ", ecode.message ());
 920  			Terminate ();
 921  		}
 922  		else
 923  		{
 924  			LogPrint (eLogDebug, "NTCP2: SessionCreated sent");
 925  			m_Establisher->m_SessionConfirmedBuffer = new uint8_t[m_Establisher->m3p2Len + 48];
 926  			boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_SessionConfirmedBuffer, m_Establisher->m3p2Len + 48), boost::asio::transfer_all (),
 927  				std::bind(&NTCP2Session::HandleSessionConfirmedReceived , shared_from_this (), std::placeholders::_1, std::placeholders::_2));
 928  		}
 929  	}
 930  
 931  	void NTCP2Session::HandleSessionConfirmedReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
 932  	{
 933  		(void) bytes_transferred;
 934  		if (ecode)
 935  		{
 936  			LogPrint (eLogWarning, "NTCP2: SessionConfirmed read error: ", ecode.message ());
 937  			Terminate ();
 938  		}
 939  		else
 940  		{
 941  			m_HandshakeInterval = i2p::util::GetMillisecondsSinceEpoch () - m_HandshakeInterval;
 942  			boost::asio::post (m_Server.GetEstablisherService (),
 943  				[s = shared_from_this ()] ()
 944  				{
 945  					s->ProcessSessionConfirmed ();;
 946  				});
 947  		}
 948  	}
 949  
 950  	void NTCP2Session::ProcessSessionConfirmed ()
 951  	{
 952  		// run on establisher thread
 953  		LogPrint (eLogDebug, "NTCP2: SessionConfirmed received");
 954  		// part 1
 955  		if (m_Establisher->ProcessSessionConfirmedMessagePart1 ())
 956  		{
 957  			// part 2
 958  			auto buf = std::make_shared<std::vector<uint8_t> > (m_Establisher->m3p2Len - 16); // -MAC
 959  			if (m_Establisher->ProcessSessionConfirmedMessagePart2 (buf->data ())) // TODO:handle in establisher thread
 960  			{
 961  				// payload
 962  				// RI block must be first
 963  				if ((*buf)[0] != eNTCP2BlkRouterInfo)
 964  				{
 965  					LogPrint (eLogWarning, "NTCP2: Unexpected block ", (int)(*buf)[0], " in SessionConfirmed");
 966  					boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
 967  					return;
 968  				}
 969  				auto size = bufbe16toh (buf->data () + 1);
 970  				if (size > buf->size () - 3 || size > i2p::data::MAX_RI_BUFFER_SIZE + 1)
 971  				{
 972  					LogPrint (eLogError, "NTCP2: Unexpected RouterInfo size ", size, " in SessionConfirmed");
 973  					boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
 974  					return;
 975  				}
 976  				boost::asio::post (m_Server.GetService (),
 977  					[s = shared_from_this (), buf, size] ()
 978  					{
 979  						s->EstablishSessionAfterSessionConfirmed (buf, size);
 980  					});
 981  			}
 982  			else
 983  				boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
 984  		}
 985  		else
 986  			boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
 987  	}
 988  
 989  	void NTCP2Session::EstablishSessionAfterSessionConfirmed (std::shared_ptr<std::vector<uint8_t> > buf, size_t size)
 990  	{
 991  		// run on main NTCP2 thread
 992  		KeyDerivationFunctionDataPhase ();
 993  		// Bob data phase keys
 994  		m_SendKey = m_Kba;
 995  		m_ReceiveKey = m_Kab;
 996  		SetSipKeys (m_Sipkeysba, m_Sipkeysab);
 997  		memcpy (m_ReceiveIV.buf, m_Sipkeysab + 16, 8);
 998  		memcpy (m_SendIV.buf, m_Sipkeysba + 16, 8);
 999  		// we need to set keys for SendTerminationAndTerminate
1000  		// TODO: check flag
1001  		i2p::data::RouterInfo ri (buf->data () + 4, size - 1); // 1 byte block type + 2 bytes size + 1 byte flag
1002  		if (ri.IsUnreachable ())
1003  		{
1004  			LogPrint (eLogError, "NTCP2: RouterInfo verification failed in SessionConfirmed from ", GetRemoteEndpoint ());
1005  			SendTerminationAndTerminate (eNTCP2RouterInfoSignatureVerificationFail);
1006  			return;
1007  		}
1008  		LogPrint(eLogDebug, "NTCP2: SessionConfirmed from ", GetRemoteEndpoint (),
1009  			" (", i2p::data::GetIdentHashAbbreviation (ri.GetIdentHash ()), ")");
1010  		auto ts = i2p::util::GetMillisecondsSinceEpoch ();
1011  		if (ts > ri.GetTimestamp () + i2p::data::NETDB_MIN_EXPIRATION_TIMEOUT*1000LL) // 90 minutes
1012  		{
1013  			LogPrint (eLogError, "NTCP2: RouterInfo is too old in SessionConfirmed for ", (ts - ri.GetTimestamp ())/1000LL, " seconds");
1014  			SendTerminationAndTerminate (eNTCP2Message3Error);
1015  			return;
1016  		}
1017  		if (ts + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri.GetTimestamp ()) // 2 minutes
1018  		{
1019  			LogPrint (eLogError, "NTCP2: RouterInfo is from future for ", (ri.GetTimestamp () - ts)/1000LL, " seconds");
1020  			SendTerminationAndTerminate (eNTCP2Message3Error);
1021  			return;
1022  		}
1023  		if (ri.GetVersion () < i2p::data::NETDB_MIN_ALLOWED_VERSION && !ri.IsHighBandwidth ())
1024  		{
1025  			LogPrint (eLogInfo, "NTCP2: Router version ", ri.GetVersion (), " is too old in SessionConfirmed");
1026  			SendTerminationAndTerminate (eNTCP2Banned);
1027  			return;
1028  		}
1029  		// update RouterInfo in netdb
1030  		auto ri1 = i2p::data::netdb.AddRouterInfo (ri.GetBuffer (), ri.GetBufferLen ()); // ri1 points to one from netdb now
1031  		if (!ri1)
1032  		{
1033  			LogPrint (eLogError, "NTCP2: Couldn't update RouterInfo from SessionConfirmed in netdb");
1034  			Terminate ();
1035  			return;
1036  		}
1037  
1038  		bool isOlder = false;
1039  		if (ri.GetTimestamp () + i2p::data::NETDB_EXPIRATION_TIMEOUT_THRESHOLD*1000LL < ri1->GetTimestamp ())
1040  		{
1041  			// received RouterInfo is older than one in netdb
1042  			isOlder = true;
1043  			if (ri1->HasProfile ())
1044  			{
1045  				auto profile = i2p::data::GetRouterProfile (ri1->GetIdentHash ()); // retrieve profile
1046  				if (profile && profile->IsDuplicated ())
1047  				{
1048  					SendTerminationAndTerminate (eNTCP2Banned);
1049  					return;
1050  				}
1051  			}
1052  		}
1053  
1054  		auto addr = m_RemoteEndpoint.address ().is_v4 () ? ri1->GetNTCP2V4Address () :
1055  			(i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ? ri1->GetYggdrasilAddress () : ri1->GetNTCP2V6Address ());
1056  		if (!addr)
1057  		{
1058  			LogPrint (eLogError, "NTCP2: Address not found in SessionConfirmed");
1059  			Terminate ();
1060  			return;
1061  		}
1062  		if (addr->IsPublishedNTCP2 () && m_RemoteEndpoint.address () != addr->host &&
1063  		    (!m_RemoteEndpoint.address ().is_v6 () || (i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ?
1064  		     memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data () + 1, addr->host.to_v6 ().to_bytes ().data () + 1, 7) : // from the same yggdrasil subnet
1065  		     memcmp (m_RemoteEndpoint.address ().to_v6 ().to_bytes ().data (), addr->host.to_v6 ().to_bytes ().data (), 8)))) // temporary address
1066  		{
1067  			if (isOlder) // older router?
1068  				i2p::data::UpdateRouterProfile (ri1->GetIdentHash (),
1069  					[](std::shared_ptr<i2p::data::RouterProfile> profile)
1070  					{
1071  						if (profile) profile->Duplicated (); // mark router as duplicated in profile
1072  					});
1073  			else
1074  				LogPrint (eLogInfo, "NTCP2: Host mismatch between published address ", addr->host, " and actual endpoint ", m_RemoteEndpoint.address ());
1075  			SendTerminationAndTerminate (eNTCP2Banned);
1076  			return;
1077  		}
1078  		if (memcmp (m_Establisher->m_RemoteStaticKey, addr->s, 32))
1079  		{
1080  			LogPrint (eLogError, "NTCP2: Wrong static key in SessionConfirmed");
1081  			if (addr->IsPublishedNTCP2 ())
1082  				i2p::transport::transports.AddBan (m_RemoteEndpoint.address ());
1083  			Terminate ();
1084  			return;
1085  		}
1086  		// TODO: process options block
1087  
1088  		// ready to communicate
1089  		SetRemoteIdentity (ri1->GetRouterIdentity ());
1090  		if (m_Server.AddNTCP2Session (shared_from_this (), true))
1091  		{
1092  			Established ();
1093  			if (ri1->GetCongestion () == i2p::data::RouterInfo::eRejectAll)
1094  			{
1095  				auto terminationTimeout = GetTerminationTimeout ()/2;
1096  				if (terminationTimeout < NTCP2_ESTABLISH_TIMEOUT) terminationTimeout = NTCP2_ESTABLISH_TIMEOUT;
1097  				SetTerminationTimeout (terminationTimeout);
1098  			}
1099  			ReceiveLength ();
1100  		}
1101  		else
1102  			Terminate ();
1103  	}
1104  
1105  	void NTCP2Session::SetSipKeys (const uint8_t * sendSipKey, const uint8_t * receiveSipKey)
1106  	{
1107  #if OPENSSL_SIPHASH
1108  		EVP_PKEY * sipKey = EVP_PKEY_new_raw_private_key (EVP_PKEY_SIPHASH, nullptr, sendSipKey, 16);
1109  		m_SendMDCtx = EVP_MD_CTX_create ();
1110  		EVP_PKEY_CTX *ctx = nullptr;
1111  		EVP_DigestSignInit (m_SendMDCtx, &ctx, nullptr, nullptr, sipKey);
1112  		EVP_PKEY_CTX_ctrl (ctx, -1, EVP_PKEY_OP_SIGNCTX, EVP_PKEY_CTRL_SET_DIGEST_SIZE, 8, nullptr);
1113  		EVP_PKEY_free (sipKey);
1114  
1115  		sipKey = EVP_PKEY_new_raw_private_key (EVP_PKEY_SIPHASH, nullptr, receiveSipKey, 16);
1116  		m_ReceiveMDCtx = EVP_MD_CTX_create ();
1117  		ctx = nullptr;
1118  		EVP_DigestSignInit (m_ReceiveMDCtx, &ctx, NULL, NULL, sipKey);
1119  		EVP_PKEY_CTX_ctrl (ctx, -1, EVP_PKEY_OP_SIGNCTX, EVP_PKEY_CTRL_SET_DIGEST_SIZE, 8, nullptr);
1120  		EVP_PKEY_free (sipKey);
1121  #else
1122  		m_SendSipKey = sendSipKey;
1123  		m_ReceiveSipKey = receiveSipKey;
1124  #endif
1125  	}
1126  
1127  	void NTCP2Session::ClientLogin ()
1128  	{
1129  		m_Establisher->CreateEphemeralKey ();
1130  		boost::asio::post (m_Server.GetEstablisherService (),
1131  		    [s = shared_from_this ()] ()
1132  			{
1133  				s->SendSessionRequest ();
1134  			});
1135  	}
1136  
1137  	void NTCP2Session::ServerLogin (int version)
1138  	{
1139          if (m_Establisher) m_Establisher->SetVersion (version);
1140  		SetTerminationTimeout (NTCP2_ESTABLISH_TIMEOUT);
1141  		SetLastActivityTimestamp (i2p::util::GetSecondsSinceEpoch ());
1142  		boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_Buffer, 64), boost::asio::transfer_all (),
1143  			std::bind(&NTCP2Session::HandleSessionRequestReceived, shared_from_this (),
1144  			std::placeholders::_1, std::placeholders::_2));
1145  	}
1146  
1147  	void NTCP2Session::ReceiveLength ()
1148  	{
1149  		if (IsTerminated ()) return;
1150  #ifdef __linux__
1151  		const int one = 1;
1152  		setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
1153  #endif
1154  		boost::asio::async_read (m_Socket, boost::asio::buffer(&m_NextReceivedLen, 2), boost::asio::transfer_all (),
1155  			std::bind(&NTCP2Session::HandleReceivedLength, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
1156  	}
1157  
1158  	void NTCP2Session::HandleReceivedLength (const boost::system::error_code& ecode, std::size_t bytes_transferred)
1159  	{
1160  		if (ecode)
1161  		{
1162  			if (ecode != boost::asio::error::operation_aborted)
1163  				LogPrint (eLogWarning, "NTCP2: Receive length read error: ", ecode.message ());
1164  			Terminate ();
1165  		}
1166  		else
1167  		{
1168  #if OPENSSL_SIPHASH
1169  			EVP_DigestSignInit (m_ReceiveMDCtx, nullptr, nullptr, nullptr, nullptr);
1170  			EVP_DigestSignUpdate (m_ReceiveMDCtx, m_ReceiveIV.buf, 8);
1171  			size_t l = 8;
1172  			EVP_DigestSignFinal (m_ReceiveMDCtx, m_ReceiveIV.buf, &l);
1173  #else
1174  			i2p::crypto::Siphash<8> (m_ReceiveIV.buf, m_ReceiveIV.buf, 8, m_ReceiveSipKey);
1175  #endif
1176  			// m_NextReceivedLen comes from the network in BigEndian
1177  			m_NextReceivedLen = be16toh (m_NextReceivedLen) ^ le16toh (m_ReceiveIV.key);
1178  			LogPrint (eLogDebug, "NTCP2: Received length ", m_NextReceivedLen);
1179  			if (m_NextReceivedLen >= 16)
1180  			{
1181  				CreateNextReceivedBuffer (m_NextReceivedLen);
1182  				boost::system::error_code ec;
1183  				size_t moreBytes = m_Socket.available(ec);
1184  				if (!ec)
1185  				{
1186  					if (moreBytes >= m_NextReceivedLen)
1187  					{
1188  						// read and process message immediately if available
1189  						moreBytes = boost::asio::read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (), ec);
1190  						HandleReceived (ec, moreBytes);
1191  					}
1192  					else
1193  						Receive ();
1194  				}
1195  				else
1196  					LogPrint (eLogWarning, "NTCP2: Socket error: ", ec.message ());
1197  			}
1198  			else
1199  			{
1200  				LogPrint (eLogError, "NTCP2: Received length ", m_NextReceivedLen, " is too short");
1201  				Terminate ();
1202  			}
1203  		}
1204  	}
1205  
1206  	void NTCP2Session::Receive ()
1207  	{
1208  		if (IsTerminated ()) return;
1209  #ifdef __linux__
1210  		const int one = 1;
1211  		setsockopt(m_Socket.native_handle(), IPPROTO_TCP, TCP_QUICKACK, &one, sizeof(one));
1212  #endif
1213  		m_IsReceiving = true;
1214  		boost::asio::async_read (m_Socket, boost::asio::buffer(m_NextReceivedBuffer, m_NextReceivedLen), boost::asio::transfer_all (),
1215  			std::bind(&NTCP2Session::HandleReceived, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
1216  	}
1217  
1218  	void NTCP2Session::HandleReceived (const boost::system::error_code& ecode, std::size_t bytes_transferred)
1219  	{
1220  		if (ecode)
1221  		{
1222  			if (ecode != boost::asio::error::operation_aborted)
1223  				LogPrint (eLogWarning, "NTCP2: Receive read error: ", ecode.message ());
1224  			Terminate ();
1225  		}
1226  		else
1227  		{
1228  			UpdateNumReceivedBytes (bytes_transferred + 2);
1229  			i2p::transport::transports.UpdateReceivedBytes (bytes_transferred + 2);
1230  			uint8_t nonce[12];
1231  			CreateNonce (m_ReceiveSequenceNumber, nonce); m_ReceiveSequenceNumber++;
1232  			if (m_Server.AEADChaCha20Poly1305Decrypt (m_NextReceivedBuffer, m_NextReceivedLen-16, nullptr, 0, m_ReceiveKey, nonce, m_NextReceivedBuffer, m_NextReceivedLen))
1233  			{
1234  				LogPrint (eLogDebug, "NTCP2: Received message decrypted");
1235  				ProcessNextFrame (m_NextReceivedBuffer, m_NextReceivedLen-16);
1236  				m_IsReceiving = false;
1237  				ReceiveLength ();
1238  			}
1239  			else
1240  			{
1241  				LogPrint (eLogWarning, "NTCP2: Received AEAD verification failed ");
1242  				SendTerminationAndTerminate (eNTCP2DataPhaseAEADFailure);
1243  			}
1244  		}
1245  	}
1246  
1247  	void NTCP2Session::ProcessNextFrame (const uint8_t * frame, size_t len)
1248  	{
1249  		size_t offset = 0;
1250  		while (offset < len)
1251  		{
1252  			uint8_t blk = frame[offset];
1253  			offset++;
1254  			auto size = bufbe16toh (frame + offset);
1255  			offset += 2;
1256  			LogPrint (eLogDebug, "NTCP2: Block type ", (int)blk, " of size ", size);
1257  			if (offset + size > len)
1258  			{
1259  				LogPrint (eLogError, "NTCP2: Unexpected block length ", size);
1260  				break;
1261  			}
1262  			switch (blk)
1263  			{
1264  				case eNTCP2BlkDateTime:
1265  				{
1266  					LogPrint (eLogDebug, "NTCP2: Datetime");
1267  					if (m_IsEstablished)
1268  					{
1269  						uint64_t ts = i2p::util::GetSecondsSinceEpoch ();
1270  						uint64_t tsA = bufbe32toh (frame + offset);
1271  						if (tsA < ts - NTCP2_CLOCK_SKEW || tsA > ts + NTCP2_CLOCK_SKEW)
1272  						{
1273  							LogPrint (eLogWarning, "NTCP2: Established session time difference ", (int)(ts - tsA), " exceeds clock skew");
1274  							SendTerminationAndTerminate (eNTCP2ClockSkew);
1275  						}
1276  					}
1277  					break;
1278  				}
1279  				case eNTCP2BlkOptions:
1280  					LogPrint (eLogDebug, "NTCP2: Options");
1281  				break;
1282  				case eNTCP2BlkRouterInfo:
1283  				{
1284  					LogPrint (eLogDebug, "NTCP2: RouterInfo flag=", (int)frame[offset]);
1285  					if (size <= i2p::data::MAX_RI_BUFFER_SIZE + 1)
1286  					{
1287  						auto newRi = i2p::data::netdb.AddRouterInfo (frame + offset + 1, size - 1);
1288  						if (newRi)
1289  						{
1290  							auto remoteIdentity = GetRemoteIdentity ();
1291  							if (remoteIdentity && remoteIdentity->GetIdentHash () == newRi->GetIdentHash ())
1292  								// peer's RouterInfo update
1293  								SetRemoteIdentity (newRi->GetIdentity ());
1294  							i2p::transport::transports.UpdatePeerParams (newRi);
1295  						}
1296  					}
1297  					else
1298  						LogPrint (eLogInfo, "NTCP2: RouterInfo block is too long ", size);
1299  					break;
1300  				}
1301  				case eNTCP2BlkI2NPMessage:
1302  				{
1303  					LogPrint (eLogDebug, "NTCP2: I2NP");
1304  					if (size > I2NP_MAX_MESSAGE_SIZE)
1305  					{
1306  						LogPrint (eLogError, "NTCP2: I2NP block is too long ", size);
1307  						break;
1308  					}
1309  					auto nextMsg = (frame[offset] == eI2NPTunnelData) ? NewI2NPTunnelMessage (true) : NewI2NPMessage (size);
1310  					nextMsg->len = nextMsg->offset + size + 7; // 7 more bytes for full I2NP header
1311  					if (nextMsg->len <= nextMsg->maxLen)
1312  					{
1313  						memcpy (nextMsg->GetNTCP2Header (), frame + offset, size);
1314  						nextMsg->FromNTCP2 ();
1315  						m_Handler.PutNextMessage (std::move (nextMsg));
1316  					}
1317  					else
1318  						LogPrint (eLogError, "NTCP2: I2NP block is too long for I2NP message");
1319  					break;
1320  				}
1321  				case eNTCP2BlkTermination:
1322  					if (size >= 9)
1323  					{
1324  						LogPrint (eLogDebug, "NTCP2: Termination. reason=", (int)(frame[offset + 8]));
1325  						Terminate ();
1326  					}
1327  					else
1328  						LogPrint (eLogWarning, "NTCP2: Unexpected termination block size ", size);
1329  				break;
1330  				case eNTCP2BlkPadding:
1331  					LogPrint (eLogDebug, "NTCP2: Padding");
1332  				break;
1333  				default:
1334  					LogPrint (eLogWarning, "NTCP2: Unknown block type ", (int)blk);
1335  			}
1336  			offset += size;
1337  		}
1338  		m_Handler.Flush ();
1339  	}
1340  
1341  	void NTCP2Session::SetNextSentFrameLength (size_t frameLen, uint8_t * lengthBuf)
1342  	{
1343  #if OPENSSL_SIPHASH
1344  		EVP_DigestSignInit (m_SendMDCtx, nullptr, nullptr, nullptr, nullptr);
1345  		EVP_DigestSignUpdate (m_SendMDCtx, m_SendIV.buf, 8);
1346  		size_t l = 8;
1347  		EVP_DigestSignFinal (m_SendMDCtx, m_SendIV.buf, &l);
1348  #else
1349  		i2p::crypto::Siphash<8> (m_SendIV.buf, m_SendIV.buf, 8, m_SendSipKey);
1350  #endif
1351  		// length must be in BigEndian
1352  		htobe16buf (lengthBuf, frameLen ^ le16toh (m_SendIV.key));
1353  		LogPrint (eLogDebug, "NTCP2: Sent length ", frameLen);
1354  	}
1355  
1356  	void NTCP2Session::SendI2NPMsgs (std::vector<std::shared_ptr<I2NPMessage> >& msgs)
1357  	{
1358  		if (msgs.empty () || IsTerminated ()) return;
1359  
1360  		size_t totalLen = 0;
1361  		std::vector<std::pair<uint8_t *, size_t> > encryptBufs;
1362  		std::vector<boost::asio::const_buffer> bufs;
1363  		std::shared_ptr<I2NPMessage> first;
1364  		uint8_t * macBuf = nullptr;
1365  		for (auto& it: msgs)
1366  		{
1367  			it->ToNTCP2 ();
1368  			auto buf = it->GetNTCP2Header ();
1369  			auto len = it->GetNTCP2Length ();
1370  			// block header
1371  			buf -= 3;
1372  			buf[0] = eNTCP2BlkI2NPMessage; // blk
1373  			htobe16buf (buf + 1, len); // size
1374  			len += 3;
1375  			totalLen += len;
1376  			encryptBufs.push_back ( {buf, len} );
1377  			if (&it == &msgs.front ()) // first message
1378  			{
1379  				// allocate two bytes for length
1380  				buf -= 2; len += 2;
1381  				first = it;
1382  			}
1383  			if (&it == &msgs.back () && it->len + 16 < it->maxLen) // last message
1384  			{
1385  				// if it's long enough we add padding and MAC to it
1386  				// create padding block
1387  				auto paddingLen = CreatePaddingBlock (totalLen, buf + len, it->maxLen - it->len - 16);
1388  				if (paddingLen)
1389  				{
1390  					encryptBufs.push_back ( {buf + len, paddingLen} );
1391  					len += paddingLen;
1392  					totalLen += paddingLen;
1393  				}
1394  				macBuf = buf + len;
1395  				// allocate 16 bytes for MAC
1396  				len += 16;
1397  			}
1398  
1399  			bufs.push_back (boost::asio::buffer (buf, len));
1400  		}
1401  
1402  		if (!macBuf) // last block was not enough for MAC
1403  		{
1404  			// allocate send buffer
1405  			m_NextSendBuffer = new uint8_t[287]; // can be any size > 16, we just allocate 287 frequently
1406  			// create padding block
1407  			auto paddingLen = CreatePaddingBlock (totalLen, m_NextSendBuffer, 287 - 16);
1408  			// and padding block to encrypt and send
1409  			if (paddingLen)
1410  				encryptBufs.push_back ( {m_NextSendBuffer, paddingLen} );
1411  			bufs.push_back (boost::asio::buffer (m_NextSendBuffer, paddingLen + 16));
1412  			macBuf = m_NextSendBuffer + paddingLen;
1413  			totalLen += paddingLen;
1414  		}
1415  		if (totalLen > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE)
1416  		{
1417  			LogPrint (eLogError, "NTCP2: Frame to send is too long ", totalLen);
1418  			return;
1419  		}
1420  		uint8_t nonce[12];
1421  		CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++;
1422  		m_Server.AEADChaCha20Poly1305Encrypt (encryptBufs, m_SendKey, nonce, macBuf); // encrypt buffers
1423  		SetNextSentFrameLength (totalLen + 16, first->GetNTCP2Header () - 5); // frame length right before first block
1424  
1425  		// send buffers
1426  		m_IsSending = true;
1427  		boost::asio::async_write (m_Socket, bufs, boost::asio::transfer_all (),
1428  			std::bind(&NTCP2Session::HandleI2NPMsgsSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2, msgs));
1429  	}
1430  
1431  	void NTCP2Session::HandleI2NPMsgsSent (const boost::system::error_code& ecode, std::size_t bytes_transferred, std::vector<std::shared_ptr<I2NPMessage> > msgs)
1432  	{
1433  		HandleNextFrameSent (ecode, bytes_transferred);
1434  		// msgs get destroyed here
1435  	}
1436  
1437  	void NTCP2Session::EncryptAndSendNextBuffer (size_t payloadLen)
1438  	{
1439  		if (IsTerminated ())
1440  		{
1441  			delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr;
1442  			return;
1443  		}
1444  		if (payloadLen > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE)
1445  		{
1446  			LogPrint (eLogError, "NTCP2: Buffer to send is too long ", payloadLen);
1447  			delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr;
1448  			return;
1449  		}
1450  		// encrypt
1451  		uint8_t nonce[12];
1452  		CreateNonce (m_SendSequenceNumber, nonce); m_SendSequenceNumber++;
1453  		m_Server.AEADChaCha20Poly1305Encrypt ({ {m_NextSendBuffer + 2, payloadLen} }, m_SendKey, nonce, m_NextSendBuffer + payloadLen + 2);
1454  		SetNextSentFrameLength (payloadLen + 16, m_NextSendBuffer);
1455  		// send
1456  		m_IsSending = true;
1457  		boost::asio::async_write (m_Socket, boost::asio::buffer (m_NextSendBuffer, payloadLen + 16 + 2), boost::asio::transfer_all (),
1458  			std::bind(&NTCP2Session::HandleNextFrameSent, shared_from_this (), std::placeholders::_1, std::placeholders::_2));
1459  	}
1460  
1461  	void NTCP2Session::HandleNextFrameSent (const boost::system::error_code& ecode, std::size_t bytes_transferred)
1462  	{
1463  		m_IsSending = false;
1464  		delete[] m_NextSendBuffer; m_NextSendBuffer = nullptr;
1465  
1466  		if (ecode)
1467  		{
1468  			if (ecode != boost::asio::error::operation_aborted)
1469  				LogPrint (eLogWarning, "NTCP2: Couldn't send frame ", ecode.message ());
1470  			Terminate ();
1471  		}
1472  		else
1473  		{
1474  			UpdateNumSentBytes (bytes_transferred);
1475  			i2p::transport::transports.UpdateSentBytes (bytes_transferred);
1476  			LogPrint (eLogDebug, "NTCP2: Next frame sent ", bytes_transferred);
1477  			if (GetLastActivityTimestamp () > m_NextRouterInfoResendTime)
1478  			{
1479  				m_NextRouterInfoResendTime += NTCP2_ROUTERINFO_RESEND_INTERVAL +
1480  					m_Server.GetRng ()() % NTCP2_ROUTERINFO_RESEND_INTERVAL_THRESHOLD;
1481  				SendRouterInfo ();
1482  			}
1483  			else
1484  			{
1485  				SendQueue ();
1486  				SetSendQueueSize (m_SendQueue.size ());
1487  			}
1488  		}
1489  	}
1490  
1491  	void NTCP2Session::SendQueue ()
1492  	{
1493  		if (!m_SendQueue.empty () && m_IsEstablished)
1494  		{
1495  			std::vector<std::shared_ptr<I2NPMessage> > msgs;
1496  			auto ts = i2p::util::GetMillisecondsSinceEpoch ();
1497  			size_t s = 0;
1498  			while (!m_SendQueue.empty ())
1499  			{
1500  				auto msg = m_SendQueue.front ();
1501  				if (!msg || msg->IsExpired (ts))
1502  				{
1503  					// drop null or expired message
1504  					if (msg) msg->Drop ();
1505  					m_SendQueue.pop_front ();
1506  					continue;
1507  				}
1508  				size_t len = msg->GetNTCP2Length ();
1509  				if (s + len + 3 <= NTCP2_UNENCRYPTED_FRAME_MAX_SIZE) // 3 bytes block header
1510  				{
1511  					msgs.push_back (msg);
1512  					s += (len + 3);
1513  					m_SendQueue.pop_front ();
1514  					if (s >= NTCP2_SEND_AFTER_FRAME_SIZE)
1515  						break; // send frame right a way
1516  				}
1517  				else if (len + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE)
1518  				{
1519  					LogPrint (eLogError, "NTCP2: I2NP message of size ", len, " can't be sent. Dropped");
1520  					msg->Drop ();
1521  					m_SendQueue.pop_front ();
1522  				}
1523  				else
1524  					break;
1525  			}
1526  			SendI2NPMsgs (msgs);
1527  		}
1528  	}
1529  
1530  	void NTCP2Session::MoveSendQueue (std::shared_ptr<NTCP2Session> other)
1531  	{
1532  		if (!other || m_SendQueue.empty ()) return;
1533  		std::list<std::shared_ptr<I2NPMessage> > msgs;
1534  		auto ts = i2p::util::GetMillisecondsSinceEpoch ();
1535  		for (auto it: m_SendQueue)
1536  			if (!it->IsExpired (ts))
1537  				msgs.push_back (it);
1538  			else
1539  				it->Drop ();
1540  		m_SendQueue.clear ();
1541  		if (!msgs.empty ())
1542  			other->SendI2NPMessages (msgs);
1543  	}
1544  
1545  	size_t NTCP2Session::CreatePaddingBlock (size_t msgLen, uint8_t * buf, size_t len)
1546  	{
1547  		if (len < 3) return 0;
1548  		len -= 3;
1549  		if (msgLen < 256) msgLen = 256; // for short message padding should not be always zero
1550  		size_t paddingSize = (msgLen*NTCP2_MAX_PADDING_RATIO)/100;
1551  		if (msgLen + paddingSize + 3 > NTCP2_UNENCRYPTED_FRAME_MAX_SIZE)
1552  		{
1553  			int l = (int)NTCP2_UNENCRYPTED_FRAME_MAX_SIZE - msgLen -3;
1554  			if (l <= 0) return 0;
1555  			paddingSize = l;
1556  		}
1557  		if (paddingSize > len) paddingSize = len;
1558  		if (paddingSize)
1559  		{
1560  			if (m_NextPaddingSize >= 16)
1561  			{
1562  				RAND_bytes ((uint8_t *)m_PaddingSizes, sizeof (m_PaddingSizes));
1563  				m_NextPaddingSize = 0;
1564  			}
1565  			paddingSize = m_PaddingSizes[m_NextPaddingSize++] % (paddingSize + 1);
1566  		}
1567  		buf[0] = eNTCP2BlkPadding; // blk
1568  		htobe16buf (buf + 1, paddingSize); // size
1569  		memset (buf + 3, 0, paddingSize);
1570  		return paddingSize + 3;
1571  	}
1572  
1573  	void NTCP2Session::SendRouterInfo ()
1574  	{
1575  		if (!IsEstablished ()) return;
1576  		auto riBuffer =  i2p::context.CopyRouterInfoBuffer ();
1577  		auto riLen = riBuffer->GetBufferLen ();
1578  		size_t payloadLen = riLen + 3 + 1 + 7; // 3 bytes block header + 1 byte RI flag + 7 bytes DateTime
1579  		m_NextSendBuffer = new uint8_t[payloadLen + 16 + 2 + 64]; // up to 64 bytes padding
1580  		// DateTime	block
1581  		m_NextSendBuffer[2] = eNTCP2BlkDateTime;
1582  		htobe16buf (m_NextSendBuffer + 3, 4);
1583  		htobe32buf (m_NextSendBuffer + 5, (i2p::util::GetMillisecondsSinceEpoch () + 500)/1000);
1584  		// RouterInfo block
1585  		m_NextSendBuffer[9] = eNTCP2BlkRouterInfo;
1586  		htobe16buf (m_NextSendBuffer + 10, riLen + 1); // size
1587  		m_NextSendBuffer[12] = 0; // flag
1588  		memcpy (m_NextSendBuffer + 13, riBuffer->data (), riLen); // TODO: eliminate extra copy
1589  		// padding block
1590  		auto paddingSize = CreatePaddingBlock (payloadLen, m_NextSendBuffer + 2 + payloadLen, 64);
1591  		payloadLen += paddingSize;
1592  		// encrypt and send
1593  		EncryptAndSendNextBuffer (payloadLen);
1594  	}
1595  
1596  	void NTCP2Session::SendTermination (NTCP2TerminationReason reason)
1597  	{
1598  		if (!m_SendKey ||
1599  #if OPENSSL_SIPHASH
1600  			!m_SendMDCtx
1601  #else
1602  			!m_SendSipKey
1603  #endif
1604  		) return;
1605  		m_NextSendBuffer = new uint8_t[49]; // 49 = 12 bytes message + 16 bytes MAC + 2 bytes size + up to 19 padding block
1606  		// termination block
1607  		m_NextSendBuffer[2] = eNTCP2BlkTermination;
1608  		m_NextSendBuffer[3] = 0; m_NextSendBuffer[4] = 9; // 9 bytes block size
1609  		htobe64buf (m_NextSendBuffer + 5, m_ReceiveSequenceNumber);
1610  		m_NextSendBuffer[13] = (uint8_t)reason;
1611  		// padding block
1612  		auto paddingSize = CreatePaddingBlock (12, m_NextSendBuffer + 14, 19);
1613  		// encrypt and send
1614  		EncryptAndSendNextBuffer (paddingSize + 12);
1615  	}
1616  
1617  	void NTCP2Session::SendTerminationAndTerminate (NTCP2TerminationReason reason)
1618  	{
1619  		SendTermination (reason);
1620  		boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ())); // let termination message go
1621  	}
1622  
1623  	void NTCP2Session::ReadSomethingAndTerminate ()
1624  	{
1625  		size_t len = m_Server.GetRng ()() % NTCP2_SESSION_REQUEST_MAX_SIZE;
1626  		if (len > 0 && m_Establisher)
1627  			boost::asio::async_read (m_Socket, boost::asio::buffer(m_Establisher->m_Buffer, len), boost::asio::transfer_all (),
1628  				[s = shared_from_this()](const boost::system::error_code& ecode, size_t bytes_transferred)
1629  			    {
1630  					s->Terminate ();
1631  				});
1632  		else
1633  			boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::Terminate, shared_from_this ()));
1634  	}
1635  
1636  	void NTCP2Session::SendI2NPMessages (std::list<std::shared_ptr<I2NPMessage> >& msgs)
1637  	{
1638  		if (m_IsTerminated || msgs.empty ())
1639  		{
1640  			msgs.clear ();
1641  			return;
1642  		}
1643  		bool empty = false;
1644  		{
1645  			std::lock_guard<std::mutex> l(m_IntermediateQueueMutex);
1646  			empty = m_IntermediateQueue.empty ();
1647  			m_IntermediateQueue.splice (m_IntermediateQueue.end (), msgs);
1648  		}
1649  		if (empty)
1650  			boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::PostI2NPMessages, shared_from_this ()));
1651  	}
1652  
1653  	void NTCP2Session::PostI2NPMessages ()
1654  	{
1655  		if (m_IsTerminated) return;
1656  		std::list<std::shared_ptr<I2NPMessage> > msgs;
1657  		{
1658  			std::lock_guard<std::mutex> l(m_IntermediateQueueMutex);
1659  			m_IntermediateQueue.swap (msgs);
1660  		}
1661  		bool isSemiFull = m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE/2;
1662  		if (isSemiFull)
1663  		{
1664  			for (auto it: msgs)
1665  				if (it->onDrop)
1666  					it->Drop (); // drop earlier because we can handle it
1667  				else
1668  					m_SendQueue.push_back (std::move (it));
1669  		}
1670  		else
1671  			m_SendQueue.splice (m_SendQueue.end (), msgs);
1672  
1673  		if (!m_IsSending && m_IsEstablished)
1674  			SendQueue ();
1675  		else if (m_SendQueue.size () > NTCP2_MAX_OUTGOING_QUEUE_SIZE)
1676  		{
1677  			LogPrint (eLogWarning, "NTCP2: Outgoing messages queue size to ",
1678  				GetIdentHashBase64(), " exceeds ", NTCP2_MAX_OUTGOING_QUEUE_SIZE);
1679  			Terminate ();
1680  		}
1681  		SetSendQueueSize (m_SendQueue.size ());
1682  	}
1683  
1684  	void NTCP2Session::SendLocalRouterInfo (bool update)
1685  	{
1686  		if (update || !IsOutgoing ()) // we send it in SessionConfirmed for outgoing session
1687  			boost::asio::post (m_Server.GetService (), std::bind (&NTCP2Session::SendRouterInfo, shared_from_this ()));
1688  	}
1689  
1690  	i2p::data::RouterInfo::SupportedTransports NTCP2Session::GetTransportType () const
1691  	{
1692  		if (m_RemoteEndpoint.address ().is_v4 ()) return i2p::data::RouterInfo::eNTCP2V4;
1693  		return i2p::util::net::IsYggdrasilAddress (m_RemoteEndpoint.address ()) ? i2p::data::RouterInfo::eNTCP2V6Mesh : i2p::data::RouterInfo::eNTCP2V6;
1694  	}
1695  
1696  	NTCP2Server::NTCP2Server ():
1697  		RunnableServiceWithWork ("NTCP2"), m_TerminationTimer (GetService ()),
1698  		m_ProxyType(eNoProxy), m_Resolver(GetService ()),
1699  		m_Rng(i2p::util::GetMonotonicMicroseconds ()%1000000LL),
1700  		m_Version (2)
1701  	{
1702  	}
1703  
1704  	NTCP2Server::~NTCP2Server ()
1705  	{
1706  		Stop ();
1707  	}
1708  
1709  	void NTCP2Server::Start ()
1710  	{
1711  		m_EstablisherService.Start ();
1712  		if (!IsRunning ())
1713  		{
1714  			StartIOService ();
1715  			if(UsingProxy())
1716  			{
1717  				LogPrint(eLogInfo, "NTCP2: Using proxy to connect to peers");
1718  				// TODO: resolve proxy until it is resolved
1719  				boost::system::error_code e;
1720  				auto itr = m_Resolver.resolve(m_ProxyAddress, std::to_string(m_ProxyPort), e);
1721  				if(e)
1722  					LogPrint(eLogCritical, "NTCP2: Failed to resolve proxy ", e.message());
1723  				else
1724  				{
1725  					m_ProxyEndpoint.reset (new boost::asio::ip::tcp::endpoint(*itr.begin ()));
1726  					if (m_ProxyEndpoint)
1727  						LogPrint(eLogDebug, "NTCP2: m_ProxyEndpoint ", *m_ProxyEndpoint);
1728  				}
1729  			}
1730  			else
1731  				LogPrint(eLogInfo, "NTCP2: Proxy is not used");
1732  			// start acceptors
1733  			auto addresses = context.GetRouterInfo ().GetAddresses ();
1734  			if (!addresses) return;
1735  			for (const auto& address: *addresses)
1736  			{
1737  				if (!address) continue;
1738  				if (address->IsPublishedNTCP2 () && address->port)
1739  				{
1740  					if (address->IsV4())
1741  					{
1742  						try
1743  						{
1744  							auto ep = m_Address4 ? boost::asio::ip::tcp::endpoint (m_Address4->address(), address->port):
1745  								boost::asio::ip::tcp::endpoint (boost::asio::ip::tcp::v4(), address->port);
1746  							m_NTCP2Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService (), ep));
1747  						}
1748  						catch ( std::exception & ex )
1749  						{
1750  							LogPrint(eLogCritical, "NTCP2: Failed to bind to v4 port ", address->port, ex.what());
1751  							ThrowFatal ("Unable to start IPv4 NTCP2 transport at port ", address->port, ": ", ex.what ());
1752  							continue;
1753  						}
1754  
1755  						LogPrint (eLogInfo, "NTCP2: Start listening v4 TCP port ", address->port);
1756  						auto conn = std::make_shared<NTCP2Session>(*this);
1757  						m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this, conn, std::placeholders::_1));
1758  					}
1759  					else if (address->IsV6() && (context.SupportsV6 () || context.SupportsMesh ()))
1760  					{
1761  #if defined(__HAIKU__)
1762  						LogPrint (eLogInfo, "NTCP2: Can't listen v6 TCP port ", address->port, ". IPV6_V6ONLY is not supported");
1763  						continue; // IPV6_V6ONLY is not supported. Don't listen ipv6
1764  #endif
1765  						m_NTCP2V6Acceptor.reset (new boost::asio::ip::tcp::acceptor (GetService ()));
1766  						try
1767  						{
1768  							m_NTCP2V6Acceptor->open (boost::asio::ip::tcp::v6());
1769  							m_NTCP2V6Acceptor->set_option (boost::asio::ip::v6_only (true));
1770  							m_NTCP2V6Acceptor->set_option (boost::asio::socket_base::reuse_address (true));
1771  #if defined(__linux__) && !defined(_NETINET_IN_H)
1772  							if (!m_Address6 && !m_YggdrasilAddress) // only if not binded to address
1773  							{
1774  								// Set preference to use public IPv6 address -- tested on linux, not works on windows, and not tested on others
1775  #if (BOOST_VERSION >= 105500)
1776  								typedef boost::asio::detail::socket_option::integer<BOOST_ASIO_OS_DEF(IPPROTO_IPV6), IPV6_ADDR_PREFERENCES> ipv6PreferAddr;
1777  #else
1778  								typedef boost::asio::detail::socket_option::integer<IPPROTO_IPV6, IPV6_ADDR_PREFERENCES> ipv6PreferAddr;
1779  #endif
1780  								m_NTCP2V6Acceptor->set_option (ipv6PreferAddr(IPV6_PREFER_SRC_PUBLIC | IPV6_PREFER_SRC_HOME | IPV6_PREFER_SRC_NONCGA));
1781  							}
1782  #endif
1783  							auto ep = boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v6(), address->port);
1784  							if (m_Address6 && !context.SupportsMesh ())
1785  								ep = boost::asio::ip::tcp::endpoint (m_Address6->address(), address->port);
1786  							else if (m_YggdrasilAddress && !context.SupportsV6 ())
1787  								ep = boost::asio::ip::tcp::endpoint (m_YggdrasilAddress->address(), address->port);
1788  							m_NTCP2V6Acceptor->bind (ep);
1789  							m_NTCP2V6Acceptor->listen ();
1790  
1791  							LogPrint (eLogInfo, "NTCP2: Start listening v6 TCP port ", address->port);
1792  							auto conn = std::make_shared<NTCP2Session> (*this);
1793  							m_NTCP2V6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAcceptV6, this, conn, std::placeholders::_1));
1794  						}
1795  						catch ( std::exception & ex )
1796  						{
1797  							LogPrint(eLogCritical, "NTCP2: Failed to bind to v6 port ", address->port, ": ", ex.what());
1798  							ThrowFatal ("Unable to start IPv6 NTCP2 transport at port ", address->port, ": ", ex.what ());
1799  							continue;
1800  						}
1801  					}
1802  				}
1803  			}
1804  			ScheduleTermination ();
1805  		}
1806  	}
1807  
1808  	void NTCP2Server::Stop ()
1809  	{
1810  		m_EstablisherService.Stop ();
1811  		{
1812  			// we have to copy it because Terminate changes m_NTCP2Sessions
1813  			auto ntcpSessions = m_NTCP2Sessions;
1814  			for (auto& it: ntcpSessions)
1815  				it.second->Terminate ();
1816  			for (auto& it: m_PendingIncomingSessions)
1817  				it.second->Terminate ();
1818  		}
1819  		m_NTCP2Sessions.clear ();
1820  
1821  		if (IsRunning ())
1822  		{
1823  			m_TerminationTimer.cancel ();
1824  			m_ProxyEndpoint = nullptr;
1825  		}
1826  		StopIOService ();
1827  	}
1828  
1829  	bool NTCP2Server::AddNTCP2Session (std::shared_ptr<NTCP2Session> session, bool incoming)
1830  	{
1831  		if (!session) return false;
1832  		if (incoming)
1833  			m_PendingIncomingSessions.erase (session->GetRemoteEndpoint ().address ());
1834  		if (!session->GetRemoteIdentity ())
1835  		{
1836  			LogPrint (eLogWarning, "NTCP2: Unknown identity for ", session->GetRemoteEndpoint ());
1837  			session->Terminate ();
1838  			return false;
1839  		}
1840  		auto& ident = session->GetRemoteIdentity ()->GetIdentHash ();
1841  		auto it = m_NTCP2Sessions.find (ident);
1842  		if (it != m_NTCP2Sessions.end ())
1843  		{
1844  			LogPrint (eLogWarning, "NTCP2: Session with ", ident.ToBase64 (), " already exists. ", incoming ? "Replaced" : "Dropped");
1845  			if (incoming)
1846  			{
1847  				// replace by new session
1848  				auto s = it->second;
1849  				s->MoveSendQueue (session);
1850  				m_NTCP2Sessions.erase (it);
1851  				s->Terminate ();
1852  			}
1853  			else
1854  			{
1855  				session->Terminate ();
1856  				return false;
1857  			}
1858  		}
1859  		m_NTCP2Sessions.emplace (ident, session);
1860  		return true;
1861  	}
1862  
1863  	void NTCP2Server::RemoveNTCP2Session (std::shared_ptr<NTCP2Session> session)
1864  	{
1865  		if (session && session->GetRemoteIdentity ())
1866  		{
1867  			auto it = m_NTCP2Sessions.find (session->GetRemoteIdentity ()->GetIdentHash ());
1868  			if (it != m_NTCP2Sessions.end () && it->second == session)
1869  				m_NTCP2Sessions.erase (it);
1870  		}
1871  	}
1872  
1873  	std::shared_ptr<NTCP2Session> NTCP2Server::FindNTCP2Session (const i2p::data::IdentHash& ident)
1874  	{
1875  		auto it = m_NTCP2Sessions.find (ident);
1876  		if (it != m_NTCP2Sessions.end ())
1877  			return it->second;
1878  		return nullptr;
1879  	}
1880  
1881  	void NTCP2Server::Connect(std::shared_ptr<NTCP2Session> conn)
1882  	{
1883  		if (!conn || conn->GetRemoteEndpoint ().address ().is_unspecified ())
1884  		{
1885  			LogPrint (eLogError, "NTCP2: Can't connect to unspecified address");
1886  			return;
1887  		}
1888  		LogPrint (eLogDebug, "NTCP2: Connecting to ", conn->GetRemoteEndpoint (),
1889  			" (", i2p::data::GetIdentHashAbbreviation (conn->GetRemoteIdentity ()->GetIdentHash ()), ")");
1890  		boost::asio::post (GetService (), [this, conn]()
1891  			{
1892  				if (this->AddNTCP2Session (conn))
1893  				{
1894  					auto timer = std::make_shared<boost::asio::steady_timer>(GetService ());
1895  					auto timeout = NTCP2_CONNECT_TIMEOUT * 5;
1896  					conn->SetTerminationTimeout(timeout * 2);
1897  					timer->expires_after (std::chrono::seconds(timeout));
1898  					timer->async_wait ([conn, timeout](const boost::system::error_code& ecode)
1899  					{
1900  						if (ecode != boost::asio::error::operation_aborted)
1901  						{
1902  							LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds");
1903  							conn->Terminate ();
1904  						}
1905  					});
1906  					// bind to local address
1907  					std::shared_ptr<boost::asio::ip::tcp::endpoint> localAddress;
1908  					if (conn->GetRemoteEndpoint ().address ().is_v6 ())
1909  					{
1910  						if (i2p::util::net::IsYggdrasilAddress (conn->GetRemoteEndpoint ().address ()))
1911  							localAddress = m_YggdrasilAddress;
1912  						else
1913  							localAddress = m_Address6;
1914  						conn->GetSocket ().open (boost::asio::ip::tcp::v6 ());
1915  					}
1916  					else
1917  					{
1918  						localAddress = m_Address4;
1919  						conn->GetSocket ().open (boost::asio::ip::tcp::v4 ());
1920  					}
1921  					if (localAddress)
1922  					{
1923  						boost::system::error_code ec;
1924  						conn->GetSocket ().bind (*localAddress, ec);
1925  						if (ec)
1926  							LogPrint (eLogError, "NTCP2: Can't bind to ", localAddress->address ().to_string (), ": ", ec.message ());
1927  					}
1928  					conn->GetSocket ().async_connect (conn->GetRemoteEndpoint (), std::bind (&NTCP2Server::HandleConnect, this, std::placeholders::_1, conn, timer));
1929  				}
1930  				else
1931  					conn->Terminate ();
1932  			});
1933  	}
1934  
1935  	void NTCP2Server::HandleConnect (const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::steady_timer> timer)
1936  	{
1937  		timer->cancel ();
1938  		if (ecode)
1939  		{
1940  			LogPrint (eLogInfo, "NTCP2: Connect error ", ecode.message ());
1941  			conn->Terminate ();
1942  		}
1943  		else
1944  		{
1945  			LogPrint (eLogDebug, "NTCP2: Connected to ", conn->GetRemoteEndpoint (),
1946  				" (", i2p::data::GetIdentHashAbbreviation (conn->GetRemoteIdentity ()->GetIdentHash ()), ")");
1947  			conn->ClientLogin ();
1948  		}
1949  	}
1950  
1951  	void NTCP2Server::HandleAccept (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error)
1952  	{
1953  		if (!error && conn)
1954  		{
1955  			boost::system::error_code ec;
1956  			auto ep = conn->GetSocket ().remote_endpoint(ec);
1957  			if (!ec)
1958  			{
1959  				LogPrint (eLogDebug, "NTCP2: Connected from ", ep);
1960  				if (!i2p::transport::transports.IsInReservedRange(ep.address ()) && !i2p::transport::transports.IsBanned(ep.address ()))
1961  				{
1962  					if (m_PendingIncomingSessions.emplace (ep.address (), conn).second)
1963  					{
1964  						conn->SetRemoteEndpoint (ep);
1965  						conn->ServerLogin (m_Version);
1966  						conn = nullptr;
1967  					}
1968  					else
1969  						LogPrint (eLogInfo, "NTCP2: Incoming session from ", ep.address (), " is already pending");
1970  				}
1971  				else
1972  					LogPrint (eLogError, "NTCP2: Incoming connection from invalid or banned IP ", ep.address ());
1973  			}
1974  			else
1975  				LogPrint (eLogError, "NTCP2: Connected from error ", ec.message ());
1976  		}
1977  		else
1978  		{
1979  			LogPrint (eLogError, "NTCP2: Accept error ", error.message ());
1980  			if (error == boost::asio::error::no_descriptors)
1981  			{
1982  				i2p::context.SetError (eRouterErrorNoDescriptors);
1983  				return;
1984  			}
1985  		}
1986  
1987  		if (error != boost::asio::error::operation_aborted)
1988  		{
1989  			if (!conn) // connection is used, create new one
1990  				conn = std::make_shared<NTCP2Session> (*this);
1991  			else // reuse failed
1992  				conn->Close ();
1993  			m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this,
1994  				conn, std::placeholders::_1));
1995  		}
1996  	}
1997  
1998  	void NTCP2Server::HandleAcceptV6 (std::shared_ptr<NTCP2Session> conn, const boost::system::error_code& error)
1999  	{
2000  		if (!error && conn)
2001  		{
2002  			boost::system::error_code ec;
2003  			auto ep = conn->GetSocket ().remote_endpoint(ec);
2004  			if (!ec)
2005  			{
2006  				LogPrint (eLogDebug, "NTCP2: Connected from ", ep);
2007  				if ((!i2p::transport::transports.IsInReservedRange(ep.address ()) ||
2008  				    i2p::util::net::IsYggdrasilAddress (ep.address ())) &&
2009  				    !i2p::transport::transports.IsBanned(ep.address ()))
2010  				{
2011  					if (m_PendingIncomingSessions.emplace (ep.address (), conn).second)
2012  					{
2013  						conn->SetRemoteEndpoint (ep);
2014  						conn->ServerLogin (i2p::util::net::IsYggdrasilAddress (ep.address ()) ? 2 : m_Version); // yggdrasil is always 2 for now
2015  						conn = nullptr;
2016  					}
2017  					else
2018  						LogPrint (eLogInfo, "NTCP2: Incoming session from ", ep.address (), " is already pending");
2019  				}
2020  				else
2021  					LogPrint (eLogError, "NTCP2: Incoming connection from invalid or banned IP ", ep.address ());
2022  			}
2023  			else
2024  				LogPrint (eLogError, "NTCP2: Connected from error ", ec.message ());
2025  		}
2026  		else
2027  		{
2028  			LogPrint (eLogError, "NTCP2: Accept ipv6 error ", error.message ());
2029  			if (error == boost::asio::error::no_descriptors)
2030  			{
2031  				i2p::context.SetErrorV6 (eRouterErrorNoDescriptors);
2032  				return;
2033  			}
2034  		}
2035  
2036  		if (error != boost::asio::error::operation_aborted)
2037  		{
2038  			if (!conn) // connection is used, create new one
2039  				conn = std::make_shared<NTCP2Session> (*this);
2040  			else // reuse failed
2041  				conn->Close ();
2042  			m_NTCP2V6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAcceptV6, this,
2043  				conn, std::placeholders::_1));
2044  		}
2045  	}
2046  
2047  	void NTCP2Server::ScheduleTermination ()
2048  	{
2049  		m_TerminationTimer.expires_after (std::chrono::seconds(
2050  			NTCP2_TERMINATION_CHECK_TIMEOUT + m_Rng () % NTCP2_TERMINATION_CHECK_TIMEOUT_VARIANCE));
2051  		m_TerminationTimer.async_wait (std::bind (&NTCP2Server::HandleTerminationTimer,
2052  			this, std::placeholders::_1));
2053  	}
2054  
2055  	void NTCP2Server::HandleTerminationTimer (const boost::system::error_code& ecode)
2056  	{
2057  		if (ecode != boost::asio::error::operation_aborted)
2058  		{
2059  			auto ts = i2p::util::GetSecondsSinceEpoch ();
2060  			// established
2061  			for (auto& it: m_NTCP2Sessions)
2062  				if (it.second->IsTerminationTimeoutExpired (ts))
2063  				{
2064  					auto session = it.second;
2065  					LogPrint (eLogDebug, "NTCP2: No activity for ", session->GetTerminationTimeout (), " seconds");
2066  					session->TerminateByTimeout (); // it doesn't change m_NTCP2Session right a way
2067  				}
2068  				else
2069  					it.second->DeleteNextReceiveBuffer (ts);
2070  			// pending
2071  			for (auto it = m_PendingIncomingSessions.begin (); it != m_PendingIncomingSessions.end ();)
2072  			{
2073  				if (it->second->IsEstablished () || it->second->IsTerminationTimeoutExpired (ts))
2074  				{
2075  					it->second->Terminate ();
2076  					it = m_PendingIncomingSessions.erase (it); // established of expired
2077  				}
2078  				else if (it->second->IsTerminated ())
2079  					it = m_PendingIncomingSessions.erase (it); // already terminated
2080  				else
2081  					it++;
2082  			}
2083  			ScheduleTermination ();
2084  
2085  			// try to restart acceptors if no description
2086  			// we do it after timer to let timer take descriptor first
2087  			if (i2p::context.GetError () == eRouterErrorNoDescriptors)
2088  			{
2089  				i2p::context.SetError (eRouterErrorNone);
2090  				auto conn = std::make_shared<NTCP2Session> (*this);
2091  				m_NTCP2Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAccept, this,
2092  					conn, std::placeholders::_1));
2093  			}
2094  			if (i2p::context.GetErrorV6 () == eRouterErrorNoDescriptors)
2095  			{
2096  				i2p::context.SetErrorV6 (eRouterErrorNone);
2097  				auto conn = std::make_shared<NTCP2Session> (*this);
2098  				m_NTCP2V6Acceptor->async_accept(conn->GetSocket (), std::bind (&NTCP2Server::HandleAcceptV6, this,
2099  					conn, std::placeholders::_1));
2100  			}
2101  		}
2102  	}
2103  
2104  	void NTCP2Server::ConnectWithProxy (std::shared_ptr<NTCP2Session> conn)
2105  	{
2106  		if(!m_ProxyEndpoint) return;
2107  		if (!conn || conn->GetRemoteEndpoint ().address ().is_unspecified ())
2108  		{
2109  			LogPrint (eLogError, "NTCP2: Can't connect to unspecified address");
2110  			return;
2111  		}
2112  		boost::asio::post (GetService(), [this, conn]()
2113  		{
2114  			if (this->AddNTCP2Session (conn))
2115  			{
2116  				auto timer = std::make_shared<boost::asio::steady_timer>(GetService());
2117  				auto timeout = NTCP2_CONNECT_TIMEOUT * 5;
2118  				conn->SetTerminationTimeout(timeout * 2);
2119  				timer->expires_after (std::chrono::seconds(timeout));
2120  				timer->async_wait ([conn, timeout](const boost::system::error_code& ecode)
2121  				{
2122  					if (ecode != boost::asio::error::operation_aborted)
2123  					{
2124  						LogPrint (eLogInfo, "NTCP2: Not connected in ", timeout, " seconds");
2125  						conn->Terminate ();
2126  					}
2127  				});
2128  				conn->GetSocket ().async_connect (*m_ProxyEndpoint, std::bind (&NTCP2Server::HandleProxyConnect, this, std::placeholders::_1, conn, timer));
2129  			}
2130  		});
2131  	}
2132  
2133  	void NTCP2Server::UseProxy(ProxyType proxytype, const std::string& addr, uint16_t port,
2134  		const std::string& user, const std::string& pass)
2135  	{
2136  		m_ProxyType = proxytype;
2137  		m_ProxyAddress = addr;
2138  		m_ProxyPort = port;
2139  		if (m_ProxyType == eHTTPProxy )
2140  			m_ProxyAuthorization = i2p::http::CreateBasicAuthorizationString (user, pass);
2141  	}
2142  
2143  	void NTCP2Server::HandleProxyConnect(const boost::system::error_code& ecode, std::shared_ptr<NTCP2Session> conn, std::shared_ptr<boost::asio::steady_timer> timer)
2144  	{
2145  		if (ecode)
2146  		{
2147  			LogPrint(eLogWarning, "NTCP2: Failed to connect to proxy ", ecode.message());
2148  			timer->cancel();
2149  			conn->Terminate();
2150  			return;
2151  		}
2152  		switch (m_ProxyType)
2153  		{
2154  			case eSocksProxy:
2155  			{
2156  				// TODO: support username/password auth etc
2157  				Socks5Handshake (conn->GetSocket(), conn->GetRemoteEndpoint (),
2158  					[conn, timer](const boost::system::error_code& ec)
2159  				    {
2160  						timer->cancel();
2161  						if (!ec)
2162  							conn->ClientLogin();
2163  						else
2164  						{
2165  							LogPrint(eLogError, "NTCP2: SOCKS proxy handshake error ", ec.message());
2166  							conn->Terminate();
2167  						}
2168  					});
2169  				break;
2170  			}
2171  			case eHTTPProxy:
2172  			{
2173  				auto& ep = conn->GetRemoteEndpoint ();
2174  				i2p::http::HTTPReq req;
2175  				req.method = "CONNECT";
2176  				req.version ="HTTP/1.1";
2177  				if(ep.address ().is_v6 ())
2178  					req.uri = "[" + ep.address ().to_string() + "]:" + std::to_string(ep.port ());
2179  				else
2180  					req.uri = ep.address ().to_string() + ":" + std::to_string(ep.port ());
2181  				if (!m_ProxyAuthorization.empty ())
2182  					req.AddHeader("Proxy-Authorization", m_ProxyAuthorization);
2183  
2184  				boost::asio::streambuf writebuff;
2185  				std::ostream out(&writebuff);
2186  				out << req.to_string();
2187  
2188  				boost::asio::async_write(conn->GetSocket(), writebuff.data(), boost::asio::transfer_all(),
2189  					[](const boost::system::error_code & ec, std::size_t transferred)
2190  					{
2191  						(void) transferred;
2192  						if(ec)
2193  							LogPrint(eLogError, "NTCP2: HTTP proxy write error ", ec.message());
2194  					});
2195  
2196  				auto readbuff = std::make_shared<boost::asio::streambuf>();
2197  				boost::asio::async_read_until(conn->GetSocket(), *readbuff, "\r\n\r\n",
2198  					[readbuff, timer, conn] (const boost::system::error_code & ec, std::size_t transferred)
2199  					{
2200  						if(ec)
2201  						{
2202  							LogPrint(eLogError, "NTCP2: HTTP proxy read error ", ec.message());
2203  							timer->cancel();
2204  							conn->Terminate();
2205  						}
2206  						else
2207  						{
2208  							readbuff->commit(transferred);
2209  							i2p::http::HTTPRes res;
2210  							if(res.parse(std::string {boost::asio::buffers_begin(readbuff->data ()), boost::asio::buffers_begin(readbuff->data ()) + readbuff->size ()}) > 0)
2211  							{
2212  								if(res.code == 200)
2213  								{
2214  									timer->cancel();
2215  									conn->ClientLogin();
2216  									return;
2217  								}
2218  								else
2219  									LogPrint(eLogError, "NTCP2: HTTP proxy rejected request ", res.code);
2220  							}
2221  							else
2222  								LogPrint(eLogError, "NTCP2: HTTP proxy gave malformed response");
2223  							timer->cancel();
2224  							conn->Terminate();
2225  						}
2226  					});
2227  				break;
2228  			}
2229  			default:
2230  				LogPrint(eLogError, "NTCP2: Unknown proxy type, invalid state");
2231  		}
2232  	}
2233  
2234  	void NTCP2Server::SetLocalAddress (const boost::asio::ip::address& localAddress)
2235  	{
2236  		auto addr = std::make_shared<boost::asio::ip::tcp::endpoint>(boost::asio::ip::tcp::endpoint(localAddress, 0));
2237  		if (localAddress.is_v6 ())
2238  		{
2239  			if (i2p::util::net::IsYggdrasilAddress (localAddress))
2240  				m_YggdrasilAddress = addr;
2241  			else
2242  				m_Address6 = addr;
2243  		}
2244  		else
2245  			m_Address4 = addr;
2246  	}
2247  
2248  	void NTCP2Server::AEADChaCha20Poly1305Encrypt (const std::vector<std::pair<uint8_t *, size_t> >& bufs,
2249  		const uint8_t * key, const uint8_t * nonce, uint8_t * mac)
2250  	{
2251  		return m_Encryptor.Encrypt (bufs, key, nonce, mac);
2252  	}
2253  
2254  	bool NTCP2Server::AEADChaCha20Poly1305Decrypt (const uint8_t * msg, size_t msgLen,
2255  		const uint8_t * ad, size_t adLen, const uint8_t * key, const uint8_t * nonce, uint8_t * buf, size_t len)
2256  	{
2257  		return m_Decryptor.Decrypt (msg, msgLen, ad, adLen, key, nonce, buf, len);
2258  	}
2259  
2260  	void NTCP2Server::SetVersion (int version)
2261  	{
2262  #if OPENSSL_PQ
2263          m_Version = version;
2264  #endif
2265  	}
2266  }
2267  }