/ libi2pd_client / ClientContext.cpp
ClientContext.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 <fstream> 10 #include <iostream> 11 #include <boost/property_tree/ptree.hpp> 12 #include <boost/property_tree/ini_parser.hpp> 13 #include "Config.h" 14 #include "FS.h" 15 #include "Log.h" 16 #include "Identity.h" 17 #include "util.h" 18 #include "ClientContext.h" 19 #include "HTTPProxy.h" 20 #include "SOCKS.h" 21 #include "MatchedDestination.h" 22 23 namespace i2p 24 { 25 namespace client 26 { 27 ClientContext context; 28 29 ClientContext::ClientContext (): m_SharedLocalDestination (nullptr), 30 m_HttpProxy (nullptr), m_SocksProxy (nullptr), m_SamBridge (nullptr), 31 m_BOBCommandChannel (nullptr), m_I2CPServer (nullptr) 32 { 33 } 34 35 ClientContext::~ClientContext () 36 { 37 delete m_HttpProxy; 38 delete m_SocksProxy; 39 delete m_SamBridge; 40 delete m_BOBCommandChannel; 41 delete m_I2CPServer; 42 } 43 44 void ClientContext::Start () 45 { 46 // shared local destination 47 if (!m_SharedLocalDestination) 48 CreateNewSharedLocalDestination (); 49 50 // addressbook 51 m_AddressBook.Start (); 52 53 // HTTP proxy 54 ReadHttpProxy (); 55 56 // SOCKS proxy 57 ReadSocksProxy (); 58 59 // I2P tunnels 60 ReadTunnels (); 61 62 // SAM 63 bool sam; i2p::config::GetOption("sam.enabled", sam); 64 if (sam) 65 { 66 std::string samAddr; i2p::config::GetOption("sam.address", samAddr); 67 uint16_t samPortTCP; i2p::config::GetOption("sam.port", samPortTCP); 68 uint16_t samPortUDP; i2p::config::GetOption("sam.portudp", samPortUDP); 69 bool singleThread; i2p::config::GetOption("sam.singlethread", singleThread); 70 LogPrint(eLogInfo, "Clients: Starting SAM bridge at ", samAddr, ":[", samPortTCP, "|", samPortUDP, "]"); 71 try 72 { 73 m_SamBridge = new SAMBridge (samAddr, samPortTCP, samPortUDP, singleThread); 74 m_SamBridge->Start (); 75 } 76 catch (std::exception& e) 77 { 78 LogPrint(eLogCritical, "Clients: Exception in SAM bridge: ", e.what()); 79 ThrowFatal ("Unable to start SAM bridge at ", samAddr, ":[", samPortTCP, "|", samPortUDP,"]: ", e.what ()); 80 } 81 } 82 83 // BOB 84 bool bob; i2p::config::GetOption("bob.enabled", bob); 85 if (bob) { 86 std::string bobAddr; i2p::config::GetOption("bob.address", bobAddr); 87 uint16_t bobPort; i2p::config::GetOption("bob.port", bobPort); 88 LogPrint(eLogInfo, "Clients: Starting BOB command channel at ", bobAddr, ":", bobPort); 89 try 90 { 91 m_BOBCommandChannel = new BOBCommandChannel (bobAddr, bobPort); 92 m_BOBCommandChannel->Start (); 93 } 94 catch (std::exception& e) 95 { 96 LogPrint(eLogCritical, "Clients: Exception in BOB bridge: ", e.what()); 97 ThrowFatal ("Unable to start BOB bridge at ", bobAddr, ":", bobPort, ": ", e.what ()); 98 } 99 } 100 101 // I2CP 102 bool i2cp; i2p::config::GetOption("i2cp.enabled", i2cp); 103 if (i2cp) 104 { 105 std::string i2cpAddr; i2p::config::GetOption("i2cp.address", i2cpAddr); 106 uint16_t i2cpPort; i2p::config::GetOption("i2cp.port", i2cpPort); 107 bool singleThread; i2p::config::GetOption("i2cp.singlethread", singleThread); 108 LogPrint(eLogInfo, "Clients: Starting I2CP at ", i2cpAddr, ":", i2cpPort); 109 try 110 { 111 m_I2CPServer = new I2CPServer (i2cpAddr, i2cpPort, singleThread); 112 m_I2CPServer->Start (); 113 } 114 catch (std::exception& e) 115 { 116 LogPrint(eLogCritical, "Clients: Exception in I2CP: ", e.what()); 117 ThrowFatal ("Unable to start I2CP at ", i2cpAddr, ":", i2cpPort, ": ", e.what ()); 118 } 119 } 120 121 m_AddressBook.StartResolvers (); 122 123 // start UDP cleanup 124 if (!m_ServerForwards.empty ()) 125 { 126 m_CleanupUDPTimer.reset (new boost::asio::deadline_timer(m_SharedLocalDestination->GetService ())); 127 ScheduleCleanupUDP(); 128 } 129 } 130 131 void ClientContext::Stop () 132 { 133 if (m_HttpProxy) 134 { 135 LogPrint(eLogInfo, "Clients: Stopping HTTP Proxy"); 136 m_HttpProxy->Stop(); 137 delete m_HttpProxy; 138 m_HttpProxy = nullptr; 139 } 140 141 if (m_SocksProxy) 142 { 143 LogPrint(eLogInfo, "Clients: Stopping SOCKS Proxy"); 144 m_SocksProxy->Stop(); 145 delete m_SocksProxy; 146 m_SocksProxy = nullptr; 147 } 148 149 for (auto& it: m_ClientTunnels) 150 { 151 LogPrint(eLogInfo, "Clients: Stopping I2P client tunnel on port ", it.first); 152 it.second->Stop (); 153 } 154 m_ClientTunnels.clear (); 155 156 for (auto& it: m_ServerTunnels) 157 { 158 LogPrint(eLogInfo, "Clients: Stopping I2P server tunnel"); 159 it.second->Stop (); 160 } 161 m_ServerTunnels.clear (); 162 163 if (m_SamBridge) 164 { 165 LogPrint(eLogInfo, "Clients: Stopping SAM bridge"); 166 m_SamBridge->Stop (); 167 delete m_SamBridge; 168 m_SamBridge = nullptr; 169 } 170 171 if (m_BOBCommandChannel) 172 { 173 LogPrint(eLogInfo, "Clients: Stopping BOB command channel"); 174 m_BOBCommandChannel->Stop (); 175 delete m_BOBCommandChannel; 176 m_BOBCommandChannel = nullptr; 177 } 178 179 if (m_I2CPServer) 180 { 181 LogPrint(eLogInfo, "Clients: Stopping I2CP"); 182 m_I2CPServer->Stop (); 183 delete m_I2CPServer; 184 m_I2CPServer = nullptr; 185 } 186 187 LogPrint(eLogInfo, "Clients: Stopping AddressBook"); 188 m_AddressBook.Stop (); 189 190 LogPrint(eLogInfo, "Clients: Stopping UDP Tunnels"); 191 { 192 std::lock_guard<std::mutex> lock(m_ForwardsMutex); 193 m_ServerForwards.clear(); 194 m_ClientForwards.clear(); 195 } 196 197 LogPrint(eLogInfo, "Clients: Stopping UDP Tunnels timers"); 198 if (m_CleanupUDPTimer) 199 { 200 m_CleanupUDPTimer->cancel (); 201 m_CleanupUDPTimer = nullptr; 202 } 203 204 { 205 LogPrint(eLogInfo, "Clients: Stopping Destinations"); 206 std::lock_guard<std::mutex> lock(m_DestinationsMutex); 207 for (auto& it: m_Destinations) 208 it.second->Stop (); 209 LogPrint(eLogInfo, "Clients: Stopping Destinations - Clear"); 210 m_Destinations.clear (); 211 } 212 213 LogPrint(eLogInfo, "Clients: Stopping SharedLocalDestination"); 214 m_SharedLocalDestination->Release (); 215 m_SharedLocalDestination = nullptr; 216 } 217 218 void ClientContext::ReloadConfig () 219 { 220 // TODO: handle config changes 221 /*std::string config; i2p::config::GetOption("conf", config); 222 i2p::config::ParseConfig(config);*/ 223 224 // change shared local destination 225 m_SharedLocalDestination->Release (); 226 CreateNewSharedLocalDestination (); 227 228 // recreate HTTP proxy 229 if (m_HttpProxy) 230 { 231 m_HttpProxy->Stop (); 232 delete m_HttpProxy; 233 m_HttpProxy = nullptr; 234 } 235 ReadHttpProxy (); 236 237 // recreate SOCKS proxy 238 if (m_SocksProxy) 239 { 240 m_SocksProxy->Stop (); 241 delete m_SocksProxy; 242 m_SocksProxy = nullptr; 243 } 244 ReadSocksProxy (); 245 246 // handle tunnels 247 // reset isUpdated for each tunnel 248 VisitTunnels (false); 249 // reload tunnels 250 ReadTunnels(); 251 // delete not updated tunnels (not in config anymore) 252 VisitTunnels (true); 253 254 // delete unused destinations 255 std::unique_lock<std::mutex> l(m_DestinationsMutex); 256 for (auto it = m_Destinations.begin (); it != m_Destinations.end ();) 257 { 258 auto dest = it->second; 259 if (dest->GetRefCounter () > 0) ++it; // skip 260 else 261 { 262 dest->Stop (); 263 it = m_Destinations.erase (it); 264 } 265 } 266 } 267 268 bool ClientContext::LoadPrivateKeys (i2p::data::PrivateKeys& keys, std::string_view filename, 269 i2p::data::SigningKeyType sigType, i2p::data::CryptoKeyType cryptoType) 270 { 271 #if __cplusplus >= 202002L // C++20 272 if (filename.starts_with ("transient")) 273 #else 274 std::string_view transient("transient"); 275 if (!filename.compare (0, transient.length (), transient)) // starts with transient 276 #endif 277 { 278 keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType, true); 279 LogPrint (eLogInfo, "Clients: New transient keys address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created"); 280 return true; 281 } 282 283 bool success = true; 284 std::string fullPath = i2p::fs::DataDirPath (filename); 285 std::ifstream s(fullPath, std::ifstream::binary); 286 if (s.is_open ()) 287 { 288 s.seekg (0, std::ios::end); 289 size_t len = s.tellg(); 290 s.seekg (0, std::ios::beg); 291 uint8_t * buf = new uint8_t[len]; 292 s.read ((char *)buf, len); 293 if(!keys.FromBuffer (buf, len)) 294 { 295 LogPrint (eLogCritical, "Clients: Failed to load keyfile ", filename); 296 success = false; 297 } 298 else 299 LogPrint (eLogInfo, "Clients: Local address ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " loaded"); 300 delete[] buf; 301 } 302 else 303 { 304 LogPrint (eLogInfo, "Clients: Can't open file ", fullPath, " Creating new one with signature type ", sigType, " crypto type ", cryptoType); 305 keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType, true); 306 std::ofstream f (fullPath, std::ofstream::binary | std::ofstream::out); 307 size_t len = keys.GetFullLen (); 308 uint8_t * buf = new uint8_t[len]; 309 len = keys.ToBuffer (buf, len); 310 f.write ((char *)buf, len); 311 delete[] buf; 312 313 LogPrint (eLogInfo, "Clients: New private keys file ", fullPath, " for ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " created"); 314 } 315 return success; 316 } 317 318 std::vector<std::shared_ptr<DatagramSessionInfo> > ClientContext::GetForwardInfosFor(const i2p::data::IdentHash & destination) 319 { 320 std::vector<std::shared_ptr<DatagramSessionInfo> > infos; 321 std::lock_guard<std::mutex> lock(m_ForwardsMutex); 322 for(const auto & c : m_ClientForwards) 323 { 324 if (c.second->IsLocalDestination(destination)) 325 { 326 for (auto & i : c.second->GetSessions()) infos.push_back(i); 327 break; 328 } 329 } 330 for(const auto & s : m_ServerForwards) 331 { 332 if(std::get<0>(s.first) == destination) 333 { 334 for( auto & i : s.second->GetSessions()) infos.push_back(i); 335 break; 336 } 337 } 338 return infos; 339 } 340 341 std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (bool isPublic, 342 i2p::data::SigningKeyType sigType, i2p::data::CryptoKeyType cryptoType, 343 const i2p::util::Mapping * params) 344 { 345 i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType, true); 346 auto localDestination = std::make_shared<RunnableClientDestination> (keys, isPublic, params); 347 AddLocalDestination (localDestination); 348 return localDestination; 349 } 350 351 std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination ( 352 boost::asio::io_context& service, bool isPublic, 353 i2p::data::SigningKeyType sigType, i2p::data::CryptoKeyType cryptoType, 354 const i2p::util::Mapping * params) 355 { 356 i2p::data::PrivateKeys keys = i2p::data::PrivateKeys::CreateRandomKeys (sigType, cryptoType, true); 357 auto localDestination = std::make_shared<ClientDestination> (service, keys, isPublic, params); 358 AddLocalDestination (localDestination); 359 return localDestination; 360 } 361 362 std::shared_ptr<ClientDestination> ClientContext::CreateNewMatchedTunnelDestination(const i2p::data::PrivateKeys &keys, 363 const std::string & name, const i2p::util::Mapping * params) 364 { 365 auto localDestination = std::make_shared<MatchedTunnelDestination>(keys, name, params); 366 AddLocalDestination (localDestination); 367 return localDestination; 368 } 369 370 void ClientContext::AddLocalDestination (std::shared_ptr<ClientDestination> localDestination) 371 { 372 std::unique_lock<std::mutex> l(m_DestinationsMutex); 373 m_Destinations[localDestination->GetIdentHash ()] = localDestination; 374 localDestination->Start (); 375 } 376 377 void ClientContext::DeleteLocalDestination (std::shared_ptr<ClientDestination> destination) 378 { 379 if (!destination) return; 380 auto it = m_Destinations.find (destination->GetIdentHash ()); 381 if (it != m_Destinations.end ()) 382 { 383 auto d = it->second; 384 { 385 std::unique_lock<std::mutex> l(m_DestinationsMutex); 386 m_Destinations.erase (it); 387 } 388 d->Stop (); 389 } 390 } 391 392 std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (const i2p::data::PrivateKeys& keys, bool isPublic, 393 const i2p::util::Mapping * params) 394 { 395 auto it = m_Destinations.find (keys.GetPublic ()->GetIdentHash ()); 396 if (it != m_Destinations.end ()) 397 { 398 LogPrint (eLogWarning, "Clients: Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " exists"); 399 it->second->Start (); // make sure to start 400 return it->second; 401 } 402 auto localDestination = std::make_shared<RunnableClientDestination> (keys, isPublic, params); 403 AddLocalDestination (localDestination); 404 return localDestination; 405 } 406 407 std::shared_ptr<ClientDestination> ClientContext::CreateNewLocalDestination (boost::asio::io_context& service, 408 const i2p::data::PrivateKeys& keys, bool isPublic, const i2p::util::Mapping * params) 409 { 410 auto it = m_Destinations.find (keys.GetPublic ()->GetIdentHash ()); 411 if (it != m_Destinations.end ()) 412 { 413 LogPrint (eLogWarning, "Clients: Local destination ", m_AddressBook.ToAddress(keys.GetPublic ()->GetIdentHash ()), " exists"); 414 it->second->Start (); // make sure to start 415 return it->second; 416 } 417 auto localDestination = std::make_shared<ClientDestination> (service, keys, isPublic, params); 418 AddLocalDestination (localDestination); 419 return localDestination; 420 } 421 422 void ClientContext::CreateNewSharedLocalDestination () 423 { 424 i2p::util::Mapping params; 425 ReadI2CPOptionsFromConfig ("shareddest.", params); 426 params.Insert (I2CP_PARAM_OUTBOUND_NICKNAME, "SharedDest"); 427 428 m_SharedLocalDestination = CreateNewLocalDestination (false, i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519, 429 i2p::data::CRYPTO_KEY_TYPE_ELGAMAL, ¶ms); // non-public, EDDSA 430 m_SharedLocalDestination->Acquire (); 431 } 432 433 std::shared_ptr<ClientDestination> ClientContext::FindLocalDestination (const i2p::data::IdentHash& destination) const 434 { 435 auto it = m_Destinations.find (destination); 436 if (it != m_Destinations.end ()) 437 return it->second; 438 return nullptr; 439 } 440 441 template<typename Section, typename Type> 442 std::string ClientContext::GetI2CPOption (const Section& section, const std::string& name, const Type& value) const 443 { 444 return section.second.get (boost::property_tree::ptree::path_type (name, '/'), std::to_string (value)); 445 } 446 447 template<typename Section> 448 std::string ClientContext::GetI2CPStringOption (const Section& section, const std::string& name, const std::string& value) const 449 { 450 return section.second.get (boost::property_tree::ptree::path_type (name, '/'), value); 451 } 452 453 template<typename Section> 454 void ClientContext::ReadI2CPOptionsGroup (const Section& section, const std::string& group, 455 i2p::util::Mapping& options) const 456 { 457 for (auto it: section.second) 458 { 459 if (it.first.length () >= group.length () && !it.first.compare (0, group.length (), group)) 460 options.Insert (it.first, it.second.get_value ("")); 461 } 462 } 463 464 template<typename Section> 465 void ClientContext::ReadI2CPOptions (const Section& section, bool isServer, i2p::util::Mapping& options) const 466 { 467 options.Insert (I2CP_PARAM_INBOUND_TUNNEL_LENGTH, GetI2CPOption (section, I2CP_PARAM_INBOUND_TUNNEL_LENGTH, DEFAULT_INBOUND_TUNNEL_LENGTH)); 468 options.Insert (I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, GetI2CPOption (section, I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, DEFAULT_OUTBOUND_TUNNEL_LENGTH)); 469 options.Insert (I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, GetI2CPOption (section, I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, DEFAULT_INBOUND_TUNNELS_QUANTITY)); 470 options.Insert (I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, GetI2CPOption (section, I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, DEFAULT_OUTBOUND_TUNNELS_QUANTITY)); 471 options.Insert (I2CP_PARAM_INBOUND_TUNNELS_LENGTH_VARIANCE, GetI2CPOption (section, I2CP_PARAM_INBOUND_TUNNELS_LENGTH_VARIANCE, DEFAULT_INBOUND_TUNNELS_LENGTH_VARIANCE)); 472 options.Insert (I2CP_PARAM_OUTBOUND_TUNNELS_LENGTH_VARIANCE, GetI2CPOption (section, I2CP_PARAM_OUTBOUND_TUNNELS_LENGTH_VARIANCE, DEFAULT_OUTBOUND_TUNNELS_LENGTH_VARIANCE)); 473 options.Insert (I2CP_PARAM_TAGS_TO_SEND, GetI2CPOption (section, I2CP_PARAM_TAGS_TO_SEND, DEFAULT_TAGS_TO_SEND)); 474 options.Insert (I2CP_PARAM_MIN_TUNNEL_LATENCY, GetI2CPOption(section, I2CP_PARAM_MIN_TUNNEL_LATENCY, DEFAULT_MIN_TUNNEL_LATENCY)); 475 options.Insert (I2CP_PARAM_MAX_TUNNEL_LATENCY, GetI2CPOption(section, I2CP_PARAM_MAX_TUNNEL_LATENCY, DEFAULT_MAX_TUNNEL_LATENCY)); 476 options.Insert (I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY, GetI2CPOption(section, I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY, DEFAULT_INITIAL_ACK_DELAY)); 477 options.Insert (I2CP_PARAM_STREAMING_MAX_OUTBOUND_SPEED, GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_OUTBOUND_SPEED, DEFAULT_MAX_OUTBOUND_SPEED)); 478 options.Insert (I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED, GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_INBOUND_SPEED, DEFAULT_MAX_INBOUND_SPEED)); 479 options.Insert (I2CP_PARAM_STREAMING_MAX_CONCURRENT_STREAMS, GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_CONCURRENT_STREAMS, DEFAULT_MAX_CONCURRENT_STREAMS)); 480 options.Insert (I2CP_PARAM_STREAMING_MAX_CONNS_PER_MINUTE, GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_CONNS_PER_MINUTE, DEFAULT_MAX_CONNS_PER_MINUTE)); 481 options.Insert (I2CP_PARAM_STREAMING_ANSWER_PINGS, GetI2CPOption(section, I2CP_PARAM_STREAMING_ANSWER_PINGS, isServer ? DEFAULT_ANSWER_PINGS : false)); 482 options.Insert (I2CP_PARAM_STREAMING_DONT_SIGN, GetI2CPOption(section, I2CP_PARAM_STREAMING_DONT_SIGN, DEFAULT_DONT_SIGN)); 483 options.Insert (I2CP_PARAM_STREAMING_PROFILE, GetI2CPOption(section, I2CP_PARAM_STREAMING_PROFILE, DEFAULT_STREAMING_PROFILE)); 484 options.Insert (I2CP_PARAM_STREAMING_MAX_WINDOW_SIZE, GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_WINDOW_SIZE, i2p::stream::MAX_WINDOW_SIZE)); 485 options.Insert (I2CP_PARAM_LEASESET_TYPE, GetI2CPOption(section, I2CP_PARAM_LEASESET_TYPE, DEFAULT_LEASESET_TYPE)); 486 options.Insert (I2CP_PARAM_STREAMING_MAX_RESENDS, GetI2CPOption(section, I2CP_PARAM_STREAMING_MAX_RESENDS, i2p::stream::MAX_NUM_RESEND_ATTEMPTS)); 487 #if OPENSSL_PQ 488 std::string encType = GetI2CPStringOption(section, I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, isServer ? "6,4" : "6,4,0"); 489 #else 490 std::string encType = GetI2CPStringOption(section, I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, isServer ? "4" : "4,0"); 491 #endif 492 if (encType.length () > 0) options.Insert (I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, encType); 493 std::string privKey = GetI2CPStringOption(section, I2CP_PARAM_LEASESET_PRIV_KEY, ""); 494 if (privKey.length () > 0) options.Insert (I2CP_PARAM_LEASESET_PRIV_KEY, privKey); 495 auto authType = GetI2CPOption(section, I2CP_PARAM_LEASESET_AUTH_TYPE, 0); 496 if (authType != "0") // auth is set 497 { 498 options.Insert (I2CP_PARAM_LEASESET_AUTH_TYPE, authType); 499 if (authType == "1") // DH 500 ReadI2CPOptionsGroup (section, I2CP_PARAM_LEASESET_CLIENT_DH, options); 501 else if (authType == "2") // PSK 502 ReadI2CPOptionsGroup (section, I2CP_PARAM_LEASESET_CLIENT_PSK, options); 503 } 504 std::string explicitPeers = GetI2CPStringOption(section, I2CP_PARAM_EXPLICIT_PEERS, ""); 505 if (explicitPeers.length () > 0) options.Insert (I2CP_PARAM_EXPLICIT_PEERS, explicitPeers); 506 std::string trustedRouters = GetI2CPStringOption(section, I2CP_PARAM_TRUSTED_ROUTERS, ""); 507 if (trustedRouters.length () > 0) options.Insert (I2CP_PARAM_TRUSTED_ROUTERS, trustedRouters); 508 std::string ratchetInboundTags = GetI2CPStringOption(section, I2CP_PARAM_RATCHET_INBOUND_TAGS, ""); 509 if (ratchetInboundTags.length () > 0) options.Insert (I2CP_PARAM_RATCHET_INBOUND_TAGS, ratchetInboundTags); 510 } 511 512 void ClientContext::ReadI2CPOptionsFromConfig (const std::string& prefix, i2p::util::Mapping& options) const 513 { 514 std::string value; 515 if (i2p::config::GetOption(prefix + I2CP_PARAM_INBOUND_TUNNEL_LENGTH, value)) 516 options.Insert (I2CP_PARAM_INBOUND_TUNNEL_LENGTH, value); 517 if (i2p::config::GetOption(prefix + I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, value)) 518 options.Insert (I2CP_PARAM_INBOUND_TUNNELS_QUANTITY, value); 519 if (i2p::config::GetOption(prefix + I2CP_PARAM_INBOUND_TUNNELS_LENGTH_VARIANCE, value)) 520 options.Insert (I2CP_PARAM_INBOUND_TUNNELS_LENGTH_VARIANCE, value); 521 if (i2p::config::GetOption(prefix + I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, value)) 522 options.Insert (I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH, value); 523 if (i2p::config::GetOption(prefix + I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, value)) 524 options.Insert (I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY, value); 525 if (i2p::config::GetOption(prefix + I2CP_PARAM_OUTBOUND_TUNNELS_LENGTH_VARIANCE, value)) 526 options.Insert (I2CP_PARAM_OUTBOUND_TUNNELS_LENGTH_VARIANCE, value); 527 if (i2p::config::GetOption(prefix + I2CP_PARAM_MIN_TUNNEL_LATENCY, value)) 528 options.Insert (I2CP_PARAM_MIN_TUNNEL_LATENCY, value); 529 if (i2p::config::GetOption(prefix + I2CP_PARAM_MAX_TUNNEL_LATENCY, value)) 530 options.Insert (I2CP_PARAM_MAX_TUNNEL_LATENCY, value); 531 if (i2p::config::GetOption(prefix + I2CP_PARAM_LEASESET_TYPE, value)) 532 options.Insert (I2CP_PARAM_LEASESET_TYPE, value); 533 if (i2p::config::GetOption(prefix + I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, value)) 534 options.Insert (I2CP_PARAM_LEASESET_ENCRYPTION_TYPE, value); 535 if (i2p::config::GetOption(prefix + I2CP_PARAM_LEASESET_PRIV_KEY, value) && !value.empty ()) 536 options.Insert (I2CP_PARAM_LEASESET_PRIV_KEY, value); 537 if (i2p::config::GetOption(prefix + I2CP_PARAM_STREAMING_PROFILE, value)) 538 options.Insert (I2CP_PARAM_STREAMING_PROFILE, value); 539 if (i2p::config::GetOption(prefix + I2CP_PARAM_STREAMING_MAX_WINDOW_SIZE, value)) 540 options.Insert (I2CP_PARAM_STREAMING_MAX_WINDOW_SIZE, value); 541 if (i2p::config::GetOption(prefix + I2CP_PARAM_STREAMING_MAX_RESENDS, value)) 542 options.Insert (I2CP_PARAM_STREAMING_MAX_RESENDS, value); 543 } 544 545 void ClientContext::ReadTunnels () 546 { 547 int numClientTunnels = 0, numServerTunnels = 0; 548 std::string tunConf; i2p::config::GetOption("tunconf", tunConf); 549 if (tunConf.empty ()) 550 tunConf = i2p::fs::DataDirPath ("tunnels.conf"); 551 552 if (i2p::fs::Exists (tunConf)) 553 { 554 LogPrint(eLogDebug, "Clients: Tunnels config file: ", tunConf); 555 ReadTunnels (tunConf, numClientTunnels, numServerTunnels); 556 } 557 558 std::string tunDir; i2p::config::GetOption("tunnelsdir", tunDir); 559 if (tunDir.empty ()) 560 tunDir = i2p::fs::DataDirPath ("tunnels.d"); 561 562 if (i2p::fs::Exists (tunDir)) 563 { 564 std::vector<std::string> files; 565 if (i2p::fs::ReadDir (tunDir, files)) 566 { 567 for (auto& it: files) 568 { 569 #if __cplusplus >= 202002L // C++20 570 if (!it.ends_with (".conf")) continue; 571 #else 572 if (it.substr(it.size() - 5) != ".conf") continue; // skip files which not ends with ".conf" 573 #endif 574 LogPrint(eLogDebug, "Clients: Tunnels extra config file: ", it); 575 ReadTunnels (it, numClientTunnels, numServerTunnels); 576 } 577 } 578 } 579 580 LogPrint (eLogInfo, "Clients: ", numClientTunnels, " I2P client tunnels created"); 581 LogPrint (eLogInfo, "Clients: ", numServerTunnels, " I2P server tunnels created"); 582 } 583 584 void ClientContext::ReadTunnels (const std::string& tunConf, int& numClientTunnels, int& numServerTunnels) 585 { 586 boost::property_tree::ptree pt; 587 try { 588 boost::property_tree::read_ini (tunConf, pt); 589 } catch (std::exception& ex) { 590 LogPrint (eLogWarning, "Clients: Can't read ", tunConf, ": ", ex.what ()); 591 return; 592 } 593 594 std::map<std::string, std::shared_ptr<ClientDestination> > destinations; // keys -> destination 595 for (auto& section: pt) 596 { 597 std::string name = section.first; 598 try 599 { 600 std::string type = section.second.get<std::string> (I2P_TUNNELS_SECTION_TYPE); 601 if (type == I2P_TUNNELS_SECTION_TYPE_CLIENT 602 || type == I2P_TUNNELS_SECTION_TYPE_SOCKS 603 || type == I2P_TUNNELS_SECTION_TYPE_WEBSOCKS 604 || type == I2P_TUNNELS_SECTION_TYPE_HTTPPROXY 605 || type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) 606 { 607 // mandatory params 608 std::string dest; 609 if (type == I2P_TUNNELS_SECTION_TYPE_CLIENT || type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) 610 dest = section.second.get<std::string> (I2P_CLIENT_TUNNEL_DESTINATION); 611 uint16_t port = section.second.get<uint16_t> (I2P_CLIENT_TUNNEL_PORT); 612 // optional params 613 bool matchTunnels = section.second.get (I2P_CLIENT_TUNNEL_MATCH_TUNNELS, false); 614 std::string keys = section.second.get<std::string> (I2P_CLIENT_TUNNEL_KEYS, "transient"); 615 std::string address = section.second.get<std::string> (I2P_CLIENT_TUNNEL_ADDRESS, "127.0.0.1"); 616 uint16_t destinationPort = section.second.get<uint16_t> (I2P_CLIENT_TUNNEL_DESTINATION_PORT, 0); 617 i2p::data::SigningKeyType sigType = section.second.get (I2P_CLIENT_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519); 618 #if !OPENSSL_PQ 619 if (sigType >= i2p::data::SIGNING_KEY_TYPE_MLDSA44) sigType = i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519; 620 #endif 621 i2p::data::CryptoKeyType cryptoType = section.second.get (I2P_CLIENT_TUNNEL_CRYPTO_TYPE, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL); 622 // I2CP 623 i2p::util::Mapping options; 624 ReadI2CPOptions (section, false, options); 625 626 // Set I2CP name if not set 627 if (!options.Contains (I2CP_PARAM_OUTBOUND_NICKNAME)) 628 options.Insert (I2CP_PARAM_OUTBOUND_NICKNAME, name); 629 630 std::shared_ptr<ClientDestination> localDestination = nullptr; 631 if (keys == "shareddest") 632 localDestination = m_SharedLocalDestination; 633 else if (keys.length () > 0) 634 { 635 auto it = destinations.find (keys); 636 if (it != destinations.end ()) 637 localDestination = it->second; 638 else 639 { 640 i2p::data::PrivateKeys k; 641 if(LoadPrivateKeys (k, keys, sigType, cryptoType)) 642 { 643 localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ()); 644 if (!localDestination) 645 { 646 if(matchTunnels) 647 localDestination = CreateNewMatchedTunnelDestination(k, dest, &options); 648 else 649 localDestination = CreateNewLocalDestination (k, type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT, &options); 650 if (keys != "transient") 651 destinations[keys] = localDestination; 652 } 653 } 654 } 655 } 656 657 if (type == I2P_TUNNELS_SECTION_TYPE_UDPCLIENT) 658 { 659 // udp client 660 // TODO: hostnames 661 boost::asio::ip::udp::endpoint end (boost::asio::ip::make_address(address), port); 662 if (!localDestination) 663 localDestination = m_SharedLocalDestination; 664 665 bool gzip = section.second.get (I2P_CLIENT_TUNNEL_GZIP, true); 666 int datagramVersion = (i2p::datagram::DatagramVersion)section.second.get (UDP_CLIENT_TUNNEL_DATAGRAM_VERSION, (int)i2p::datagram::eDatagramV3); 667 auto clientTunnel = std::make_shared<I2PUDPClientTunnel> (name, dest, end, 668 localDestination, destinationPort, gzip, (i2p::datagram::DatagramVersion)datagramVersion); 669 670 auto ins = m_ClientForwards.insert (std::make_pair (end, clientTunnel)); 671 if (ins.second) 672 { 673 clientTunnel->Start (); 674 numClientTunnels++; 675 } 676 else 677 { 678 // TODO: update 679 if (ins.first->second->GetLocalDestination () != clientTunnel->GetLocalDestination ()) 680 { 681 LogPrint (eLogInfo, "Clients: I2P UDP client tunnel destination updated"); 682 ins.first->second->Stop (); 683 ins.first->second->SetLocalDestination (clientTunnel->GetLocalDestination ()); 684 ins.first->second->Start (); 685 } 686 ins.first->second->isUpdated = true; 687 LogPrint(eLogError, "Clients: I2P Client forward for endpoint ", end, " already exists"); 688 } 689 690 } 691 else 692 { 693 boost::asio::ip::tcp::endpoint clientEndpoint; 694 std::shared_ptr<I2PService> clientTunnel; 695 if (type == I2P_TUNNELS_SECTION_TYPE_SOCKS) 696 { 697 // socks proxy 698 std::string outproxy = section.second.get("outproxy", ""); 699 auto tun = std::make_shared<i2p::proxy::SOCKSProxy>(name, address, port, !outproxy.empty(), outproxy, destinationPort, localDestination); 700 clientTunnel = tun; 701 clientEndpoint = tun->GetLocalEndpoint (); 702 } 703 else if (type == I2P_TUNNELS_SECTION_TYPE_HTTPPROXY) 704 { 705 // http proxy 706 std::string outproxy = section.second.get("outproxy", ""); 707 bool addresshelper = section.second.get("addresshelper", true); 708 bool senduseragent = section.second.get("senduseragent", false); 709 auto tun = std::make_shared<i2p::proxy::HTTPProxy>(name, address, port, 710 outproxy, addresshelper, senduseragent, localDestination); 711 clientTunnel = tun; 712 clientEndpoint = tun->GetLocalEndpoint (); 713 } 714 else if (type == I2P_TUNNELS_SECTION_TYPE_WEBSOCKS) 715 { 716 LogPrint(eLogWarning, "Clients: I2P Client tunnel websocks is deprecated, not starting ", name, " tunnel"); 717 continue; 718 } 719 else 720 { 721 // tcp client 722 auto tun = std::make_shared<I2PClientTunnel> (name, dest, address, port, localDestination, destinationPort); 723 clientTunnel = tun; 724 clientEndpoint = tun->GetLocalEndpoint (); 725 726 uint32_t keepAlive = section.second.get<uint32_t>(I2P_CLIENT_TUNNEL_KEEP_ALIVE_INTERVAL, 0); 727 if (keepAlive) 728 { 729 tun->SetKeepAliveInterval (keepAlive); 730 LogPrint(eLogInfo, "Clients: I2P Client tunnel keep alive interval set to ", keepAlive); 731 } 732 } 733 734 uint32_t timeout = section.second.get<uint32_t>(I2P_CLIENT_TUNNEL_CONNECT_TIMEOUT, 0); 735 if(timeout) 736 { 737 clientTunnel->SetConnectTimeout(timeout); 738 LogPrint(eLogInfo, "Clients: I2P Client tunnel connect timeout set to ", timeout); 739 } 740 741 auto ins = m_ClientTunnels.insert (std::make_pair (clientEndpoint, clientTunnel)); 742 if (ins.second) 743 { 744 clientTunnel->Start (); 745 numClientTunnels++; 746 } 747 else 748 { 749 // TODO: update 750 if (ins.first->second->GetLocalDestination () != clientTunnel->GetLocalDestination ()) 751 { 752 LogPrint (eLogInfo, "Clients: I2P client tunnel destination updated"); 753 ins.first->second->Stop (); 754 ins.first->second->SetLocalDestination (clientTunnel->GetLocalDestination ()); 755 ins.first->second->Start (); 756 } 757 ins.first->second->isUpdated = true; 758 LogPrint (eLogInfo, "Clients: I2P client tunnel for endpoint ", clientEndpoint, " already exists"); 759 } 760 } 761 } 762 763 else if (type == I2P_TUNNELS_SECTION_TYPE_SERVER 764 || type == I2P_TUNNELS_SECTION_TYPE_HTTP 765 || type == I2P_TUNNELS_SECTION_TYPE_IRC 766 || type == I2P_TUNNELS_SECTION_TYPE_UDPSERVER) 767 { 768 // mandatory params 769 std::string host = section.second.get<std::string> (I2P_SERVER_TUNNEL_HOST); 770 uint16_t port = section.second.get<uint16_t> (I2P_SERVER_TUNNEL_PORT); 771 std::string keys = section.second.get<std::string> (I2P_SERVER_TUNNEL_KEYS); 772 // optional params 773 uint16_t inPort = section.second.get<uint16_t> (I2P_SERVER_TUNNEL_INPORT, port); 774 std::string accessList = section.second.get<std::string> (I2P_SERVER_TUNNEL_ACCESS_LIST, ""); 775 if(accessList == "") 776 accessList = section.second.get<std::string> (I2P_SERVER_TUNNEL_WHITE_LIST, ""); 777 bool gzip = section.second.get (I2P_SERVER_TUNNEL_GZIP, false); 778 i2p::data::SigningKeyType sigType = section.second.get (I2P_SERVER_TUNNEL_SIGNATURE_TYPE, i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519); 779 #if !OPENSSL_PQ 780 if (sigType >= i2p::data::SIGNING_KEY_TYPE_MLDSA44) sigType = i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519; 781 #endif 782 i2p::data::CryptoKeyType cryptoType = section.second.get (I2P_CLIENT_TUNNEL_CRYPTO_TYPE, i2p::data::CRYPTO_KEY_TYPE_ELGAMAL); 783 784 std::string address = section.second.get<std::string> (I2P_SERVER_TUNNEL_ADDRESS, ""); 785 bool isUniqueLocal = section.second.get (I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL, (host == "::1") ? false : true); 786 bool ssl = section.second.get (I2P_SERVER_TUNNEL_SSL, false); 787 788 // I2CP 789 i2p::util::Mapping options; 790 ReadI2CPOptions (section, true, options); 791 792 // Set I2CP name if not set 793 if (!options.Contains (I2CP_PARAM_INBOUND_NICKNAME)) 794 options.Insert (I2CP_PARAM_INBOUND_NICKNAME, name); 795 796 std::shared_ptr<ClientDestination> localDestination = nullptr; 797 if (keys == "shareddest") 798 localDestination = m_SharedLocalDestination; 799 else 800 { 801 auto it = destinations.find (keys); 802 if (it != destinations.end ()) 803 { 804 localDestination = it->second; 805 localDestination->SetPublic (true); 806 } 807 else 808 { 809 i2p::data::PrivateKeys k; 810 if(!LoadPrivateKeys (k, keys, sigType, cryptoType)) 811 continue; 812 localDestination = FindLocalDestination (k.GetPublic ()->GetIdentHash ()); 813 if (!localDestination) 814 { 815 localDestination = CreateNewLocalDestination (k, true, &options); 816 destinations[keys] = localDestination; 817 } 818 else 819 localDestination->SetPublic (true); 820 } 821 } 822 if (type == I2P_TUNNELS_SECTION_TYPE_UDPSERVER) 823 { 824 // udp server tunnel 825 // TODO: hostnames 826 boost::asio::ip::udp::endpoint endpoint(boost::asio::ip::make_address(host), port); 827 if (address.empty ()) 828 { 829 if (!endpoint.address ().is_unspecified () && endpoint.address ().is_v6 ()) 830 address = "::1"; 831 else 832 address = "127.0.0.1"; 833 } 834 auto localAddress = boost::asio::ip::make_address(address); 835 auto serverTunnel = std::make_shared<I2PUDPServerTunnel>(name, localDestination, localAddress, endpoint, inPort, gzip); 836 if(!isUniqueLocal) 837 { 838 LogPrint(eLogInfo, "Clients: Disabling loopback address mapping"); 839 serverTunnel->SetUniqueLocal(isUniqueLocal); 840 } 841 std::lock_guard<std::mutex> lock(m_ForwardsMutex); 842 auto ins = m_ServerForwards.insert(std::make_pair( 843 std::make_pair(localDestination->GetIdentHash(), port), 844 serverTunnel)); 845 if (ins.second) 846 { 847 serverTunnel->Start(); 848 LogPrint(eLogInfo, "Clients: I2P Server Forward created for UDP Endpoint ", host, ":", port, " bound on ", address, " for ",localDestination->GetIdentHash().ToBase32()); 849 } 850 else 851 { 852 ins.first->second->isUpdated = true; 853 LogPrint(eLogError, "Clients: I2P Server Forward for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash()), "/", port, " already exists"); 854 } 855 856 continue; 857 } 858 859 std::shared_ptr<I2PServerTunnel> serverTunnel; 860 if (type == I2P_TUNNELS_SECTION_TYPE_HTTP) 861 { 862 std::string hostOverride = section.second.get<std::string> (I2P_SERVER_TUNNEL_HOST_OVERRIDE, ""); 863 bool i2pheaders = section.second.get (I2P_SERVER_TUNNEL_I2P_HEADERS, true); 864 serverTunnel = std::make_shared<I2PServerTunnelHTTP> (name, host, port, localDestination, hostOverride, inPort, gzip, i2pheaders); 865 } 866 else if (type == I2P_TUNNELS_SECTION_TYPE_IRC) 867 { 868 std::string webircpass = section.second.get<std::string> (I2P_SERVER_TUNNEL_WEBIRC_PASSWORD, ""); 869 serverTunnel = std::make_shared<I2PServerTunnelIRC> (name, host, port, localDestination, webircpass, inPort, gzip); 870 } 871 else // regular server tunnel by default 872 serverTunnel = std::make_shared<I2PServerTunnel> (name, host, port, localDestination, inPort, gzip); 873 874 if (!address.empty ()) 875 serverTunnel->SetLocalAddress (address); 876 if (!isUniqueLocal) 877 { 878 LogPrint(eLogInfo, "Clients: Disabling loopback address mapping"); 879 serverTunnel->SetUniqueLocal(isUniqueLocal); 880 } 881 if (ssl) 882 serverTunnel->SetSSL (true); 883 if (accessList.length () > 0) 884 { 885 std::set<i2p::data::IdentHash> idents; 886 size_t pos = 0, comma; 887 do 888 { 889 comma = accessList.find (',', pos); 890 i2p::data::IdentHash ident; 891 ident.FromBase32 (accessList.substr (pos, comma != std::string::npos ? comma - pos : std::string::npos)); 892 idents.insert (ident); 893 pos = comma + 1; 894 } 895 while (comma != std::string::npos); 896 serverTunnel->SetAccessList (idents); 897 } 898 auto ins = m_ServerTunnels.insert (std::make_pair ( 899 std::make_pair (localDestination->GetIdentHash (), inPort), 900 serverTunnel)); 901 if (ins.second) 902 { 903 serverTunnel->Start (); 904 numServerTunnels++; 905 } 906 else 907 { 908 // TODO: update 909 if (ins.first->second->GetLocalDestination () != serverTunnel->GetLocalDestination ()) 910 { 911 LogPrint (eLogInfo, "Clients: I2P server tunnel destination updated"); 912 ins.first->second->Stop (); 913 ins.first->second->SetLocalDestination (serverTunnel->GetLocalDestination ()); 914 ins.first->second->Start (); 915 } 916 ins.first->second->isUpdated = true; 917 LogPrint (eLogInfo, "Clients: I2P server tunnel for destination/port ", m_AddressBook.ToAddress(localDestination->GetIdentHash ()), "/", inPort, " already exists"); 918 } 919 920 } 921 else 922 LogPrint (eLogError, "Clients: Unknown section type = ", type, " of ", name, " in ", tunConf); 923 } 924 catch (std::exception& ex) 925 { 926 LogPrint (eLogCritical, "Clients: Can't read tunnel ", name, " params: ", ex.what ()); 927 ThrowFatal ("Unable to start tunnel ", name, ": ", ex.what ()); 928 } 929 } 930 } 931 932 void ClientContext::ReadHttpProxy () 933 { 934 std::shared_ptr<ClientDestination> localDestination; 935 bool httproxy; i2p::config::GetOption("httpproxy.enabled", httproxy); 936 if (httproxy) 937 { 938 std::string httpProxyKeys; i2p::config::GetOption("httpproxy.keys", httpProxyKeys); 939 std::string httpProxyAddr; i2p::config::GetOption("httpproxy.address", httpProxyAddr); 940 uint16_t httpProxyPort; i2p::config::GetOption("httpproxy.port", httpProxyPort); 941 std::string httpOutProxyURL; i2p::config::GetOption("httpproxy.outproxy", httpOutProxyURL); 942 bool httpAddresshelper; i2p::config::GetOption("httpproxy.addresshelper", httpAddresshelper); 943 bool httpSendUserAgent; i2p::config::GetOption("httpproxy.senduseragent", httpSendUserAgent); 944 if (httpAddresshelper) 945 i2p::config::GetOption("addressbook.enabled", httpAddresshelper); // addresshelper is not supported without address book 946 i2p::data::SigningKeyType sigType; i2p::config::GetOption("httpproxy.signaturetype", sigType); 947 #if !OPENSSL_PQ 948 if (sigType >= i2p::data::SIGNING_KEY_TYPE_MLDSA44) sigType = i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519; 949 #endif 950 LogPrint(eLogInfo, "Clients: Starting HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort); 951 if (httpProxyKeys == "shareddest") 952 { 953 localDestination = m_SharedLocalDestination; 954 localDestination->Acquire (); 955 } 956 else if (httpProxyKeys.length () > 0) 957 { 958 i2p::data::PrivateKeys keys; 959 if(LoadPrivateKeys (keys, httpProxyKeys, sigType)) 960 { 961 i2p::util::Mapping params; 962 ReadI2CPOptionsFromConfig ("httpproxy.", params); 963 params.Insert (I2CP_PARAM_OUTBOUND_NICKNAME, "HTTPProxy"); 964 localDestination = CreateNewLocalDestination (keys, false, ¶ms); 965 if (localDestination) localDestination->Acquire (); 966 } 967 else 968 LogPrint(eLogCritical, "Clients: Failed to load HTTP Proxy key"); 969 } 970 try 971 { 972 m_HttpProxy = new i2p::proxy::HTTPProxy("HTTP Proxy", httpProxyAddr, httpProxyPort, 973 httpOutProxyURL, httpAddresshelper, httpSendUserAgent, localDestination); 974 m_HttpProxy->Start(); 975 } 976 catch (std::exception& e) 977 { 978 LogPrint(eLogCritical, "Clients: Exception in HTTP Proxy: ", e.what()); 979 ThrowFatal ("Unable to start HTTP Proxy at ", httpProxyAddr, ":", httpProxyPort, ": ", e.what ()); 980 } 981 } 982 } 983 984 void ClientContext::ReadSocksProxy () 985 { 986 std::shared_ptr<ClientDestination> localDestination; 987 bool socksproxy; i2p::config::GetOption("socksproxy.enabled", socksproxy); 988 if (socksproxy) 989 { 990 std::string httpProxyKeys; i2p::config::GetOption("httpproxy.keys", httpProxyKeys); 991 // we still need httpProxyKeys to compare with sockProxyKeys 992 std::string socksProxyKeys; i2p::config::GetOption("socksproxy.keys", socksProxyKeys); 993 std::string socksProxyAddr; i2p::config::GetOption("socksproxy.address", socksProxyAddr); 994 uint16_t socksProxyPort; i2p::config::GetOption("socksproxy.port", socksProxyPort); 995 bool socksOutProxy; i2p::config::GetOption("socksproxy.outproxy.enabled", socksOutProxy); 996 std::string socksOutProxyAddr; i2p::config::GetOption("socksproxy.outproxy", socksOutProxyAddr); 997 uint16_t socksOutProxyPort; i2p::config::GetOption("socksproxy.outproxyport", socksOutProxyPort); 998 i2p::data::SigningKeyType sigType; i2p::config::GetOption("socksproxy.signaturetype", sigType); 999 #if !OPENSSL_PQ 1000 if (sigType >= i2p::data::SIGNING_KEY_TYPE_MLDSA44) sigType = i2p::data::SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519; 1001 #endif 1002 LogPrint(eLogInfo, "Clients: Starting SOCKS Proxy at ", socksProxyAddr, ":", socksProxyPort); 1003 if (socksProxyKeys == "shareddest") 1004 { 1005 localDestination = m_SharedLocalDestination; 1006 localDestination->Acquire (); 1007 } 1008 else if (httpProxyKeys == socksProxyKeys && m_HttpProxy) 1009 { 1010 localDestination = m_HttpProxy->GetLocalDestination (); 1011 localDestination->Acquire (); 1012 } 1013 else if (socksProxyKeys.length () > 0) 1014 { 1015 i2p::data::PrivateKeys keys; 1016 if (LoadPrivateKeys (keys, socksProxyKeys, sigType)) 1017 { 1018 i2p::util::Mapping params; 1019 ReadI2CPOptionsFromConfig ("socksproxy.", params); 1020 params.Insert (I2CP_PARAM_OUTBOUND_NICKNAME, "SOCKSProxy"); 1021 localDestination = CreateNewLocalDestination (keys, false, ¶ms); 1022 if (localDestination) localDestination->Acquire (); 1023 } 1024 else 1025 LogPrint(eLogCritical, "Clients: Failed to load SOCKS Proxy key"); 1026 } 1027 try 1028 { 1029 m_SocksProxy = new i2p::proxy::SOCKSProxy("SOCKS", socksProxyAddr, socksProxyPort, 1030 socksOutProxy, socksOutProxyAddr, socksOutProxyPort, localDestination); 1031 m_SocksProxy->Start(); 1032 } 1033 catch (std::exception& e) 1034 { 1035 LogPrint(eLogCritical, "Clients: Exception in SOCKS Proxy: ", e.what()); 1036 ThrowFatal ("Unable to start SOCKS Proxy at ", socksProxyAddr, ":", socksProxyPort, ": ", e.what ()); 1037 } 1038 } 1039 } 1040 1041 void ClientContext::ScheduleCleanupUDP() 1042 { 1043 if (m_CleanupUDPTimer) 1044 { 1045 // schedule cleanup in 17 seconds 1046 m_CleanupUDPTimer->expires_from_now (boost::posix_time::seconds (17)); 1047 m_CleanupUDPTimer->async_wait(std::bind(&ClientContext::CleanupUDP, this, std::placeholders::_1)); 1048 } 1049 } 1050 1051 void ClientContext::CleanupUDP(const boost::system::error_code & ecode) 1052 { 1053 if(!ecode) 1054 { 1055 std::lock_guard<std::mutex> lock(m_ForwardsMutex); 1056 for (auto & s : m_ServerForwards ) s.second->ExpireStale(); 1057 ScheduleCleanupUDP(); 1058 } 1059 } 1060 1061 void ClientContext::VisitTunnels (bool clean) 1062 { 1063 for (auto it = m_ClientTunnels.begin (); it != m_ClientTunnels.end ();) 1064 { 1065 if(clean && !it->second->isUpdated) { 1066 it->second->Stop (); 1067 it = m_ClientTunnels.erase(it); 1068 } else { 1069 it->second->isUpdated = false; 1070 it++; 1071 } 1072 } 1073 1074 for (auto it = m_ServerTunnels.begin (); it != m_ServerTunnels.end ();) 1075 { 1076 if(clean && !it->second->isUpdated) { 1077 it->second->Stop (); 1078 it = m_ServerTunnels.erase(it); 1079 } else { 1080 it->second->isUpdated = false; 1081 it++; 1082 } 1083 } 1084 1085 // TODO: Write correct UDP tunnels stop 1086 for (auto it = m_ClientForwards.begin (); it != m_ClientForwards.end ();) 1087 { 1088 if(clean && !it->second->isUpdated) { 1089 it->second->Stop (); 1090 it = m_ClientForwards.erase(it); 1091 } else { 1092 it->second->isUpdated = false; 1093 it++; 1094 } 1095 } 1096 1097 for (auto it = m_ServerForwards.begin (); it != m_ServerForwards.end ();) 1098 { 1099 if(clean && !it->second->isUpdated) { 1100 it->second->Stop (); 1101 it = m_ServerForwards.erase(it); 1102 } else { 1103 it->second->isUpdated = false; 1104 it++; 1105 } 1106 } 1107 } 1108 } 1109 }