2020-05-22 13:18:41 +00:00
/*
* Copyright ( c ) 2013 - 2020 , The PurpleI2P Project
*
* 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-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>
2020-04-15 22:01:01 +00:00
# include <set>
# include <vector>
# include <boost/algorithm/string.hpp>
2016-05-11 19:12:38 +00:00
# include "Crypto.h"
2020-09-30 23:06:13 +00:00
# include "Config.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"
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
{
2020-02-02 23:58:58 +00:00
LeaseSetDestination : : LeaseSetDestination ( boost : : asio : : io_service & service ,
2020-03-01 10:25:50 +00:00
bool isPublic , const std : : map < std : : string , std : : string > * params ) :
m_Service ( service ) , m_IsPublic ( isPublic ) , m_PublishReplyToken ( 0 ) ,
2020-02-02 23:58:58 +00:00
m_LastSubmissionTime ( 0 ) , m_PublishConfirmationTimer ( m_Service ) ,
2019-01-11 18:58:02 +00:00
m_PublishVerificationTimer ( m_Service ) , m_PublishDelayTimer ( m_Service ) , m_CleanupTimer ( m_Service ) ,
2019-09-06 15:02:19 +00:00
m_LeaseSetType ( DEFAULT_LEASESET_TYPE ) , m_AuthType ( i2p : : data : : ENCRYPTED_LEASESET_AUTH_TYPE_NONE )
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 " ) ;
2020-06-13 00:42:54 +00:00
it = params - > find ( I2CP_PARAM_RATCHET_INBOUND_TAGS ) ;
if ( it ! = params - > end ( ) )
SetNumRatchetInboundTags ( std : : stoi ( it - > second ) ) ;
2016-10-26 00:00:00 +00:00
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 ;
2018-07-10 09:39:21 +00:00
// otherwise we set default nickname in Start when we know local address
2017-12-20 16:38:35 +00:00
}
2019-01-11 18:58:02 +00:00
it = params - > find ( I2CP_PARAM_LEASESET_TYPE ) ;
if ( it ! = params - > end ( ) )
m_LeaseSetType = std : : stoi ( it - > second ) ;
2019-09-06 15:02:19 +00:00
if ( m_LeaseSetType = = i2p : : data : : NETDB_STORE_TYPE_ENCRYPTED_LEASESET2 )
{
// authentication for encrypted LeaseSet
it = params - > find ( I2CP_PARAM_LEASESET_AUTH_TYPE ) ;
if ( it ! = params - > end ( ) )
{
auto authType = std : : stoi ( it - > second ) ;
if ( authType > = i2p : : data : : ENCRYPTED_LEASESET_AUTH_TYPE_NONE & & authType < = i2p : : data : : ENCRYPTED_LEASESET_AUTH_TYPE_PSK )
m_AuthType = authType ;
else
LogPrint ( eLogError , " Destination: Unknown auth type " , authType ) ;
}
}
2019-06-07 18:51:08 +00:00
it = params - > find ( I2CP_PARAM_LEASESET_PRIV_KEY ) ;
if ( it ! = params - > end ( ) )
{
m_LeaseSetPrivKey . reset ( new i2p : : data : : Tag < 32 > ( ) ) ;
if ( m_LeaseSetPrivKey - > FromBase64 ( it - > second ) ! = 32 )
{
LogPrint ( eLogError , " Destination: invalid value i2cp.leaseSetPrivKey " , it - > second ) ;
m_LeaseSetPrivKey . reset ( nullptr ) ;
}
}
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
{
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
2020-02-02 23:58:58 +00:00
void LeaseSetDestination : : Start ( )
2014-10-09 14:05:28 +00:00
{
2020-02-02 23:58:58 +00:00
if ( m_Nickname . empty ( ) )
m_Nickname = i2p : : data : : GetIdentHashAbbreviation ( GetIdentHash ( ) ) ; // set default nickname
LoadTags ( ) ;
m_Pool - > SetLocalDestination ( shared_from_this ( ) ) ;
m_Pool - > SetActive ( true ) ;
m_CleanupTimer . expires_from_now ( boost : : posix_time : : minutes ( DESTINATION_CLEANUP_TIMEOUT ) ) ;
m_CleanupTimer . async_wait ( std : : bind ( & LeaseSetDestination : : HandleCleanupTimer ,
shared_from_this ( ) , std : : placeholders : : _1 ) ) ;
2014-10-09 14:05:28 +00:00
}
2017-08-31 16:08:22 +00:00
2020-02-02 23:58:58 +00:00
void LeaseSetDestination : : Stop ( )
2017-08-31 16:08:22 +00:00
{
2020-02-02 23:58:58 +00:00
m_CleanupTimer . cancel ( ) ;
m_PublishConfirmationTimer . cancel ( ) ;
m_PublishVerificationTimer . cancel ( ) ;
if ( m_Pool )
2017-08-31 16:08:22 +00:00
{
2020-02-02 23:58:58 +00:00
m_Pool - > SetLocalDestination ( nullptr ) ;
i2p : : tunnel : : tunnels . StopTunnelPool ( m_Pool ) ;
2017-08-31 16:08:22 +00:00
}
2020-02-02 23:58:58 +00:00
SaveTags ( ) ;
CleanUp ( ) ; // GarlicDestination
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 " ;
}
2020-03-01 10:25:50 +00:00
2018-01-02 16:34:58 +00:00
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 ;
2020-03-01 10:25:50 +00:00
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 ) ;
}
2020-03-01 10:25:50 +00:00
2019-03-27 20:04:46 +00:00
std : : shared_ptr < 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 ( ) ;
2019-04-10 16:04:19 +00:00
auto ls = GetLeaseSetMt ( ) ;
return ( ls & & ls - > GetInnerLeaseSet ( ) ) ? ls - > GetInnerLeaseSet ( ) : ls ; // always non-encrypted
2019-03-10 13:22:42 +00:00
}
std : : shared_ptr < const i2p : : data : : LocalLeaseSet > LeaseSetDestination : : GetLeaseSetMt ( )
{
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
}
2020-03-01 10:25:50 +00:00
2019-03-10 13:22:42 +00:00
void LeaseSetDestination : : SetLeaseSet ( std : : shared_ptr < const i2p : : data : : LocalLeaseSet > newLeaseSet )
2016-05-29 13:33:50 +00:00
{
2017-08-31 16:08:22 +00:00
{
2016-10-25 18:07:34 +00:00
std : : lock_guard < std : : mutex > l ( m_LeaseSetMutex ) ;
2019-03-10 13:22:42 +00:00
m_LeaseSet = newLeaseSet ;
2016-10-25 18:07:34 +00:00
}
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 ( ) ;
2020-03-01 10:25:50 +00:00
} ) ;
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
{
2020-01-06 19:37:40 +00:00
uint32_t msgID = bufbe32toh ( msg - > GetPayload ( ) + DELIVERY_STATUS_MSGID_OFFSET ) ;
m_Service . post ( std : : bind ( & LeaseSetDestination : : HandleDeliveryStatusMessage , shared_from_this ( ) , msgID ) ) ;
2014-10-16 16:37:39 +00:00
}
2020-01-07 20:20:55 +00:00
void LeaseSetDestination : : HandleI2NPMessage ( const uint8_t * buf , size_t len )
2014-10-16 16:37:39 +00:00
{
2020-01-16 17:47:08 +00:00
I2NPMessageType typeID = ( I2NPMessageType ) ( buf [ I2NP_HEADER_TYPEID_OFFSET ] ) ;
2020-01-07 20:20:55 +00:00
LeaseSetDestination : : HandleCloveI2NPMessage ( typeID , buf + I2NP_HEADER_SIZE , GetI2NPMessageLength ( buf , len ) - I2NP_HEADER_SIZE ) ;
2020-01-06 20:31:20 +00:00
}
2020-01-16 17:47:08 +00:00
bool LeaseSetDestination : : HandleCloveI2NPMessage ( I2NPMessageType typeID , const uint8_t * payload , size_t len )
2020-01-06 20:31:20 +00:00
{
2015-01-02 04:00:33 +00:00
switch ( typeID )
2017-08-31 16:08:22 +00:00
{
2014-10-16 16:37:39 +00:00
case eI2NPData :
2020-01-06 20:31:20 +00:00
HandleDataMessage ( payload , len ) ;
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
2020-01-06 20:31:20 +00:00
HandleDeliveryStatusMessage ( bufbe32toh ( payload + DELIVERY_STATUS_MSGID_OFFSET ) ) ;
2017-08-31 16:08:22 +00:00
break ;
2014-10-16 16:37:39 +00:00
case eI2NPDatabaseStore :
2020-01-06 20:31:20 +00:00
HandleDatabaseStoreMessage ( payload , len ) ;
2014-12-25 21:47:15 +00:00
break ;
case eI2NPDatabaseSearchReply :
2020-01-06 20:31:20 +00:00
HandleDatabaseSearchReplyMessage ( payload , len ) ;
2017-08-31 16:08:22 +00:00
break ;
2014-10-16 16:37:39 +00:00
default :
2020-01-07 20:20:55 +00:00
LogPrint ( eLogWarning , " Destination: Unexpected I2NP message type " , typeID ) ;
2020-01-06 20:31:20 +00:00
return false ;
2017-08-31 16:08:22 +00:00
}
2020-01-06 20:31:20 +00:00
return true ;
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 ;
2019-03-07 19:52:59 +00:00
switch ( buf [ DATABASE_STORE_TYPE_OFFSET ] )
2014-10-16 16:37:39 +00:00
{
2019-03-07 19:52:59 +00:00
case i2p : : data : : NETDB_STORE_TYPE_LEASESET : // 1
case i2p : : data : : NETDB_STORE_TYPE_STANDARD_LEASESET2 : // 3
2014-10-16 16:37:39 +00:00
{
2019-03-07 19:52:59 +00:00
LogPrint ( eLogDebug , " Destination: Remote LeaseSet " ) ;
std : : lock_guard < std : : mutex > lock ( m_RemoteLeaseSetsMutex ) ;
auto it = m_RemoteLeaseSets . find ( key ) ;
2020-12-17 23:58:30 +00:00
if ( it ! = m_RemoteLeaseSets . end ( ) & &
it - > second - > GetStoreType ( ) = = buf [ DATABASE_STORE_TYPE_OFFSET ] ) // update only if same type
2017-08-31 16:08:22 +00:00
{
2019-03-07 19:52:59 +00:00
leaseSet = it - > second ;
if ( leaseSet - > IsNewer ( buf + offset , len - offset ) )
{
leaseSet - > Update ( buf + offset , len - offset ) ;
if ( leaseSet - > IsValid ( ) & & leaseSet - > GetIdentHash ( ) = = key )
LogPrint ( eLogDebug , " Destination: Remote LeaseSet updated " ) ;
else
{
LogPrint ( eLogDebug , " Destination: Remote LeaseSet update failed " ) ;
m_RemoteLeaseSets . erase ( it ) ;
leaseSet = nullptr ;
}
}
else
LogPrint ( eLogDebug , " Destination: Remote LeaseSet is older. Not updated " ) ;
}
else
{
2020-12-17 23:58:30 +00:00
// add or replace
2019-03-07 19:52:59 +00:00
if ( buf [ DATABASE_STORE_TYPE_OFFSET ] = = i2p : : data : : NETDB_STORE_TYPE_LEASESET )
leaseSet = std : : make_shared < i2p : : data : : LeaseSet > ( buf + offset , len - offset ) ; // LeaseSet
else
2020-03-19 22:33:42 +00:00
leaseSet = std : : make_shared < i2p : : data : : LeaseSet2 > ( buf [ DATABASE_STORE_TYPE_OFFSET ] , buf + offset , len - offset , true , GetPreferredCryptoType ( ) ) ; // LeaseSet2
2016-11-07 23:32:22 +00:00
if ( leaseSet - > IsValid ( ) & & leaseSet - > GetIdentHash ( ) = = key )
2019-03-07 19:52:59 +00:00
{
if ( leaseSet - > GetIdentHash ( ) ! = GetIdentHash ( ) )
{
LogPrint ( eLogDebug , " Destination: New remote LeaseSet added " ) ;
m_RemoteLeaseSets [ key ] = leaseSet ;
}
else
LogPrint ( eLogDebug , " Destination: Own remote LeaseSet dropped " ) ;
}
2016-02-17 03:57:38 +00:00
else
{
2019-03-07 19:52:59 +00:00
LogPrint ( eLogError , " Destination: New remote LeaseSet failed " ) ;
2016-02-17 03:57:38 +00:00
leaseSet = nullptr ;
}
2015-04-08 14:34:16 +00:00
}
2019-03-07 19:52:59 +00:00
break ;
2014-10-16 16:37:39 +00:00
}
2019-03-07 19:52:59 +00:00
case i2p : : data : : NETDB_STORE_TYPE_ENCRYPTED_LEASESET2 : // 5
2017-08-31 16:08:22 +00:00
{
2019-03-07 19:52:59 +00:00
auto it2 = m_LeaseSetRequests . find ( key ) ;
2019-03-22 19:32:13 +00:00
if ( it2 ! = m_LeaseSetRequests . end ( ) & & it2 - > second - > requestedBlindedKey )
2015-04-08 14:34:16 +00:00
{
2020-05-06 14:08:01 +00:00
auto ls2 = std : : make_shared < i2p : : data : : LeaseSet2 > ( buf + offset , len - offset ,
2020-05-06 18:08:54 +00:00
it2 - > second - > requestedBlindedKey , m_LeaseSetPrivKey ? ( ( const uint8_t * ) * m_LeaseSetPrivKey ) : nullptr , GetPreferredCryptoType ( ) ) ;
2019-03-07 19:52:59 +00:00
if ( ls2 - > IsValid ( ) )
2016-02-11 19:45:33 +00:00
{
2019-03-07 19:52:59 +00:00
m_RemoteLeaseSets [ ls2 - > GetIdentHash ( ) ] = ls2 ; // ident is not key
2019-03-27 20:04:46 +00:00
m_RemoteLeaseSets [ key ] = ls2 ; // also store as key for next lookup
2019-03-07 19:52:59 +00:00
leaseSet = ls2 ;
2016-02-11 19:45:33 +00:00
}
2015-04-08 14:34:16 +00:00
}
else
2019-03-07 19:52:59 +00:00
LogPrint ( eLogInfo , " Destination: Couldn't find request for encrypted LeaseSet2 " ) ;
break ;
2017-08-31 16:08:22 +00:00
}
2019-03-07 19:52:59 +00:00
default :
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 + + )
{
2020-10-03 21:20:04 +00:00
i2p : : data : : IdentHash peerHash ( buf + 33 + i * 32 ) ;
if ( ! request - > excluded . count ( peerHash ) & & ! i2p : : data : : netdb . FindRouter ( peerHash ) )
{
LogPrint ( eLogInfo , " Destination: Found new floodfill, request it " ) ;
i2p : : data : : netdb . RequestDestination ( peerHash , nullptr , false ) ; // through exploratory
}
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
}
2020-01-06 19:37:40 +00:00
void LeaseSetDestination : : HandleDeliveryStatusMessage ( uint32_t msgID )
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
2020-01-06 19:37:40 +00:00
i2p : : garlic : : GarlicDestination : : HandleDeliveryStatusMessage ( msgID ) ;
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
{
2019-03-10 13:22:42 +00:00
auto leaseSet = GetLeaseSetMt ( ) ;
if ( ! 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 ;
}
2019-03-10 13:22:42 +00:00
auto floodfill = i2p : : data : : netdb . GetClosestFloodfill ( 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 ) ;
2020-12-12 22:14:58 +00:00
auto msg = WrapMessageForRouter ( floodfill , i2p : : CreateDatabaseStoreMsg ( 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 )
{
2020-03-01 10:25:50 +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
{
2020-03-01 10:25:50 +00:00
LogPrint ( eLogWarning , " Destination: Publish confirmation was not received in " , PUBLISH_CONFIRMATION_TIMEOUT , " seconds from Java floodfill for crypto type " , ( int ) GetIdentity ( ) - > GetCryptoKeyType ( ) ) ;
2019-04-08 19:22:42 +00:00
// Java floodfill never sends confirmation back for unknown crypto type
2017-11-17 19:28:48 +00:00
// 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
{
2019-04-10 16:04:19 +00:00
auto ls = GetLeaseSetMt ( ) ;
if ( ! ls )
{
LogPrint ( eLogWarning , " Destination: couldn't verify LeaseSet for " , GetIdentHash ( ) . ToBase32 ( ) ) ;
return ;
2020-03-01 10:25:50 +00:00
}
2016-02-11 19:45:33 +00:00
auto s = shared_from_this ( ) ;
2019-04-10 16:04:19 +00:00
RequestLeaseSet ( ls - > GetStoreHash ( ) ,
2020-09-26 23:32:19 +00:00
[ s , ls ] ( std : : shared_ptr < const 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
{
2019-04-10 16:04:19 +00:00
if ( * ls = = * leaseSet )
2017-02-12 15:08:52 +00:00
{
// we got latest LeasetSet
2019-04-10 16:04:19 +00:00
LogPrint ( eLogDebug , " Destination: published LeaseSet verified for " , s - > GetIdentHash ( ) . ToBase32 ( ) ) ;
2017-02-12 15:08:52 +00:00
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
2019-04-10 16:04:19 +00:00
LogPrint ( eLogDebug , " Destination: LeaseSet is different than just published for " , s - > GetIdentHash ( ) . ToBase32 ( ) ) ;
2017-08-31 16:08:22 +00:00
}
2016-02-11 19:45:33 +00:00
else
2019-04-10 16:04:19 +00:00
LogPrint ( eLogWarning , " Destination: couldn't find published LeaseSet for " , s - > 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
}
2019-03-07 19:52:59 +00:00
m_Service . post ( std : : bind ( & LeaseSetDestination : : RequestLeaseSet , shared_from_this ( ) , dest , requestComplete , nullptr ) ) ;
return true ;
}
2019-03-27 20:04:46 +00:00
bool LeaseSetDestination : : RequestDestinationWithEncryptedLeaseSet ( std : : shared_ptr < const i2p : : data : : BlindedPublicKey > dest , RequestComplete requestComplete )
2019-03-07 19:52:59 +00:00
{
2019-04-02 20:32:18 +00:00
if ( ! dest | | ! m_Pool | | ! IsReady ( ) )
2019-03-07 19:52:59 +00:00
{
if ( requestComplete )
m_Service . post ( [ requestComplete ] ( void ) { requestComplete ( nullptr ) ; } ) ;
return false ;
2020-03-01 10:25:50 +00:00
}
2019-04-02 20:32:18 +00:00
auto storeHash = dest - > GetStoreHash ( ) ;
2020-03-01 10:25:50 +00:00
auto leaseSet = FindLeaseSet ( storeHash ) ;
2019-03-27 20:04:46 +00:00
if ( leaseSet )
{
if ( requestComplete )
m_Service . post ( [ requestComplete , leaseSet ] ( void ) { requestComplete ( leaseSet ) ; } ) ;
return true ;
}
2019-04-02 20:32:18 +00:00
m_Service . post ( std : : bind ( & LeaseSetDestination : : RequestLeaseSet , shared_from_this ( ) , storeHash , requestComplete , dest ) ) ;
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
2019-03-27 20:04:46 +00:00
void LeaseSetDestination : : CancelDestinationRequestWithEncryptedLeaseSet ( std : : shared_ptr < const i2p : : data : : BlindedPublicKey > dest , bool notify )
2019-03-07 19:52:59 +00:00
{
2019-04-02 20:32:18 +00:00
if ( dest )
CancelDestinationRequest ( dest - > GetStoreHash ( ) , notify ) ;
2019-03-07 19:52:59 +00:00
}
2019-03-22 19:32:13 +00:00
void LeaseSetDestination : : RequestLeaseSet ( const i2p : : data : : IdentHash & dest , RequestComplete requestComplete , std : : shared_ptr < const i2p : : data : : BlindedPublicKey > requestedBlindedKey )
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 ) ;
2019-03-22 19:32:13 +00:00
request - > requestedBlindedKey = requestedBlindedKey ; // for encrypted LeaseSet2
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 ,
2020-03-01 10:25:50 +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 ( ) ;
2020-11-14 23:28:50 +00:00
bool isECIES = SupportsEncryptionType ( i2p : : data : : CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ) & &
2020-09-20 01:15:42 +00:00
nextFloodfill - > GetVersion ( ) > = MAKE_VERSION_NUMBER ( 0 , 9 , 46 ) ; // >= 0.9.46;
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
2020-09-20 01:15:42 +00:00
RAND_bytes ( replyTag , isECIES ? 8 : 32 ) ; // random session tag
if ( isECIES )
AddECIESx25519Key ( replyKey , replyTag ) ;
else
AddSessionKey ( replyKey , replyTag ) ;
2020-12-12 22:14:58 +00:00
auto msg = WrapMessageForRouter ( nextFloodfill , CreateLeaseSetDatabaseLookupMsg ( dest ,
request - > excluded , request - > replyTunnel , replyKey , replyTag , isECIES ) ) ;
2016-02-26 21:17:29 +00:00
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
{
2020-03-01 10:25:50 +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
2020-03-19 22:33:42 +00:00
i2p : : data : : CryptoKeyType LeaseSetDestination : : GetPreferredCryptoType ( ) const
{
2020-11-14 23:28:50 +00:00
if ( SupportsEncryptionType ( i2p : : data : : CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ) )
return i2p : : data : : CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ;
2020-03-01 10:25:50 +00:00
return i2p : : data : : CRYPTO_KEY_TYPE_ELGAMAL ;
}
ClientDestination : : ClientDestination ( boost : : asio : : io_service & service , const i2p : : data : : PrivateKeys & keys ,
2020-02-04 19:17:23 +00:00
bool isPublic , const std : : map < std : : string , std : : string > * params ) :
2020-09-30 21:12:28 +00:00
LeaseSetDestination ( service , isPublic , params ) ,
m_Keys ( keys ) , m_StreamingAckDelay ( DEFAULT_INITIAL_ACK_DELAY ) ,
m_IsStreamingAnswerPings ( DEFAULT_ANSWER_PINGS ) ,
2017-11-24 20:37:17 +00:00
m_DatagramDestination ( nullptr ) , m_RefCounter ( 0 ) ,
2020-02-04 19:17:23 +00:00
m_ReadyChecker ( service )
2016-05-23 14:33:01 +00:00
{
2019-02-12 19:56:39 +00:00
if ( keys . IsOfflineSignature ( ) & & GetLeaseSetType ( ) = = i2p : : data : : NETDB_STORE_TYPE_LEASESET )
SetLeaseSetType ( i2p : : data : : NETDB_STORE_TYPE_STANDARD_LEASESET2 ) ; // offline keys can be published with LS2 only
2019-01-15 20:43:21 +00:00
// extract encryption type params for LS2
2020-04-15 22:01:01 +00:00
std : : set < i2p : : data : : CryptoKeyType > encryptionKeyTypes ;
2020-09-10 23:27:29 +00:00
if ( params )
2019-01-15 20:43:21 +00:00
{
auto it = params - > find ( I2CP_PARAM_LEASESET_ENCRYPTION_TYPE ) ;
if ( it ! = params - > end ( ) )
2020-04-15 22:01:01 +00:00
{
// comma-separated values
std : : vector < std : : string > values ;
boost : : split ( values , it - > second , boost : : is_any_of ( " , " ) ) ;
for ( auto & it1 : values )
{
try
{
encryptionKeyTypes . insert ( std : : stoi ( it1 ) ) ;
}
catch ( std : : exception & ex )
{
LogPrint ( eLogInfo , " Destination: Unexpected crypto type " , it1 , " . " , ex . what ( ) ) ;
continue ;
2020-03-01 10:25:50 +00:00
}
}
}
}
// if no param or valid crypto type use from identity
bool isSingleKey = false ;
if ( encryptionKeyTypes . empty ( ) )
2020-04-16 02:04:18 +00:00
{
isSingleKey = true ;
encryptionKeyTypes . insert ( GetIdentity ( ) - > GetCryptoKeyType ( ) ) ;
2020-03-01 10:25:50 +00:00
}
2020-04-15 22:01:01 +00:00
for ( auto & it : encryptionKeyTypes )
2020-03-01 10:25:50 +00:00
{
2020-04-15 22:01:01 +00:00
auto encryptionKey = new EncryptionKey ( it ) ;
2020-03-01 10:25:50 +00:00
if ( isPublic )
2020-04-16 02:04:18 +00:00
PersistTemporaryKeys ( encryptionKey , isSingleKey ) ;
2020-04-15 22:01:01 +00:00
else
encryptionKey - > GenerateKeys ( ) ;
2020-03-01 10:25:50 +00:00
encryptionKey - > CreateDecryptor ( ) ;
2020-11-14 23:28:50 +00:00
if ( it = = i2p : : data : : CRYPTO_KEY_TYPE_ECIES_X25519_AEAD )
2020-06-05 19:41:30 +00:00
{
2020-04-15 22:01:01 +00:00
m_ECIESx25519EncryptionKey . reset ( encryptionKey ) ;
2020-06-05 19:41:30 +00:00
if ( GetLeaseSetType ( ) = = i2p : : data : : NETDB_STORE_TYPE_LEASESET )
SetLeaseSetType ( i2p : : data : : NETDB_STORE_TYPE_STANDARD_LEASESET2 ) ; // Rathets must use LeaseSet2
}
2020-04-15 22:01:01 +00:00
else
2020-03-01 10:25:50 +00:00
m_StandardEncryptionKey . reset ( encryptionKey ) ;
}
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
2019-07-16 20:31:17 +00:00
try
2020-03-01 10:25:50 +00:00
{
2019-07-16 20:31:17 +00:00
if ( params )
{
// extract streaming params
auto it = params - > find ( I2CP_PARAM_STREAMING_INITIAL_ACK_DELAY ) ;
if ( it ! = params - > end ( ) )
m_StreamingAckDelay = std : : stoi ( it - > second ) ;
2020-09-30 21:12:28 +00:00
it = params - > find ( I2CP_PARAM_STREAMING_ANSWER_PINGS ) ;
if ( it ! = params - > end ( ) )
2020-09-30 23:06:13 +00:00
i2p : : config : : GetOption ( it - > second , m_IsStreamingAnswerPings ) ;
2020-09-30 21:12:28 +00:00
2019-07-16 20:31:17 +00:00
if ( GetLeaseSetType ( ) = = i2p : : data : : NETDB_STORE_TYPE_ENCRYPTED_LEASESET2 )
{
// authentication for encrypted LeaseSet
2019-09-06 15:02:19 +00:00
auto authType = GetAuthType ( ) ;
if ( authType > 0 )
2019-07-16 20:31:17 +00:00
{
m_AuthKeys = std : : make_shared < std : : vector < i2p : : data : : AuthPublicKey > > ( ) ;
2019-09-06 15:02:19 +00:00
if ( authType = = i2p : : data : : ENCRYPTED_LEASESET_AUTH_TYPE_DH )
2020-03-01 10:25:50 +00:00
ReadAuthKey ( I2CP_PARAM_LEASESET_CLIENT_DH , params ) ;
2019-09-06 15:02:19 +00:00
else if ( authType = = i2p : : data : : ENCRYPTED_LEASESET_AUTH_TYPE_PSK )
2020-03-01 10:25:50 +00:00
ReadAuthKey ( I2CP_PARAM_LEASESET_CLIENT_PSK , params ) ;
2019-07-16 20:31:17 +00:00
else
2019-09-06 15:02:19 +00:00
LogPrint ( eLogError , " Destination: Unexpected auth type " , authType ) ;
2019-07-16 20:31:17 +00:00
if ( m_AuthKeys - > size ( ) )
LogPrint ( eLogInfo , " Destination: " , m_AuthKeys - > size ( ) , " auth keys read " ) ;
else
{
2019-09-06 15:02:19 +00:00
LogPrint ( eLogError , " Destination: No auth keys read for auth type " , authType ) ;
2020-03-01 10:25:50 +00:00
m_AuthKeys = nullptr ;
2019-07-16 20:31:17 +00:00
}
}
}
}
}
catch ( std : : exception & ex )
2017-11-24 20:37:17 +00:00
{
2019-07-16 20:31:17 +00:00
LogPrint ( eLogError , " Destination: unable to parse parameters for destination: " , ex . what ( ) ) ;
2017-11-24 20:37:17 +00:00
}
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
}
2020-02-02 23:58:58 +00:00
void ClientDestination : : Start ( )
2016-05-23 18:31:22 +00:00
{
2020-02-04 19:17:23 +00:00
LeaseSetDestination : : Start ( ) ;
m_StreamingDestination = std : : make_shared < i2p : : stream : : StreamingDestination > ( GetSharedFromThis ( ) ) ; // TODO:
m_StreamingDestination - > Start ( ) ;
for ( auto & it : m_StreamingDestinationsByPorts )
it . second - > Start ( ) ;
2017-08-31 16:08:22 +00:00
}
2020-02-02 23:58:58 +00:00
void ClientDestination : : Stop ( )
2016-05-23 18:31:22 +00:00
{
2020-02-04 19:17:23 +00:00
LeaseSetDestination : : Stop ( ) ;
m_ReadyChecker . cancel ( ) ;
m_StreamingDestination - > Stop ( ) ;
//m_StreamingDestination->SetOwner (nullptr);
m_StreamingDestination = nullptr ;
for ( auto & it : m_StreamingDestinationsByPorts )
2016-05-23 18:31:22 +00:00
{
2020-02-04 19:17:23 +00:00
it . second - > Stop ( ) ;
//it.second->SetOwner (nullptr);
}
m_StreamingDestinationsByPorts . clear ( ) ;
if ( m_DatagramDestination )
{
delete m_DatagramDestination ;
m_DatagramDestination = nullptr ;
2016-05-23 18:31:22 +00:00
}
2017-08-31 16:08:22 +00:00
}
2016-05-23 18:31: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 ;
2019-07-10 01:33:55 +00:00
case PROTOCOL_TYPE_RAW :
// raw datagram
if ( m_DatagramDestination )
m_DatagramDestination - > HandleDataMessagePayload ( fromPort , toPort , buf , length , true ) ;
else
LogPrint ( eLogError , " Destination: Missing raw datagram destination " ) ;
2020-03-01 10:25:50 +00:00
break ;
2016-05-23 18:31:22 +00:00
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 ,
2019-03-27 20:04:46 +00:00
[ s , streamRequestComplete , port ] ( std : : shared_ptr < const i2p : : data : : LeaseSet > ls )
2017-08-31 14:38:26 +00:00
{
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
}
}
2019-03-27 20:04:46 +00:00
void ClientDestination : : CreateStream ( StreamRequestComplete streamRequestComplete , std : : shared_ptr < const i2p : : data : : BlindedPublicKey > dest , int port )
{
if ( ! streamRequestComplete )
{
LogPrint ( eLogError , " Destination: request callback is not specified in CreateStream " ) ;
return ;
}
auto s = GetSharedFromThis ( ) ;
RequestDestinationWithEncryptedLeaseSet ( dest ,
[ s , streamRequestComplete , port ] ( std : : shared_ptr < i2p : : data : : LeaseSet > ls )
{
if ( ls )
streamRequestComplete ( s - > CreateStream ( ls , port ) ) ;
else
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
}
2020-03-01 10:25:50 +00:00
i2p : : datagram : : DatagramDestination * ClientDestination : : CreateDatagramDestination ( bool gzip )
2016-05-23 18:31:22 +00:00
{
2016-08-22 01:17:09 +00:00
if ( m_DatagramDestination = = nullptr )
2020-05-18 16:01:13 +00:00
m_DatagramDestination = new i2p : : datagram : : DatagramDestination ( GetSharedFromThis ( ) , gzip ) ;
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
2020-04-16 02:04:18 +00:00
void ClientDestination : : PersistTemporaryKeys ( EncryptionKey * keys , bool isSingleKey )
2016-05-29 13:33:50 +00:00
{
2020-04-16 02:04:18 +00:00
if ( ! keys ) return ;
2016-05-29 13:33:50 +00:00
std : : string ident = GetIdentHash ( ) . ToBase32 ( ) ;
2020-03-01 10:25:50 +00:00
std : : string path = i2p : : fs : : DataDirPath ( " destinations " ,
2020-04-16 02:04:18 +00:00
isSingleKey ? ( ident + " .dat " ) : ( ident + " . " + std : : to_string ( keys - > keyType ) + " .dat " ) ) ;
2016-05-29 13:33:50 +00:00
std : : ifstream f ( path , std : : ifstream : : binary ) ;
if ( f ) {
2020-04-14 23:12:44 +00:00
f . read ( ( char * ) keys - > pub , 256 ) ;
f . read ( ( char * ) keys - > priv , 256 ) ;
2016-05-29 13:33:50 +00:00
return ;
}
2019-01-15 23:41:00 +00:00
LogPrint ( eLogInfo , " Destination: Creating new temporary keys of type for address " , ident , " .b32.i2p " ) ;
2020-04-14 23:12:44 +00:00
memset ( keys - > priv , 0 , 256 ) ;
2020-03-01 10:25:50 +00:00
memset ( keys - > pub , 0 , 256 ) ;
2020-04-14 23:12:44 +00:00
keys - > GenerateKeys ( ) ;
2020-01-12 15:03:30 +00:00
// TODO:: persist crypto key type
2016-05-29 13:33:50 +00:00
std : : ofstream f1 ( path , std : : ofstream : : binary | std : : ofstream : : out ) ;
if ( f1 ) {
2020-03-01 10:25:50 +00:00
f1 . write ( ( char * ) keys - > pub , 256 ) ;
2020-04-14 23:12:44 +00:00
f1 . write ( ( char * ) keys - > priv , 256 ) ;
2016-05-29 13:33:50 +00:00
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 )
{
2019-03-10 13:22:42 +00:00
std : : shared_ptr < i2p : : data : : LocalLeaseSet > leaseSet ;
2019-01-11 18:58:02 +00:00
if ( GetLeaseSetType ( ) = = i2p : : data : : NETDB_STORE_TYPE_LEASESET )
{
2020-04-14 23:12:44 +00:00
if ( m_StandardEncryptionKey )
2020-03-01 10:25:50 +00:00
{
2020-04-14 23:12:44 +00:00
leaseSet = std : : make_shared < i2p : : data : : LocalLeaseSet > ( GetIdentity ( ) , m_StandardEncryptionKey - > pub , tunnels ) ;
// sign
2020-03-01 10:25:50 +00:00
Sign ( leaseSet - > GetBuffer ( ) , leaseSet - > GetBufferLen ( ) - leaseSet - > GetSignatureLen ( ) , leaseSet - > GetSignature ( ) ) ;
}
2020-04-14 23:12:44 +00:00
else
LogPrint ( eLogError , " Destinations: Wrong encryption key type for LeaseSet type 1 " ) ;
2019-01-11 18:58:02 +00:00
}
else
{
2019-04-10 16:04:19 +00:00
// standard LS2 (type 3) first
2020-04-14 23:12:44 +00:00
i2p : : data : : LocalLeaseSet2 : : KeySections keySections ;
if ( m_ECIESx25519EncryptionKey )
keySections . push_back ( { m_ECIESx25519EncryptionKey - > keyType , 32 , m_ECIESx25519EncryptionKey - > pub } ) ;
if ( m_StandardEncryptionKey )
2020-03-01 10:25:50 +00:00
keySections . push_back ( { m_StandardEncryptionKey - > keyType , ( uint16_t ) m_StandardEncryptionKey - > decryptor - > GetPublicKeyLen ( ) , m_StandardEncryptionKey - > pub } ) ;
2020-04-14 23:12:44 +00:00
2020-03-01 10:25:50 +00:00
bool isPublishedEncrypted = GetLeaseSetType ( ) = = i2p : : data : : NETDB_STORE_TYPE_ENCRYPTED_LEASESET2 ;
2019-04-10 16:04:19 +00:00
auto ls2 = std : : make_shared < i2p : : data : : LocalLeaseSet2 > ( i2p : : data : : NETDB_STORE_TYPE_STANDARD_LEASESET2 ,
2020-04-14 23:12:44 +00:00
m_Keys , keySections , tunnels , IsPublic ( ) , isPublishedEncrypted ) ;
2019-08-07 19:43:03 +00:00
if ( isPublishedEncrypted ) // encrypt if type 5
2019-09-06 15:02:19 +00:00
ls2 = std : : make_shared < i2p : : data : : LocalEncryptedLeaseSet2 > ( ls2 , m_Keys , GetAuthType ( ) , m_AuthKeys ) ;
2019-04-10 16:04:19 +00:00
leaseSet = ls2 ;
2019-01-11 18:58:02 +00:00
}
2016-05-29 13:33:50 +00:00
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 ( ) ;
}
2020-03-31 21:35:51 +00:00
bool ClientDestination : : Decrypt ( const uint8_t * encrypted , uint8_t * data , BN_CTX * ctx , i2p : : data : : CryptoKeyType preferredCrypto ) const
2017-11-08 18:49:48 +00:00
{
2020-11-14 23:28:50 +00:00
if ( preferredCrypto = = i2p : : data : : CRYPTO_KEY_TYPE_ECIES_X25519_AEAD )
2020-04-14 23:12:44 +00:00
if ( m_ECIESx25519EncryptionKey & & m_ECIESx25519EncryptionKey - > decryptor )
return m_ECIESx25519EncryptionKey - > decryptor - > Decrypt ( encrypted , data , ctx , true ) ;
if ( m_StandardEncryptionKey & & m_StandardEncryptionKey - > decryptor )
return m_StandardEncryptionKey - > 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
}
2019-07-16 20:31:17 +00:00
2020-03-01 10:25:50 +00:00
bool ClientDestination : : SupportsEncryptionType ( i2p : : data : : CryptoKeyType keyType ) const
{
2020-11-14 23:28:50 +00:00
return keyType = = i2p : : data : : CRYPTO_KEY_TYPE_ECIES_X25519_AEAD ? ( bool ) m_ECIESx25519EncryptionKey : ( bool ) m_StandardEncryptionKey ;
2020-04-14 23:12:44 +00:00
}
2020-03-01 10:25:50 +00:00
const uint8_t * ClientDestination : : GetEncryptionPublicKey ( i2p : : data : : CryptoKeyType keyType ) const
{
2020-11-14 23:28:50 +00:00
if ( keyType = = i2p : : data : : CRYPTO_KEY_TYPE_ECIES_X25519_AEAD )
2020-04-14 23:12:44 +00:00
return m_ECIESx25519EncryptionKey ? m_ECIESx25519EncryptionKey - > pub : nullptr ;
return m_StandardEncryptionKey ? m_StandardEncryptionKey - > pub : nullptr ;
}
2020-03-01 10:25:50 +00:00
2019-07-16 20:31:17 +00:00
void ClientDestination : : ReadAuthKey ( const std : : string & group , const std : : map < std : : string , std : : string > * params )
{
for ( auto it : * params )
if ( it . first . length ( ) > = group . length ( ) & & ! it . first . compare ( 0 , group . length ( ) , group ) )
{
auto pos = it . second . find ( ' : ' ) ;
if ( pos ! = std : : string : : npos )
{
i2p : : data : : AuthPublicKey pubKey ;
if ( pubKey . FromBase64 ( it . second . substr ( pos + 1 ) ) )
m_AuthKeys - > push_back ( pubKey ) ;
else
LogPrint ( eLogError , " Destination: Unexpected auth key " , it . second . substr ( pos + 1 ) ) ;
2020-03-01 10:25:50 +00:00
}
2019-07-16 20:31:17 +00:00
}
}
2020-02-04 19:17:23 +00:00
2020-03-04 20:54:09 +00:00
bool ClientDestination : : DeleteStream ( uint32_t recvStreamID )
{
if ( m_StreamingDestination - > DeleteStream ( recvStreamID ) )
return true ;
for ( auto it : m_StreamingDestinationsByPorts )
if ( it . second - > DeleteStream ( recvStreamID ) )
return true ;
return false ;
2020-03-01 10:25:50 +00:00
}
2020-02-04 19:17:23 +00:00
RunnableClientDestination : : RunnableClientDestination ( const i2p : : data : : PrivateKeys & keys , bool isPublic , const std : : map < std : : string , std : : string > * params ) :
2020-03-01 10:25:50 +00:00
RunnableService ( " Destination " ) ,
2020-02-04 19:17:23 +00:00
ClientDestination ( GetIOService ( ) , keys , isPublic , params )
{
}
RunnableClientDestination : : ~ RunnableClientDestination ( )
{
if ( IsRunning ( ) )
Stop ( ) ;
2020-03-01 10:25:50 +00:00
}
2020-02-04 19:17:23 +00:00
void RunnableClientDestination : : Start ( )
{
if ( ! IsRunning ( ) )
{
ClientDestination : : Start ( ) ;
StartIOService ( ) ;
}
}
void RunnableClientDestination : : Stop ( )
{
if ( IsRunning ( ) )
{
ClientDestination : : Stop ( ) ;
StopIOService ( ) ;
}
}
2014-10-16 16:37:39 +00:00
}
2014-10-05 12:54:59 +00:00
}