2015-01-06 22:51:10 +00:00
# include <cassert>
2015-11-03 14:15:49 +00:00
# include "Base.h"
2014-08-13 19:25:52 +00:00
# include "Log.h"
2014-10-05 12:54:59 +00:00
# include "Destination.h"
2014-10-16 00:52:17 +00:00
# include "ClientContext.h"
2014-08-13 01:14:19 +00:00
# include "I2PTunnel.h"
namespace i2p
{
2014-10-16 14:28:44 +00:00
namespace client
2014-08-13 01:14:19 +00:00
{
2015-04-06 18:41:07 +00:00
I2PTunnelConnection : : I2PTunnelConnection ( I2PService * owner , std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > socket ,
2015-03-13 17:29:27 +00:00
std : : shared_ptr < const i2p : : data : : LeaseSet > leaseSet , int port ) :
2015-01-07 18:09:59 +00:00
I2PServiceHandler ( owner ) , m_Socket ( socket ) , m_RemoteEndpoint ( socket - > remote_endpoint ( ) ) ,
2014-12-05 19:46:59 +00:00
m_IsQuiet ( true )
2014-08-13 01:14:19 +00:00
{
2015-03-13 17:29:27 +00:00
m_Stream = GetOwner ( ) - > GetLocalDestination ( ) - > CreateStream ( leaseSet , port ) ;
2014-08-13 01:14:19 +00:00
}
2015-01-07 18:09:59 +00:00
I2PTunnelConnection : : I2PTunnelConnection ( I2PService * owner ,
2015-04-06 18:41:07 +00:00
std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > socket , std : : shared_ptr < i2p : : stream : : Stream > stream ) :
2015-01-07 18:09:59 +00:00
I2PServiceHandler ( owner ) , m_Socket ( socket ) , m_Stream ( stream ) ,
2015-01-03 01:43:59 +00:00
m_RemoteEndpoint ( socket - > remote_endpoint ( ) ) , m_IsQuiet ( true )
{
}
2015-01-07 18:09:59 +00:00
I2PTunnelConnection : : I2PTunnelConnection ( I2PService * owner , std : : shared_ptr < i2p : : stream : : Stream > stream ,
2015-04-06 18:41:07 +00:00
std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > socket , const boost : : asio : : ip : : tcp : : endpoint & target , bool quiet ) :
2015-01-07 18:09:59 +00:00
I2PServiceHandler ( owner ) , m_Socket ( socket ) , m_Stream ( stream ) ,
m_RemoteEndpoint ( target ) , m_IsQuiet ( quiet )
2014-08-20 19:03:10 +00:00
{
}
2014-08-13 01:14:19 +00:00
I2PTunnelConnection : : ~ I2PTunnelConnection ( )
{
2014-08-14 01:04:23 +00:00
}
2014-12-04 01:37:20 +00:00
void I2PTunnelConnection : : I2PConnect ( const uint8_t * msg , size_t len )
2014-11-24 03:23:17 +00:00
{
2015-01-06 22:51:10 +00:00
if ( m_Stream )
{
if ( msg )
m_Stream - > Send ( msg , len ) ; // connect and send
else
m_Stream - > Send ( m_Buffer , 0 ) ; // connect
}
2014-11-24 03:23:17 +00:00
StreamReceive ( ) ;
Receive ( ) ;
}
void I2PTunnelConnection : : Connect ( )
{
if ( m_Socket )
m_Socket - > async_connect ( m_RemoteEndpoint , std : : bind ( & I2PTunnelConnection : : HandleConnect ,
shared_from_this ( ) , std : : placeholders : : _1 ) ) ;
}
2014-08-14 01:04:23 +00:00
void I2PTunnelConnection : : Terminate ( )
2015-01-07 18:09:59 +00:00
{
if ( Kill ( ) ) return ;
2014-10-08 23:44:12 +00:00
if ( m_Stream )
{
m_Stream - > Close ( ) ;
2014-11-23 16:33:58 +00:00
m_Stream . reset ( ) ;
2014-10-08 23:44:12 +00:00
}
2014-08-17 23:14:40 +00:00
m_Socket - > close ( ) ;
2015-01-07 18:09:59 +00:00
Done ( shared_from_this ( ) ) ;
2014-08-13 19:25:52 +00:00
}
void I2PTunnelConnection : : Receive ( )
{
m_Socket - > async_read_some ( boost : : asio : : buffer ( m_Buffer , I2P_TUNNEL_CONNECTION_BUFFER_SIZE ) ,
2014-11-24 03:23:17 +00:00
std : : bind ( & I2PTunnelConnection : : HandleReceived , shared_from_this ( ) ,
std : : placeholders : : _1 , std : : placeholders : : _2 ) ) ;
2014-08-13 19:25:52 +00:00
}
void I2PTunnelConnection : : HandleReceived ( const boost : : system : : error_code & ecode , std : : size_t bytes_transferred )
{
if ( ecode )
2015-01-03 02:57:37 +00:00
{
2015-12-18 12:12:46 +00:00
LogPrint ( eLogError , " I2PTunnel: read error: " , ecode . message ( ) ) ;
2014-10-08 23:44:12 +00:00
if ( ecode ! = boost : : asio : : error : : operation_aborted )
Terminate ( ) ;
2014-08-13 19:25:52 +00:00
}
else
2014-08-14 01:04:23 +00:00
{
2014-08-13 19:25:52 +00:00
if ( m_Stream )
2015-04-09 22:40:23 +00:00
{
auto s = shared_from_this ( ) ;
m_Stream - > AsyncSend ( m_Buffer , bytes_transferred ,
[ s ] ( const boost : : system : : error_code & ecode )
{
if ( ! ecode )
s - > Receive ( ) ;
else
s - > Terminate ( ) ;
} ) ;
}
2014-08-13 19:25:52 +00:00
}
}
void I2PTunnelConnection : : HandleWrite ( const boost : : system : : error_code & ecode )
{
2014-08-17 23:14:40 +00:00
if ( ecode )
{
2015-12-18 12:12:46 +00:00
LogPrint ( eLogError , " I2PTunnel: write error: " , ecode . message ( ) ) ;
2014-10-08 23:44:12 +00:00
if ( ecode ! = boost : : asio : : error : : operation_aborted )
Terminate ( ) ;
2014-08-17 23:14:40 +00:00
}
else
StreamReceive ( ) ;
2014-08-13 19:25:52 +00:00
}
void I2PTunnelConnection : : StreamReceive ( )
{
if ( m_Stream )
m_Stream - > AsyncReceive ( boost : : asio : : buffer ( m_StreamBuffer , I2P_TUNNEL_CONNECTION_BUFFER_SIZE ) ,
2014-11-24 03:23:17 +00:00
std : : bind ( & I2PTunnelConnection : : HandleStreamReceive , shared_from_this ( ) ,
std : : placeholders : : _1 , std : : placeholders : : _2 ) ,
2014-08-13 19:25:52 +00:00
I2P_TUNNEL_CONNECTION_MAX_IDLE ) ;
2014-08-13 01:14:19 +00:00
}
2014-08-13 19:25:52 +00:00
void I2PTunnelConnection : : HandleStreamReceive ( const boost : : system : : error_code & ecode , std : : size_t bytes_transferred )
{
if ( ecode )
{
2015-12-18 12:12:46 +00:00
LogPrint ( eLogError , " I2PTunnel: stream read error: " , ecode . message ( ) ) ;
2014-10-08 23:44:12 +00:00
if ( ecode ! = boost : : asio : : error : : operation_aborted )
Terminate ( ) ;
2014-08-13 19:25:52 +00:00
}
else
2015-06-02 17:03:22 +00:00
Write ( m_StreamBuffer , bytes_transferred ) ;
}
void I2PTunnelConnection : : Write ( const uint8_t * buf , size_t len )
{
2016-02-03 00:24:49 +00:00
boost : : asio : : async_write ( * m_Socket , boost : : asio : : buffer ( buf , len ) , boost : : asio : : transfer_all ( ) ,
2015-06-02 17:03:22 +00:00
std : : bind ( & I2PTunnelConnection : : HandleWrite , shared_from_this ( ) , std : : placeholders : : _1 ) ) ;
2014-08-13 19:25:52 +00:00
}
2014-08-20 19:03:10 +00:00
void I2PTunnelConnection : : HandleConnect ( const boost : : system : : error_code & ecode )
{
if ( ecode )
{
2015-12-18 12:12:46 +00:00
LogPrint ( eLogError , " I2PTunnel: connect error: " , ecode . message ( ) ) ;
2014-11-24 03:23:17 +00:00
Terminate ( ) ;
2014-08-20 19:03:10 +00:00
}
else
{
2015-12-18 12:12:46 +00:00
LogPrint ( eLogDebug , " I2PTunnel: connected " ) ;
2014-12-05 19:46:59 +00:00
if ( m_IsQuiet )
StreamReceive ( ) ;
else
{
// send destination first like received from I2P
2015-11-03 14:15:49 +00:00
std : : string dest = m_Stream - > GetRemoteIdentity ( ) - > ToBase64 ( ) ;
2014-12-05 19:46:59 +00:00
dest + = " \n " ;
memcpy ( m_StreamBuffer , dest . c_str ( ) , dest . size ( ) ) ;
HandleStreamReceive ( boost : : system : : error_code ( ) , dest . size ( ) ) ;
}
2014-08-20 19:03:10 +00:00
Receive ( ) ;
}
}
2015-06-02 17:03:22 +00:00
I2PTunnelConnectionHTTP : : I2PTunnelConnectionHTTP ( I2PService * owner , std : : shared_ptr < i2p : : stream : : Stream > stream ,
std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > socket ,
const boost : : asio : : ip : : tcp : : endpoint & target , const std : : string & host ) :
2016-01-11 18:48:18 +00:00
I2PTunnelConnection ( owner , stream , socket , target ) , m_Host ( host ) , m_HeaderSent ( false ) , m_From ( stream - > GetRemoteIdentity ( ) )
2015-06-02 17:03:22 +00:00
{
}
2015-06-02 20:21:38 +00:00
void I2PTunnelConnectionHTTP : : Write ( const uint8_t * buf , size_t len )
{
if ( m_HeaderSent )
I2PTunnelConnection : : Write ( buf , len ) ;
else
2015-06-03 16:30:15 +00:00
{
m_InHeader . clear ( ) ;
m_InHeader . write ( ( const char * ) buf , len ) ;
std : : string line ;
bool endOfHeader = false ;
while ( ! endOfHeader )
{
std : : getline ( m_InHeader , line ) ;
if ( ! m_InHeader . fail ( ) )
{
if ( line = = " \r " ) endOfHeader = true ;
2016-02-03 00:24:49 +00:00
else
{
if ( line . find ( " Host: " ) ! = std : : string : : npos )
m_OutHeader < < " Host: " < < m_Host < < " \r \n " ;
else
m_OutHeader < < line < < " \n " ;
}
2015-06-03 16:30:15 +00:00
}
else
break ;
}
2016-01-11 18:48:18 +00:00
// add X-I2P fields
if ( m_From )
{
2016-01-19 14:36:56 +00:00
m_OutHeader < < X_I2P_DEST_B32 < < " : " < < context . GetAddressBook ( ) . ToAddress ( m_From - > GetIdentHash ( ) ) < < " \r \n " ;
2016-01-11 18:48:18 +00:00
m_OutHeader < < X_I2P_DEST_HASH < < " : " < < m_From - > GetIdentHash ( ) . ToBase64 ( ) < < " \r \n " ;
2016-01-19 14:36:56 +00:00
m_OutHeader < < X_I2P_DEST_B64 < < " : " < < m_From - > ToBase64 ( ) < < " \r \n " ;
2016-01-11 18:48:18 +00:00
}
2015-06-03 16:30:15 +00:00
if ( endOfHeader )
{
2016-02-03 00:24:49 +00:00
m_OutHeader < < " \r \n " ; // end of header
2016-02-03 03:00:51 +00:00
m_OutHeader < < m_InHeader . str ( ) . substr ( m_InHeader . tellg ( ) ) ; // data right after header
2015-06-03 16:30:15 +00:00
m_HeaderSent = true ;
I2PTunnelConnection : : Write ( ( uint8_t * ) m_OutHeader . str ( ) . c_str ( ) , m_OutHeader . str ( ) . length ( ) ) ;
}
2015-06-02 20:21:38 +00:00
}
}
2015-01-08 02:28:54 +00:00
/* This handler tries to stablish a connection with the desired server and dies if it fails to do so */
class I2PClientTunnelHandler : public I2PServiceHandler , public std : : enable_shared_from_this < I2PClientTunnelHandler >
{
public :
I2PClientTunnelHandler ( I2PClientTunnel * parent , i2p : : data : : IdentHash destination ,
2015-04-06 18:41:07 +00:00
int destinationPort , std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > socket ) :
2015-03-13 17:29:27 +00:00
I2PServiceHandler ( parent ) , m_DestinationIdentHash ( destination ) ,
m_DestinationPort ( destinationPort ) , m_Socket ( socket ) { } ;
2015-01-08 02:28:54 +00:00
void Handle ( ) ;
void Terminate ( ) ;
private :
void HandleStreamRequestComplete ( std : : shared_ptr < i2p : : stream : : Stream > stream ) ;
i2p : : data : : IdentHash m_DestinationIdentHash ;
2015-03-13 17:29:27 +00:00
int m_DestinationPort ;
2015-04-06 18:41:07 +00:00
std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > m_Socket ;
2015-01-08 02:28:54 +00:00
} ;
void I2PClientTunnelHandler : : Handle ( )
{
2015-03-13 17:29:27 +00:00
GetOwner ( ) - > GetLocalDestination ( ) - > CreateStream (
std : : bind ( & I2PClientTunnelHandler : : HandleStreamRequestComplete , shared_from_this ( ) , std : : placeholders : : _1 ) ,
m_DestinationIdentHash , m_DestinationPort ) ;
2015-01-08 02:28:54 +00:00
}
void I2PClientTunnelHandler : : HandleStreamRequestComplete ( std : : shared_ptr < i2p : : stream : : Stream > stream )
{
if ( stream )
{
if ( Kill ( ) ) return ;
2015-12-18 12:12:46 +00:00
LogPrint ( eLogDebug , " I2PTunnel: new connection " ) ;
2015-01-08 02:28:54 +00:00
auto connection = std : : make_shared < I2PTunnelConnection > ( GetOwner ( ) , m_Socket , stream ) ;
GetOwner ( ) - > AddHandler ( connection ) ;
connection - > I2PConnect ( ) ;
Done ( shared_from_this ( ) ) ;
}
else
{
2015-12-18 12:12:46 +00:00
LogPrint ( eLogError , " I2PTunnel: Client Tunnel Issue when creating the stream, check the previous warnings for more info. " ) ;
2015-01-08 02:28:54 +00:00
Terminate ( ) ;
}
}
void I2PClientTunnelHandler : : Terminate ( )
{
if ( Kill ( ) ) return ;
if ( m_Socket )
{
m_Socket - > close ( ) ;
m_Socket = nullptr ;
}
Done ( shared_from_this ( ) ) ;
}
2016-01-14 01:21:53 +00:00
I2PClientTunnel : : I2PClientTunnel ( const std : : string & name , const std : : string & destination ,
const std : : string & address , int port , std : : shared_ptr < ClientDestination > localDestination , int destinationPort ) :
TCPIPAcceptor ( address , port , localDestination ) , m_Name ( name ) , m_Destination ( destination ) ,
m_DestinationIdentHash ( nullptr ) , m_DestinationPort ( destinationPort )
{
}
2014-08-13 01:14:19 +00:00
2014-08-13 19:25:52 +00:00
void I2PClientTunnel : : Start ( )
{
2015-01-08 12:39:35 +00:00
TCPIPAcceptor : : Start ( ) ;
2015-01-03 01:17:01 +00:00
GetIdentHash ( ) ;
2014-08-13 19:25:52 +00:00
}
void I2PClientTunnel : : Stop ( )
{
2015-01-08 02:49:35 +00:00
TCPIPAcceptor : : Stop ( ) ;
2015-01-03 01:07:55 +00:00
auto * originalIdentHash = m_DestinationIdentHash ;
2014-08-13 19:25:52 +00:00
m_DestinationIdentHash = nullptr ;
2015-01-03 01:07:55 +00:00
delete originalIdentHash ;
2014-08-13 19:25:52 +00:00
}
2015-01-03 01:17:01 +00:00
/* HACK: maybe we should create a caching IdentHash provider in AddressBook */
const i2p : : data : : IdentHash * I2PClientTunnel : : GetIdentHash ( )
{
if ( ! m_DestinationIdentHash )
{
i2p : : data : : IdentHash identHash ;
if ( i2p : : client : : context . GetAddressBook ( ) . GetIdentHash ( m_Destination , identHash ) )
m_DestinationIdentHash = new i2p : : data : : IdentHash ( identHash ) ;
else
2015-12-18 12:12:46 +00:00
LogPrint ( eLogWarning , " I2PTunnel: Remote destination " , m_Destination , " not found " ) ;
2015-01-03 01:17:01 +00:00
}
return m_DestinationIdentHash ;
}
2015-04-06 18:41:07 +00:00
std : : shared_ptr < I2PServiceHandler > I2PClientTunnel : : CreateHandler ( std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > socket )
2014-08-13 01:14:19 +00:00
{
2015-01-08 02:49:35 +00:00
const i2p : : data : : IdentHash * identHash = GetIdentHash ( ) ;
if ( identHash )
2015-03-13 17:29:27 +00:00
return std : : make_shared < I2PClientTunnelHandler > ( this , * identHash , m_DestinationPort , socket ) ;
2014-08-13 01:14:19 +00:00
else
2015-01-08 02:49:35 +00:00
return nullptr ;
2014-10-15 16:07:06 +00:00
}
2016-01-14 01:21:53 +00:00
I2PServerTunnel : : I2PServerTunnel ( const std : : string & name , const std : : string & address ,
int port , std : : shared_ptr < ClientDestination > localDestination , int inport ) :
I2PService ( localDestination ) , m_Name ( name ) , m_Address ( address ) , m_Port ( port ) , m_IsAccessList ( false )
2014-08-20 19:03:10 +00:00
{
2015-03-15 15:28:30 +00:00
m_PortDestination = localDestination - > CreateStreamingDestination ( inport > 0 ? inport : port ) ;
2014-08-20 19:03:10 +00:00
}
void I2PServerTunnel : : Start ( )
{
2015-06-02 17:18:41 +00:00
m_Endpoint . port ( m_Port ) ;
boost : : system : : error_code ec ;
auto addr = boost : : asio : : ip : : address : : from_string ( m_Address , ec ) ;
if ( ! ec )
{
m_Endpoint . address ( addr ) ;
Accept ( ) ;
}
else
{
auto resolver = std : : make_shared < boost : : asio : : ip : : tcp : : resolver > ( GetService ( ) ) ;
resolver - > async_resolve ( boost : : asio : : ip : : tcp : : resolver : : query ( m_Address , " " ) ,
std : : bind ( & I2PServerTunnel : : HandleResolve , this ,
std : : placeholders : : _1 , std : : placeholders : : _2 , resolver ) ) ;
}
2014-08-20 19:03:10 +00:00
}
void I2PServerTunnel : : Stop ( )
{
2015-01-07 18:09:59 +00:00
ClearHandlers ( ) ;
2014-08-20 19:03:10 +00:00
}
2015-06-02 17:18:41 +00:00
void I2PServerTunnel : : HandleResolve ( const boost : : system : : error_code & ecode , boost : : asio : : ip : : tcp : : resolver : : iterator it ,
std : : shared_ptr < boost : : asio : : ip : : tcp : : resolver > resolver )
{
if ( ! ecode )
{
auto addr = ( * it ) . endpoint ( ) . address ( ) ;
2015-12-18 12:12:46 +00:00
LogPrint ( eLogInfo , " I2PTunnel: server tunnel " , ( * it ) . host_name ( ) , " has been resolved to " , addr ) ;
2015-06-02 17:18:41 +00:00
m_Endpoint . address ( addr ) ;
Accept ( ) ;
}
else
2015-12-18 12:12:46 +00:00
LogPrint ( eLogError , " I2PTunnel: Unable to resolve server tunnel address: " , ecode . message ( ) ) ;
2015-06-02 17:18:41 +00:00
}
2015-03-16 18:52:42 +00:00
void I2PServerTunnel : : SetAccessList ( const std : : set < i2p : : data : : IdentHash > & accessList )
{
m_AccessList = accessList ;
m_IsAccessList = true ;
}
2014-08-20 19:03:10 +00:00
void I2PServerTunnel : : Accept ( )
{
2015-03-03 19:52:16 +00:00
if ( m_PortDestination )
m_PortDestination - > SetAcceptor ( std : : bind ( & I2PServerTunnel : : HandleAccept , this , std : : placeholders : : _1 ) ) ;
2014-10-01 14:58:28 +00:00
auto localDestination = GetLocalDestination ( ) ;
if ( localDestination )
2015-03-03 19:52:16 +00:00
{
if ( ! localDestination - > IsAcceptingStreams ( ) ) // set it as default if not set yet
localDestination - > AcceptStreams ( std : : bind ( & I2PServerTunnel : : HandleAccept , this , std : : placeholders : : _1 ) ) ;
}
2014-10-01 14:58:28 +00:00
else
2015-12-18 12:12:46 +00:00
LogPrint ( eLogError , " I2PTunnel: Local destination not set for server tunnel " ) ;
2014-08-20 19:03:10 +00:00
}
2014-11-23 16:33:58 +00:00
void I2PServerTunnel : : HandleAccept ( std : : shared_ptr < i2p : : stream : : Stream > stream )
2014-08-20 19:03:10 +00:00
{
if ( stream )
2014-11-24 03:23:17 +00:00
{
2015-03-16 18:52:42 +00:00
if ( m_IsAccessList )
{
2015-11-03 14:15:49 +00:00
if ( ! m_AccessList . count ( stream - > GetRemoteIdentity ( ) - > GetIdentHash ( ) ) )
2015-03-16 18:52:42 +00:00
{
2015-12-18 12:12:46 +00:00
LogPrint ( eLogWarning , " I2PTunnel: Address " , stream - > GetRemoteIdentity ( ) - > GetIdentHash ( ) . ToBase32 ( ) , " is not in white list. Incoming connection dropped " ) ;
2015-03-16 18:52:42 +00:00
stream - > Close ( ) ;
return ;
}
}
2015-06-02 17:03:22 +00:00
CreateI2PConnection ( stream ) ;
2014-11-24 03:23:17 +00:00
}
2014-08-20 19:03:10 +00:00
}
2015-05-20 20:00:09 +00:00
2015-06-02 17:03:22 +00:00
void I2PServerTunnel : : CreateI2PConnection ( std : : shared_ptr < i2p : : stream : : Stream > stream )
{
auto conn = std : : make_shared < I2PTunnelConnection > ( this , stream , std : : make_shared < boost : : asio : : ip : : tcp : : socket > ( GetService ( ) ) , GetEndpoint ( ) ) ;
AddHandler ( conn ) ;
conn - > Connect ( ) ;
}
2016-01-14 01:21:53 +00:00
I2PServerTunnelHTTP : : I2PServerTunnelHTTP ( const std : : string & name , const std : : string & address ,
int port , std : : shared_ptr < ClientDestination > localDestination , int inport ) :
I2PServerTunnel ( name , address , port , localDestination , inport )
2015-06-02 17:03:22 +00:00
{
}
void I2PServerTunnelHTTP : : CreateI2PConnection ( std : : shared_ptr < i2p : : stream : : Stream > stream )
2015-05-20 20:00:09 +00:00
{
2015-06-02 17:03:22 +00:00
auto conn = std : : make_shared < I2PTunnelConnectionHTTP > ( this , stream , std : : make_shared < boost : : asio : : ip : : tcp : : socket > ( GetService ( ) ) , GetEndpoint ( ) , GetAddress ( ) ) ;
AddHandler ( conn ) ;
conn - > Connect ( ) ;
2015-05-20 20:00:09 +00:00
}
2014-08-13 01:14:19 +00:00
}
}