2014-10-05 12:54:59 +00:00
# include <algorithm>
2015-01-02 12:35:38 +00:00
# include <cassert>
2017-10-27 12:42:54 +00:00
# include <string>
2016-05-11 19:12:38 +00:00
# include "Crypto.h"
2014-10-05 12:54:59 +00:00
# include "Log.h"
2016-02-11 00:00:00 +00:00
# include "FS.h"
2014-12-25 21:47:15 +00:00
# include "Timestamp.h"
2017-04-22 00:04:16 +00:00
# include "NetDb.hpp"
2015-01-06 00:32:46 +00:00
# include "Destination.h"
2016-04-27 16:08:08 +00:00
# include "util.h"
2014-10-05 12:54:59 +00:00
namespace i2p
{
2014-10-16 16:37:39 +00:00
namespace client
2014-10-05 12:54:59 +00:00
{
2016-05-23 14:33:01 +00:00
LeaseSetDestination : : LeaseSetDestination ( bool isPublic , const std : : map < std : : string , std : : string > * params ) :
2017-08-31 16:08:22 +00:00
m_IsRunning ( false ) , m_Thread ( nullptr ) , m_IsPublic ( isPublic ) ,
m_PublishReplyToken ( 0 ) , m_LastSubmissionTime ( 0 ) , m_PublishConfirmationTimer ( m_Service ) ,
2017-08-31 14:38:26 +00:00
m_PublishVerificationTimer ( m_Service ) , m_PublishDelayTimer ( m_Service ) , m_CleanupTimer ( m_Service )
2014-10-05 12:54:59 +00:00
{
2016-10-26 00:00:00 +00:00
int inLen = DEFAULT_INBOUND_TUNNEL_LENGTH ;
int inQty = DEFAULT_INBOUND_TUNNELS_QUANTITY ;
int outLen = DEFAULT_OUTBOUND_TUNNEL_LENGTH ;
int outQty = DEFAULT_OUTBOUND_TUNNELS_QUANTITY ;
2016-01-24 01:52:21 +00:00
int numTags = DEFAULT_TAGS_TO_SEND ;
2015-06-10 19:32:55 +00:00
std : : shared_ptr < std : : vector < i2p : : data : : IdentHash > > explicitPeers ;
2018-01-06 03:48:51 +00:00
try
2017-10-04 16:27:08 +00:00
{
2018-01-06 03:48:51 +00:00
if ( params )
2017-10-04 16:27:08 +00:00
{
2016-10-26 00:00:00 +00:00
auto it = params - > find ( I2CP_PARAM_INBOUND_TUNNEL_LENGTH ) ;
if ( it ! = params - > end ( ) )
inLen = std : : stoi ( it - > second ) ;
it = params - > find ( I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH ) ;
if ( it ! = params - > end ( ) )
outLen = std : : stoi ( it - > second ) ;
it = params - > find ( I2CP_PARAM_INBOUND_TUNNELS_QUANTITY ) ;
if ( it ! = params - > end ( ) )
inQty = std : : stoi ( it - > second ) ;
it = params - > find ( I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY ) ;
if ( it ! = params - > end ( ) )
outQty = std : : stoi ( it - > second ) ;
it = params - > find ( I2CP_PARAM_TAGS_TO_SEND ) ;
if ( it ! = params - > end ( ) )
numTags = std : : stoi ( it - > second ) ;
LogPrint ( eLogInfo , " Destination: parameters for tunnel set to: " , inQty , " inbound ( " , inLen , " hops), " , outQty , " outbound ( " , outLen , " hops), " , numTags , " tags " ) ;
it = params - > find ( I2CP_PARAM_EXPLICIT_PEERS ) ;
if ( it ! = params - > end ( ) )
2015-06-10 19:32:55 +00:00
{
2016-10-26 00:00:00 +00:00
explicitPeers = std : : make_shared < std : : vector < i2p : : data : : IdentHash > > ( ) ;
std : : stringstream ss ( it - > second ) ;
std : : string b64 ;
while ( std : : getline ( ss , b64 , ' , ' ) )
{
i2p : : data : : IdentHash ident ;
ident . FromBase64 ( b64 ) ;
explicitPeers - > push_back ( ident ) ;
LogPrint ( eLogInfo , " Destination: Added to explicit peers list: " , b64 ) ;
}
2015-06-10 19:32:55 +00:00
}
2017-10-04 16:27:08 +00:00
it = params - > find ( I2CP_PARAM_INBOUND_NICKNAME ) ;
2018-01-06 03:48:51 +00:00
if ( it ! = params - > end ( ) ) m_Nickname = it - > second ;
2017-12-20 16:38:35 +00:00
else // try outbound
2018-01-06 03:48:51 +00:00
{
2017-12-20 16:38:35 +00:00
it = params - > find ( I2CP_PARAM_OUTBOUND_NICKNAME ) ;
2018-01-06 03:48:51 +00:00
if ( it ! = params - > end ( ) ) m_Nickname = it - > second ;
2017-12-20 16:38:35 +00:00
// otherwise we set deafult nickname in Start when we know local address
}
2015-06-10 19:32:55 +00:00
}
2018-01-06 03:48:51 +00:00
}
catch ( std : : exception & ex )
2017-10-04 16:27:08 +00:00
{
2016-10-26 00:00:00 +00:00
LogPrint ( eLogError , " Destination: unable to parse parameters for destination: " , ex . what ( ) ) ;
}
2016-01-24 01:52:21 +00:00
SetNumTags ( numTags ) ;
2016-10-26 00:00:00 +00:00
m_Pool = i2p : : tunnel : : tunnels . CreateTunnelPool ( inLen , outLen , inQty , outQty ) ;
2015-06-10 19:32:55 +00:00
if ( explicitPeers )
m_Pool - > SetExplicitPeers ( explicitPeers ) ;
2016-11-15 15:20:09 +00:00
if ( params )
{
auto itr = params - > find ( I2CP_PARAM_MAX_TUNNEL_LATENCY ) ;
if ( itr ! = params - > end ( ) ) {
auto maxlatency = std : : stoi ( itr - > second ) ;
itr = params - > find ( I2CP_PARAM_MIN_TUNNEL_LATENCY ) ;
if ( itr ! = params - > end ( ) ) {
auto minlatency = std : : stoi ( itr - > second ) ;
if ( minlatency > 0 & & maxlatency > 0 ) {
// set tunnel pool latency
LogPrint ( eLogInfo , " Destination: requiring tunnel latency [ " , minlatency , " ms, " , maxlatency , " ms] " ) ;
m_Pool - > RequireLatency ( minlatency , maxlatency ) ;
}
}
}
}
2014-10-05 12:54:59 +00:00
}
2016-05-23 14:33:01 +00:00
LeaseSetDestination : : ~ LeaseSetDestination ( )
2014-10-05 12:54:59 +00:00
{
2017-08-31 16:08:22 +00:00
if ( m_IsRunning )
2014-12-19 17:07:54 +00:00
Stop ( ) ;
2014-10-13 15:21:57 +00:00
if ( m_Pool )
2017-08-31 16:08:22 +00:00
i2p : : tunnel : : tunnels . DeleteTunnelPool ( m_Pool ) ;
2016-12-02 00:23:55 +00:00
for ( auto & it : m_LeaseSetRequests )
it . second - > Complete ( nullptr ) ;
2017-08-31 16:08:22 +00:00
}
2014-10-05 12:54:59 +00:00
2016-05-23 14:33:01 +00:00
void LeaseSetDestination : : Run ( )
2014-10-09 14:05:28 +00:00
{
2014-12-02 02:26:51 +00:00
while ( m_IsRunning )
{
try
2017-08-31 16:08:22 +00:00
{
2014-12-16 03:50:11 +00:00
m_Service . run ( ) ;
2014-12-02 02:26:51 +00:00
}
catch ( std : : exception & ex )
{
2015-12-18 13:11:56 +00:00
LogPrint ( eLogError , " Destination: runtime exception: " , ex . what ( ) ) ;
2017-08-31 16:08:22 +00:00
}
}
}
2014-10-09 14:05:28 +00:00
2016-05-23 18:31:22 +00:00
bool LeaseSetDestination : : Start ( )
2017-08-31 16:08:22 +00:00
{
2015-01-03 20:20:11 +00:00
if ( ! m_IsRunning )
2017-08-31 16:08:22 +00:00
{
2017-10-04 16:40:43 +00:00
if ( m_Nickname . empty ( ) )
m_Nickname = i2p : : data : : GetIdentHashAbbreviation ( GetIdentHash ( ) ) ; // set default nickname
2017-04-03 19:05:10 +00:00
LoadTags ( ) ;
2015-01-03 20:20:11 +00:00
m_IsRunning = true ;
2015-12-16 19:52:48 +00:00
m_Pool - > SetLocalDestination ( shared_from_this ( ) ) ;
2017-08-31 16:08:22 +00:00
m_Pool - > SetActive ( true ) ;
2015-01-23 17:48:25 +00:00
m_CleanupTimer . expires_from_now ( boost : : posix_time : : minutes ( DESTINATION_CLEANUP_TIMEOUT ) ) ;
2016-05-23 14:33:01 +00:00
m_CleanupTimer . async_wait ( std : : bind ( & LeaseSetDestination : : HandleCleanupTimer ,
2017-08-31 16:08:22 +00:00
shared_from_this ( ) , std : : placeholders : : _1 ) ) ;
2016-11-28 18:47:10 +00:00
m_Thread = new std : : thread ( std : : bind ( & LeaseSetDestination : : Run , shared_from_this ( ) ) ) ;
2017-08-31 16:08:22 +00:00
2016-05-23 18:31:22 +00:00
return true ;
2017-08-31 16:08:22 +00:00
}
2016-05-23 18:31:22 +00:00
else
return false ;
2014-10-09 14:05:28 +00:00
}
2017-08-31 16:08:22 +00:00
2016-05-23 18:31:22 +00:00
bool LeaseSetDestination : : Stop ( )
2017-08-31 16:08:22 +00:00
{
2015-01-03 20:20:11 +00:00
if ( m_IsRunning )
2017-08-31 16:08:22 +00:00
{
2015-01-23 17:48:25 +00:00
m_CleanupTimer . cancel ( ) ;
2016-02-11 19:45:33 +00:00
m_PublishConfirmationTimer . cancel ( ) ;
2017-08-31 16:08:22 +00:00
m_PublishVerificationTimer . cancel ( ) ;
2016-11-28 19:37:17 +00:00
2015-01-03 20:20:11 +00:00
m_IsRunning = false ;
if ( m_Pool )
2017-08-31 16:08:22 +00:00
{
2015-01-03 20:20:11 +00:00
m_Pool - > SetLocalDestination ( nullptr ) ;
i2p : : tunnel : : tunnels . StopTunnelPool ( m_Pool ) ;
2017-08-31 16:08:22 +00:00
}
2015-01-03 20:20:11 +00:00
m_Service . stop ( ) ;
if ( m_Thread )
2017-08-31 16:08:22 +00:00
{
m_Thread - > join ( ) ;
2015-01-03 20:20:11 +00:00
delete m_Thread ;
m_Thread = 0 ;
2017-08-31 16:08:22 +00:00
}
2017-04-03 19:05:10 +00:00
SaveTags ( ) ;
2016-11-29 03:47:37 +00:00
CleanUp ( ) ; // GarlicDestination
2016-05-23 18:31:22 +00:00
return true ;
2017-08-31 16:08:22 +00:00
}
2016-05-23 18:31:22 +00:00
else
return false ;
2017-08-31 16:08:22 +00:00
}
2018-01-02 16:34:58 +00:00
bool LeaseSetDestination : : Reconfigure ( std : : map < std : : string , std : : string > params )
{
auto itr = params . find ( " i2cp.dontPublishLeaseSet " ) ;
if ( itr ! = params . end ( ) )
{
m_IsPublic = itr - > second ! = " true " ;
}
int inLen , outLen , inQuant , outQuant , numTags , minLatency , maxLatency ;
std : : map < std : : string , int & > intOpts = {
{ I2CP_PARAM_INBOUND_TUNNEL_LENGTH , inLen } ,
{ I2CP_PARAM_OUTBOUND_TUNNEL_LENGTH , outLen } ,
{ I2CP_PARAM_INBOUND_TUNNELS_QUANTITY , inQuant } ,
{ I2CP_PARAM_OUTBOUND_TUNNELS_QUANTITY , outQuant } ,
{ I2CP_PARAM_TAGS_TO_SEND , numTags } ,
{ I2CP_PARAM_MIN_TUNNEL_LATENCY , minLatency } ,
{ I2CP_PARAM_MAX_TUNNEL_LATENCY , maxLatency }
} ;
auto pool = GetTunnelPool ( ) ;
inLen = pool - > GetNumInboundHops ( ) ;
outLen = pool - > GetNumOutboundHops ( ) ;
inQuant = pool - > GetNumInboundTunnels ( ) ;
outQuant = pool - > GetNumOutboundTunnels ( ) ;
minLatency = 0 ;
maxLatency = 0 ;
2018-01-02 17:06:10 +00:00
for ( auto & opt : intOpts )
2018-01-02 16:34:58 +00:00
{
itr = params . find ( opt . first ) ;
if ( itr ! = params . end ( ) )
{
opt . second = std : : stoi ( itr - > second ) ;
}
}
pool - > RequireLatency ( minLatency , maxLatency ) ;
return pool - > Reconfigure ( inLen , outLen , inQuant , outQuant ) ;
}
2016-05-23 14:33:01 +00:00
std : : shared_ptr < const i2p : : data : : LeaseSet > LeaseSetDestination : : FindLeaseSet ( const i2p : : data : : IdentHash & ident )
2014-10-05 12:54:59 +00:00
{
2016-10-12 13:39:16 +00:00
std : : shared_ptr < i2p : : data : : LeaseSet > remoteLS ;
2016-07-22 13:56:17 +00:00
{
2016-10-12 13:39:16 +00:00
std : : lock_guard < std : : mutex > lock ( m_RemoteLeaseSetsMutex ) ;
auto it = m_RemoteLeaseSets . find ( ident ) ;
if ( it ! = m_RemoteLeaseSets . end ( ) )
remoteLS = it - > second ;
}
2017-08-31 16:08:22 +00:00
if ( remoteLS )
2016-10-12 13:39:16 +00:00
{
if ( ! remoteLS - > IsExpired ( ) )
2016-07-22 13:56:17 +00:00
{
2016-10-12 13:39:16 +00:00
if ( remoteLS - > ExpiresSoon ( ) )
2016-07-22 13:56:17 +00:00
{
LogPrint ( eLogDebug , " Destination: Lease Set expires soon, updating before expire " ) ;
// update now before expiration for smooth handover
2016-10-12 13:39:16 +00:00
auto s = shared_from_this ( ) ;
RequestDestination ( ident , [ s , ident ] ( std : : shared_ptr < i2p : : data : : LeaseSet > ls ) {
2016-07-22 13:56:17 +00:00
if ( ls & & ! ls - > IsExpired ( ) )
{
ls - > PopulateLeases ( ) ;
2016-10-10 13:04:24 +00:00
{
2016-10-12 13:39:16 +00:00
std : : lock_guard < std : : mutex > _lock ( s - > m_RemoteLeaseSetsMutex ) ;
s - > m_RemoteLeaseSets [ ident ] = ls ;
2016-10-10 13:04:24 +00:00
}
2016-07-22 13:56:17 +00:00
}
} ) ;
}
2016-10-12 13:39:16 +00:00
return remoteLS ;
2016-07-22 13:56:17 +00:00
}
2014-10-05 12:54:59 +00:00
else
2016-10-25 18:07:34 +00:00
{
2016-02-08 00:45:06 +00:00
LogPrint ( eLogWarning , " Destination: remote LeaseSet expired " ) ;
2016-10-25 18:07:34 +00:00
std : : lock_guard < std : : mutex > lock ( m_RemoteLeaseSetsMutex ) ;
m_RemoteLeaseSets . erase ( ident ) ;
return nullptr ;
}
2017-08-31 16:08:22 +00:00
}
2014-10-16 16:37:39 +00:00
else
2017-08-31 16:08:22 +00:00
{
2014-10-16 16:37:39 +00:00
auto ls = i2p : : data : : netdb . FindLeaseSet ( ident ) ;
2016-02-13 01:56:29 +00:00
if ( ls & & ! ls - > IsExpired ( ) )
2014-10-16 16:37:39 +00:00
{
2016-02-08 00:45:06 +00:00
ls - > PopulateLeases ( ) ; // since we don't store them in netdb
2016-10-12 13:39:16 +00:00
std : : lock_guard < std : : mutex > _lock ( m_RemoteLeaseSetsMutex ) ;
2016-10-03 15:01:31 +00:00
m_RemoteLeaseSets [ ident ] = ls ;
2014-10-16 16:37:39 +00:00
return ls ;
2017-08-31 16:08:22 +00:00
}
2014-10-16 16:37:39 +00:00
}
return nullptr ;
2016-10-03 15:01:31 +00:00
}
2014-10-05 12:54:59 +00:00
2016-05-25 19:10:28 +00:00
std : : shared_ptr < const i2p : : data : : LocalLeaseSet > LeaseSetDestination : : GetLeaseSet ( )
2014-10-05 12:54:59 +00:00
{
if ( ! m_Pool ) return nullptr ;
if ( ! m_LeaseSet )
UpdateLeaseSet ( ) ;
2016-10-25 18:07:34 +00:00
std : : lock_guard < std : : mutex > l ( m_LeaseSetMutex ) ;
2014-10-05 12:54:59 +00:00
return m_LeaseSet ;
2017-08-31 16:08:22 +00:00
}
2014-10-05 12:54:59 +00:00
2016-05-29 13:33:50 +00:00
void LeaseSetDestination : : SetLeaseSet ( i2p : : data : : LocalLeaseSet * newLeaseSet )
{
2017-08-31 16:08:22 +00:00
{
2016-10-25 18:07:34 +00:00
std : : lock_guard < std : : mutex > l ( m_LeaseSetMutex ) ;
m_LeaseSet . reset ( newLeaseSet ) ;
}
2016-09-01 13:48:04 +00:00
i2p : : garlic : : GarlicDestination : : SetLeaseSetUpdated ( ) ;
2016-05-29 13:33:50 +00:00
if ( m_IsPublic )
{
2018-03-23 15:41:36 +00:00
auto s = shared_from_this ( ) ;
m_Service . post ( [ s ] ( void )
{
s - > m_PublishVerificationTimer . cancel ( ) ;
s - > Publish ( ) ;
} ) ;
2016-05-29 13:33:50 +00:00
}
2017-08-31 16:08:22 +00:00
}
2016-05-23 14:33:01 +00:00
void LeaseSetDestination : : UpdateLeaseSet ( )
2014-10-05 12:54:59 +00:00
{
2017-08-31 16:08:22 +00:00
int numTunnels = m_Pool - > GetNumInboundTunnels ( ) + 2 ; // 2 backup tunnels
if ( numTunnels > i2p : : data : : MAX_NUM_LEASES ) numTunnels = i2p : : data : : MAX_NUM_LEASES ; // 16 tunnels maximum
2016-05-29 13:33:50 +00:00
CreateNewLeaseSet ( m_Pool - > GetInboundTunnels ( numTunnels ) ) ;
2017-08-31 16:08:22 +00:00
}
2014-10-16 16:37:39 +00:00
2016-05-23 14:33:01 +00:00
bool LeaseSetDestination : : SubmitSessionKey ( const uint8_t * key , const uint8_t * tag )
2014-12-08 20:36:00 +00:00
{
2014-12-16 03:50:11 +00:00
struct
2014-12-08 20:36:00 +00:00
{
2014-12-16 03:50:11 +00:00
uint8_t k [ 32 ] , t [ 32 ] ;
2017-08-31 16:08:22 +00:00
} data ;
2014-12-16 03:50:11 +00:00
memcpy ( data . k , key , 32 ) ;
memcpy ( data . t , tag , 32 ) ;
2016-02-17 03:57:38 +00:00
auto s = shared_from_this ( ) ;
m_Service . post ( [ s , data ] ( void )
2014-12-09 19:15:02 +00:00
{
2016-02-17 03:57:38 +00:00
s - > AddSessionKey ( data . k , data . t ) ;
2014-12-16 03:50:11 +00:00
} ) ;
return true ;
2014-12-08 20:36:00 +00:00
}
2016-05-23 14:33:01 +00:00
void LeaseSetDestination : : ProcessGarlicMessage ( std : : shared_ptr < I2NPMessage > msg )
2014-10-16 16:37:39 +00:00
{
2017-08-31 16:08:22 +00:00
m_Service . post ( std : : bind ( & LeaseSetDestination : : HandleGarlicMessage , shared_from_this ( ) , msg ) ) ;
2014-10-16 16:37:39 +00:00
}
2016-05-23 14:33:01 +00:00
void LeaseSetDestination : : ProcessDeliveryStatusMessage ( std : : shared_ptr < I2NPMessage > msg )
2014-10-16 16:37:39 +00:00
{
2017-08-31 16:08:22 +00:00
m_Service . post ( std : : bind ( & LeaseSetDestination : : HandleDeliveryStatusMessage , shared_from_this ( ) , msg ) ) ;
2014-10-16 16:37:39 +00:00
}
2016-10-10 12:59:48 +00:00
void LeaseSetDestination : : HandleI2NPMessage ( const uint8_t * buf , size_t len , std : : shared_ptr < i2p : : tunnel : : InboundTunnel > from )
2014-10-16 16:37:39 +00:00
{
2015-01-02 04:00:33 +00:00
uint8_t typeID = buf [ I2NP_HEADER_TYPEID_OFFSET ] ;
switch ( typeID )
2017-08-31 16:08:22 +00:00
{
2014-10-16 16:37:39 +00:00
case eI2NPData :
2018-04-29 22:05:28 +00:00
HandleDataMessage ( buf + I2NP_HEADER_SIZE , GetI2NPMessageLength ( buf , len ) - I2NP_HEADER_SIZE ) ;
2014-10-16 16:37:39 +00:00
break ;
2015-06-30 01:40:43 +00:00
case eI2NPDeliveryStatus :
// we assume tunnel tests non-encrypted
2017-12-01 17:57:05 +00:00
HandleDeliveryStatusMessage ( CreateI2NPMessage ( buf , GetI2NPMessageLength ( buf , len ) , from ) ) ;
2017-08-31 16:08:22 +00:00
break ;
2014-10-16 16:37:39 +00:00
case eI2NPDatabaseStore :
2018-04-29 22:05:28 +00:00
HandleDatabaseStoreMessage ( buf + I2NP_HEADER_SIZE , GetI2NPMessageLength ( buf , len ) - I2NP_HEADER_SIZE ) ;
2014-12-25 21:47:15 +00:00
break ;
case eI2NPDatabaseSearchReply :
2018-04-29 22:05:28 +00:00
HandleDatabaseSearchReplyMessage ( buf + I2NP_HEADER_SIZE , GetI2NPMessageLength ( buf , len ) - I2NP_HEADER_SIZE ) ;
2017-08-31 16:08:22 +00:00
break ;
2014-10-16 16:37:39 +00:00
default :
2017-12-01 17:57:05 +00:00
i2p : : HandleI2NPMessage ( CreateI2NPMessage ( buf , GetI2NPMessageLength ( buf , len ) , from ) ) ;
2017-08-31 16:08:22 +00:00
}
}
2014-10-16 16:37:39 +00:00
2016-05-23 14:33:01 +00:00
void LeaseSetDestination : : HandleDatabaseStoreMessage ( const uint8_t * buf , size_t len )
2014-10-16 16:37:39 +00:00
{
2015-01-03 02:11:40 +00:00
uint32_t replyToken = bufbe32toh ( buf + DATABASE_STORE_REPLY_TOKEN_OFFSET ) ;
size_t offset = DATABASE_STORE_HEADER_SIZE ;
2017-08-31 16:08:22 +00:00
if ( replyToken )
2015-01-30 20:29:33 +00:00
{
2015-12-18 13:11:56 +00:00
LogPrint ( eLogInfo , " Destination: Reply token is ignored for DatabaseStore " ) ;
2014-10-16 16:37:39 +00:00
offset + = 36 ;
2015-01-30 20:29:33 +00:00
}
2016-11-07 23:32:22 +00:00
i2p : : data : : IdentHash key ( buf + DATABASE_STORE_KEY_OFFSET ) ;
2015-04-07 16:02:25 +00:00
std : : shared_ptr < i2p : : data : : LeaseSet > leaseSet ;
2015-01-03 02:11:40 +00:00
if ( buf [ DATABASE_STORE_TYPE_OFFSET ] = = 1 ) // LeaseSet
2014-10-16 16:37:39 +00:00
{
2016-10-26 17:02:19 +00:00
LogPrint ( eLogDebug , " Destination: Remote LeaseSet " ) ;
2016-07-22 13:56:17 +00:00
std : : lock_guard < std : : mutex > lock ( m_RemoteLeaseSetsMutex ) ;
2016-11-07 23:32:22 +00:00
auto it = m_RemoteLeaseSets . find ( key ) ;
2014-10-16 16:37:39 +00:00
if ( it ! = m_RemoteLeaseSets . end ( ) )
{
2015-04-07 16:02:25 +00:00
leaseSet = it - > second ;
2016-02-17 03:57:38 +00:00
if ( leaseSet - > IsNewer ( buf + offset , len - offset ) )
2017-08-31 16:08:22 +00:00
{
leaseSet - > Update ( buf + offset , len - offset ) ;
2016-11-07 23:32:22 +00:00
if ( leaseSet - > IsValid ( ) & & leaseSet - > GetIdentHash ( ) = = key )
2016-10-26 17:02:19 +00:00
LogPrint ( eLogDebug , " Destination: Remote LeaseSet updated " ) ;
2016-02-17 03:57:38 +00:00
else
{
2016-10-26 17:02:19 +00:00
LogPrint ( eLogDebug , " Destination: Remote LeaseSet update failed " ) ;
2016-02-17 03:57:38 +00:00
m_RemoteLeaseSets . erase ( it ) ;
leaseSet = nullptr ;
}
2015-04-08 14:34:16 +00:00
}
2016-02-17 03:57:38 +00:00
else
2016-10-26 17:02:19 +00:00
LogPrint ( eLogDebug , " Destination: Remote LeaseSet is older. Not updated " ) ;
2014-10-16 16:37:39 +00:00
}
else
2017-08-31 16:08:22 +00:00
{
2015-04-07 16:02:25 +00:00
leaseSet = std : : make_shared < i2p : : data : : LeaseSet > ( buf + offset , len - offset ) ;
2016-11-07 23:32:22 +00:00
if ( leaseSet - > IsValid ( ) & & leaseSet - > GetIdentHash ( ) = = key )
2015-04-08 14:34:16 +00:00
{
2016-02-11 19:45:33 +00:00
if ( leaseSet - > GetIdentHash ( ) ! = GetIdentHash ( ) )
{
2016-10-26 17:02:19 +00:00
LogPrint ( eLogDebug , " Destination: New remote LeaseSet added " ) ;
2016-11-07 23:32:22 +00:00
m_RemoteLeaseSets [ key ] = leaseSet ;
2016-02-11 19:45:33 +00:00
}
else
2016-10-26 17:02:19 +00:00
LogPrint ( eLogDebug , " Destination: Own remote LeaseSet dropped " ) ;
2015-04-08 14:34:16 +00:00
}
else
{
2016-10-26 17:02:19 +00:00
LogPrint ( eLogError , " Destination: New remote LeaseSet failed " ) ;
2015-04-08 14:34:16 +00:00
leaseSet = nullptr ;
}
2017-08-31 16:08:22 +00:00
}
}
2014-10-16 16:37:39 +00:00
else
2015-12-18 13:11:56 +00:00
LogPrint ( eLogError , " Destination: Unexpected client's DatabaseStore type " , buf [ DATABASE_STORE_TYPE_OFFSET ] , " , dropped " ) ;
2017-08-31 16:08:22 +00:00
2016-11-07 23:32:22 +00:00
auto it1 = m_LeaseSetRequests . find ( key ) ;
2014-12-28 20:45:58 +00:00
if ( it1 ! = m_LeaseSetRequests . end ( ) )
{
it1 - > second - > requestTimeoutTimer . cancel ( ) ;
2016-11-17 03:28:13 +00:00
if ( it1 - > second ) it1 - > second - > Complete ( leaseSet ) ;
2014-12-28 20:45:58 +00:00
m_LeaseSetRequests . erase ( it1 ) ;
2017-08-31 16:08:22 +00:00
}
2015-01-05 11:36:09 +00:00
}
2014-11-28 18:01:35 +00:00
2016-10-10 12:59:48 +00:00
void LeaseSetDestination : : HandleDatabaseSearchReplyMessage ( const uint8_t * buf , size_t len )
2014-12-25 21:47:15 +00:00
{
i2p : : data : : IdentHash key ( buf ) ;
int num = buf [ 32 ] ; // num
2015-12-18 13:11:56 +00:00
LogPrint ( eLogDebug , " Destination: DatabaseSearchReply for " , key . ToBase64 ( ) , " num= " , num ) ;
2014-12-25 21:47:15 +00:00
auto it = m_LeaseSetRequests . find ( key ) ;
2014-12-27 00:09:44 +00:00
if ( it ! = m_LeaseSetRequests . end ( ) )
2014-12-25 21:47:15 +00:00
{
2015-12-13 15:51:43 +00:00
auto request = it - > second ;
2014-12-25 21:47:15 +00:00
bool found = false ;
2014-12-27 00:09:44 +00:00
if ( request - > excluded . size ( ) < MAX_NUM_FLOODFILLS_PER_REQUEST )
2017-08-31 16:08:22 +00:00
{
2014-12-25 21:47:15 +00:00
for ( int i = 0 ; i < num ; i + + )
2016-10-25 18:07:34 +00:00
{
i2p : : data : : IdentHash peerHash ( buf + 33 + i * 32 ) ;
if ( ! request - > excluded . count ( peerHash ) & & ! i2p : : data : : netdb . FindRouter ( peerHash ) )
2014-12-25 21:47:15 +00:00
{
2016-10-25 18:07:34 +00:00
LogPrint ( eLogInfo , " Destination: Found new floodfill, request it " ) ; // TODO: recheck this message
i2p : : data : : netdb . RequestDestination ( peerHash ) ;
2017-08-31 16:08:22 +00:00
}
2016-10-25 18:07:34 +00:00
}
2017-08-31 16:08:22 +00:00
2016-10-17 22:45:20 +00:00
auto floodfill = i2p : : data : : netdb . GetClosestFloodfill ( key , request - > excluded ) ;
if ( floodfill )
{
LogPrint ( eLogInfo , " Destination: Requesting " , key . ToBase64 ( ) , " at " , floodfill - > GetIdentHash ( ) . ToBase64 ( ) ) ;
if ( SendLeaseSetRequest ( key , floodfill , request ) )
found = true ;
2017-08-31 16:08:22 +00:00
}
}
2014-12-25 21:47:15 +00:00
if ( ! found )
2017-08-31 16:08:22 +00:00
{
2016-10-17 22:45:20 +00:00
LogPrint ( eLogInfo , " Destination: " , key . ToBase64 ( ) , " was not found on " , MAX_NUM_FLOODFILLS_PER_REQUEST , " floodfills " ) ;
2016-11-17 03:28:13 +00:00
request - > Complete ( nullptr ) ;
2014-12-27 00:09:44 +00:00
m_LeaseSetRequests . erase ( key ) ;
2017-08-31 16:08:22 +00:00
}
}
else
2015-12-18 13:11:56 +00:00
LogPrint ( eLogWarning , " Destination: Request for " , key . ToBase64 ( ) , " not found " ) ;
2017-08-31 16:08:22 +00:00
}
2016-05-23 14:33:01 +00:00
void LeaseSetDestination : : HandleDeliveryStatusMessage ( std : : shared_ptr < I2NPMessage > msg )
2014-11-28 18:01:35 +00:00
{
2015-01-02 22:39:35 +00:00
uint32_t msgID = bufbe32toh ( msg - > GetPayload ( ) + DELIVERY_STATUS_MSGID_OFFSET ) ;
2014-11-28 18:01:35 +00:00
if ( msgID = = m_PublishReplyToken )
{
2016-06-29 21:59:56 +00:00
LogPrint ( eLogDebug , " Destination: Publishing LeaseSet confirmed for " , GetIdentHash ( ) . ToBase32 ( ) ) ;
2014-12-07 21:10:25 +00:00
m_ExcludedFloodfills . clear ( ) ;
2014-11-28 18:01:35 +00:00
m_PublishReplyToken = 0 ;
2016-02-11 19:45:33 +00:00
// schedule verification
m_PublishVerificationTimer . expires_from_now ( boost : : posix_time : : seconds ( PUBLISH_VERIFICATION_TIMEOUT ) ) ;
2016-05-23 14:33:01 +00:00
m_PublishVerificationTimer . async_wait ( std : : bind ( & LeaseSetDestination : : HandlePublishVerificationTimer ,
2017-08-31 16:08:22 +00:00
shared_from_this ( ) , std : : placeholders : : _1 ) ) ;
2014-11-28 18:01:35 +00:00
}
else
i2p : : garlic : : GarlicDestination : : HandleDeliveryStatusMessage ( msg ) ;
2017-08-31 16:08:22 +00:00
}
2014-10-16 16:37:39 +00:00
2016-05-23 14:33:01 +00:00
void LeaseSetDestination : : SetLeaseSetUpdated ( )
2017-08-31 16:08:22 +00:00
{
2014-10-16 16:37:39 +00:00
UpdateLeaseSet ( ) ;
2014-11-28 18:01:35 +00:00
}
2017-08-31 16:08:22 +00:00
2016-05-23 14:33:01 +00:00
void LeaseSetDestination : : Publish ( )
2017-08-31 16:08:22 +00:00
{
if ( ! m_LeaseSet | | ! m_Pool )
2014-11-28 18:01:35 +00:00
{
2015-12-18 13:11:56 +00:00
LogPrint ( eLogError , " Destination: Can't publish non-existing LeaseSet " ) ;
2014-11-28 18:01:35 +00:00
return ;
}
if ( m_PublishReplyToken )
{
2015-12-18 13:11:56 +00:00
LogPrint ( eLogDebug , " Destination: Publishing LeaseSet is pending " ) ;
2014-11-28 18:01:35 +00:00
return ;
}
2017-02-13 01:52:46 +00:00
auto ts = i2p : : util : : GetSecondsSinceEpoch ( ) ;
if ( ts < m_LastSubmissionTime + PUBLISH_MIN_INTERVAL )
{
LogPrint ( eLogDebug , " Destination: Publishing LeaseSet is too fast. Wait for " , PUBLISH_MIN_INTERVAL , " seconds " ) ;
m_PublishDelayTimer . cancel ( ) ;
m_PublishDelayTimer . expires_from_now ( boost : : posix_time : : seconds ( PUBLISH_MIN_INTERVAL ) ) ;
m_PublishDelayTimer . async_wait ( std : : bind ( & LeaseSetDestination : : HandlePublishDelayTimer ,
2017-08-31 16:08:22 +00:00
shared_from_this ( ) , std : : placeholders : : _1 ) ) ;
2017-02-13 01:52:46 +00:00
return ;
2017-08-31 16:08:22 +00:00
}
2014-11-28 18:01:35 +00:00
auto outbound = m_Pool - > GetNextOutboundTunnel ( ) ;
if ( ! outbound )
{
2015-12-18 13:11:56 +00:00
LogPrint ( eLogError , " Destination: Can't publish LeaseSet. No outbound tunnels " ) ;
2014-11-28 18:01:35 +00:00
return ;
}
2016-05-25 16:55:58 +00:00
auto inbound = m_Pool - > GetNextInboundTunnel ( ) ;
if ( ! inbound )
{
LogPrint ( eLogError , " Destination: Can't publish LeaseSet. No inbound tunnels " ) ;
return ;
}
2017-08-31 16:08:22 +00:00
auto floodfill = i2p : : data : : netdb . GetClosestFloodfill ( m_LeaseSet - > GetIdentHash ( ) , m_ExcludedFloodfills ) ;
2014-11-28 18:01:35 +00:00
if ( ! floodfill )
{
2015-12-18 13:11:56 +00:00
LogPrint ( eLogError , " Destination: Can't publish LeaseSet, no more floodfills found " ) ;
2014-12-07 21:10:25 +00:00
m_ExcludedFloodfills . clear ( ) ;
2014-11-28 18:01:35 +00:00
return ;
2017-08-31 16:08:22 +00:00
}
2014-12-07 21:10:25 +00:00
m_ExcludedFloodfills . insert ( floodfill - > GetIdentHash ( ) ) ;
2015-12-18 13:11:56 +00:00
LogPrint ( eLogDebug , " Destination: Publish LeaseSet of " , GetIdentHash ( ) . ToBase32 ( ) ) ;
2015-11-03 14:15:49 +00:00
RAND_bytes ( ( uint8_t * ) & m_PublishReplyToken , 4 ) ;
2017-08-31 16:08:22 +00:00
auto msg = WrapMessage ( floodfill , i2p : : CreateDatabaseStoreMsg ( m_LeaseSet , m_PublishReplyToken , inbound ) ) ;
2014-12-16 03:50:11 +00:00
m_PublishConfirmationTimer . expires_from_now ( boost : : posix_time : : seconds ( PUBLISH_CONFIRMATION_TIMEOUT ) ) ;
2016-05-23 14:33:01 +00:00
m_PublishConfirmationTimer . async_wait ( std : : bind ( & LeaseSetDestination : : HandlePublishConfirmationTimer ,
2017-08-31 16:08:22 +00:00
shared_from_this ( ) , std : : placeholders : : _1 ) ) ;
outbound - > SendTunnelDataMsg ( floodfill - > GetIdentHash ( ) , 0 , msg ) ;
2017-02-13 01:52:46 +00:00
m_LastSubmissionTime = ts ;
2014-11-28 18:01:35 +00:00
}
2016-05-23 14:33:01 +00:00
void LeaseSetDestination : : HandlePublishConfirmationTimer ( const boost : : system : : error_code & ecode )
2014-11-28 18:01:35 +00:00
{
if ( ecode ! = boost : : asio : : error : : operation_aborted )
2017-08-31 16:08:22 +00:00
{
2014-11-28 18:01:35 +00:00
if ( m_PublishReplyToken )
{
m_PublishReplyToken = 0 ;
2017-11-17 19:28:48 +00:00
if ( GetIdentity ( ) - > GetCryptoKeyType ( ) = = i2p : : data : : CRYPTO_KEY_TYPE_ELGAMAL )
{
2018-01-06 03:48:51 +00:00
LogPrint ( eLogWarning , " Destination: Publish confirmation was not received in " , PUBLISH_CONFIRMATION_TIMEOUT , " seconds, will try again " ) ;
2017-11-17 19:28:48 +00:00
Publish ( ) ;
}
else
{
LogPrint ( eLogWarning , " Destination: Publish confirmation was not received in " , PUBLISH_CONFIRMATION_TIMEOUT , " seconds from Java floodfill for crypto type " , ( int ) GetIdentity ( ) - > GetCryptoKeyType ( ) ) ;
// Java floodfill never sends confirmantion back for unknown crypto type
// assume it successive and try to verify
m_PublishVerificationTimer . expires_from_now ( boost : : posix_time : : seconds ( PUBLISH_VERIFICATION_TIMEOUT ) ) ;
m_PublishVerificationTimer . async_wait ( std : : bind ( & LeaseSetDestination : : HandlePublishVerificationTimer ,
shared_from_this ( ) , std : : placeholders : : _1 ) ) ;
2018-01-06 03:48:51 +00:00
2017-11-17 19:28:48 +00:00
}
2014-11-28 18:01:35 +00:00
}
}
2014-10-16 16:37:39 +00:00
}
2016-05-23 14:33:01 +00:00
void LeaseSetDestination : : HandlePublishVerificationTimer ( const boost : : system : : error_code & ecode )
2016-02-11 19:45:33 +00:00
{
if ( ecode ! = boost : : asio : : error : : operation_aborted )
2017-08-31 16:08:22 +00:00
{
2016-02-11 19:45:33 +00:00
auto s = shared_from_this ( ) ;
2017-08-31 16:08:22 +00:00
RequestLeaseSet ( GetIdentHash ( ) ,
2016-02-22 12:57:25 +00:00
// "this" added due to bug in gcc 4.7-4.8
2016-02-20 01:00:00 +00:00
[ s , this ] ( std : : shared_ptr < i2p : : data : : LeaseSet > leaseSet )
2016-02-11 19:45:33 +00:00
{
2017-08-31 16:08:22 +00:00
if ( leaseSet )
2016-02-11 19:45:33 +00:00
{
2017-02-12 15:08:52 +00:00
if ( s - > m_LeaseSet & & * s - > m_LeaseSet = = * leaseSet )
{
// we got latest LeasetSet
LogPrint ( eLogDebug , " Destination: published LeaseSet verified for " , GetIdentHash ( ) . ToBase32 ( ) ) ;
s - > m_PublishVerificationTimer . expires_from_now ( boost : : posix_time : : seconds ( PUBLISH_REGULAR_VERIFICATION_INTERNAL ) ) ;
2017-08-31 16:08:22 +00:00
s - > m_PublishVerificationTimer . async_wait ( std : : bind ( & LeaseSetDestination : : HandlePublishVerificationTimer , s , std : : placeholders : : _1 ) ) ;
2017-02-12 15:08:52 +00:00
return ;
2017-08-31 16:08:22 +00:00
}
2017-02-12 15:08:52 +00:00
else
LogPrint ( eLogDebug , " Destination: LeaseSet is different than just published for " , GetIdentHash ( ) . ToBase32 ( ) ) ;
2017-08-31 16:08:22 +00:00
}
2016-02-11 19:45:33 +00:00
else
2016-06-29 22:05:08 +00:00
LogPrint ( eLogWarning , " Destination: couldn't find published LeaseSet for " , GetIdentHash ( ) . ToBase32 ( ) ) ;
2016-02-11 19:45:33 +00:00
// we have to publish again
2016-07-14 20:59:26 +00:00
s - > Publish ( ) ;
2016-02-11 19:45:33 +00:00
} ) ;
}
}
2017-02-13 01:52:46 +00:00
void LeaseSetDestination : : HandlePublishDelayTimer ( const boost : : system : : error_code & ecode )
{
if ( ecode ! = boost : : asio : : error : : operation_aborted )
Publish ( ) ;
2017-08-31 16:08:22 +00:00
}
2016-05-23 14:33:01 +00:00
bool LeaseSetDestination : : RequestDestination ( const i2p : : data : : IdentHash & dest , RequestComplete requestComplete )
2014-12-25 21:47:15 +00:00
{
2017-08-31 16:08:22 +00:00
if ( ! m_Pool | | ! IsReady ( ) )
{
if ( requestComplete )
2016-08-09 02:15:09 +00:00
m_Service . post ( [ requestComplete ] ( void ) { requestComplete ( nullptr ) ; } ) ;
2015-01-03 03:37:46 +00:00
return false ;
2017-08-31 16:08:22 +00:00
}
2016-05-23 14:33:01 +00:00
m_Service . post ( std : : bind ( & LeaseSetDestination : : RequestLeaseSet , shared_from_this ( ) , dest , requestComplete ) ) ;
2014-12-25 21:47:15 +00:00
return true ;
}
2016-08-08 15:53:38 +00:00
void LeaseSetDestination : : CancelDestinationRequest ( const i2p : : data : : IdentHash & dest , bool notify )
2015-12-13 19:40:43 +00:00
{
auto s = shared_from_this ( ) ;
2016-08-08 15:53:38 +00:00
m_Service . post ( [ dest , notify , s ] ( void )
2015-12-13 19:40:43 +00:00
{
auto it = s - > m_LeaseSetRequests . find ( dest ) ;
if ( it ! = s - > m_LeaseSetRequests . end ( ) )
2017-08-31 16:08:22 +00:00
{
auto requestComplete = it - > second ;
2016-02-14 04:02:58 +00:00
s - > m_LeaseSetRequests . erase ( it ) ;
2016-11-17 03:28:13 +00:00
if ( notify & & requestComplete ) requestComplete - > Complete ( nullptr ) ;
2017-08-31 16:08:22 +00:00
}
} ) ;
2015-12-13 19:40:43 +00:00
}
2017-08-31 16:08:22 +00:00
2016-05-23 14:33:01 +00:00
void LeaseSetDestination : : RequestLeaseSet ( const i2p : : data : : IdentHash & dest , RequestComplete requestComplete )
2014-12-25 21:47:15 +00:00
{
std : : set < i2p : : data : : IdentHash > excluded ;
auto floodfill = i2p : : data : : netdb . GetClosestFloodfill ( dest , excluded ) ;
if ( floodfill )
{
2015-12-13 15:51:43 +00:00
auto request = std : : make_shared < LeaseSetRequest > ( m_Service ) ;
2016-12-02 21:10:49 +00:00
if ( requestComplete )
request - > requestComplete . push_back ( requestComplete ) ;
2016-11-19 22:24:38 +00:00
auto ts = i2p : : util : : GetSecondsSinceEpoch ( ) ;
2015-12-13 15:51:43 +00:00
auto ret = m_LeaseSetRequests . insert ( std : : pair < i2p : : data : : IdentHash , std : : shared_ptr < LeaseSetRequest > > ( dest , request ) ) ;
2015-01-09 03:04:41 +00:00
if ( ret . second ) // inserted
2014-12-27 00:09:44 +00:00
{
2016-11-19 22:24:38 +00:00
request - > requestTime = ts ;
2015-01-09 03:04:41 +00:00
if ( ! SendLeaseSetRequest ( dest , floodfill , request ) )
{
// request failed
2016-11-19 22:24:38 +00:00
m_LeaseSetRequests . erase ( ret . first ) ;
2016-12-02 21:10:49 +00:00
if ( requestComplete ) requestComplete ( nullptr ) ;
2015-01-09 03:04:41 +00:00
}
2017-08-31 16:08:22 +00:00
}
2015-01-09 03:04:41 +00:00
else // duplicate
{
2016-11-17 03:28:13 +00:00
LogPrint ( eLogInfo , " Destination: Request of LeaseSet " , dest . ToBase64 ( ) , " is pending already " ) ;
2016-11-19 22:24:38 +00:00
if ( ts > ret . first - > second - > requestTime + MAX_LEASESET_REQUEST_TIMEOUT )
2017-08-31 16:08:22 +00:00
{
2016-12-11 19:17:09 +00:00
// something went wrong
2016-11-19 22:24:38 +00:00
m_LeaseSetRequests . erase ( ret . first ) ;
2016-12-11 19:17:09 +00:00
if ( requestComplete ) requestComplete ( nullptr ) ;
}
else if ( requestComplete )
ret . first - > second - > requestComplete . push_back ( requestComplete ) ;
2017-08-31 16:08:22 +00:00
}
}
2014-12-25 21:47:15 +00:00
else
2017-08-31 16:08:22 +00:00
{
2015-12-18 13:11:56 +00:00
LogPrint ( eLogError , " Destination: Can't request LeaseSet, no floodfills found " ) ;
2016-12-02 21:10:49 +00:00
if ( requestComplete ) requestComplete ( nullptr ) ;
2017-08-31 16:08:22 +00:00
}
}
bool LeaseSetDestination : : SendLeaseSetRequest ( const i2p : : data : : IdentHash & dest ,
2015-12-13 15:51:43 +00:00
std : : shared_ptr < const i2p : : data : : RouterInfo > nextFloodfill , std : : shared_ptr < LeaseSetRequest > request )
2014-12-25 21:47:15 +00:00
{
2016-02-26 21:17:29 +00:00
if ( ! request - > replyTunnel | | ! request - > replyTunnel - > IsEstablished ( ) )
request - > replyTunnel = m_Pool - > GetNextInboundTunnel ( ) ;
if ( ! request - > replyTunnel ) LogPrint ( eLogError , " Destination: Can't send LeaseSet request, no inbound tunnels found " ) ;
if ( ! request - > outboundTunnel | | ! request - > outboundTunnel - > IsEstablished ( ) )
request - > outboundTunnel = m_Pool - > GetNextOutboundTunnel ( ) ;
if ( ! request - > outboundTunnel ) LogPrint ( eLogError , " Destination: Can't send LeaseSet request, no outbound tunnels found " ) ;
2017-08-31 16:08:22 +00:00
2016-02-26 21:17:29 +00:00
if ( request - > replyTunnel & & request - > outboundTunnel )
2017-08-31 16:08:22 +00:00
{
2014-12-25 21:47:15 +00:00
request - > excluded . insert ( nextFloodfill - > GetIdentHash ( ) ) ;
request - > requestTimeoutTimer . cancel ( ) ;
2014-12-30 17:25:08 +00:00
uint8_t replyKey [ 32 ] , replyTag [ 32 ] ;
2017-08-31 16:08:22 +00:00
RAND_bytes ( replyKey , 32 ) ; // random session key
2015-11-03 14:15:49 +00:00
RAND_bytes ( replyTag , 32 ) ; // random session tag
2014-12-30 17:25:08 +00:00
AddSessionKey ( replyKey , replyTag ) ;
2015-06-22 02:29:50 +00:00
auto msg = WrapMessage ( nextFloodfill ,
2017-08-31 16:08:22 +00:00
CreateLeaseSetDatabaseLookupMsg ( dest , request - > excluded ,
2016-02-26 21:17:29 +00:00
request - > replyTunnel , replyKey , replyTag ) ) ;
request - > outboundTunnel - > SendTunnelDataMsg (
2014-12-25 21:47:15 +00:00
{
2017-08-31 16:08:22 +00:00
i2p : : tunnel : : TunnelMessageBlock
{
2014-12-25 21:47:15 +00:00
i2p : : tunnel : : eDeliveryTypeRouter ,
2015-06-22 02:29:50 +00:00
nextFloodfill - > GetIdentHash ( ) , 0 , msg
2014-12-25 21:47:15 +00:00
}
2017-08-31 16:08:22 +00:00
} ) ;
2014-12-25 21:47:15 +00:00
request - > requestTimeoutTimer . expires_from_now ( boost : : posix_time : : seconds ( LEASESET_REQUEST_TIMEOUT ) ) ;
2016-05-23 14:33:01 +00:00
request - > requestTimeoutTimer . async_wait ( std : : bind ( & LeaseSetDestination : : HandleRequestTimoutTimer ,
2016-02-11 19:45:33 +00:00
shared_from_this ( ) , std : : placeholders : : _1 , dest ) ) ;
2017-08-31 16:08:22 +00:00
}
2014-12-25 21:47:15 +00:00
else
2014-12-27 00:09:44 +00:00
return false ;
return true ;
2017-08-31 16:08:22 +00:00
}
2014-12-25 21:47:15 +00:00
2016-05-23 14:33:01 +00:00
void LeaseSetDestination : : HandleRequestTimoutTimer ( const boost : : system : : error_code & ecode , const i2p : : data : : IdentHash & dest )
2014-12-25 21:47:15 +00:00
{
if ( ecode ! = boost : : asio : : error : : operation_aborted )
{
auto it = m_LeaseSetRequests . find ( dest ) ;
if ( it ! = m_LeaseSetRequests . end ( ) )
{
bool done = false ;
uint64_t ts = i2p : : util : : GetSecondsSinceEpoch ( ) ;
if ( ts < it - > second - > requestTime + MAX_LEASESET_REQUEST_TIMEOUT )
{
auto floodfill = i2p : : data : : netdb . GetClosestFloodfill ( dest , it - > second - > excluded ) ;
if ( floodfill )
2016-02-26 21:17:29 +00:00
{
// reset tunnels, because one them might fail
it - > second - > outboundTunnel = nullptr ;
2017-08-31 16:08:22 +00:00
it - > second - > replyTunnel = nullptr ;
2016-02-26 21:17:29 +00:00
done = ! SendLeaseSetRequest ( dest , floodfill , it - > second ) ;
}
2014-12-25 21:47:15 +00:00
else
done = true ;
}
else
2017-08-31 16:08:22 +00:00
{
2015-12-18 13:11:56 +00:00
LogPrint ( eLogWarning , " Destination: " , dest . ToBase64 ( ) , " was not found within " , MAX_LEASESET_REQUEST_TIMEOUT , " seconds " ) ;
2014-12-25 21:47:15 +00:00
done = true ;
}
2017-08-31 16:08:22 +00:00
2014-12-25 21:47:15 +00:00
if ( done )
{
2017-08-31 16:08:22 +00:00
auto requestComplete = it - > second ;
2014-12-25 21:47:15 +00:00
m_LeaseSetRequests . erase ( it ) ;
2016-11-17 03:28:13 +00:00
if ( requestComplete ) requestComplete - > Complete ( nullptr ) ;
2017-08-31 16:08:22 +00:00
}
}
}
2015-01-23 17:48:25 +00:00
}
2016-05-23 14:33:01 +00:00
void LeaseSetDestination : : HandleCleanupTimer ( const boost : : system : : error_code & ecode )
2015-01-23 17:48:25 +00:00
{
if ( ecode ! = boost : : asio : : error : : operation_aborted )
{
2016-02-07 22:45:11 +00:00
CleanupExpiredTags ( ) ;
2015-01-28 19:20:28 +00:00
CleanupRemoteLeaseSets ( ) ;
2016-09-08 14:16:42 +00:00
CleanupDestination ( ) ;
2015-01-23 17:48:25 +00:00
m_CleanupTimer . expires_from_now ( boost : : posix_time : : minutes ( DESTINATION_CLEANUP_TIMEOUT ) ) ;
2016-05-23 14:33:01 +00:00
m_CleanupTimer . async_wait ( std : : bind ( & LeaseSetDestination : : HandleCleanupTimer ,
2015-11-03 14:15:49 +00:00
shared_from_this ( ) , std : : placeholders : : _1 ) ) ;
2015-01-23 17:48:25 +00:00
}
2017-08-31 16:08:22 +00:00
}
2015-01-28 19:20:28 +00:00
2016-05-23 14:33:01 +00:00
void LeaseSetDestination : : CleanupRemoteLeaseSets ( )
2015-01-28 19:20:28 +00:00
{
2016-02-08 00:45:06 +00:00
auto ts = i2p : : util : : GetMillisecondsSinceEpoch ( ) ;
2016-07-22 13:56:17 +00:00
std : : lock_guard < std : : mutex > lock ( m_RemoteLeaseSetsMutex ) ;
2015-01-28 19:20:28 +00:00
for ( auto it = m_RemoteLeaseSets . begin ( ) ; it ! = m_RemoteLeaseSets . end ( ) ; )
{
2016-02-10 03:42:01 +00:00
if ( it - > second - > IsEmpty ( ) | | ts > it - > second - > GetExpirationTime ( ) ) // leaseset expired
2015-01-28 19:20:28 +00:00
{
2015-12-18 13:11:56 +00:00
LogPrint ( eLogWarning , " Destination: Remote LeaseSet " , it - > second - > GetIdentHash ( ) . ToBase64 ( ) , " expired " ) ;
2015-01-28 19:20:28 +00:00
it = m_RemoteLeaseSets . erase ( it ) ;
2017-08-31 16:08:22 +00:00
}
else
2016-08-05 18:23:54 +00:00
+ + it ;
2015-01-28 19:20:28 +00:00
}
2017-08-31 16:08:22 +00:00
}
2016-05-26 19:53:32 +00:00
2016-05-23 14:33:01 +00:00
ClientDestination : : ClientDestination ( const i2p : : data : : PrivateKeys & keys , bool isPublic , const std : : map < std : : string , std : : string > * params ) :
2017-11-24 20:37:17 +00:00
LeaseSetDestination ( isPublic , params ) , m_Keys ( keys ) , m_StreamingAckDelay ( DEFAULT_INITIAL_ACK_DELAY ) ,
m_DatagramDestination ( nullptr ) , m_RefCounter ( 0 ) ,
2016-08-30 17:27:57 +00:00
m_ReadyChecker ( GetService ( ) )
2016-05-23 14:33:01 +00:00
{
2017-08-31 16:08:22 +00:00
if ( isPublic )
2016-05-29 13:33:50 +00:00
PersistTemporaryKeys ( ) ;
else
2018-01-06 03:48:51 +00:00
i2p : : data : : PrivateKeys : : GenerateCryptoKeyPair ( GetIdentity ( ) - > GetCryptoKeyType ( ) ,
2017-11-02 20:13:10 +00:00
m_EncryptionPrivateKey , m_EncryptionPublicKey ) ;
2018-01-06 03:48:51 +00:00
m_Decryptor = m_Keys . CreateDecryptor ( m_EncryptionPrivateKey ) ;
2016-05-23 14:33:01 +00:00
if ( isPublic )
LogPrint ( eLogInfo , " Destination: Local address " , GetIdentHash ( ) . ToBase32 ( ) , " created " ) ;
2017-11-24 20:37:17 +00:00
// extract streaming params
2018-01-06 03:48:51 +00:00
if ( params )
2017-11-24 20:37:17 +00:00
{
auto it = params - > find ( I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY ) ;
if ( it ! = params - > end ( ) )
m_StreamingAckDelay = std : : stoi ( it - > second ) ;
}
2017-08-31 16:08:22 +00:00
}
2016-05-23 14:33:01 +00:00
2017-08-31 16:08:22 +00:00
ClientDestination : : ~ ClientDestination ( )
2016-05-23 18:31:22 +00:00
{
2017-08-31 16:08:22 +00:00
}
2016-05-23 18:31:22 +00:00
bool ClientDestination : : Start ( )
{
if ( LeaseSetDestination : : Start ( ) )
2017-08-31 16:08:22 +00:00
{
2016-05-25 20:18:02 +00:00
m_StreamingDestination = std : : make_shared < i2p : : stream : : StreamingDestination > ( GetSharedFromThis ( ) ) ; // TODO:
2017-08-31 16:08:22 +00:00
m_StreamingDestination - > Start ( ) ;
2016-08-05 18:23:54 +00:00
for ( auto & it : m_StreamingDestinationsByPorts )
2016-05-23 18:31:22 +00:00
it . second - > Start ( ) ;
return true ;
2017-08-31 16:08:22 +00:00
}
2016-05-23 18:31:22 +00:00
else
return false ;
2017-08-31 16:08:22 +00:00
}
2016-05-23 18:31:22 +00:00
bool ClientDestination : : Stop ( )
{
if ( LeaseSetDestination : : Stop ( ) )
{
2016-08-30 17:27:57 +00:00
m_ReadyChecker . cancel ( ) ;
2016-05-23 18:31:22 +00:00
m_StreamingDestination - > Stop ( ) ;
2016-12-02 00:23:55 +00:00
//m_StreamingDestination->SetOwner (nullptr);
2016-05-23 18:31:22 +00:00
m_StreamingDestination = nullptr ;
2016-08-05 18:23:54 +00:00
for ( auto & it : m_StreamingDestinationsByPorts )
2017-08-31 16:08:22 +00:00
{
2016-05-23 18:31:22 +00:00
it . second - > Stop ( ) ;
2016-12-02 00:23:55 +00:00
//it.second->SetOwner (nullptr);
2016-11-26 03:36:35 +00:00
}
m_StreamingDestinationsByPorts . clear ( ) ;
if ( m_DatagramDestination )
2017-08-31 16:08:22 +00:00
{
2016-11-26 03:36:35 +00:00
delete m_DatagramDestination ;
m_DatagramDestination = nullptr ;
2017-08-31 16:08:22 +00:00
}
2018-01-06 04:01:44 +00:00
return true ;
2016-05-23 18:31:22 +00:00
}
else
return false ;
2017-08-31 16:08:22 +00:00
}
2016-05-23 18:31:22 +00:00
2016-10-19 14:23:02 +00:00
# ifdef I2LUA
2016-08-30 17:27:57 +00:00
void ClientDestination : : Ready ( ReadyPromise & p )
{
ScheduleCheckForReady ( & p ) ;
}
void ClientDestination : : ScheduleCheckForReady ( ReadyPromise * p )
{
// tick every 100ms
m_ReadyChecker . expires_from_now ( boost : : posix_time : : milliseconds ( 100 ) ) ;
m_ReadyChecker . async_wait ( [ & , p ] ( const boost : : system : : error_code & ecode ) {
HandleCheckForReady ( ecode , p ) ;
} ) ;
}
void ClientDestination : : HandleCheckForReady ( const boost : : system : : error_code & ecode , ReadyPromise * p )
{
if ( ecode ) // error happened
p - > set_value ( nullptr ) ;
else if ( IsReady ( ) ) // we are ready
p - > set_value ( std : : shared_ptr < ClientDestination > ( this ) ) ;
else // we are not ready
ScheduleCheckForReady ( p ) ;
}
2016-10-19 14:23:02 +00:00
# endif
2017-08-31 16:08:22 +00:00
2016-10-10 12:59:48 +00:00
void ClientDestination : : HandleDataMessage ( const uint8_t * buf , size_t len )
2016-05-23 18:31:22 +00:00
{
uint32_t length = bufbe32toh ( buf ) ;
2018-04-29 14:53:04 +00:00
if ( length > len - 4 )
{
LogPrint ( eLogError , " Destination: Data message length " , length , " exceeds buffer length " , len ) ;
return ;
}
2016-05-23 18:31:22 +00:00
buf + = 4 ;
// we assume I2CP payload
uint16_t fromPort = bufbe16toh ( buf + 4 ) , // source
2017-08-31 16:08:22 +00:00
toPort = bufbe16toh ( buf + 6 ) ; // destination
2016-05-23 18:31:22 +00:00
switch ( buf [ 9 ] )
{
case PROTOCOL_TYPE_STREAMING :
{
// streaming protocol
auto dest = GetStreamingDestination ( toPort ) ;
if ( dest )
dest - > HandleDataMessagePayload ( buf , length ) ;
else
LogPrint ( eLogError , " Destination: Missing streaming destination " ) ;
}
break ;
case PROTOCOL_TYPE_DATAGRAM :
// datagram protocol
if ( m_DatagramDestination )
m_DatagramDestination - > HandleDataMessagePayload ( fromPort , toPort , buf , length ) ;
else
LogPrint ( eLogError , " Destination: Missing datagram destination " ) ;
break ;
default :
LogPrint ( eLogError , " Destination: Data: unexpected protocol " , buf [ 9 ] ) ;
}
}
2017-08-31 16:08:22 +00:00
void ClientDestination : : CreateStream ( StreamRequestComplete streamRequestComplete , const i2p : : data : : IdentHash & dest , int port )
2016-05-23 18:31:22 +00:00
{
2017-08-31 16:08:22 +00:00
if ( ! streamRequestComplete )
2016-05-23 18:31:22 +00:00
{
LogPrint ( eLogError , " Destination: request callback is not specified in CreateStream " ) ;
return ;
2017-08-31 16:08:22 +00:00
}
2017-08-31 14:38:26 +00:00
auto leaseSet = FindLeaseSet ( dest ) ;
if ( leaseSet )
streamRequestComplete ( CreateStream ( leaseSet , port ) ) ;
2016-05-23 18:31:22 +00:00
else
{
2017-08-31 14:38:26 +00:00
auto s = GetSharedFromThis ( ) ;
RequestDestination ( dest ,
[ s , streamRequestComplete , port ] ( std : : shared_ptr < i2p : : data : : LeaseSet > ls )
{
if ( ls )
streamRequestComplete ( s - > CreateStream ( ls , port ) ) ;
2016-05-23 18:31:22 +00:00
else
2017-08-31 14:38:26 +00:00
streamRequestComplete ( nullptr ) ;
} ) ;
2016-05-23 18:31:22 +00:00
}
}
std : : shared_ptr < i2p : : stream : : Stream > ClientDestination : : CreateStream ( std : : shared_ptr < const i2p : : data : : LeaseSet > remote , int port )
{
if ( m_StreamingDestination )
return m_StreamingDestination - > CreateNewOutgoingStream ( remote , port ) ;
else
return nullptr ;
}
2017-08-31 16:08:22 +00:00
std : : shared_ptr < i2p : : stream : : StreamingDestination > ClientDestination : : GetStreamingDestination ( int port ) const
{
if ( port )
2016-05-23 18:31:22 +00:00
{
auto it = m_StreamingDestinationsByPorts . find ( port ) ;
if ( it ! = m_StreamingDestinationsByPorts . end ( ) )
return it - > second ;
2017-08-31 16:08:22 +00:00
}
2016-05-23 18:31:22 +00:00
// if port is zero or not found, use default destination
2017-08-31 16:08:22 +00:00
return m_StreamingDestination ;
2016-05-23 18:31:22 +00:00
}
2017-08-31 16:08:22 +00:00
2016-05-23 18:31:22 +00:00
void ClientDestination : : AcceptStreams ( const i2p : : stream : : StreamingDestination : : Acceptor & acceptor )
{
if ( m_StreamingDestination )
m_StreamingDestination - > SetAcceptor ( acceptor ) ;
}
void ClientDestination : : StopAcceptingStreams ( )
{
if ( m_StreamingDestination )
m_StreamingDestination - > ResetAcceptor ( ) ;
}
2017-08-31 16:08:22 +00:00
2016-05-23 18:31:22 +00:00
bool ClientDestination : : IsAcceptingStreams ( ) const
{
if ( m_StreamingDestination )
return m_StreamingDestination - > IsAcceptorSet ( ) ;
return false ;
2017-08-31 16:08:22 +00:00
}
2016-05-23 18:31:22 +00:00
2016-12-24 13:53:35 +00:00
void ClientDestination : : AcceptOnce ( const i2p : : stream : : StreamingDestination : : Acceptor & acceptor )
{
if ( m_StreamingDestination )
m_StreamingDestination - > AcceptOnce ( acceptor ) ;
2017-08-31 16:08:22 +00:00
}
2016-05-23 18:31:22 +00:00
std : : shared_ptr < i2p : : stream : : StreamingDestination > ClientDestination : : CreateStreamingDestination ( int port , bool gzip )
{
2017-08-31 16:08:22 +00:00
auto dest = std : : make_shared < i2p : : stream : : StreamingDestination > ( GetSharedFromThis ( ) , port , gzip ) ;
2016-05-23 18:31:22 +00:00
if ( port )
m_StreamingDestinationsByPorts [ port ] = dest ;
2017-08-31 16:08:22 +00:00
else // update default
2016-05-23 18:31:22 +00:00
m_StreamingDestination = dest ;
return dest ;
2017-08-31 16:08:22 +00:00
}
2016-08-22 02:29:55 +00:00
i2p : : datagram : : DatagramDestination * ClientDestination : : CreateDatagramDestination ( )
2016-05-23 18:31:22 +00:00
{
2016-08-22 01:17:09 +00:00
if ( m_DatagramDestination = = nullptr )
2016-08-22 02:29:55 +00:00
m_DatagramDestination = new i2p : : datagram : : DatagramDestination ( GetSharedFromThis ( ) ) ;
2017-08-31 16:08:22 +00:00
return m_DatagramDestination ;
2016-05-23 18:31:22 +00:00
}
std : : vector < std : : shared_ptr < const i2p : : stream : : Stream > > ClientDestination : : GetAllStreams ( ) const
{
std : : vector < std : : shared_ptr < const i2p : : stream : : Stream > > ret ;
if ( m_StreamingDestination )
{
for ( auto & it : m_StreamingDestination - > GetStreams ( ) )
ret . push_back ( it . second ) ;
2017-08-31 16:08:22 +00:00
}
2016-05-23 18:31:22 +00:00
for ( auto & it : m_StreamingDestinationsByPorts )
for ( auto & it1 : it . second - > GetStreams ( ) )
ret . push_back ( it1 . second ) ;
return ret ;
2017-08-31 16:08:22 +00:00
}
2016-05-29 13:33:50 +00:00
void ClientDestination : : PersistTemporaryKeys ( )
{
std : : string ident = GetIdentHash ( ) . ToBase32 ( ) ;
std : : string path = i2p : : fs : : DataDirPath ( " destinations " , ( ident + " .dat " ) ) ;
std : : ifstream f ( path , std : : ifstream : : binary ) ;
if ( f ) {
f . read ( ( char * ) m_EncryptionPublicKey , 256 ) ;
f . read ( ( char * ) m_EncryptionPrivateKey , 256 ) ;
return ;
}
LogPrint ( eLogInfo , " Destination: Creating new temporary keys for address " , ident , " .b32.i2p " ) ;
2018-01-06 03:48:51 +00:00
i2p : : data : : PrivateKeys : : GenerateCryptoKeyPair ( GetIdentity ( ) - > GetCryptoKeyType ( ) ,
2017-11-12 22:31:00 +00:00
m_EncryptionPrivateKey , m_EncryptionPublicKey ) ;
2016-05-29 13:33:50 +00:00
std : : ofstream f1 ( path , std : : ofstream : : binary | std : : ofstream : : out ) ;
if ( f1 ) {
f1 . write ( ( char * ) m_EncryptionPublicKey , 256 ) ;
f1 . write ( ( char * ) m_EncryptionPrivateKey , 256 ) ;
return ;
}
LogPrint ( eLogError , " Destinations: Can't save keys to " , path ) ;
2017-08-31 16:08:22 +00:00
}
2016-05-29 13:33:50 +00:00
void ClientDestination : : CreateNewLeaseSet ( std : : vector < std : : shared_ptr < i2p : : tunnel : : InboundTunnel > > tunnels )
{
auto leaseSet = new i2p : : data : : LocalLeaseSet ( GetIdentity ( ) , m_EncryptionPublicKey , tunnels ) ;
// sign
Sign ( leaseSet - > GetBuffer ( ) , leaseSet - > GetBufferLen ( ) - leaseSet - > GetSignatureLen ( ) , leaseSet - > GetSignature ( ) ) ; // TODO
SetLeaseSet ( leaseSet ) ;
2017-08-31 16:08:22 +00:00
}
2016-09-08 14:16:42 +00:00
void ClientDestination : : CleanupDestination ( )
{
if ( m_DatagramDestination ) m_DatagramDestination - > CleanUp ( ) ;
}
2017-11-09 01:45:53 +00:00
bool ClientDestination : : Decrypt ( const uint8_t * encrypted , uint8_t * data , BN_CTX * ctx ) const
2017-11-08 18:49:48 +00:00
{
if ( m_Decryptor )
2018-03-09 19:56:06 +00:00
return m_Decryptor - > Decrypt ( encrypted , data , ctx , true ) ;
2017-11-08 18:49:48 +00:00
else
LogPrint ( eLogError , " Destinations: decryptor is not set " ) ;
2017-11-09 01:45:53 +00:00
return false ;
2017-11-08 18:49:48 +00:00
}
2014-10-16 16:37:39 +00:00
}
2014-10-05 12:54:59 +00:00
}