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 }