2020-05-22 13:18:41 +00:00
/*
2022-03-08 03:20:11 +00:00
* Copyright ( c ) 2013 - 2022 , The PurpleI2P Project
2020-05-22 13:18:41 +00:00
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
2014-11-28 21:04:57 +00:00
# include <fstream>
2015-02-12 21:11:56 +00:00
# include <iostream>
2015-03-13 20:05:39 +00:00
# include <boost/property_tree/ptree.hpp>
# include <boost/property_tree/ini_parser.hpp>
2016-01-20 00:00:00 +00:00
# include "Config.h"
2016-02-11 00:00:00 +00:00
# include "FS.h"
2014-10-16 01:39:39 +00:00
# include "Log.h"
2014-11-28 21:04:57 +00:00
# include "Identity.h"
2016-06-14 18:37:22 +00:00
# include "util.h"
2014-10-16 00:52:17 +00:00
# include "ClientContext.h"
2017-01-07 13:32:50 +00:00
# include "SOCKS.h"
2017-04-08 16:51:35 +00:00
# include "MatchedDestination.h"
2014-10-16 00:52:17 +00:00
namespace i2p
{
namespace client
{
2017-04-08 16:51:35 +00:00
ClientContext context ;
2014-10-16 01:39:39 +00:00
ClientContext : : ClientContext ( ) : m_SharedLocalDestination ( nullptr ) ,
2017-04-08 16:51:35 +00:00
m_HttpProxy ( nullptr ) , m_SocksProxy ( nullptr ) , m_SamBridge ( nullptr ) ,
2016-09-16 14:31:11 +00:00
m_BOBCommandChannel ( nullptr ) , m_I2CPServer ( nullptr )
2014-10-16 01:39:39 +00:00
{
}
2017-04-08 16:51:35 +00:00
ClientContext : : ~ ClientContext ( )
2014-10-16 01:39:39 +00:00
{
delete m_HttpProxy ;
delete m_SocksProxy ;
delete m_SamBridge ;
2014-12-02 15:34:02 +00:00
delete m_BOBCommandChannel ;
2016-05-12 19:37:46 +00:00
delete m_I2CPServer ;
2014-10-16 01:39:39 +00:00
}
2017-04-08 16:51:35 +00:00
2014-10-16 00:52:17 +00:00
void ClientContext : : Start ( )
{
2018-01-23 20:13:43 +00:00
// shared local destination
2014-10-16 00:52:17 +00:00
if ( ! m_SharedLocalDestination )
2018-01-23 19:40:05 +00:00
CreateNewSharedLocalDestination ( ) ;
2017-04-08 16:51:35 +00:00
2019-04-25 20:06:14 +00:00
// addressbook
2017-04-08 16:51:35 +00:00
m_AddressBook . Start ( ) ;
2018-01-23 20:13:43 +00:00
// HTTP proxy
ReadHttpProxy ( ) ;
2017-04-08 16:51:35 +00:00
2018-01-23 20:13:43 +00:00
// SOCKS proxy
ReadSocksProxy ( ) ;
2015-02-12 21:11:56 +00:00
2016-08-22 17:04:36 +00:00
// I2P tunnels
2017-04-08 16:51:35 +00:00
ReadTunnels ( ) ;
2015-02-12 21:11:56 +00:00
// SAM
2016-01-20 00:00:00 +00:00
bool sam ; i2p : : config : : GetOption ( " sam.enabled " , sam ) ;
2020-03-01 10:25:50 +00:00
if ( sam )
2020-02-04 20:31:04 +00:00
{
2016-01-20 00:00:00 +00:00
std : : string samAddr ; i2p : : config : : GetOption ( " sam.address " , samAddr ) ;
uint16_t samPort ; i2p : : config : : GetOption ( " sam.port " , samPort ) ;
2020-03-01 10:25:50 +00:00
bool singleThread ; i2p : : config : : GetOption ( " sam.singlethread " , singleThread ) ;
2021-11-27 19:53:53 +00:00
LogPrint ( eLogInfo , " Clients: Starting SAM bridge at " , samAddr , " : " , samPort ) ;
2020-03-01 10:25:50 +00:00
try
2020-05-05 13:35:41 +00:00
{
2020-02-04 20:31:04 +00:00
m_SamBridge = new SAMBridge ( samAddr , samPort , singleThread ) ;
2020-05-04 23:36:34 +00:00
m_SamBridge - > Start ( ) ;
2020-03-01 10:25:50 +00:00
}
catch ( std : : exception & e )
2020-05-05 13:35:41 +00:00
{
2020-05-04 23:36:34 +00:00
LogPrint ( eLogError , " Clients: Exception in SAM bridge: " , e . what ( ) ) ;
2020-05-05 13:35:41 +00:00
ThrowFatal ( " Unable to start SAM bridge at " , samAddr , " : " , samPort , " : " , e . what ( ) ) ;
2016-03-29 22:03:15 +00:00
}
2017-04-08 16:51:35 +00:00
}
2015-02-12 21:11:56 +00:00
// BOB
2016-01-20 00:00:00 +00:00
bool bob ; i2p : : config : : GetOption ( " bob.enabled " , bob ) ;
if ( bob ) {
std : : string bobAddr ; i2p : : config : : GetOption ( " bob.address " , bobAddr ) ;
uint16_t bobPort ; i2p : : config : : GetOption ( " bob.port " , bobPort ) ;
2021-11-27 19:53:53 +00:00
LogPrint ( eLogInfo , " Clients: Starting BOB command channel at " , bobAddr , " : " , bobPort ) ;
2020-03-01 10:25:50 +00:00
try
2020-05-05 13:35:41 +00:00
{
2020-05-04 23:36:34 +00:00
m_BOBCommandChannel = new BOBCommandChannel ( bobAddr , bobPort ) ;
m_BOBCommandChannel - > Start ( ) ;
2020-03-01 10:25:50 +00:00
}
catch ( std : : exception & e )
2020-05-05 13:35:41 +00:00
{
2020-05-04 23:36:34 +00:00
LogPrint ( eLogError , " Clients: Exception in BOB bridge: " , e . what ( ) ) ;
2020-05-05 13:35:41 +00:00
ThrowFatal ( " Unable to start BOB bridge at " , bobAddr , " : " , bobPort , " : " , e . what ( ) ) ;
2016-03-29 22:03:15 +00:00
}
2017-04-08 16:51:35 +00:00
}
2016-03-26 14:31:47 +00:00
2016-05-31 15:54:45 +00:00
// I2CP
bool i2cp ; i2p : : config : : GetOption ( " i2cp.enabled " , i2cp ) ;
2017-04-08 16:51:35 +00:00
if ( i2cp )
2016-05-31 15:54:45 +00:00
{
std : : string i2cpAddr ; i2p : : config : : GetOption ( " i2cp.address " , i2cpAddr ) ;
uint16_t i2cpPort ; i2p : : config : : GetOption ( " i2cp.port " , i2cpPort ) ;
2020-10-02 17:13:27 +00:00
bool singleThread ; i2p : : config : : GetOption ( " i2cp.singlethread " , singleThread ) ;
2021-11-27 19:53:53 +00:00
LogPrint ( eLogInfo , " Clients: Starting I2CP at " , i2cpAddr , " : " , i2cpPort ) ;
2020-03-01 10:25:50 +00:00
try
2020-05-05 13:35:41 +00:00
{
2020-10-02 17:13:27 +00:00
m_I2CPServer = new I2CPServer ( i2cpAddr , i2cpPort , singleThread ) ;
2018-01-06 04:01:44 +00:00
m_I2CPServer - > Start ( ) ;
2020-03-01 10:25:50 +00:00
}
catch ( std : : exception & e )
2020-05-05 13:35:41 +00:00
{
2016-05-31 15:54:45 +00:00
LogPrint ( eLogError , " Clients: Exception in I2CP: " , e . what ( ) ) ;
2020-05-05 13:35:41 +00:00
ThrowFatal ( " Unable to start I2CP at " , i2cpAddr , " : " , i2cpPort , " : " , e . what ( ) ) ;
2016-05-31 15:54:45 +00:00
}
2017-04-08 16:51:35 +00:00
}
2016-05-31 15:54:45 +00:00
2017-04-08 16:51:35 +00:00
m_AddressBook . StartResolvers ( ) ;
2016-09-16 14:31:11 +00:00
// start UDP cleanup
if ( ! m_ServerForwards . empty ( ) )
{
m_CleanupUDPTimer . reset ( new boost : : asio : : deadline_timer ( m_SharedLocalDestination - > GetService ( ) ) ) ;
ScheduleCleanupUDP ( ) ;
}
2014-10-16 00:52:17 +00:00
}
2017-04-08 16:51:35 +00:00
2014-10-16 00:52:17 +00:00
void ClientContext : : Stop ( )
{
2016-03-02 17:04:02 +00:00
if ( m_HttpProxy )
{
2021-11-27 19:53:53 +00:00
LogPrint ( eLogInfo , " Clients: Stopping HTTP Proxy " ) ;
2016-03-02 17:04:02 +00:00
m_HttpProxy - > Stop ( ) ;
delete m_HttpProxy ;
m_HttpProxy = nullptr ;
}
2015-12-18 12:44:03 +00:00
2016-03-02 17:04:02 +00:00
if ( m_SocksProxy )
{
2021-11-27 19:53:53 +00:00
LogPrint ( eLogInfo , " Clients: Stopping SOCKS Proxy " ) ;
2016-03-02 17:04:02 +00:00
m_SocksProxy - > Stop ( ) ;
delete m_SocksProxy ;
m_SocksProxy = nullptr ;
}
2015-12-18 12:44:03 +00:00
2015-02-12 21:11:56 +00:00
for ( auto & it : m_ClientTunnels )
2014-10-16 01:39:39 +00:00
{
2021-11-27 19:53:53 +00:00
LogPrint ( eLogInfo , " Clients: Stopping I2P client tunnel on port " , it . first ) ;
2015-02-13 15:18:42 +00:00
it . second - > Stop ( ) ;
2014-10-16 01:39:39 +00:00
}
2017-04-08 16:51:35 +00:00
m_ClientTunnels . clear ( ) ;
2015-12-18 12:44:03 +00:00
2015-02-13 20:56:57 +00:00
for ( auto & it : m_ServerTunnels )
2014-10-16 01:39:39 +00:00
{
2021-11-27 19:53:53 +00:00
LogPrint ( eLogInfo , " Clients: Stopping I2P server tunnel " ) ;
2015-02-13 20:56:57 +00:00
it . second - > Stop ( ) ;
}
2017-04-08 16:51:35 +00:00
m_ServerTunnels . clear ( ) ;
2015-12-18 12:44:03 +00:00
2014-10-16 01:39:39 +00:00
if ( m_SamBridge )
{
2021-11-27 19:53:53 +00:00
LogPrint ( eLogInfo , " Clients: Stopping SAM bridge " ) ;
2014-10-16 01:39:39 +00:00
m_SamBridge - > Stop ( ) ;
2017-04-08 16:51:35 +00:00
delete m_SamBridge ;
2014-10-16 01:39:39 +00:00
m_SamBridge = nullptr ;
2017-04-08 16:51:35 +00:00
}
2015-12-18 12:44:03 +00:00
2014-12-02 20:47:44 +00:00
if ( m_BOBCommandChannel )
{
2021-11-27 19:53:53 +00:00
LogPrint ( eLogInfo , " Clients: Stopping BOB command channel " ) ;
2014-12-02 20:47:44 +00:00
m_BOBCommandChannel - > Stop ( ) ;
2017-04-08 16:51:35 +00:00
delete m_BOBCommandChannel ;
2014-12-02 20:47:44 +00:00
m_BOBCommandChannel = nullptr ;
2015-12-18 12:44:03 +00:00
}
2016-05-31 15:54:45 +00:00
if ( m_I2CPServer )
{
2021-11-27 19:53:53 +00:00
LogPrint ( eLogInfo , " Clients: Stopping I2CP " ) ;
2016-05-31 15:54:45 +00:00
m_I2CPServer - > Stop ( ) ;
2017-04-08 16:51:35 +00:00
delete m_I2CPServer ;
2016-05-31 15:54:45 +00:00
m_I2CPServer = nullptr ;
}
2021-11-27 19:53:53 +00:00
LogPrint ( eLogInfo , " Clients: Stopping AddressBook " ) ;
2016-08-21 19:02:17 +00:00
m_AddressBook . Stop ( ) ;
2021-09-03 20:25:47 +00:00
{
2016-09-03 15:46:47 +00:00
std : : lock_guard < std : : mutex > lock ( m_ForwardsMutex ) ;
m_ServerForwards . clear ( ) ;
m_ClientForwards . clear ( ) ;
}
2017-04-08 16:51:35 +00:00
2016-09-16 14:31:11 +00:00
if ( m_CleanupUDPTimer )
{
2017-04-08 16:51:35 +00:00
m_CleanupUDPTimer - > cancel ( ) ;
m_CleanupUDPTimer = nullptr ;
2016-09-16 14:31:11 +00:00
}
2016-08-05 18:23:54 +00:00
for ( auto & it : m_Destinations )
2014-10-16 00:52:17 +00:00
it . second - > Stop ( ) ;
m_Destinations . clear ( ) ;
2021-09-03 20:25:47 +00:00
m_SharedLocalDestination - > Release ( ) ;
2016-08-21 19:02:17 +00:00
m_SharedLocalDestination = nullptr ;
2017-04-08 16:51:35 +00:00
}
2016-05-12 15:38:18 +00:00
void ClientContext : : ReloadConfig ( )
{
2017-08-31 16:08:22 +00:00
// TODO: handle config changes
2017-07-28 19:12:15 +00:00
/*std::string config; i2p::config::GetOption("conf", config);
i2p : : config : : ParseConfig ( config ) ; */
2018-01-23 19:40:05 +00:00
// change shared local destination
m_SharedLocalDestination - > Release ( ) ;
CreateNewSharedLocalDestination ( ) ;
2018-01-23 20:13:43 +00:00
// recreate HTTP proxy
if ( m_HttpProxy )
{
m_HttpProxy - > Stop ( ) ;
2021-09-03 20:25:47 +00:00
delete m_HttpProxy ;
2018-01-23 20:13:43 +00:00
m_HttpProxy = nullptr ;
2019-04-25 20:06:14 +00:00
}
2018-01-23 20:13:43 +00:00
ReadHttpProxy ( ) ;
2019-04-25 20:06:14 +00:00
2018-01-23 20:13:43 +00:00
// recreate SOCKS proxy
if ( m_SocksProxy )
{
m_SocksProxy - > Stop ( ) ;
2021-09-03 20:25:47 +00:00
delete m_SocksProxy ;
2018-01-23 20:13:43 +00:00
m_SocksProxy = nullptr ;
2019-04-25 20:06:14 +00:00
}
ReadSocksProxy ( ) ;
2018-01-23 20:13:43 +00:00
2021-09-03 20:25:47 +00:00
// handle tunnels
// reset isUpdated for each tunnel
VisitTunnels ( false ) ;
// reload tunnels
ReadTunnels ( ) ;
// delete not updated tunnels (not in config anymore)
VisitTunnels ( true ) ;
2017-07-07 19:12:34 +00:00
// delete unused destinations
std : : unique_lock < std : : mutex > l ( m_DestinationsMutex ) ;
for ( auto it = m_Destinations . begin ( ) ; it ! = m_Destinations . end ( ) ; )
{
2017-08-31 16:08:22 +00:00
auto dest = it - > second ;
2017-07-07 19:12:34 +00:00
if ( dest - > GetRefCounter ( ) > 0 ) + + it ; // skip
else
{
dest - > Stop ( ) ;
it = m_Destinations . erase ( it ) ;
}
}
2016-05-12 15:38:18 +00:00
}
2017-04-08 16:51:35 +00:00
2018-01-06 03:48:51 +00:00
bool ClientContext : : LoadPrivateKeys ( i2p : : data : : PrivateKeys & keys , const std : : string & filename ,
2017-11-08 20:59:41 +00:00
i2p : : data : : SigningKeyType sigType , i2p : : data : : CryptoKeyType cryptoType )
2014-10-16 00:52:17 +00:00
{
2020-08-10 21:49:46 +00:00
static const std : : string transient ( " transient " ) ;
if ( ! filename . compare ( 0 , transient . length ( ) , transient ) ) // starts with transient
2017-11-22 19:49:45 +00:00
{
keys = i2p : : data : : PrivateKeys : : CreateRandomKeys ( sigType , cryptoType ) ;
LogPrint ( eLogInfo , " Clients: New transient keys address " , m_AddressBook . ToAddress ( keys . GetPublic ( ) - > GetIdentHash ( ) ) , " created " ) ;
return true ;
}
2016-07-25 15:13:54 +00:00
bool success = true ;
2016-02-11 00:00:00 +00:00
std : : string fullPath = i2p : : fs : : DataDirPath ( filename ) ;
std : : ifstream s ( fullPath , std : : ifstream : : binary ) ;
2017-04-08 16:51:35 +00:00
if ( s . is_open ( ) )
{
2014-11-28 21:04:57 +00:00
s . seekg ( 0 , std : : ios : : end ) ;
size_t len = s . tellg ( ) ;
s . seekg ( 0 , std : : ios : : beg ) ;
uint8_t * buf = new uint8_t [ len ] ;
s . read ( ( char * ) buf , len ) ;
2016-07-25 15:13:54 +00:00
if ( ! keys . FromBuffer ( buf , len ) )
{
2021-11-27 19:53:53 +00:00
LogPrint ( eLogError , " Clients: Failed to load keyfile " , filename ) ;
2016-07-25 15:13:54 +00:00
success = false ;
}
else
LogPrint ( eLogInfo , " Clients: Local address " , m_AddressBook . ToAddress ( keys . GetPublic ( ) - > GetIdentHash ( ) ) , " loaded " ) ;
2014-11-28 21:04:57 +00:00
delete [ ] buf ;
2017-04-08 16:51:35 +00:00
}
2014-11-28 21:04:57 +00:00
else
{
2021-11-27 19:53:53 +00:00
LogPrint ( eLogError , " Clients: Can't open file " , fullPath , " Creating new one with signature type " , sigType , " crypto type " , cryptoType ) ;
2017-11-08 20:59:41 +00:00
keys = i2p : : data : : PrivateKeys : : CreateRandomKeys ( sigType , cryptoType ) ;
2014-11-28 21:04:57 +00:00
std : : ofstream f ( fullPath , std : : ofstream : : binary | std : : ofstream : : out ) ;
size_t len = keys . GetFullLen ( ) ;
uint8_t * buf = new uint8_t [ len ] ;
len = keys . ToBuffer ( buf , len ) ;
f . write ( ( char * ) buf , len ) ;
delete [ ] buf ;
2017-04-08 16:51:35 +00:00
2015-12-18 12:44:03 +00:00
LogPrint ( eLogInfo , " Clients: New private keys file " , fullPath , " for " , m_AddressBook . ToAddress ( keys . GetPublic ( ) - > GetIdentHash ( ) ) , " created " ) ;
2016-07-25 15:13:54 +00:00
}
return success ;
2014-10-16 00:52:17 +00:00
}
2016-09-03 21:53:46 +00:00
std : : vector < std : : shared_ptr < DatagramSessionInfo > > ClientContext : : GetForwardInfosFor ( const i2p : : data : : IdentHash & destination )
2016-09-03 17:58:34 +00:00
{
2016-09-03 21:53:46 +00:00
std : : vector < std : : shared_ptr < DatagramSessionInfo > > infos ;
2016-09-03 17:58:34 +00:00
std : : lock_guard < std : : mutex > lock ( m_ForwardsMutex ) ;
2016-09-03 21:53:46 +00:00
for ( const auto & c : m_ClientForwards )
2016-09-03 17:58:34 +00:00
{
if ( c . second - > IsLocalDestination ( destination ) )
2016-09-03 21:53:46 +00:00
{
for ( auto & i : c . second - > GetSessions ( ) ) infos . push_back ( i ) ;
break ;
}
2016-09-03 17:58:34 +00:00
}
2016-09-03 21:53:46 +00:00
for ( const auto & s : m_ServerForwards )
2016-09-03 17:58:34 +00:00
{
if ( std : : get < 0 > ( s . first ) = = destination )
2016-09-03 21:53:46 +00:00
{
for ( auto & i : s . second - > GetSessions ( ) ) infos . push_back ( i ) ;
break ;
}
2016-09-03 17:58:34 +00:00
}
2016-09-03 21:53:46 +00:00
return infos ;
2016-09-03 17:58:34 +00:00
}
2017-04-08 16:51:35 +00:00
2017-11-14 20:05:07 +00:00
std : : shared_ptr < ClientDestination > ClientContext : : CreateNewLocalDestination ( bool isPublic ,
2018-01-06 04:01:44 +00:00
i2p : : data : : SigningKeyType sigType , i2p : : data : : CryptoKeyType cryptoType ,
2017-11-14 20:05:07 +00:00
const std : : map < std : : string , std : : string > * params )
2014-10-16 00:52:17 +00:00
{
2017-11-14 20:05:07 +00:00
i2p : : data : : PrivateKeys keys = i2p : : data : : PrivateKeys : : CreateRandomKeys ( sigType , cryptoType ) ;
2020-02-04 19:17:23 +00:00
auto localDestination = std : : make_shared < RunnableClientDestination > ( keys , isPublic , params ) ;
2020-02-04 20:31:04 +00:00
AddLocalDestination ( localDestination ) ;
return localDestination ;
}
std : : shared_ptr < ClientDestination > ClientContext : : CreateNewLocalDestination (
boost : : asio : : io_service & service , bool isPublic ,
i2p : : data : : SigningKeyType sigType , i2p : : data : : CryptoKeyType cryptoType ,
const std : : map < std : : string , std : : string > * params )
{
i2p : : data : : PrivateKeys keys = i2p : : data : : PrivateKeys : : CreateRandomKeys ( sigType , cryptoType ) ;
auto localDestination = std : : make_shared < ClientDestination > ( service , keys , isPublic , params ) ;
AddLocalDestination ( localDestination ) ;
2014-10-16 00:52:17 +00:00
return localDestination ;
}
2017-04-08 16:51:35 +00:00
std : : shared_ptr < ClientDestination > ClientContext : : CreateNewMatchedTunnelDestination ( const i2p : : data : : PrivateKeys & keys , const std : : string & name , const std : : map < std : : string , std : : string > * params )
{
2020-02-04 20:31:04 +00:00
auto localDestination = std : : make_shared < MatchedTunnelDestination > ( keys , name , params ) ;
AddLocalDestination ( localDestination ) ;
return localDestination ;
}
void ClientContext : : AddLocalDestination ( std : : shared_ptr < ClientDestination > localDestination )
{
2017-04-08 16:51:35 +00:00
std : : unique_lock < std : : mutex > l ( m_DestinationsMutex ) ;
m_Destinations [ localDestination - > GetIdentHash ( ) ] = localDestination ;
localDestination - > Start ( ) ;
}
2015-02-24 20:40:50 +00:00
void ClientContext : : DeleteLocalDestination ( std : : shared_ptr < ClientDestination > destination )
2014-10-16 00:52:17 +00:00
{
if ( ! destination ) return ;
auto it = m_Destinations . find ( destination - > GetIdentHash ( ) ) ;
if ( it ! = m_Destinations . end ( ) )
{
auto d = it - > second ;
{
std : : unique_lock < std : : mutex > l ( m_DestinationsMutex ) ;
m_Destinations . erase ( it ) ;
2017-04-08 16:51:35 +00:00
}
2014-10-16 00:52:17 +00:00
d - > Stop ( ) ;
}
}
2015-02-24 20:40:50 +00:00
std : : shared_ptr < ClientDestination > ClientContext : : CreateNewLocalDestination ( const i2p : : data : : PrivateKeys & keys , bool isPublic ,
2014-11-30 15:51:22 +00:00
const std : : map < std : : string , std : : string > * params )
2014-10-16 00:52:17 +00:00
{
2015-11-03 14:15:49 +00:00
auto it = m_Destinations . find ( keys . GetPublic ( ) - > GetIdentHash ( ) ) ;
2014-10-16 00:52:17 +00:00
if ( it ! = m_Destinations . end ( ) )
{
2015-12-18 12:44:03 +00:00
LogPrint ( eLogWarning , " Clients: Local destination " , m_AddressBook . ToAddress ( keys . GetPublic ( ) - > GetIdentHash ( ) ) , " exists " ) ;
2020-02-04 16:48:56 +00:00
it - > second - > Start ( ) ; // make sure to start
2018-12-13 14:53:16 +00:00
return it - > second ;
2017-04-08 16:51:35 +00:00
}
2020-02-04 19:17:23 +00:00
auto localDestination = std : : make_shared < RunnableClientDestination > ( keys , isPublic , params ) ;
2020-02-04 20:31:04 +00:00
AddLocalDestination ( localDestination ) ;
return localDestination ;
}
std : : shared_ptr < ClientDestination > ClientContext : : CreateNewLocalDestination ( boost : : asio : : io_service & service ,
const i2p : : data : : PrivateKeys & keys , bool isPublic , const std : : map < std : : string , std : : string > * params )
{
auto it = m_Destinations . find ( keys . GetPublic ( ) - > GetIdentHash ( ) ) ;
if ( it ! = m_Destinations . end ( ) )
{
LogPrint ( eLogWarning , " Clients: Local destination " , m_AddressBook . ToAddress ( keys . GetPublic ( ) - > GetIdentHash ( ) ) , " exists " ) ;
it - > second - > Start ( ) ; // make sure to start
return it - > second ;
}
auto localDestination = std : : make_shared < ClientDestination > ( service , keys , isPublic , params ) ;
AddLocalDestination ( localDestination ) ;
2014-10-16 00:52:17 +00:00
return localDestination ;
}
2017-04-08 16:51:35 +00:00
2018-01-23 19:40:05 +00:00
void ClientContext : : CreateNewSharedLocalDestination ( )
{
2021-11-27 20:30:35 +00:00
std : : map < std : : string , std : : string > params
2020-09-27 23:07:58 +00:00
{
2021-01-29 12:46:20 +00:00
{ I2CP_PARAM_INBOUND_TUNNELS_QUANTITY , " 3 " } ,
{ I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY , " 3 " } ,
{ I2CP_PARAM_LEASESET_TYPE , " 3 " } ,
{ I2CP_PARAM_LEASESET_ENCRYPTION_TYPE , " 0,4 " }
2020-09-27 23:07:58 +00:00
} ;
m_SharedLocalDestination = CreateNewLocalDestination ( false , i2p : : data : : SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 ,
i2p : : data : : CRYPTO_KEY_TYPE_ELGAMAL , & params ) ; // non-public, EDDSA
2018-01-23 19:40:05 +00:00
m_SharedLocalDestination - > Acquire ( ) ;
}
2015-02-24 20:40:50 +00:00
std : : shared_ptr < ClientDestination > ClientContext : : FindLocalDestination ( const i2p : : data : : IdentHash & destination ) const
2014-10-16 00:52:17 +00:00
{
auto it = m_Destinations . find ( destination ) ;
if ( it ! = m_Destinations . end ( ) )
return it - > second ;
return nullptr ;
2017-04-08 16:51:35 +00:00
}
2015-02-12 21:11:56 +00:00
2016-01-15 17:24:40 +00:00
template < typename Section , typename Type >
std : : string ClientContext : : GetI2CPOption ( const Section & section , const std : : string & name , const Type & value ) const
{
2020-03-01 10:25:50 +00:00
return section . second . get ( boost : : property_tree : : ptree : : path_type ( name , ' / ' ) , std : : to_string ( value ) ) ;
2017-04-08 16:51:35 +00:00
}
2016-01-15 17:24:40 +00:00
2019-01-15 20:43:21 +00:00
template < typename Section >
std : : string ClientContext : : GetI2CPStringOption ( const Section & section , const std : : string & name , const std : : string & value ) const
{
2020-03-01 10:25:50 +00:00
return section . second . get ( boost : : property_tree : : ptree : : path_type ( name , ' / ' ) , value ) ;
2019-01-15 20:43:21 +00:00
}
2019-07-13 00:58:17 +00:00
template < typename Section >
void ClientContext : : ReadI2CPOptionsGroup ( const Section & section , const std : : string & group , std : : map < std : : string , std : : string > & options ) const
{
for ( auto it : section . second )
{
if ( it . first . length ( ) > = group . length ( ) & & ! it . first . compare ( 0 , group . length ( ) , group ) )
options [ it . first ] = it . second . get_value ( " " ) ;
2020-03-01 10:25:50 +00:00
}
2019-07-13 00:58:17 +00:00
}
2020-03-01 10:25:50 +00:00
2016-01-15 17:24:40 +00:00
template < typename Section >
2020-10-04 23:52:12 +00:00
void ClientContext : : ReadI2CPOptions ( const Section & section , bool isServer , std : : map < std : : string , std : : string > & options ) const
2016-01-15 17:24:40 +00:00
{
2020-03-01 10:25:50 +00:00
options [ I2CP_PARAM_INBOUND_TUNNEL_LENGTH ] = GetI2CPOption ( section , I2CP_PARAM_INBOUND_TUNNEL_LENGTH , DEFAULT_INBOUND_TUNNEL_LENGTH ) ;
2016-01-15 17:24:40 +00:00
options [ I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH ] = GetI2CPOption ( section , I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH , DEFAULT_OUTBOUND_TUNNEL_LENGTH ) ;
options [ I2CP_PARAM_INBOUND_TUNNELS_QUANTITY ] = GetI2CPOption ( section , I2CP_PARAM_INBOUND_TUNNELS_QUANTITY , DEFAULT_INBOUND_TUNNELS_QUANTITY ) ;
options [ I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY ] = GetI2CPOption ( section , I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY , DEFAULT_OUTBOUND_TUNNELS_QUANTITY ) ;
2022-03-08 03:20:11 +00:00
options [ I2CP_PARAM_INBOUND_TUNNELS_LENGTH_VARIANCE ] = GetI2CPOption ( section , I2CP_PARAM_INBOUND_TUNNELS_LENGTH_VARIANCE , DEFAULT_INBOUND_TUNNELS_LENGTH_VARIANCE ) ;
options [ I2CP_PARAM_OUTBOUND_TUNNELS_LENGTH_VARIANCE ] = GetI2CPOption ( section , I2CP_PARAM_OUTBOUND_TUNNELS_LENGTH_VARIANCE , DEFAULT_OUTBOUND_TUNNELS_LENGTH_VARIANCE ) ;
2016-01-24 01:52:21 +00:00
options [ I2CP_PARAM_TAGS_TO_SEND ] = GetI2CPOption ( section , I2CP_PARAM_TAGS_TO_SEND , DEFAULT_TAGS_TO_SEND ) ;
2016-11-15 15:20:09 +00:00
options [ I2CP_PARAM_MIN_TUNNEL_LATENCY ] = GetI2CPOption ( section , I2CP_PARAM_MIN_TUNNEL_LATENCY , DEFAULT_MIN_TUNNEL_LATENCY ) ;
options [ I2CP_PARAM_MAX_TUNNEL_LATENCY ] = GetI2CPOption ( section , I2CP_PARAM_MAX_TUNNEL_LATENCY , DEFAULT_MAX_TUNNEL_LATENCY ) ;
2019-04-25 20:06:14 +00:00
options [ I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY ] = GetI2CPOption ( section , I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY , DEFAULT_INITIAL_ACK_DELAY ) ;
2020-10-04 23:52:12 +00:00
options [ I2CP_PARAM_STREAMING_ANSWER_PINGS ] = GetI2CPOption ( section , I2CP_PARAM_STREAMING_ANSWER_PINGS , isServer ? DEFAULT_ANSWER_PINGS : false ) ;
2019-01-15 20:43:21 +00:00
options [ I2CP_PARAM_LEASESET_TYPE ] = GetI2CPOption ( section , I2CP_PARAM_LEASESET_TYPE , DEFAULT_LEASESET_TYPE ) ;
2021-08-06 16:32:21 +00:00
std : : string encType = GetI2CPStringOption ( section , I2CP_PARAM_LEASESET_ENCRYPTION_TYPE , " 0,4 " ) ;
2019-04-25 20:06:14 +00:00
if ( encType . length ( ) > 0 ) options [ I2CP_PARAM_LEASESET_ENCRYPTION_TYPE ] = encType ;
2019-06-07 18:51:08 +00:00
std : : string privKey = GetI2CPStringOption ( section , I2CP_PARAM_LEASESET_PRIV_KEY , " " ) ;
if ( privKey . length ( ) > 0 ) options [ I2CP_PARAM_LEASESET_PRIV_KEY ] = privKey ;
2019-07-13 00:58:17 +00:00
auto authType = GetI2CPOption ( section , I2CP_PARAM_LEASESET_AUTH_TYPE , 0 ) ;
if ( authType ! = " 0 " ) // auth is set
{
2019-08-22 00:26:19 +00:00
options [ I2CP_PARAM_LEASESET_AUTH_TYPE ] = authType ;
2019-07-13 00:58:17 +00:00
if ( authType = = " 1 " ) // DH
ReadI2CPOptionsGroup ( section , I2CP_PARAM_LEASESET_CLIENT_DH , options ) ;
else if ( authType = = " 2 " ) // PSK
ReadI2CPOptionsGroup ( section , I2CP_PARAM_LEASESET_CLIENT_PSK , options ) ;
}
2020-05-26 01:40:46 +00:00
std : : string explicitPeers = GetI2CPStringOption ( section , I2CP_PARAM_EXPLICIT_PEERS , " " ) ;
if ( explicitPeers . length ( ) > 0 ) options [ I2CP_PARAM_EXPLICIT_PEERS ] = explicitPeers ;
2020-06-13 00:42:54 +00:00
std : : string ratchetInboundTags = GetI2CPStringOption ( section , I2CP_PARAM_RATCHET_INBOUND_TAGS , " " ) ;
if ( ratchetInboundTags . length ( ) > 0 ) options [ I2CP_PARAM_RATCHET_INBOUND_TAGS ] = ratchetInboundTags ;
2017-04-08 16:51:35 +00:00
}
2016-01-15 17:24:40 +00:00
2016-11-03 19:28:33 +00:00
void ClientContext : : ReadI2CPOptionsFromConfig ( const std : : string & prefix , std : : map < std : : string , std : : string > & options ) const
{
2017-04-08 16:51:35 +00:00
std : : string value ;
if ( i2p : : config : : GetOption ( prefix + I2CP_PARAM_INBOUND_TUNNEL_LENGTH , value ) )
2016-11-03 19:28:33 +00:00
options [ I2CP_PARAM_INBOUND_TUNNEL_LENGTH ] = value ;
2017-04-08 16:51:35 +00:00
if ( i2p : : config : : GetOption ( prefix + I2CP_PARAM_INBOUND_TUNNELS_QUANTITY , value ) )
options [ I2CP_PARAM_INBOUND_TUNNELS_QUANTITY ] = value ;
2022-03-08 03:20:11 +00:00
if ( i2p : : config : : GetOption ( prefix + I2CP_PARAM_INBOUND_TUNNELS_LENGTH_VARIANCE , value ) )
options [ I2CP_PARAM_INBOUND_TUNNELS_LENGTH_VARIANCE ] = value ;
2017-04-08 16:51:35 +00:00
if ( i2p : : config : : GetOption ( prefix + I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH , value ) )
2016-11-03 19:28:33 +00:00
options [ I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH ] = value ;
2017-04-08 16:51:35 +00:00
if ( i2p : : config : : GetOption ( prefix + I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY , value ) )
2016-11-15 15:20:09 +00:00
options [ I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY ] = value ;
2022-03-08 03:20:11 +00:00
if ( i2p : : config : : GetOption ( prefix + I2CP_PARAM_OUTBOUND_TUNNELS_LENGTH_VARIANCE , value ) )
options [ I2CP_PARAM_OUTBOUND_TUNNELS_LENGTH_VARIANCE ] = value ;
2016-11-15 15:20:09 +00:00
if ( i2p : : config : : GetOption ( prefix + I2CP_PARAM_MIN_TUNNEL_LATENCY , value ) )
options [ I2CP_PARAM_MIN_TUNNEL_LATENCY ] = value ;
if ( i2p : : config : : GetOption ( prefix + I2CP_PARAM_MAX_TUNNEL_LATENCY , value ) )
2018-01-06 03:48:51 +00:00
options [ I2CP_PARAM_MAX_TUNNEL_LATENCY ] = value ;
2020-05-21 19:36:16 +00:00
if ( i2p : : config : : GetOption ( prefix + I2CP_PARAM_LEASESET_TYPE , value ) )
options [ I2CP_PARAM_LEASESET_TYPE ] = value ;
if ( i2p : : config : : GetOption ( prefix + I2CP_PARAM_LEASESET_ENCRYPTION_TYPE , value ) )
options [ I2CP_PARAM_LEASESET_ENCRYPTION_TYPE ] = value ;
2021-05-20 18:10:31 +00:00
if ( i2p : : config : : GetOption ( prefix + I2CP_PARAM_LEASESET_PRIV_KEY , value ) & & ! value . empty ( ) )
options [ I2CP_PARAM_LEASESET_PRIV_KEY ] = value ;
2017-04-08 16:51:35 +00:00
}
2016-11-03 19:28:33 +00:00
2015-03-13 23:51:31 +00:00
void ClientContext : : ReadTunnels ( )
2015-03-13 20:05:39 +00:00
{
2018-10-19 19:23:46 +00:00
int numClientTunnels = 0 , numServerTunnels = 0 ;
2016-02-22 20:27:40 +00:00
std : : string tunConf ; i2p : : config : : GetOption ( " tunconf " , tunConf ) ;
2019-04-25 20:06:14 +00:00
if ( tunConf . empty ( ) )
2021-09-03 20:25:47 +00:00
tunConf = i2p : : fs : : DataDirPath ( " tunnels.conf " ) ;
2021-11-27 19:53:53 +00:00
LogPrint ( eLogDebug , " Clients: Tunnels config file: " , tunConf ) ;
2018-10-19 19:23:46 +00:00
ReadTunnels ( tunConf , numClientTunnels , numServerTunnels ) ;
2019-04-25 20:06:14 +00:00
2018-10-19 19:23:46 +00:00
std : : string tunDir ; i2p : : config : : GetOption ( " tunnelsdir " , tunDir ) ;
if ( tunDir . empty ( ) )
2019-04-25 20:06:14 +00:00
tunDir = i2p : : fs : : DataDirPath ( " tunnels.d " ) ;
2021-09-03 20:25:47 +00:00
2018-10-19 19:23:46 +00:00
if ( i2p : : fs : : Exists ( tunDir ) )
{
std : : vector < std : : string > files ;
if ( i2p : : fs : : ReadDir ( tunDir , files ) )
{
for ( auto & it : files )
{
2020-04-27 10:23:29 +00:00
if ( it . substr ( it . size ( ) - 5 ) ! = " .conf " ) continue ; // skip files which not ends with ".conf"
2021-11-27 19:53:53 +00:00
LogPrint ( eLogDebug , " Clients: Tunnels extra config file: " , it ) ;
2018-10-19 19:23:46 +00:00
ReadTunnels ( it , numClientTunnels , numServerTunnels ) ;
}
2016-03-28 00:00:00 +00:00
}
}
2018-10-19 19:23:46 +00:00
LogPrint ( eLogInfo , " Clients: " , numClientTunnels , " I2P client tunnels created " ) ;
LogPrint ( eLogInfo , " Clients: " , numServerTunnels , " I2P server tunnels created " ) ;
}
void ClientContext : : ReadTunnels ( const std : : string & tunConf , int & numClientTunnels , int & numServerTunnels )
{
boost : : property_tree : : ptree pt ;
2020-05-04 23:36:34 +00:00
try {
2016-02-22 20:27:40 +00:00
boost : : property_tree : : read_ini ( tunConf , pt ) ;
2020-05-04 23:36:34 +00:00
} catch ( std : : exception & ex ) {
2016-02-22 20:27:40 +00:00
LogPrint ( eLogWarning , " Clients: Can't read " , tunConf , " : " , ex . what ( ) ) ;
2015-03-13 20:05:39 +00:00
return ;
}
2017-04-08 16:51:35 +00:00
2020-08-10 21:49:46 +00:00
std : : map < std : : string , std : : shared_ptr < ClientDestination > > destinations ; // keys -> destination
2015-03-13 20:05:39 +00:00
for ( auto & section : pt )
{
2017-04-08 16:51:35 +00:00
std : : string name = section . first ;
2015-03-13 23:51:31 +00:00
try
2015-03-13 20:05:39 +00:00
{
2015-03-13 23:51:31 +00:00
std : : string type = section . second . get < std : : string > ( I2P_TUNNELS_SECTION_TYPE ) ;
2017-01-07 13:32:50 +00:00
if ( type = = I2P_TUNNELS_SECTION_TYPE_CLIENT
2020-03-01 10:25:50 +00:00
| | type = = I2P_TUNNELS_SECTION_TYPE_SOCKS
| | type = = I2P_TUNNELS_SECTION_TYPE_WEBSOCKS
| | type = = I2P_TUNNELS_SECTION_TYPE_HTTPPROXY
| | type = = I2P_TUNNELS_SECTION_TYPE_UDPCLIENT )
2015-03-13 20:05:39 +00:00
{
// mandatory params
2017-01-07 18:55:17 +00:00
std : : string dest ;
if ( type = = I2P_TUNNELS_SECTION_TYPE_CLIENT | | type = = I2P_TUNNELS_SECTION_TYPE_UDPCLIENT )
dest = section . second . get < std : : string > ( I2P_CLIENT_TUNNEL_DESTINATION ) ;
2015-03-13 23:51:31 +00:00
int port = section . second . get < int > ( I2P_CLIENT_TUNNEL_PORT ) ;
2015-03-13 20:05:39 +00:00
// optional params
2017-04-08 16:51:35 +00:00
bool matchTunnels = section . second . get ( I2P_CLIENT_TUNNEL_MATCH_TUNNELS , false ) ;
2017-12-09 12:42:32 +00:00
std : : string keys = section . second . get ( I2P_CLIENT_TUNNEL_KEYS , " transient " ) ;
2015-11-30 14:44:32 +00:00
std : : string address = section . second . get ( I2P_CLIENT_TUNNEL_ADDRESS , " 127.0.0.1 " ) ;
2015-03-15 15:28:30 +00:00
int destinationPort = section . second . get ( I2P_CLIENT_TUNNEL_DESTINATION_PORT , 0 ) ;
2018-12-05 19:58:50 +00:00
i2p : : data : : SigningKeyType sigType = section . second . get ( I2P_CLIENT_TUNNEL_SIGNATURE_TYPE , i2p : : data : : SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 ) ;
2017-11-08 20:59:41 +00:00
i2p : : data : : CryptoKeyType cryptoType = section . second . get ( I2P_CLIENT_TUNNEL_CRYPTO_TYPE , i2p : : data : : CRYPTO_KEY_TYPE_ELGAMAL ) ;
2016-01-14 20:57:55 +00:00
// I2CP
2017-04-08 16:51:35 +00:00
std : : map < std : : string , std : : string > options ;
2020-10-04 23:52:12 +00:00
ReadI2CPOptions ( section , false , options ) ;
2015-03-13 20:05:39 +00:00
std : : shared_ptr < ClientDestination > localDestination = nullptr ;
if ( keys . length ( ) > 0 )
2016-01-15 19:46:29 +00:00
{
2020-08-10 21:49:46 +00:00
auto it = destinations . find ( keys ) ;
if ( it ! = destinations . end ( ) )
localDestination = it - > second ;
else
2021-09-03 20:25:47 +00:00
{
2020-08-10 21:49:46 +00:00
i2p : : data : : PrivateKeys k ;
if ( LoadPrivateKeys ( k , keys , sigType , cryptoType ) )
2017-04-08 16:51:35 +00:00
{
2020-08-10 21:49:46 +00:00
localDestination = FindLocalDestination ( k . GetPublic ( ) - > GetIdentHash ( ) ) ;
if ( ! localDestination )
{
if ( matchTunnels )
localDestination = CreateNewMatchedTunnelDestination ( k , dest , & options ) ;
else
localDestination = CreateNewLocalDestination ( k , type = = I2P_TUNNELS_SECTION_TYPE_UDPCLIENT , & options ) ;
2020-11-18 20:02:06 +00:00
if ( keys ! = " transient " )
destinations [ keys ] = localDestination ;
2020-08-10 21:49:46 +00:00
}
2017-04-08 16:51:35 +00:00
}
2021-09-03 20:25:47 +00:00
}
2016-01-15 19:46:29 +00:00
}
2017-04-08 16:51:35 +00:00
2016-09-03 15:46:47 +00:00
if ( type = = I2P_TUNNELS_SECTION_TYPE_UDPCLIENT ) {
// udp client
// TODO: hostnames
2022-05-09 07:59:25 +00:00
boost : : asio : : ip : : udp : : endpoint end ( boost : : asio : : ip : : address : : from_string ( address ) , port ) ;
2016-09-03 15:46:47 +00:00
if ( ! localDestination )
localDestination = m_SharedLocalDestination ;
2020-05-04 23:36:34 +00:00
2020-05-18 16:01:13 +00:00
bool gzip = section . second . get ( I2P_CLIENT_TUNNEL_GZIP , true ) ;
2022-05-09 07:59:25 +00:00
auto clientTunnel = std : : make_shared < I2PUDPClientTunnel > ( name , dest , end , localDestination , destinationPort , gzip ) ;
2021-09-03 20:25:47 +00:00
2022-05-09 07:59:25 +00:00
auto ins = m_ClientForwards . insert ( std : : make_pair ( end , clientTunnel ) ) ;
2021-09-03 20:25:47 +00:00
if ( ins . second )
{
2022-05-09 07:59:25 +00:00
clientTunnel - > Start ( ) ;
2021-09-03 20:25:47 +00:00
numClientTunnels + + ;
}
2016-09-03 15:46:47 +00:00
else
2021-09-03 20:25:47 +00:00
{
2022-05-09 07:59:25 +00:00
// TODO: update
if ( ins . first - > second - > GetLocalDestination ( ) ! = clientTunnel - > GetLocalDestination ( ) )
{
LogPrint ( eLogInfo , " Clients: I2P UDP client tunnel destination updated " ) ;
ins . first - > second - > Stop ( ) ;
ins . first - > second - > SetLocalDestination ( clientTunnel - > GetLocalDestination ( ) ) ;
ins . first - > second - > Start ( ) ;
}
2021-09-03 20:25:47 +00:00
ins . first - > second - > isUpdated = true ;
2016-09-03 15:46:47 +00:00
LogPrint ( eLogError , " Clients: I2P Client forward for endpoint " , end , " already exists " ) ;
2021-09-03 20:25:47 +00:00
}
2016-08-21 19:33:19 +00:00
2016-09-03 15:46:47 +00:00
} else {
2017-01-07 13:32:50 +00:00
boost : : asio : : ip : : tcp : : endpoint clientEndpoint ;
2018-04-25 20:18:07 +00:00
std : : shared_ptr < I2PService > clientTunnel ;
2017-01-07 13:32:50 +00:00
if ( type = = I2P_TUNNELS_SECTION_TYPE_SOCKS )
{
// socks proxy
2018-08-26 13:24:11 +00:00
std : : string outproxy = section . second . get ( " outproxy " , " " ) ;
auto tun = std : : make_shared < i2p : : proxy : : SOCKSProxy > ( name , address , port , ! outproxy . empty ( ) , outproxy , destinationPort , localDestination ) ;
2018-04-25 20:18:07 +00:00
clientTunnel = tun ;
clientEndpoint = tun - > GetLocalEndpoint ( ) ;
2017-01-07 13:32:50 +00:00
}
else if ( type = = I2P_TUNNELS_SECTION_TYPE_HTTPPROXY )
{
// http proxy
2017-10-27 12:42:54 +00:00
std : : string outproxy = section . second . get ( " outproxy " , " " ) ;
2019-04-25 20:06:14 +00:00
bool addresshelper = section . second . get ( " addresshelper " , true ) ;
auto tun = std : : make_shared < i2p : : proxy : : HTTPProxy > ( name , address , port , outproxy , addresshelper , localDestination ) ;
2018-04-25 20:18:07 +00:00
clientTunnel = tun ;
clientEndpoint = tun - > GetLocalEndpoint ( ) ;
2017-01-07 13:32:50 +00:00
}
else if ( type = = I2P_TUNNELS_SECTION_TYPE_WEBSOCKS )
{
2020-05-04 23:36:34 +00:00
LogPrint ( eLogWarning , " Clients: I2P Client tunnel websocks is deprecated, not starting " , name , " tunnel " ) ;
2020-03-12 00:50:21 +00:00
continue ;
2017-01-07 13:32:50 +00:00
}
else
{
// tcp client
2018-04-25 20:18:07 +00:00
auto tun = std : : make_shared < I2PClientTunnel > ( name , dest , address , port , localDestination , destinationPort ) ;
2019-04-25 20:06:14 +00:00
clientTunnel = tun ;
2018-04-25 20:18:07 +00:00
clientEndpoint = tun - > GetLocalEndpoint ( ) ;
2021-09-26 20:25:12 +00:00
uint32_t keepAlive = section . second . get < uint32_t > ( I2P_CLIENT_TUNNEL_KEEP_ALIVE_INTERVAL , 0 ) ;
if ( keepAlive )
{
tun - > SetKeepAliveInterval ( keepAlive ) ;
LogPrint ( eLogInfo , " Clients: I2P Client tunnel keep alive interval set to " , keepAlive ) ;
}
2017-01-07 13:32:50 +00:00
}
2020-05-04 23:36:34 +00:00
2017-08-31 16:08:22 +00:00
uint32_t timeout = section . second . get < uint32_t > ( I2P_CLIENT_TUNNEL_CONNECT_TIMEOUT , 0 ) ;
if ( timeout )
{
clientTunnel - > SetConnectTimeout ( timeout ) ;
LogPrint ( eLogInfo , " Clients: I2P Client tunnel connect timeout set to " , timeout ) ;
}
2018-04-25 20:18:07 +00:00
auto ins = m_ClientTunnels . insert ( std : : make_pair ( clientEndpoint , clientTunnel ) ) ;
2017-07-28 19:12:15 +00:00
if ( ins . second )
2016-09-03 15:46:47 +00:00
{
clientTunnel - > Start ( ) ;
numClientTunnels + + ;
}
else
2017-07-28 19:12:15 +00:00
{
// TODO: update
2018-04-25 20:18:07 +00:00
if ( ins . first - > second - > GetLocalDestination ( ) ! = clientTunnel - > GetLocalDestination ( ) )
2017-09-29 19:34:26 +00:00
{
LogPrint ( eLogInfo , " Clients: I2P client tunnel destination updated " ) ;
2021-09-03 20:25:47 +00:00
ins . first - > second - > Stop ( ) ;
2018-04-25 20:18:07 +00:00
ins . first - > second - > SetLocalDestination ( clientTunnel - > GetLocalDestination ( ) ) ;
2021-09-03 20:25:47 +00:00
ins . first - > second - > Start ( ) ;
2017-09-29 19:34:26 +00:00
}
2017-07-28 19:12:15 +00:00
ins . first - > second - > isUpdated = true ;
2017-09-09 17:13:45 +00:00
LogPrint ( eLogInfo , " Clients: I2P client tunnel for endpoint " , clientEndpoint , " already exists " ) ;
2017-07-28 19:12:15 +00:00
}
2016-09-03 15:46:47 +00:00
}
2015-03-13 20:05:39 +00:00
}
2021-09-03 20:25:47 +00:00
2017-01-07 13:32:50 +00:00
else if ( type = = I2P_TUNNELS_SECTION_TYPE_SERVER
2020-03-01 10:25:50 +00:00
| | type = = I2P_TUNNELS_SECTION_TYPE_HTTP
| | type = = I2P_TUNNELS_SECTION_TYPE_IRC
| | type = = I2P_TUNNELS_SECTION_TYPE_UDPSERVER )
2017-04-08 16:51:35 +00:00
{
2015-03-13 23:51:31 +00:00
// mandatory params
std : : string host = section . second . get < std : : string > ( I2P_SERVER_TUNNEL_HOST ) ;
int port = section . second . get < int > ( I2P_SERVER_TUNNEL_PORT ) ;
std : : string keys = section . second . get < std : : string > ( I2P_SERVER_TUNNEL_KEYS ) ;
// optional params
2015-03-15 15:28:30 +00:00
int inPort = section . second . get ( I2P_SERVER_TUNNEL_INPORT , 0 ) ;
2016-02-26 01:32:05 +00:00
std : : string accessList = section . second . get ( I2P_SERVER_TUNNEL_ACCESS_LIST , " " ) ;
2020-07-06 23:01:56 +00:00
if ( accessList = = " " )
accessList = section . second . get ( I2P_SERVER_TUNNEL_WHITE_LIST , " " ) ;
2016-02-26 01:32:05 +00:00
std : : string hostOverride = section . second . get ( I2P_SERVER_TUNNEL_HOST_OVERRIDE , " " ) ;
2016-03-04 06:37:38 +00:00
std : : string webircpass = section . second . get < std : : string > ( I2P_SERVER_TUNNEL_WEBIRC_PASSWORD , " " ) ;
2021-09-12 18:29:43 +00:00
bool gzip = section . second . get ( I2P_SERVER_TUNNEL_GZIP , false ) ;
2018-12-05 19:58:50 +00:00
i2p : : data : : SigningKeyType sigType = section . second . get ( I2P_SERVER_TUNNEL_SIGNATURE_TYPE , i2p : : data : : SIGNING_KEY_TYPE_EDDSA_SHA512_ED25519 ) ;
2017-11-09 21:18:59 +00:00
i2p : : data : : CryptoKeyType cryptoType = section . second . get ( I2P_CLIENT_TUNNEL_CRYPTO_TYPE , i2p : : data : : CRYPTO_KEY_TYPE_ELGAMAL ) ;
2018-04-16 13:38:32 +00:00
2021-02-24 23:40:24 +00:00
std : : string address = section . second . get < std : : string > ( I2P_SERVER_TUNNEL_ADDRESS , " " ) ;
2017-01-12 21:17:11 +00:00
bool isUniqueLocal = section . second . get ( I2P_SERVER_TUNNEL_ENABLE_UNIQUE_LOCAL , true ) ;
2016-12-25 13:56:47 +00:00
2016-01-14 20:57:55 +00:00
// I2CP
2017-04-08 16:51:35 +00:00
std : : map < std : : string , std : : string > options ;
2020-10-04 23:52:12 +00:00
ReadI2CPOptions ( section , true , options ) ;
2020-05-04 23:36:34 +00:00
2016-01-21 20:51:08 +00:00
std : : shared_ptr < ClientDestination > localDestination = nullptr ;
2020-08-10 21:49:46 +00:00
auto it = destinations . find ( keys ) ;
if ( it ! = destinations . end ( ) )
2021-11-27 20:30:35 +00:00
{
2020-08-10 21:49:46 +00:00
localDestination = it - > second ;
2021-09-04 22:45:32 +00:00
localDestination - > SetPublic ( true ) ;
2021-11-27 20:30:35 +00:00
}
2020-08-10 21:49:46 +00:00
else
2021-09-03 20:25:47 +00:00
{
2020-08-10 21:49:46 +00:00
i2p : : data : : PrivateKeys k ;
if ( ! LoadPrivateKeys ( k , keys , sigType , cryptoType ) )
continue ;
localDestination = FindLocalDestination ( k . GetPublic ( ) - > GetIdentHash ( ) ) ;
if ( ! localDestination )
2021-09-03 20:25:47 +00:00
{
2020-08-10 21:49:46 +00:00
localDestination = CreateNewLocalDestination ( k , true , & options ) ;
destinations [ keys ] = localDestination ;
2021-09-03 20:25:47 +00:00
}
2021-09-04 22:45:32 +00:00
else
localDestination - > SetPublic ( true ) ;
2021-09-03 20:25:47 +00:00
}
2016-09-03 15:46:47 +00:00
if ( type = = I2P_TUNNELS_SECTION_TYPE_UDPSERVER )
{
// udp server tunnel
// TODO: hostnames
boost : : asio : : ip : : udp : : endpoint endpoint ( boost : : asio : : ip : : address : : from_string ( host ) , port ) ;
2021-08-10 15:36:12 +00:00
if ( address . empty ( ) )
{
if ( ! endpoint . address ( ) . is_unspecified ( ) & & endpoint . address ( ) . is_v6 ( ) )
address = " ::1 " ;
else
address = " 127.0.0.1 " ;
2021-09-03 20:25:47 +00:00
}
auto localAddress = boost : : asio : : ip : : address : : from_string ( address ) ;
2020-05-18 16:01:13 +00:00
auto serverTunnel = std : : make_shared < I2PUDPServerTunnel > ( name , localDestination , localAddress , endpoint , port , gzip ) ;
2017-04-08 16:51:35 +00:00
if ( ! isUniqueLocal )
2017-01-12 21:17:11 +00:00
{
2021-11-27 19:53:53 +00:00
LogPrint ( eLogInfo , " Clients: Disabling loopback address mapping " ) ;
2017-01-12 21:17:11 +00:00
serverTunnel - > SetUniqueLocal ( isUniqueLocal ) ;
2016-12-25 13:56:47 +00:00
}
2016-09-03 15:46:47 +00:00
std : : lock_guard < std : : mutex > lock ( m_ForwardsMutex ) ;
2021-09-03 20:25:47 +00:00
auto ins = m_ServerForwards . insert ( std : : make_pair (
std : : make_pair ( localDestination - > GetIdentHash ( ) , port ) ,
serverTunnel ) ) ;
if ( ins . second )
2016-09-03 15:46:47 +00:00
{
serverTunnel - > Start ( ) ;
LogPrint ( eLogInfo , " Clients: I2P Server Forward created for UDP Endpoint " , host , " : " , port , " bound on " , address , " for " , localDestination - > GetIdentHash ( ) . ToBase32 ( ) ) ;
}
else
2021-11-27 20:30:35 +00:00
{
2021-09-03 20:25:47 +00:00
ins . first - > second - > isUpdated = true ;
2021-09-04 12:53:39 +00:00
LogPrint ( eLogError , " Clients: I2P Server Forward for destination/port " , m_AddressBook . ToAddress ( localDestination - > GetIdentHash ( ) ) , " / " , port , " already exists " ) ;
2021-11-27 20:30:35 +00:00
}
2017-04-08 16:51:35 +00:00
2016-09-03 15:46:47 +00:00
continue ;
}
2017-04-08 16:51:35 +00:00
2020-03-01 10:25:50 +00:00
std : : shared_ptr < I2PServerTunnel > serverTunnel ;
2016-02-29 19:44:15 +00:00
if ( type = = I2P_TUNNELS_SECTION_TYPE_HTTP )
2018-04-25 20:18:07 +00:00
serverTunnel = std : : make_shared < I2PServerTunnelHTTP > ( name , host , port , localDestination , hostOverride , inPort , gzip ) ;
2018-01-06 04:01:44 +00:00
else if ( type = = I2P_TUNNELS_SECTION_TYPE_IRC )
2018-04-25 20:18:07 +00:00
serverTunnel = std : : make_shared < I2PServerTunnelIRC > ( name , host , port , localDestination , webircpass , inPort , gzip ) ;
2016-02-29 19:44:15 +00:00
else // regular server tunnel by default
2018-04-25 20:18:07 +00:00
serverTunnel = std : : make_shared < I2PServerTunnel > ( name , host , port , localDestination , inPort , gzip ) ;
2016-02-22 19:33:21 +00:00
2021-02-19 20:15:58 +00:00
if ( ! address . empty ( ) )
serverTunnel - > SetLocalAddress ( address ) ;
2017-01-12 21:17:11 +00:00
if ( ! isUniqueLocal )
{
2021-11-27 19:53:53 +00:00
LogPrint ( eLogInfo , " Clients: Disabling loopback address mapping " ) ;
2017-01-12 21:17:11 +00:00
serverTunnel - > SetUniqueLocal ( isUniqueLocal ) ;
2018-01-06 04:01:44 +00:00
}
2015-03-16 18:52:42 +00:00
if ( accessList . length ( ) > 0 )
{
std : : set < i2p : : data : : IdentHash > idents ;
size_t pos = 0 , comma ;
do
{
comma = accessList . find ( ' , ' , pos ) ;
i2p : : data : : IdentHash ident ;
2017-04-08 16:51:35 +00:00
ident . FromBase32 ( accessList . substr ( pos , comma ! = std : : string : : npos ? comma - pos : std : : string : : npos ) ) ;
2015-03-16 18:52:42 +00:00
idents . insert ( ident ) ;
pos = comma + 1 ;
}
while ( comma ! = std : : string : : npos ) ;
serverTunnel - > SetAccessList ( idents ) ;
}
2017-07-28 19:12:15 +00:00
auto ins = m_ServerTunnels . insert ( std : : make_pair (
2019-04-25 20:06:14 +00:00
std : : make_pair ( localDestination - > GetIdentHash ( ) , inPort ) ,
2018-04-25 20:18:07 +00:00
serverTunnel ) ) ;
2017-07-28 19:12:15 +00:00
if ( ins . second )
2016-05-12 15:38:18 +00:00
{
2016-09-03 15:46:47 +00:00
serverTunnel - > Start ( ) ;
2016-05-12 15:38:18 +00:00
numServerTunnels + + ;
}
2015-03-13 23:51:31 +00:00
else
2017-07-28 19:12:15 +00:00
{
// TODO: update
2018-04-25 20:18:07 +00:00
if ( ins . first - > second - > GetLocalDestination ( ) ! = serverTunnel - > GetLocalDestination ( ) )
2017-09-29 19:34:26 +00:00
{
LogPrint ( eLogInfo , " Clients: I2P server tunnel destination updated " ) ;
2021-09-03 20:25:47 +00:00
ins . first - > second - > Stop ( ) ;
2018-04-25 20:18:07 +00:00
ins . first - > second - > SetLocalDestination ( serverTunnel - > GetLocalDestination ( ) ) ;
2021-09-03 20:25:47 +00:00
ins . first - > second - > Start ( ) ;
2017-09-29 19:34:26 +00:00
}
2017-07-28 19:12:15 +00:00
ins . first - > second - > isUpdated = true ;
2020-03-01 10:25:50 +00:00
LogPrint ( eLogInfo , " Clients: I2P server tunnel for destination/port " , m_AddressBook . ToAddress ( localDestination - > GetIdentHash ( ) ) , " / " , inPort , " already exists " ) ;
2017-07-28 19:12:15 +00:00
}
2017-04-08 16:51:35 +00:00
2015-03-13 20:05:39 +00:00
}
2015-03-13 23:51:31 +00:00
else
2020-05-04 23:36:34 +00:00
LogPrint ( eLogWarning , " Clients: Unknown section type = " , type , " of " , name , " in " , tunConf ) ;
2015-03-13 20:05:39 +00:00
}
2015-03-13 23:51:31 +00:00
catch ( std : : exception & ex )
2015-03-13 20:05:39 +00:00
{
2015-12-18 12:44:03 +00:00
LogPrint ( eLogError , " Clients: Can't read tunnel " , name , " params: " , ex . what ( ) ) ;
2020-05-05 13:35:41 +00:00
ThrowFatal ( " Unable to start tunnel " , name , " : " , ex . what ( ) ) ;
2015-03-13 20:05:39 +00:00
}
2017-04-08 16:51:35 +00:00
}
2016-08-21 19:02:17 +00:00
}
2017-04-08 16:51:35 +00:00
2018-01-23 20:13:43 +00:00
void ClientContext : : ReadHttpProxy ( )
{
std : : shared_ptr < ClientDestination > localDestination ;
bool httproxy ; i2p : : config : : GetOption ( " httpproxy.enabled " , httproxy ) ;
if ( httproxy )
{
2020-05-04 23:36:34 +00:00
std : : string httpProxyKeys ; i2p : : config : : GetOption ( " httpproxy.keys " , httpProxyKeys ) ;
std : : string httpProxyAddr ; i2p : : config : : GetOption ( " httpproxy.address " , httpProxyAddr ) ;
uint16_t httpProxyPort ; i2p : : config : : GetOption ( " httpproxy.port " , httpProxyPort ) ;
std : : string httpOutProxyURL ; i2p : : config : : GetOption ( " httpproxy.outproxy " , httpOutProxyURL ) ;
bool httpAddresshelper ; i2p : : config : : GetOption ( " httpproxy.addresshelper " , httpAddresshelper ) ;
2022-05-27 17:17:06 +00:00
if ( httpAddresshelper )
i2p : : config : : GetOption ( " addressbook.enabled " , httpAddresshelper ) ; // addresshelper is not supported without address book
2020-03-01 10:25:50 +00:00
i2p : : data : : SigningKeyType sigType ; i2p : : config : : GetOption ( " httpproxy.signaturetype " , sigType ) ;
2021-11-27 19:53:53 +00:00
LogPrint ( eLogInfo , " Clients: Starting HTTP Proxy at " , httpProxyAddr , " : " , httpProxyPort ) ;
2018-01-23 20:13:43 +00:00
if ( httpProxyKeys . length ( ) > 0 )
{
i2p : : data : : PrivateKeys keys ;
if ( LoadPrivateKeys ( keys , httpProxyKeys , sigType ) )
{
std : : map < std : : string , std : : string > params ;
ReadI2CPOptionsFromConfig ( " httpproxy. " , params ) ;
localDestination = CreateNewLocalDestination ( keys , false , & params ) ;
2018-12-13 14:53:16 +00:00
if ( localDestination ) localDestination - > Acquire ( ) ;
2018-01-23 20:13:43 +00:00
}
else
2021-11-27 19:53:53 +00:00
LogPrint ( eLogError , " Clients: Failed to load HTTP Proxy key " ) ;
2018-01-23 20:13:43 +00:00
}
2020-03-01 10:25:50 +00:00
try
2020-05-05 13:35:41 +00:00
{
2019-04-25 20:06:14 +00:00
m_HttpProxy = new i2p : : proxy : : HTTPProxy ( " HTTP Proxy " , httpProxyAddr , httpProxyPort , httpOutProxyURL , httpAddresshelper , localDestination ) ;
2018-01-23 20:13:43 +00:00
m_HttpProxy - > Start ( ) ;
2020-03-01 10:25:50 +00:00
}
catch ( std : : exception & e )
2020-05-05 13:35:41 +00:00
{
2018-01-23 20:13:43 +00:00
LogPrint ( eLogError , " Clients: Exception in HTTP Proxy: " , e . what ( ) ) ;
2020-05-05 13:35:41 +00:00
ThrowFatal ( " Unable to start HTTP Proxy at " , httpProxyAddr , " : " , httpProxyPort , " : " , e . what ( ) ) ;
2018-01-23 20:13:43 +00:00
}
}
}
2019-04-25 20:06:14 +00:00
2018-01-23 20:13:43 +00:00
void ClientContext : : ReadSocksProxy ( )
{
std : : shared_ptr < ClientDestination > localDestination ;
bool socksproxy ; i2p : : config : : GetOption ( " socksproxy.enabled " , socksproxy ) ;
if ( socksproxy )
{
2022-05-20 16:56:05 +00:00
std : : string httpProxyKeys ; i2p : : config : : GetOption ( " httpproxy.keys " , httpProxyKeys ) ;
2020-09-28 00:50:57 +00:00
// we still need httpProxyKeys to compare with sockProxyKeys
2020-05-04 23:36:34 +00:00
std : : string socksProxyKeys ; i2p : : config : : GetOption ( " socksproxy.keys " , socksProxyKeys ) ;
std : : string socksProxyAddr ; i2p : : config : : GetOption ( " socksproxy.address " , socksProxyAddr ) ;
uint16_t socksProxyPort ; i2p : : config : : GetOption ( " socksproxy.port " , socksProxyPort ) ;
bool socksOutProxy ; i2p : : config : : GetOption ( " socksproxy.outproxy.enabled " , socksOutProxy ) ;
std : : string socksOutProxyAddr ; i2p : : config : : GetOption ( " socksproxy.outproxy " , socksOutProxyAddr ) ;
uint16_t socksOutProxyPort ; i2p : : config : : GetOption ( " socksproxy.outproxyport " , socksOutProxyPort ) ;
i2p : : data : : SigningKeyType sigType ; i2p : : config : : GetOption ( " socksproxy.signaturetype " , sigType ) ;
2021-11-27 19:53:53 +00:00
LogPrint ( eLogInfo , " Clients: Starting SOCKS Proxy at " , socksProxyAddr , " : " , socksProxyPort ) ;
2020-09-28 00:50:57 +00:00
if ( httpProxyKeys = = socksProxyKeys & & m_HttpProxy )
{
localDestination = m_HttpProxy - > GetLocalDestination ( ) ;
localDestination - > Acquire ( ) ;
2021-09-03 20:25:47 +00:00
}
2020-09-28 00:50:57 +00:00
else if ( socksProxyKeys . length ( ) > 0 )
2018-01-23 20:13:43 +00:00
{
i2p : : data : : PrivateKeys keys ;
if ( LoadPrivateKeys ( keys , socksProxyKeys , sigType ) )
{
std : : map < std : : string , std : : string > params ;
ReadI2CPOptionsFromConfig ( " socksproxy. " , params ) ;
localDestination = CreateNewLocalDestination ( keys , false , & params ) ;
2018-12-13 14:53:16 +00:00
if ( localDestination ) localDestination - > Acquire ( ) ;
2018-01-23 20:13:43 +00:00
}
else
2021-11-27 19:53:53 +00:00
LogPrint ( eLogError , " Clients: Failed to load SOCKS Proxy key " ) ;
2018-01-23 20:13:43 +00:00
}
2020-03-01 10:25:50 +00:00
try
2020-05-05 13:35:41 +00:00
{
2018-01-23 20:13:43 +00:00
m_SocksProxy = new i2p : : proxy : : SOCKSProxy ( " SOCKS " , socksProxyAddr , socksProxyPort ,
socksOutProxy , socksOutProxyAddr , socksOutProxyPort , localDestination ) ;
m_SocksProxy - > Start ( ) ;
2020-03-01 10:25:50 +00:00
}
catch ( std : : exception & e )
2020-05-05 13:35:41 +00:00
{
2018-01-23 20:13:43 +00:00
LogPrint ( eLogError , " Clients: Exception in SOCKS Proxy: " , e . what ( ) ) ;
2020-05-05 13:35:41 +00:00
ThrowFatal ( " Unable to start SOCKS Proxy at " , socksProxyAddr , " : " , socksProxyPort , " : " , e . what ( ) ) ;
2018-01-23 20:13:43 +00:00
}
}
}
2016-09-03 15:46:47 +00:00
void ClientContext : : ScheduleCleanupUDP ( )
{
2016-09-16 14:31:11 +00:00
if ( m_CleanupUDPTimer )
{
// schedule cleanup in 17 seconds
m_CleanupUDPTimer - > expires_from_now ( boost : : posix_time : : seconds ( 17 ) ) ;
m_CleanupUDPTimer - > async_wait ( std : : bind ( & ClientContext : : CleanupUDP , this , std : : placeholders : : _1 ) ) ;
}
2016-09-03 15:46:47 +00:00
}
2016-08-21 19:02:17 +00:00
2016-09-03 15:46:47 +00:00
void ClientContext : : CleanupUDP ( const boost : : system : : error_code & ecode )
{
if ( ! ecode )
{
std : : lock_guard < std : : mutex > lock ( m_ForwardsMutex ) ;
2016-09-16 14:31:11 +00:00
for ( auto & s : m_ServerForwards ) s . second - > ExpireStale ( ) ;
2016-09-03 15:46:47 +00:00
ScheduleCleanupUDP ( ) ;
}
}
2017-07-28 19:12:15 +00:00
2021-09-03 20:25:47 +00:00
void ClientContext : : VisitTunnels ( bool clean )
2017-07-28 19:12:15 +00:00
{
2021-09-03 20:25:47 +00:00
for ( auto it = m_ClientTunnels . begin ( ) ; it ! = m_ClientTunnels . end ( ) ; )
2017-07-28 19:12:15 +00:00
{
2021-09-03 20:25:47 +00:00
if ( clean & & ! it - > second - > isUpdated ) {
2017-07-28 19:40:07 +00:00
it - > second - > Stop ( ) ;
2021-09-03 20:25:47 +00:00
it = m_ClientTunnels . erase ( it ) ;
} else {
it - > second - > isUpdated = false ;
it + + ;
2017-07-28 19:40:07 +00:00
}
2021-09-03 20:25:47 +00:00
}
for ( auto it = m_ServerTunnels . begin ( ) ; it ! = m_ServerTunnels . end ( ) ; )
{
if ( clean & & ! it - > second - > isUpdated ) {
it - > second - > Stop ( ) ;
it = m_ServerTunnels . erase ( it ) ;
} else {
it - > second - > isUpdated = false ;
2017-08-31 16:08:22 +00:00
it + + ;
2021-09-03 20:25:47 +00:00
}
2017-08-31 16:08:22 +00:00
}
2017-07-28 19:12:15 +00:00
2022-05-09 07:59:25 +00:00
// TODO: Write correct UDP tunnels stop
2021-09-03 20:25:47 +00:00
for ( auto it = m_ClientForwards . begin ( ) ; it ! = m_ClientForwards . end ( ) ; )
{
if ( clean & & ! it - > second - > isUpdated ) {
2022-05-09 07:59:25 +00:00
it - > second - > Stop ( ) ;
2021-09-03 20:25:47 +00:00
it = m_ClientForwards . erase ( it ) ;
} else {
it - > second - > isUpdated = false ;
it + + ;
}
}
for ( auto it = m_ServerForwards . begin ( ) ; it ! = m_ServerForwards . end ( ) ; )
{
if ( clean & & ! it - > second - > isUpdated ) {
2022-05-09 07:59:25 +00:00
it - > second - > Stop ( ) ;
2021-09-03 20:25:47 +00:00
it = m_ServerForwards . erase ( it ) ;
} else {
it - > second - > isUpdated = false ;
it + + ;
}
2022-05-09 07:59:25 +00:00
}
2017-07-28 19:12:15 +00:00
}
2017-04-08 16:51:35 +00:00
}
}