TunnelPool.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 #include <algorithm> 10 #include "I2PEndian.h" 11 #include "Crypto.h" 12 #include "Tunnel.h" 13 #include "NetDb.hpp" 14 #include "Timestamp.h" 15 #include "Garlic.h" 16 #include "ECIESX25519AEADRatchetSession.h" 17 #include "Transports.h" 18 #include "Log.h" 19 #include "Tunnel.h" 20 #include "TunnelPool.h" 21 #include "Destination.h" 22 23 namespace i2p 24 { 25 namespace tunnel 26 { 27 void Path::Add (std::shared_ptr<const i2p::data::RouterInfo> r) 28 { 29 if (r) 30 { 31 peers.push_back (r->GetRouterIdentity ()); 32 if (r->GetVersion () < i2p::data::NETDB_MIN_SHORT_TUNNEL_BUILD_VERSION || 33 r->GetRouterIdentity ()->GetCryptoKeyType () != i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD) 34 isShort = false; 35 } 36 } 37 38 void Path::Reverse () 39 { 40 std::reverse (peers.begin (), peers.end ()); 41 } 42 43 TunnelPool::TunnelPool (int numInboundHops, int numOutboundHops, int numInboundTunnels, 44 int numOutboundTunnels, int inboundVariance, int outboundVariance, bool isHighBandwidth): 45 m_NumInboundHops (numInboundHops), m_NumOutboundHops (numOutboundHops), 46 m_NumInboundTunnels (numInboundTunnels), m_NumOutboundTunnels (numOutboundTunnels), 47 m_InboundVariance (inboundVariance), m_OutboundVariance (outboundVariance), 48 m_IsActive (true), m_IsHighBandwidth (isHighBandwidth), m_CustomPeerSelector(nullptr) 49 { 50 if (m_NumInboundTunnels > TUNNEL_POOL_MAX_INBOUND_TUNNELS_QUANTITY) 51 m_NumInboundTunnels = TUNNEL_POOL_MAX_INBOUND_TUNNELS_QUANTITY; 52 if (m_NumOutboundTunnels > TUNNEL_POOL_MAX_OUTBOUND_TUNNELS_QUANTITY) 53 m_NumOutboundTunnels = TUNNEL_POOL_MAX_OUTBOUND_TUNNELS_QUANTITY; 54 if (m_InboundVariance < 0 && m_NumInboundHops + m_InboundVariance <= 0) 55 m_InboundVariance = m_NumInboundHops ? -m_NumInboundHops + 1 : 0; 56 if (m_OutboundVariance < 0 && m_NumOutboundHops + m_OutboundVariance <= 0) 57 m_OutboundVariance = m_NumOutboundHops ? -m_NumOutboundHops + 1 : 0; 58 if (m_InboundVariance > 0 && m_NumInboundHops + m_InboundVariance > STANDARD_NUM_RECORDS) 59 m_InboundVariance = (m_NumInboundHops < STANDARD_NUM_RECORDS) ? STANDARD_NUM_RECORDS - m_NumInboundHops : 0; 60 if (m_OutboundVariance > 0 && m_NumOutboundHops + m_OutboundVariance > STANDARD_NUM_RECORDS) 61 m_OutboundVariance = (m_NumOutboundHops < STANDARD_NUM_RECORDS) ? STANDARD_NUM_RECORDS - m_NumOutboundHops : 0; 62 m_NextManageTime = i2p::util::GetSecondsSinceEpoch () + rand () % TUNNEL_POOL_MANAGE_INTERVAL; 63 } 64 65 TunnelPool::~TunnelPool () 66 { 67 DetachTunnels (); 68 } 69 70 void TunnelPool::SetExplicitPeers (std::vector<i2p::data::IdentHash> explicitPeers) 71 { 72 m_ExplicitPeers.swap (explicitPeers); 73 int size = m_ExplicitPeers.size (); 74 if (size > 0) 75 { 76 if (m_NumInboundHops > size) 77 { 78 m_NumInboundHops = size; 79 LogPrint (eLogInfo, "Tunnels: Inbound tunnel length has been adjusted to ", size, " for explicit peers"); 80 } 81 if (m_NumOutboundHops > size) 82 { 83 m_NumOutboundHops = size; 84 LogPrint (eLogInfo, "Tunnels: Outbound tunnel length has been adjusted to ", size, " for explicit peers"); 85 } 86 m_NumInboundTunnels = 1; 87 m_NumOutboundTunnels = 1; 88 } 89 } 90 91 void TunnelPool::SetTrustedRouters (std::vector<i2p::data::IdentHash> routers) 92 { 93 m_TrustedRouters.swap (routers); 94 } 95 96 void TunnelPool::DetachTunnels () 97 { 98 { 99 std::unique_lock<std::mutex> l(m_InboundTunnelsMutex); 100 for (auto& it: m_InboundTunnels) 101 it->SetTunnelPool (nullptr); 102 m_InboundTunnels.clear (); 103 } 104 { 105 std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex); 106 for (auto& it: m_OutboundTunnels) 107 it->SetTunnelPool (nullptr); 108 m_OutboundTunnels.clear (); 109 } 110 { 111 std::unique_lock<std::mutex> l(m_TestsMutex); 112 m_Tests.clear (); 113 } 114 } 115 116 bool TunnelPool::Reconfigure(int inHops, int outHops, int inQuant, int outQuant) 117 { 118 if( inHops >= 0 && outHops >= 0 && inQuant > 0 && outQuant > 0) 119 { 120 m_NumInboundHops = inHops; 121 m_NumOutboundHops = outHops; 122 m_NumInboundTunnels = inQuant; 123 m_NumOutboundTunnels = outQuant; 124 return true; 125 } 126 return false; 127 } 128 129 void TunnelPool::TunnelCreated (std::shared_ptr<InboundTunnel> createdTunnel) 130 { 131 if (!m_IsActive) return; 132 { 133 std::unique_lock<std::mutex> l(m_InboundTunnelsMutex); 134 if (createdTunnel->IsRecreated ()) 135 { 136 // find and mark old tunnel as expired 137 createdTunnel->SetRecreated (false); 138 for (auto& it: m_InboundTunnels) 139 if (it->IsRecreated () && it->GetNextIdentHash () == createdTunnel->GetNextIdentHash ()) 140 { 141 it->SetState (eTunnelStateExpiring); 142 break; 143 } 144 } 145 m_InboundTunnels.insert (createdTunnel); 146 } 147 if (m_LocalDestination) 148 m_LocalDestination->SetLeaseSetUpdated (true); 149 } 150 151 void TunnelPool::TunnelExpired (std::shared_ptr<InboundTunnel> expiredTunnel) 152 { 153 if (expiredTunnel) 154 { 155 expiredTunnel->SetTunnelPool (nullptr); 156 { 157 std::unique_lock<std::mutex> l(m_TestsMutex); 158 for (auto& it: m_Tests) 159 if (it.second.second == expiredTunnel) it.second.second = nullptr; 160 } 161 162 std::unique_lock<std::mutex> l(m_InboundTunnelsMutex); 163 m_InboundTunnels.erase (expiredTunnel); 164 } 165 } 166 167 void TunnelPool::TunnelCreated (std::shared_ptr<OutboundTunnel> createdTunnel) 168 { 169 if (!m_IsActive) return; 170 { 171 std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex); 172 m_OutboundTunnels.insert (createdTunnel); 173 } 174 } 175 176 void TunnelPool::TunnelExpired (std::shared_ptr<OutboundTunnel> expiredTunnel) 177 { 178 if (expiredTunnel) 179 { 180 expiredTunnel->SetTunnelPool (nullptr); 181 { 182 std::unique_lock<std::mutex> l(m_TestsMutex); 183 for (auto& it: m_Tests) 184 if (it.second.first == expiredTunnel) it.second.first = nullptr; 185 } 186 187 std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex); 188 m_OutboundTunnels.erase (expiredTunnel); 189 } 190 } 191 192 std::vector<std::shared_ptr<InboundTunnel> > TunnelPool::GetInboundTunnels (int num) const 193 { 194 std::vector<std::shared_ptr<InboundTunnel> > v; 195 int i = 0; 196 std::shared_ptr<InboundTunnel> slowTunnel; 197 std::unique_lock<std::mutex> l(m_InboundTunnelsMutex); 198 for (const auto& it : m_InboundTunnels) 199 { 200 if (i >= num) break; 201 if (it->IsEstablished ()) 202 { 203 if (it->IsSlow () && !slowTunnel) 204 slowTunnel = it; 205 else 206 { 207 v.push_back (it); 208 i++; 209 } 210 } 211 } 212 if (slowTunnel && (int)v.size () < (num/2+1)) 213 v.push_back (slowTunnel); 214 return v; 215 } 216 217 std::shared_ptr<OutboundTunnel> TunnelPool::GetNextOutboundTunnel (std::shared_ptr<OutboundTunnel> excluded, 218 i2p::data::RouterInfo::CompatibleTransports compatible) 219 { 220 std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex); 221 return GetNextTunnel (m_OutboundTunnels, excluded, compatible); 222 } 223 224 std::shared_ptr<InboundTunnel> TunnelPool::GetNextInboundTunnel (std::shared_ptr<InboundTunnel> excluded, 225 i2p::data::RouterInfo::CompatibleTransports compatible) 226 { 227 std::unique_lock<std::mutex> l(m_InboundTunnelsMutex); 228 return GetNextTunnel (m_InboundTunnels, excluded, compatible); 229 } 230 231 template<class TTunnels> 232 typename TTunnels::value_type TunnelPool::GetNextTunnel (TTunnels& tunnels, 233 typename TTunnels::value_type excluded, i2p::data::RouterInfo::CompatibleTransports compatible) 234 { 235 if (tunnels.empty ()) return nullptr; 236 uint32_t ind = (m_LocalDestination ? m_LocalDestination->GetRng ()() : rand ()) % (tunnels.size ()/2 + 1), i = 0; 237 bool skipped = false; 238 typename TTunnels::value_type tunnel = nullptr; 239 for (const auto& it: tunnels) 240 { 241 if (it->IsEstablished () && it != excluded && (compatible & it->GetFarEndTransports ())) 242 { 243 if (it->IsSlow () || (HasLatencyRequirement() && it->LatencyIsKnown() && 244 !it->LatencyFitsRange(m_MinLatency, m_MaxLatency))) 245 { 246 i++; skipped = true; 247 continue; 248 } 249 tunnel = it; 250 i++; 251 } 252 if (i > ind && tunnel) break; 253 } 254 if (!tunnel && skipped) 255 { 256 ind = (m_LocalDestination ? m_LocalDestination->GetRng ()() : rand ()) % (tunnels.size ()/2 + 1), i = 0; 257 for (const auto& it: tunnels) 258 { 259 if (it->IsEstablished () && it != excluded) 260 { 261 tunnel = it; 262 i++; 263 } 264 if (i > ind && tunnel) break; 265 } 266 } 267 if (!tunnel && excluded && excluded->IsEstablished ()) tunnel = excluded; 268 return tunnel; 269 } 270 271 std::pair<std::shared_ptr<OutboundTunnel>, bool> TunnelPool::GetNewOutboundTunnel (std::shared_ptr<OutboundTunnel> old) 272 { 273 if (old && old->IsEstablished ()) return std::make_pair(old, false); 274 std::shared_ptr<OutboundTunnel> tunnel; 275 bool freshTunnel = false; 276 if (old) 277 { 278 std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex); 279 for (const auto& it: m_OutboundTunnels) 280 if (it->IsEstablished () && old->GetEndpointIdentHash () == it->GetEndpointIdentHash ()) 281 { 282 tunnel = it; 283 break; 284 } 285 } 286 287 if (!tunnel) 288 { 289 tunnel = GetNextOutboundTunnel (); 290 freshTunnel = true; 291 } 292 return std::make_pair(tunnel, freshTunnel); 293 } 294 295 void TunnelPool::CreateTunnels () 296 { 297 int num = 0; 298 { 299 std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex); 300 for (const auto& it : m_OutboundTunnels) 301 if (it->IsEstablished ()) num++; 302 } 303 num = m_NumOutboundTunnels - num; 304 if (num > 0) 305 { 306 if (num > TUNNEL_POOL_MAX_NUM_BUILD_REQUESTS) num = TUNNEL_POOL_MAX_NUM_BUILD_REQUESTS; 307 for (int i = 0; i < num; i++) 308 CreateOutboundTunnel (); 309 } 310 311 num = 0; 312 { 313 std::unique_lock<std::mutex> l(m_InboundTunnelsMutex); 314 for (const auto& it : m_InboundTunnels) 315 if (it->IsEstablished ()) num++; 316 } 317 if (!num && !m_OutboundTunnels.empty () && m_NumOutboundHops > 0 && 318 m_NumInboundHops == m_NumOutboundHops) 319 { 320 for (auto it: m_OutboundTunnels) 321 { 322 // try to create inbound tunnel through the same path as successive outbound 323 CreatePairedInboundTunnel (it); 324 num++; 325 if (num >= m_NumInboundTunnels) break; 326 } 327 } 328 num = m_NumInboundTunnels - num; 329 if (num > 0) 330 { 331 if (num > TUNNEL_POOL_MAX_NUM_BUILD_REQUESTS) num = TUNNEL_POOL_MAX_NUM_BUILD_REQUESTS; 332 for (int i = 0; i < num; i++) 333 CreateInboundTunnel (); 334 } 335 336 if (num < m_NumInboundTunnels && m_NumInboundHops <= 0 && m_LocalDestination) // zero hops IB 337 m_LocalDestination->SetLeaseSetUpdated (true); // update LeaseSet immediately 338 } 339 340 void TunnelPool::TestTunnels () 341 { 342 decltype(m_Tests) tests; 343 { 344 std::unique_lock<std::mutex> l(m_TestsMutex); 345 tests.swap(m_Tests); 346 } 347 348 for (auto& it: tests) 349 { 350 LogPrint (eLogWarning, "Tunnels: Test of tunnel ", it.first, " failed"); 351 // if test failed again with another tunnel we consider it failed 352 if (it.second.first) 353 { 354 if (it.second.first->GetState () == eTunnelStateTestFailed) 355 { 356 it.second.first->SetState (eTunnelStateFailed); 357 std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex); 358 if (m_OutboundTunnels.size () > 1) // don't fail last tunnel 359 m_OutboundTunnels.erase (it.second.first); 360 else 361 { 362 it.second.first->SetState (eTunnelStateTestFailed); 363 CreateOutboundTunnel (); // create new tunnel immediately because last one failed 364 } 365 } 366 else if (it.second.first->GetState () != eTunnelStateExpiring) 367 it.second.first->SetState (eTunnelStateTestFailed); 368 } 369 if (it.second.second) 370 { 371 if (it.second.second->GetState () == eTunnelStateTestFailed) 372 { 373 it.second.second->SetState (eTunnelStateFailed); 374 { 375 bool failed = false; 376 { 377 std::unique_lock<std::mutex> l(m_InboundTunnelsMutex); 378 if (m_InboundTunnels.size () > 1) // don't fail last tunnel 379 { 380 m_InboundTunnels.erase (it.second.second); 381 failed = true; 382 } 383 else 384 { 385 it.second.second->SetState (eTunnelStateTestFailed); 386 CreateInboundTunnel (); // create new tunnel immediately because last one failed 387 } 388 } 389 if (failed && m_LocalDestination) 390 m_LocalDestination->SetLeaseSetUpdated (true); 391 } 392 if (m_LocalDestination) 393 m_LocalDestination->SetLeaseSetUpdated (true); 394 } 395 else if (it.second.second->GetState () != eTunnelStateExpiring) 396 it.second.second->SetState (eTunnelStateTestFailed); 397 } 398 } 399 400 // new tests 401 if (!m_LocalDestination) return; 402 std::vector<std::pair<std::shared_ptr<OutboundTunnel>, std::shared_ptr<InboundTunnel> > > newTests; 403 std::vector<std::shared_ptr<OutboundTunnel> > outboundTunnels; 404 { 405 std::unique_lock<std::mutex> l(m_OutboundTunnelsMutex); 406 for (auto& it: m_OutboundTunnels) 407 if (it->IsEstablished ()) 408 outboundTunnels.push_back (it); 409 } 410 std::shuffle (outboundTunnels.begin(), outboundTunnels.end(), tunnels.GetRng ()); 411 std::vector<std::shared_ptr<InboundTunnel> > inboundTunnels; 412 { 413 std::unique_lock<std::mutex> l(m_InboundTunnelsMutex); 414 for (auto& it: m_InboundTunnels) 415 if (it->IsEstablished ()) 416 inboundTunnels.push_back (it); 417 } 418 std::shuffle (inboundTunnels.begin(), inboundTunnels.end(), tunnels.GetRng ()); 419 auto it1 = outboundTunnels.begin (); 420 auto it2 = inboundTunnels.begin (); 421 while (it1 != outboundTunnels.end () && it2 != inboundTunnels.end ()) 422 { 423 newTests.push_back(std::make_pair (*it1, *it2)); 424 ++it1; ++it2; 425 } 426 bool isECIES = m_LocalDestination->SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD); 427 for (auto& it: newTests) 428 { 429 uint32_t msgID; 430 RAND_bytes ((uint8_t *)&msgID, 4); 431 { 432 std::unique_lock<std::mutex> l(m_TestsMutex); 433 m_Tests[msgID] = it; 434 } 435 auto msg = CreateTunnelTestMsg (msgID); 436 auto outbound = it.first; 437 auto s = shared_from_this (); 438 msg->onDrop = [msgID, outbound, s]() 439 { 440 // if test msg dropped locally it's outbound tunnel to blame 441 outbound->SetState (eTunnelStateFailed); 442 { 443 std::unique_lock<std::mutex> l(s->m_TestsMutex); 444 s->m_Tests.erase (msgID); 445 } 446 { 447 std::unique_lock<std::mutex> l(s->m_OutboundTunnelsMutex); 448 s->m_OutboundTunnels.erase (outbound); 449 } 450 }; 451 // encrypt 452 if (isECIES) 453 { 454 uint8_t key[32]; RAND_bytes (key, 32); 455 uint64_t tag; RAND_bytes ((uint8_t *)&tag, 8); 456 m_LocalDestination->SubmitECIESx25519Key (key, tag); 457 msg = i2p::garlic::WrapECIESX25519Message (msg, key, tag); 458 } 459 else 460 { 461 uint8_t key[32], tag[32]; 462 RAND_bytes (key, 32); RAND_bytes (tag, 32); 463 m_LocalDestination->SubmitSessionKey (key, tag); 464 i2p::garlic::ElGamalAESSession garlic (key, tag); 465 msg = garlic.WrapSingleMessage (msg); 466 } 467 outbound->SendTunnelDataMsgTo (it.second->GetNextIdentHash (), it.second->GetNextTunnelID (), msg); 468 } 469 } 470 471 void TunnelPool::ManageTunnels (uint64_t ts) 472 { 473 if (ts > m_NextManageTime || ts + 2*TUNNEL_POOL_MANAGE_INTERVAL < m_NextManageTime) // in case if clock was adjusted 474 { 475 CreateTunnels (); 476 TestTunnels (); 477 m_NextManageTime = ts + TUNNEL_POOL_MANAGE_INTERVAL + (tunnels.GetRng ()() % TUNNEL_POOL_MANAGE_INTERVAL)/2; 478 } 479 } 480 481 void TunnelPool::ProcessGarlicMessage (std::shared_ptr<I2NPMessage> msg) 482 { 483 if (m_LocalDestination) 484 m_LocalDestination->ProcessGarlicMessage (msg); 485 else 486 LogPrint (eLogWarning, "Tunnels: Local destination doesn't exist, dropped"); 487 } 488 489 void TunnelPool::ProcessDeliveryStatus (std::shared_ptr<I2NPMessage> msg) 490 { 491 if (m_LocalDestination) 492 m_LocalDestination->ProcessDeliveryStatusMessage (msg); 493 else 494 LogPrint (eLogWarning, "Tunnels: Local destination doesn't exist, dropped"); 495 } 496 497 void TunnelPool::ProcessTunnelTest (std::shared_ptr<I2NPMessage> msg) 498 { 499 const uint8_t * buf = msg->GetPayload (); 500 uint32_t msgID = bufbe32toh (buf); 501 buf += 4; 502 uint64_t timestamp = bufbe64toh (buf); 503 504 ProcessTunnelTest (msgID, timestamp); 505 } 506 507 bool TunnelPool::ProcessTunnelTest (uint32_t msgID, uint64_t timestamp) 508 { 509 decltype(m_Tests)::mapped_type test; 510 bool found = false; 511 { 512 std::unique_lock<std::mutex> l(m_TestsMutex); 513 auto it = m_Tests.find (msgID); 514 if (it != m_Tests.end ()) 515 { 516 found = true; 517 test = it->second; 518 m_Tests.erase (it); 519 } 520 } 521 if (found) 522 { 523 int dlt = (uint64_t)i2p::util::GetMonotonicMicroseconds () - (int64_t)timestamp; 524 LogPrint (eLogDebug, "Tunnels: Test of ", msgID, " successful. ", dlt, " microseconds"); 525 if (dlt < 0) dlt = 0; // should not happen 526 int numHops = 0; 527 if (test.first) numHops += test.first->GetNumHops (); 528 if (test.second) numHops += test.second->GetNumHops (); 529 // restore from test failed state if any 530 if (test.first) 531 { 532 if (test.first->GetState () != eTunnelStateExpiring) 533 test.first->SetState (eTunnelStateEstablished); 534 // update latency 535 int latency = 0; 536 if (numHops) latency = dlt*test.first->GetNumHops ()/numHops; 537 if (!latency) latency = dlt/2; 538 test.first->AddLatencySample (latency); 539 } 540 if (test.second) 541 { 542 if (test.second->GetState () != eTunnelStateExpiring) 543 test.second->SetState (eTunnelStateEstablished); 544 // update latency 545 int latency = 0; 546 if (numHops) latency = dlt*test.second->GetNumHops ()/numHops; 547 if (!latency) latency = dlt/2; 548 test.second->AddLatencySample (latency); 549 } 550 } 551 return found; 552 } 553 554 bool TunnelPool::IsExploratory () const 555 { 556 return i2p::tunnel::tunnels.GetExploratoryPool () == shared_from_this (); 557 } 558 559 std::shared_ptr<const i2p::data::RouterInfo> TunnelPool::SelectNextHop (std::shared_ptr<const i2p::data::RouterInfo> prevHop, 560 bool reverse, bool endpoint) const 561 { 562 bool tryClient = !IsExploratory () && !i2p::context.IsLimitedConnectivity (); 563 std::shared_ptr<const i2p::data::RouterInfo> hop; 564 for (int i = 0; i < TUNNEL_POOL_MAX_HOP_SELECTION_ATTEMPTS; i++) 565 { 566 hop = tryClient ? 567 (m_IsHighBandwidth ? 568 i2p::data::netdb.GetHighBandwidthRandomRouter (prevHop, reverse, endpoint) : 569 i2p::data::netdb.GetRandomRouter (prevHop, reverse, endpoint, true)): 570 i2p::data::netdb.GetRandomRouter (prevHop, reverse, endpoint, false); 571 if (hop) 572 { 573 if (!hop->HasProfile () || !hop->GetProfile ()->IsBad ()) 574 break; 575 } 576 else if (tryClient) 577 tryClient = false; 578 else 579 return nullptr; 580 } 581 return hop; 582 } 583 584 bool TunnelPool::StandardSelectPeers(Path & path, int numHops, bool inbound, SelectHopFunc nextHop) 585 { 586 int start = 0; 587 std::shared_ptr<const i2p::data::RouterInfo> prevHop = i2p::context.GetSharedRouterInfo (); 588 if(i2p::transport::transports.RoutesRestricted() || !m_TrustedRouters.empty ()) 589 { 590 /** if routes are restricted or trusted prepend trusted first hop */ 591 auto hop = (!m_TrustedRouters.empty ()) ? SelectTrustedRouter (inbound) : 592 i2p::transport::transports.GetRestrictedPeer (); 593 if(!hop) return false; 594 path.Add (hop); 595 prevHop = hop; 596 start++; 597 } 598 else if (i2p::transport::transports.GetNumPeers () > 100 || 599 (inbound && (i2p::transport::transports.GetNumPeers () > 25 || 600 (i2p::context.IsLimitedConnectivity () && i2p::transport::transports.GetNumPeers () > 0)))) 601 { 602 auto r = i2p::transport::transports.GetRandomPeer (m_IsHighBandwidth && !i2p::context.IsLimitedConnectivity ()); 603 if (r && r->IsECIES () && (!r->HasProfile () || !r->GetProfile ()->IsBad ()) && 604 (numHops > 1 || (r->IsV4 () && (!inbound || r->IsPublished (true))))) // first inbound must be published ipv4 605 { 606 prevHop = r; 607 path.Add (r); 608 start++; 609 } 610 } 611 612 for(int i = start; i < numHops; i++ ) 613 { 614 auto hop = nextHop (prevHop, inbound, i == numHops - 1); 615 if (!hop && !i) // if no suitable peer found for first hop, try already connected 616 { 617 LogPrint (eLogInfo, "Tunnels: Can't select first hop for a tunnel. Trying already connected"); 618 hop = i2p::transport::transports.GetRandomPeer (false); 619 if (hop && !hop->IsECIES ()) hop = nullptr; 620 } 621 if (!hop) 622 { 623 LogPrint (eLogError, "Tunnels: Can't select next hop for ", prevHop->GetIdentHashBase64 ()); 624 return false; 625 } 626 prevHop = hop; 627 path.Add (hop); 628 } 629 path.farEndTransports = prevHop->GetCompatibleTransports (inbound); // last hop 630 return true; 631 } 632 633 bool TunnelPool::SelectPeers (Path& path, bool isInbound) 634 { 635 // explicit peers in use 636 if (!m_ExplicitPeers.empty ()) return SelectExplicitPeers (path, isInbound); 637 // calculate num hops 638 int numHops; 639 if (isInbound) 640 { 641 numHops = m_NumInboundHops; 642 if (m_InboundVariance) 643 { 644 int offset = tunnels.GetRng ()() % (std::abs (m_InboundVariance) + 1); 645 if (m_InboundVariance < 0) offset = -offset; 646 numHops += offset; 647 } 648 } 649 else 650 { 651 numHops = m_NumOutboundHops; 652 if (m_OutboundVariance) 653 { 654 int offset = tunnels.GetRng ()() % (std::abs (m_OutboundVariance) + 1); 655 if (m_OutboundVariance < 0) offset = -offset; 656 numHops += offset; 657 } 658 } 659 // peers is empty 660 if (numHops <= 0) return true; 661 // custom peer selector in use ? 662 { 663 std::lock_guard<std::mutex> lock(m_CustomPeerSelectorMutex); 664 if (m_CustomPeerSelector) 665 return m_CustomPeerSelector->SelectPeers(path, numHops, isInbound); 666 } 667 return StandardSelectPeers(path, numHops, isInbound, std::bind(&TunnelPool::SelectNextHop, this, 668 std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); 669 } 670 671 bool TunnelPool::SelectExplicitPeers (Path& path, bool isInbound) 672 { 673 if (m_ExplicitPeers.empty ()) return false; 674 int numHops = isInbound ? m_NumInboundHops : m_NumOutboundHops; 675 if (numHops > (int)m_ExplicitPeers.size ()) numHops = m_ExplicitPeers.size (); 676 for (int i = 0; i < numHops; i++) 677 { 678 auto& ident = m_ExplicitPeers[i]; 679 auto r = i2p::data::netdb.FindRouter (ident); 680 if (r) 681 { 682 if (r->IsECIES ()) 683 { 684 path.Add (r); 685 if (i == numHops - 1) 686 path.farEndTransports = r->GetCompatibleTransports (isInbound); 687 } 688 else 689 { 690 LogPrint (eLogError, "Tunnels: ElGamal router ", ident.ToBase64 (), " is not supported"); 691 return false; 692 } 693 } 694 else 695 { 696 LogPrint (eLogInfo, "Tunnels: Can't find router for ", ident.ToBase64 ()); 697 i2p::data::netdb.RequestDestination (ident); 698 return false; 699 } 700 } 701 return true; 702 } 703 704 std::shared_ptr<const i2p::data::RouterInfo> TunnelPool::SelectTrustedRouter (bool inbound) const 705 { 706 size_t count = m_TrustedRouters.size (); 707 if (!count) return nullptr; 708 std::shared_ptr<const i2p::data::RouterInfo> r; 709 int ind = tunnels.GetRng ()() % count; 710 for (size_t i = 0; i < count; i++) 711 { 712 auto& ident = m_TrustedRouters[(ind + i) % count]; 713 if (inbound) 714 { 715 if (i2p::transport::transports.IsConnected (ident)) 716 { 717 r = i2p::data::netdb.FindRouter (ident); 718 break; 719 } 720 } 721 else 722 { 723 auto r1 = i2p::data::netdb.FindRouter (ident); 724 if (!r1) i2p::data::netdb.RequestDestination (ident, nullptr); // request one if not in NetDB 725 if (r1 && !r1->IsUnreachable () && r1->IsReachableFrom (i2p::context.GetRouterInfo ())) 726 { 727 r = r1; 728 break; 729 } 730 } 731 } 732 return r; 733 } 734 735 void TunnelPool::CreateInboundTunnel () 736 { 737 LogPrint (eLogDebug, "Tunnels: Creating destination inbound tunnel..."); 738 Path path; 739 if (SelectPeers (path, true)) 740 { 741 auto outboundTunnel = GetNextOutboundTunnel (nullptr, path.farEndTransports); 742 if (!outboundTunnel) 743 outboundTunnel = tunnels.GetNextOutboundTunnel (); 744 std::shared_ptr<TunnelConfig> config; 745 if (m_NumInboundHops > 0) 746 { 747 path.Reverse (); 748 config = std::make_shared<TunnelConfig> (path.peers, path.isShort, path.farEndTransports); 749 } 750 auto tunnel = tunnels.CreateInboundTunnel (config, shared_from_this (), outboundTunnel); 751 if (tunnel->IsEstablished ()) // zero hops 752 TunnelCreated (tunnel); 753 } 754 else 755 LogPrint (eLogError, "Tunnels: Can't create inbound tunnel, no peers available"); 756 } 757 758 void TunnelPool::RecreateInboundTunnel (std::shared_ptr<InboundTunnel> tunnel) 759 { 760 if (IsExploratory () || tunnel->IsSlow ()) // always create new exploratory tunnel or if slow 761 { 762 CreateInboundTunnel (); 763 return; 764 } 765 auto outboundTunnel = GetNextOutboundTunnel (nullptr, tunnel->GetFarEndTransports ()); 766 if (!outboundTunnel) 767 outboundTunnel = tunnels.GetNextOutboundTunnel (); 768 LogPrint (eLogDebug, "Tunnels: Re-creating destination inbound tunnel..."); 769 std::shared_ptr<TunnelConfig> config; 770 if (m_NumInboundHops > 0) 771 { 772 auto peers = tunnel->GetPeers(); 773 if (peers.size ()&& ValidatePeers (peers)) 774 config = std::make_shared<TunnelConfig>(tunnel->GetPeers (), 775 tunnel->IsShortBuildMessage (), tunnel->GetFarEndTransports ()); 776 } 777 if (!m_NumInboundHops || config) 778 { 779 auto newTunnel = tunnels.CreateInboundTunnel (config, shared_from_this(), outboundTunnel); 780 if (newTunnel->IsEstablished ()) // zero hops 781 TunnelCreated (newTunnel); 782 else 783 newTunnel->SetRecreated (true); 784 } 785 } 786 787 void TunnelPool::CreateOutboundTunnel () 788 { 789 LogPrint (eLogDebug, "Tunnels: Creating destination outbound tunnel..."); 790 Path path; 791 if (SelectPeers (path, false)) 792 { 793 auto inboundTunnel = GetNextInboundTunnel (nullptr, path.farEndTransports); 794 if (!inboundTunnel) 795 inboundTunnel = tunnels.GetNextInboundTunnel (); 796 if (!inboundTunnel) 797 { 798 LogPrint (eLogError, "Tunnels: Can't create outbound tunnel, no inbound tunnels found"); 799 return; 800 } 801 802 if (m_LocalDestination && !m_LocalDestination->SupportsEncryptionType (i2p::data::CRYPTO_KEY_TYPE_ECIES_X25519_AEAD)) 803 path.isShort = false; // because can't handle ECIES encrypted reply 804 805 std::shared_ptr<TunnelConfig> config; 806 if (m_NumOutboundHops > 0) 807 config = std::make_shared<TunnelConfig>(path.peers, inboundTunnel->GetNextTunnelID (), 808 inboundTunnel->GetNextIdentHash (), path.isShort, path.farEndTransports); 809 810 std::shared_ptr<OutboundTunnel> tunnel; 811 if (path.isShort) 812 { 813 // TODO: implement it better 814 tunnel = tunnels.CreateOutboundTunnel (config, inboundTunnel->GetTunnelPool ()); 815 tunnel->SetTunnelPool (shared_from_this ()); 816 } 817 else 818 tunnel = tunnels.CreateOutboundTunnel (config, shared_from_this ()); 819 if (tunnel && tunnel->IsEstablished ()) // zero hops 820 TunnelCreated (tunnel); 821 } 822 else 823 LogPrint (eLogError, "Tunnels: Can't create outbound tunnel, no peers available"); 824 } 825 826 void TunnelPool::RecreateOutboundTunnel (std::shared_ptr<OutboundTunnel> tunnel) 827 { 828 if (IsExploratory () || tunnel->IsSlow ()) // always create new exploratory tunnel or if slow 829 { 830 CreateOutboundTunnel (); 831 return; 832 } 833 auto inboundTunnel = GetNextInboundTunnel (nullptr, tunnel->GetFarEndTransports ()); 834 if (!inboundTunnel) 835 inboundTunnel = tunnels.GetNextInboundTunnel (); 836 if (inboundTunnel) 837 { 838 LogPrint (eLogDebug, "Tunnels: Re-creating destination outbound tunnel..."); 839 std::shared_ptr<TunnelConfig> config; 840 if (m_NumOutboundHops > 0) 841 { 842 auto peers = tunnel->GetPeers(); 843 if (peers.size () && ValidatePeers (peers)) 844 config = std::make_shared<TunnelConfig>(peers, inboundTunnel->GetNextTunnelID (), 845 inboundTunnel->GetNextIdentHash (), inboundTunnel->IsShortBuildMessage (), tunnel->GetFarEndTransports ()); 846 } 847 if (!m_NumOutboundHops || config) 848 { 849 auto newTunnel = tunnels.CreateOutboundTunnel (config, shared_from_this ()); 850 if (newTunnel->IsEstablished ()) // zero hops 851 TunnelCreated (newTunnel); 852 } 853 } 854 else 855 LogPrint (eLogDebug, "Tunnels: Can't re-create outbound tunnel, no inbound tunnels found"); 856 } 857 858 void TunnelPool::CreatePairedInboundTunnel (std::shared_ptr<OutboundTunnel> outboundTunnel) 859 { 860 LogPrint (eLogDebug, "Tunnels: Creating paired inbound tunnel..."); 861 auto tunnel = tunnels.CreateInboundTunnel ( 862 m_NumOutboundHops > 0 ? std::make_shared<TunnelConfig>(outboundTunnel->GetInvertedPeers (), 863 outboundTunnel->IsShortBuildMessage ()) : nullptr, 864 shared_from_this (), outboundTunnel); 865 if (tunnel->IsEstablished ()) // zero hops 866 TunnelCreated (tunnel); 867 } 868 869 void TunnelPool::SetCustomPeerSelector(ITunnelPeerSelector * selector) 870 { 871 std::lock_guard<std::mutex> lock(m_CustomPeerSelectorMutex); 872 m_CustomPeerSelector = selector; 873 } 874 875 void TunnelPool::UnsetCustomPeerSelector() 876 { 877 SetCustomPeerSelector(nullptr); 878 } 879 880 bool TunnelPool::HasCustomPeerSelector() 881 { 882 std::lock_guard<std::mutex> lock(m_CustomPeerSelectorMutex); 883 return m_CustomPeerSelector != nullptr; 884 } 885 886 bool TunnelPool::ValidatePeers (std::vector<std::shared_ptr<const i2p::data::IdentityEx> >& peers) const 887 { 888 bool highBandwidth = !IsExploratory (); 889 for (auto it: peers) 890 { 891 auto r = i2p::data::netdb.FindRouter (it->GetIdentHash ()); 892 if (r) 893 { 894 if (r->IsHighCongestion (highBandwidth)) return false; 895 it = r->GetIdentity (); // use identity from updated RouterInfo 896 } 897 } 898 return true; 899 } 900 901 std::shared_ptr<InboundTunnel> TunnelPool::GetLowestLatencyInboundTunnel(std::shared_ptr<InboundTunnel> exclude) const 902 { 903 std::shared_ptr<InboundTunnel> tun = nullptr; 904 std::unique_lock<std::mutex> lock(m_InboundTunnelsMutex); 905 int min = 1000000; 906 for (const auto & itr : m_InboundTunnels) { 907 if(!itr->LatencyIsKnown()) continue; 908 auto l = itr->GetMeanLatency(); 909 if (l >= min) continue; 910 tun = itr; 911 if(tun == exclude) continue; 912 min = l; 913 } 914 return tun; 915 } 916 917 std::shared_ptr<OutboundTunnel> TunnelPool::GetLowestLatencyOutboundTunnel(std::shared_ptr<OutboundTunnel> exclude) const 918 { 919 std::shared_ptr<OutboundTunnel> tun = nullptr; 920 std::unique_lock<std::mutex> lock(m_OutboundTunnelsMutex); 921 int min = 1000000; 922 for (const auto & itr : m_OutboundTunnels) { 923 if(!itr->LatencyIsKnown()) continue; 924 auto l = itr->GetMeanLatency(); 925 if (l >= min) continue; 926 tun = itr; 927 if(tun == exclude) continue; 928 min = l; 929 } 930 return tun; 931 } 932 } 933 }