2020-05-22 16:18:41 +03: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
*/
2015-01-07 01:51:10 +03:00
# include <cassert>
2015-11-03 17:15:49 +03:00
# include "Base.h"
2014-08-13 23:25:52 +04:00
# include "Log.h"
2014-10-05 16:54:59 +04:00
# include "Destination.h"
2014-10-16 04:52:17 +04:00
# include "ClientContext.h"
2014-08-13 05:14:19 +04:00
# include "I2PTunnel.h"
namespace i2p
{
2014-10-16 18:28:44 +04:00
namespace client
2014-08-13 05:14:19 +04:00
{
2016-07-28 16:25:05 +03:00
/** set standard socket options */
static void I2PTunnelSetSocketOptions ( std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > socket )
{
2016-07-28 16:53:39 +03:00
if ( socket & & socket - > is_open ( ) )
2017-08-31 19:08:22 +03:00
{
2016-07-28 16:53:39 +03:00
boost : : asio : : socket_base : : receive_buffer_size option ( I2P_TUNNEL_CONNECTION_BUFFER_SIZE ) ;
socket - > set_option ( option ) ;
}
2016-07-28 16:25:05 +03:00
}
2017-08-31 19:08:22 +03:00
2015-04-06 21:41:07 +03:00
I2PTunnelConnection : : I2PTunnelConnection ( I2PService * owner , std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > socket ,
2017-08-31 19:08:22 +03:00
std : : shared_ptr < const i2p : : data : : LeaseSet > leaseSet , int port ) :
2015-01-07 21:09:59 +03:00
I2PServiceHandler ( owner ) , m_Socket ( socket ) , m_RemoteEndpoint ( socket - > remote_endpoint ( ) ) ,
2014-12-05 22:46:59 +03:00
m_IsQuiet ( true )
2014-08-13 05:14:19 +04:00
{
2015-03-13 20:29:27 +03:00
m_Stream = GetOwner ( ) - > GetLocalDestination ( ) - > CreateStream ( leaseSet , port ) ;
2017-08-31 19:08:22 +03:00
}
2014-08-13 05:14:19 +04:00
2015-01-07 21:09:59 +03:00
I2PTunnelConnection : : I2PTunnelConnection ( I2PService * owner ,
2017-10-04 20:15:29 +03:00
std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > socket , std : : shared_ptr < i2p : : stream : : Stream > stream ) :
2015-01-07 21:09:59 +03:00
I2PServiceHandler ( owner ) , m_Socket ( socket ) , m_Stream ( stream ) ,
2015-01-03 04:43:59 +03:00
m_RemoteEndpoint ( socket - > remote_endpoint ( ) ) , m_IsQuiet ( true )
{
}
2015-01-07 21:09:59 +03:00
I2PTunnelConnection : : I2PTunnelConnection ( I2PService * owner , std : : shared_ptr < i2p : : stream : : Stream > stream ,
2017-10-04 20:15:29 +03:00
std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > socket , const boost : : asio : : ip : : tcp : : endpoint & target , bool quiet ) :
2015-01-07 21:09:59 +03:00
I2PServiceHandler ( owner ) , m_Socket ( socket ) , m_Stream ( stream ) ,
m_RemoteEndpoint ( target ) , m_IsQuiet ( quiet )
2014-08-20 23:03:10 +04:00
{
}
2014-08-13 05:14:19 +04:00
I2PTunnelConnection : : ~ I2PTunnelConnection ( )
{
2017-08-31 19:08:22 +03:00
}
2014-12-04 04:37:20 +03:00
void I2PTunnelConnection : : I2PConnect ( const uint8_t * msg , size_t len )
2014-11-24 06:23:17 +03:00
{
2015-01-07 01:51:10 +03:00
if ( m_Stream )
{
if ( msg )
m_Stream - > Send ( msg , len ) ; // connect and send
2017-08-31 19:08:22 +03:00
else
2015-01-07 01:51:10 +03:00
m_Stream - > Send ( m_Buffer , 0 ) ; // connect
}
2014-11-24 06:23:17 +03:00
StreamReceive ( ) ;
Receive ( ) ;
}
2016-12-25 16:56:47 +03:00
static boost : : asio : : ip : : address GetLoopbackAddressFor ( const i2p : : data : : IdentHash & addr )
{
boost : : asio : : ip : : address_v4 : : bytes_type bytes ;
const uint8_t * ident = addr ;
bytes [ 0 ] = 127 ;
memcpy ( bytes . data ( ) + 1 , ident , 3 ) ;
boost : : asio : : ip : : address ourIP = boost : : asio : : ip : : address_v4 ( bytes ) ;
return ourIP ;
}
2017-08-31 19:08:22 +03:00
2020-05-14 20:59:52 +03:00
# ifdef __linux__
2016-12-25 16:56:47 +03:00
static void MapToLoopback ( const std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > & sock , const i2p : : data : : IdentHash & addr )
{
2017-08-31 19:08:22 +03:00
// bind to 127.x.x.x address
2016-12-25 16:56:47 +03:00
// where x.x.x are first three bytes from ident
auto ourIP = GetLoopbackAddressFor ( addr ) ;
sock - > bind ( boost : : asio : : ip : : tcp : : endpoint ( ourIP , 0 ) ) ;
}
2020-05-14 20:59:52 +03:00
# endif
2016-12-25 16:56:47 +03:00
2017-01-13 00:17:11 +03:00
void I2PTunnelConnection : : Connect ( bool isUniqueLocal )
2014-11-24 06:23:17 +03:00
{
2016-07-28 16:53:39 +03:00
I2PTunnelSetSocketOptions ( m_Socket ) ;
2017-08-31 19:08:22 +03:00
if ( m_Socket )
2017-01-13 00:17:11 +03:00
{
2016-12-25 16:56:47 +03:00
# ifdef __linux__
2017-01-13 00:17:11 +03:00
if ( isUniqueLocal & & m_RemoteEndpoint . address ( ) . is_v4 ( ) & &
m_RemoteEndpoint . address ( ) . to_v4 ( ) . to_bytes ( ) [ 0 ] = = 127 )
2016-08-30 00:53:26 +03:00
{
m_Socket - > open ( boost : : asio : : ip : : tcp : : v4 ( ) ) ;
2016-12-25 16:56:47 +03:00
auto ident = m_Stream - > GetRemoteIdentity ( ) - > GetIdentHash ( ) ;
MapToLoopback ( m_Socket , ident ) ;
2016-08-30 00:53:26 +03:00
}
2016-08-29 23:48:37 +03:00
# endif
2018-01-06 07:01:44 +03:00
m_Socket - > async_connect ( m_RemoteEndpoint , std : : bind ( & I2PTunnelConnection : : HandleConnect ,
2014-11-24 06:23:17 +03:00
shared_from_this ( ) , std : : placeholders : : _1 ) ) ;
2016-08-29 23:48:37 +03:00
}
2017-08-31 19:08:22 +03:00
}
2014-08-14 05:04:23 +04:00
void I2PTunnelConnection : : Terminate ( )
2015-01-07 21:09:59 +03:00
{
if ( Kill ( ) ) return ;
2014-10-09 03:44:12 +04:00
if ( m_Stream )
{
m_Stream - > Close ( ) ;
2014-11-23 19:33:58 +03:00
m_Stream . reset ( ) ;
2017-08-31 19:08:22 +03:00
}
2016-12-31 18:50:48 +03:00
boost : : system : : error_code ec ;
m_Socket - > shutdown ( boost : : asio : : ip : : tcp : : socket : : shutdown_send , ec ) ; // avoid RST
2014-08-18 03:14:40 +04:00
m_Socket - > close ( ) ;
2016-12-13 19:01:13 +03:00
2015-01-07 21:09:59 +03:00
Done ( shared_from_this ( ) ) ;
2017-08-31 19:08:22 +03:00
}
2014-08-13 23:25:52 +04:00
void I2PTunnelConnection : : Receive ( )
{
2017-08-31 19:08:22 +03:00
m_Socket - > async_read_some ( boost : : asio : : buffer ( m_Buffer , I2P_TUNNEL_CONNECTION_BUFFER_SIZE ) ,
std : : bind ( & I2PTunnelConnection : : HandleReceived , shared_from_this ( ) ,
2014-11-24 06:23:17 +03:00
std : : placeholders : : _1 , std : : placeholders : : _2 ) ) ;
2017-08-31 19:08:22 +03:00
}
2014-08-13 23:25:52 +04:00
void I2PTunnelConnection : : HandleReceived ( const boost : : system : : error_code & ecode , std : : size_t bytes_transferred )
{
if ( ecode )
2015-01-03 05:57:37 +03:00
{
2014-10-09 03:44:12 +04:00
if ( ecode ! = boost : : asio : : error : : operation_aborted )
2016-12-13 22:54:48 +03:00
{
LogPrint ( eLogError , " I2PTunnel: read error: " , ecode . message ( ) ) ;
2014-10-09 03:44:12 +04:00
Terminate ( ) ;
2016-12-13 22:54:48 +03:00
}
2014-08-13 23:25:52 +04:00
}
else
2017-08-31 19:08:22 +03:00
{
2014-08-13 23:25:52 +04:00
if ( m_Stream )
2017-08-31 19:08:22 +03:00
{
2015-04-10 01:40:23 +03:00
auto s = shared_from_this ( ) ;
m_Stream - > AsyncSend ( m_Buffer , bytes_transferred ,
[ s ] ( const boost : : system : : error_code & ecode )
2017-10-04 20:15:29 +03:00
{
2015-04-10 01:40:23 +03:00
if ( ! ecode )
s - > Receive ( ) ;
else
s - > Terminate ( ) ;
} ) ;
2017-08-31 19:08:22 +03:00
}
2014-08-13 23:25:52 +04:00
}
2017-08-31 19:08:22 +03:00
}
2014-08-13 23:25:52 +04:00
void I2PTunnelConnection : : HandleWrite ( const boost : : system : : error_code & ecode )
{
2014-08-18 03:14:40 +04:00
if ( ecode )
{
2015-12-18 15:12:46 +03:00
LogPrint ( eLogError , " I2PTunnel: write error: " , ecode . message ( ) ) ;
2014-10-09 03:44:12 +04:00
if ( ecode ! = boost : : asio : : error : : operation_aborted )
Terminate ( ) ;
2014-08-18 03:14:40 +04:00
}
else
StreamReceive ( ) ;
2014-08-13 23:25:52 +04:00
}
void I2PTunnelConnection : : StreamReceive ( )
{
if ( m_Stream )
2016-02-15 06:10:56 +03:00
{
if ( m_Stream - > GetStatus ( ) = = i2p : : stream : : eStreamStatusNew | |
2017-10-04 20:15:29 +03:00
m_Stream - > GetStatus ( ) = = i2p : : stream : : eStreamStatusOpen ) // regular
2017-08-31 19:08:22 +03:00
{
2016-02-15 06:10:56 +03:00
m_Stream - > AsyncReceive ( boost : : asio : : buffer ( m_StreamBuffer , I2P_TUNNEL_CONNECTION_BUFFER_SIZE ) ,
std : : bind ( & I2PTunnelConnection : : HandleStreamReceive , shared_from_this ( ) ,
2020-03-01 13:25:50 +03:00
std : : placeholders : : _1 , std : : placeholders : : _2 ) ,
2016-02-15 06:10:56 +03:00
I2P_TUNNEL_CONNECTION_MAX_IDLE ) ;
2017-08-31 19:08:22 +03:00
}
2016-02-15 06:10:56 +03:00
else // closed by peer
{
// get remaning data
auto len = m_Stream - > ReadSome ( m_StreamBuffer , I2P_TUNNEL_CONNECTION_BUFFER_SIZE ) ;
if ( len > 0 ) // still some data
Write ( m_StreamBuffer , len ) ;
else // no more data
2017-08-31 19:08:22 +03:00
Terminate ( ) ;
}
}
}
2014-08-13 05:14:19 +04:00
2014-08-13 23:25:52 +04:00
void I2PTunnelConnection : : HandleStreamReceive ( const boost : : system : : error_code & ecode , std : : size_t bytes_transferred )
{
if ( ecode )
{
2014-10-09 03:44:12 +04:00
if ( ecode ! = boost : : asio : : error : : operation_aborted )
2016-02-15 06:10:56 +03:00
{
2017-02-14 20:11:30 +03:00
LogPrint ( eLogError , " I2PTunnel: stream read error: " , ecode . message ( ) ) ;
2016-02-15 06:10:56 +03:00
if ( bytes_transferred > 0 )
Write ( m_StreamBuffer , bytes_transferred ) ; // postpone termination
2016-12-23 15:38:41 +03:00
else if ( ecode = = boost : : asio : : error : : timed_out & & m_Stream & & m_Stream - > IsOpen ( ) )
2016-12-17 22:49:51 +03:00
StreamReceive ( ) ;
else
2016-02-15 06:10:56 +03:00
Terminate ( ) ;
2016-10-20 22:20:08 +03:00
}
else
2016-12-17 22:49:51 +03:00
Terminate ( ) ;
2014-08-13 23:25:52 +04:00
}
else
2015-06-02 20:03:22 +03:00
Write ( m_StreamBuffer , bytes_transferred ) ;
}
void I2PTunnelConnection : : Write ( const uint8_t * buf , size_t len )
{
2016-02-03 03:24:49 +03:00
boost : : asio : : async_write ( * m_Socket , boost : : asio : : buffer ( buf , len ) , boost : : asio : : transfer_all ( ) ,
2017-10-04 20:15:29 +03:00
std : : bind ( & I2PTunnelConnection : : HandleWrite , shared_from_this ( ) , std : : placeholders : : _1 ) ) ;
2014-08-13 23:25:52 +04:00
}
2014-08-20 23:03:10 +04:00
void I2PTunnelConnection : : HandleConnect ( const boost : : system : : error_code & ecode )
{
if ( ecode )
{
2015-12-18 15:12:46 +03:00
LogPrint ( eLogError , " I2PTunnel: connect error: " , ecode . message ( ) ) ;
2014-11-24 06:23:17 +03:00
Terminate ( ) ;
2014-08-20 23:03:10 +04:00
}
else
{
2015-12-18 15:12:46 +03:00
LogPrint ( eLogDebug , " I2PTunnel: connected " ) ;
2014-12-05 22:46:59 +03:00
if ( m_IsQuiet )
StreamReceive ( ) ;
else
{
// send destination first like received from I2P
2015-11-03 17:15:49 +03:00
std : : string dest = m_Stream - > GetRemoteIdentity ( ) - > ToBase64 ( ) ;
2014-12-05 22:46:59 +03:00
dest + = " \n " ;
2016-12-25 16:18:23 +03:00
if ( sizeof ( m_StreamBuffer ) > = dest . size ( ) ) {
memcpy ( m_StreamBuffer , dest . c_str ( ) , dest . size ( ) ) ;
}
2014-12-05 22:46:59 +03:00
HandleStreamReceive ( boost : : system : : error_code ( ) , dest . size ( ) ) ;
2017-08-31 19:08:22 +03:00
}
Receive ( ) ;
2014-08-20 23:03:10 +04:00
}
}
2017-02-07 05:39:15 +03:00
void I2PClientTunnelConnectionHTTP : : Write ( const uint8_t * buf , size_t len )
{
if ( m_HeaderSent )
I2PTunnelConnection : : Write ( buf , len ) ;
else
{
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 ;
else
2017-08-31 19:08:22 +03:00
{
2017-02-07 05:39:15 +03:00
if ( ! m_ConnectionSent & & ! line . compare ( 0 , 10 , " Connection " ) )
2017-08-31 19:08:22 +03:00
{
2019-02-12 19:20:54 +03:00
/* close connection, if not Connection: (U|u)pgrade (for websocket) */
2020-03-01 13:25:50 +03:00
auto x = line . find ( " pgrade " ) ;
2019-02-12 19:20:54 +03:00
if ( x ! = std : : string : : npos & & std : : tolower ( line [ x - 1 ] ) = = ' u ' )
2019-02-12 01:18:01 +03:00
m_OutHeader < < line < < " \r \n " ;
2019-02-12 19:20:54 +03:00
else
m_OutHeader < < " Connection: close \r \n " ;
2019-02-12 01:18:01 +03:00
2017-02-07 05:39:15 +03:00
m_ConnectionSent = true ;
2017-08-31 19:08:22 +03:00
}
2017-02-07 05:39:15 +03:00
else if ( ! m_ProxyConnectionSent & & ! line . compare ( 0 , 16 , " Proxy-Connection " ) )
2017-08-31 19:08:22 +03:00
{
2017-02-07 05:39:15 +03:00
m_OutHeader < < " Proxy-Connection: close \r \n " ;
m_ProxyConnectionSent = true ;
2017-08-31 19:08:22 +03:00
}
2017-02-07 05:39:15 +03:00
else
m_OutHeader < < line < < " \n " ;
2017-08-31 19:08:22 +03:00
}
2017-02-07 05:39:15 +03:00
}
else
break ;
}
if ( endOfHeader )
{
if ( ! m_ConnectionSent ) m_OutHeader < < " Connection: close \r \n " ;
2020-03-01 13:25:50 +03:00
if ( ! m_ProxyConnectionSent ) m_OutHeader < < " Proxy-Connection: close \r \n " ;
2017-02-07 05:39:15 +03:00
m_OutHeader < < " \r \n " ; // end of header
m_OutHeader < < m_InHeader . str ( ) . substr ( m_InHeader . tellg ( ) ) ; // data right after header
m_InHeader . str ( " " ) ;
m_HeaderSent = true ;
I2PTunnelConnection : : Write ( ( uint8_t * ) m_OutHeader . str ( ) . c_str ( ) , m_OutHeader . str ( ) . length ( ) ) ;
}
}
2017-08-31 19:08:22 +03:00
}
2017-02-07 05:39:15 +03:00
I2PServerTunnelConnectionHTTP : : I2PServerTunnelConnectionHTTP ( I2PService * owner , std : : shared_ptr < i2p : : stream : : Stream > stream ,
2017-08-31 19:08:22 +03:00
std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > socket ,
2015-06-02 20:03:22 +03:00
const boost : : asio : : ip : : tcp : : endpoint & target , const std : : string & host ) :
2016-01-11 21:48:18 +03:00
I2PTunnelConnection ( owner , stream , socket , target ) , m_Host ( host ) , m_HeaderSent ( false ) , m_From ( stream - > GetRemoteIdentity ( ) )
2015-06-02 20:03:22 +03:00
{
}
2017-02-07 05:39:15 +03:00
void I2PServerTunnelConnectionHTTP : : Write ( const uint8_t * buf , size_t len )
2015-06-02 23:21:38 +03:00
{
if ( m_HeaderSent )
I2PTunnelConnection : : Write ( buf , len ) ;
else
2017-08-31 19:08:22 +03:00
{
2015-06-03 19:30:15 +03: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 03:24:49 +03:00
else
2017-08-31 19:08:22 +03:00
{
2016-11-02 17:12:54 +03:00
if ( m_Host . length ( ) > 0 & & line . find ( " Host: " ) ! = std : : string : : npos )
m_OutHeader < < " Host: " < < m_Host < < " \r \n " ; // override host
2016-02-03 03:24:49 +03:00
else
m_OutHeader < < line < < " \n " ;
2017-08-31 19:08:22 +03:00
}
2015-06-03 19:30:15 +03:00
}
else
break ;
}
2016-01-11 21:48:18 +03:00
// add X-I2P fields
if ( m_From )
{
2016-01-19 17:36:56 +03:00
m_OutHeader < < X_I2P_DEST_B32 < < " : " < < context . GetAddressBook ( ) . ToAddress ( m_From - > GetIdentHash ( ) ) < < " \r \n " ;
2016-01-11 21:48:18 +03:00
m_OutHeader < < X_I2P_DEST_HASH < < " : " < < m_From - > GetIdentHash ( ) . ToBase64 ( ) < < " \r \n " ;
2016-01-19 17:36:56 +03:00
m_OutHeader < < X_I2P_DEST_B64 < < " : " < < m_From - > ToBase64 ( ) < < " \r \n " ;
2016-01-11 21:48:18 +03:00
}
2015-06-03 19:30:15 +03:00
if ( endOfHeader )
{
2016-02-03 03:24:49 +03:00
m_OutHeader < < " \r \n " ; // end of header
2016-02-03 06:00:51 +03:00
m_OutHeader < < m_InHeader . str ( ) . substr ( m_InHeader . tellg ( ) ) ; // data right after header
2017-02-07 05:39:15 +03:00
m_InHeader . str ( " " ) ;
2015-06-03 19:30:15 +03:00
m_HeaderSent = true ;
I2PTunnelConnection : : Write ( ( uint8_t * ) m_OutHeader . str ( ) . c_str ( ) , m_OutHeader . str ( ) . length ( ) ) ;
}
2017-08-31 19:08:22 +03:00
}
2015-06-02 23:21:38 +03:00
}
2016-02-22 22:33:21 +03:00
I2PTunnelConnectionIRC : : I2PTunnelConnectionIRC ( I2PService * owner , std : : shared_ptr < i2p : : stream : : Stream > stream ,
2017-10-04 20:15:29 +03:00
std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > socket ,
const boost : : asio : : ip : : tcp : : endpoint & target , const std : : string & webircpass ) :
I2PTunnelConnection ( owner , stream , socket , target ) , m_From ( stream - > GetRemoteIdentity ( ) ) ,
m_NeedsWebIrc ( webircpass . length ( ) ? true : false ) , m_WebircPass ( webircpass )
{
}
void I2PTunnelConnectionIRC : : Write ( const uint8_t * buf , size_t len )
{
2016-10-31 16:46:59 +03:00
m_OutPacket . str ( " " ) ;
2017-10-04 20:15:29 +03:00
if ( m_NeedsWebIrc )
2016-10-31 16:46:59 +03:00
{
2017-10-04 20:15:29 +03:00
m_NeedsWebIrc = false ;
m_OutPacket < < " WEBIRC " < < m_WebircPass < < " cgiirc " < < context . GetAddressBook ( ) . ToAddress ( m_From - > GetIdentHash ( ) ) < < " " < < GetSocket ( ) - > local_endpoint ( ) . address ( ) < < std : : endl ;
}
2016-03-04 09:37:38 +03:00
2017-10-04 20:15:29 +03:00
m_InPacket . clear ( ) ;
m_InPacket . write ( ( const char * ) buf , len ) ;
2017-08-31 19:08:22 +03:00
2017-10-04 20:15:29 +03:00
while ( ! m_InPacket . eof ( ) & & ! m_InPacket . fail ( ) )
{
2016-10-31 16:46:59 +03:00
std : : string line ;
2017-10-04 20:15:29 +03:00
std : : getline ( m_InPacket , line ) ;
if ( line . length ( ) = = 0 & & m_InPacket . eof ( ) )
m_InPacket . str ( " " ) ;
auto pos = line . find ( " USER " ) ;
if ( ! pos ) // start of line
{
pos = line . find ( " " ) ;
pos + + ;
pos = line . find ( " " , pos ) ;
pos + + ;
auto nextpos = line . find ( " " , pos ) ;
m_OutPacket < < line . substr ( 0 , pos ) ;
m_OutPacket < < context . GetAddressBook ( ) . ToAddress ( m_From - > GetIdentHash ( ) ) ;
m_OutPacket < < line . substr ( nextpos ) < < ' \n ' ;
}
2016-10-31 16:46:59 +03:00
else
2017-10-04 20:15:29 +03:00
m_OutPacket < < line < < ' \n ' ;
}
I2PTunnelConnection : : Write ( ( uint8_t * ) m_OutPacket . str ( ) . c_str ( ) , m_OutPacket . str ( ) . length ( ) ) ;
}
2016-02-22 22:33:21 +03:00
2019-05-17 11:04:44 +03:00
/* This handler tries to establish a connection with the desired server and dies if it fails to do so */
2015-01-08 05:28:54 +03:00
class I2PClientTunnelHandler : public I2PServiceHandler , public std : : enable_shared_from_this < I2PClientTunnelHandler >
{
public :
2019-03-28 16:57:34 +03:00
I2PClientTunnelHandler ( I2PClientTunnel * parent , std : : shared_ptr < const Address > address ,
2015-04-06 21:41:07 +03:00
int destinationPort , std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > socket ) :
2019-03-28 16:57:34 +03:00
I2PServiceHandler ( parent ) , m_Address ( address ) ,
2015-03-13 20:29:27 +03:00
m_DestinationPort ( destinationPort ) , m_Socket ( socket ) { } ;
2015-01-08 05:28:54 +03:00
void Handle ( ) ;
void Terminate ( ) ;
private :
void HandleStreamRequestComplete ( std : : shared_ptr < i2p : : stream : : Stream > stream ) ;
2019-03-28 16:57:34 +03:00
std : : shared_ptr < const Address > m_Address ;
2015-03-13 20:29:27 +03:00
int m_DestinationPort ;
2015-04-06 21:41:07 +03:00
std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > m_Socket ;
2015-01-08 05:28:54 +03:00
} ;
void I2PClientTunnelHandler : : Handle ( )
{
2017-08-31 19:08:22 +03:00
GetOwner ( ) - > CreateStream (
std : : bind ( & I2PClientTunnelHandler : : HandleStreamRequestComplete , shared_from_this ( ) , std : : placeholders : : _1 ) ,
2019-03-28 16:57:34 +03:00
m_Address , m_DestinationPort ) ;
2015-01-08 05:28:54 +03:00
}
void I2PClientTunnelHandler : : HandleStreamRequestComplete ( std : : shared_ptr < i2p : : stream : : Stream > stream )
{
if ( stream )
{
if ( Kill ( ) ) return ;
2015-12-18 15:12:46 +03:00
LogPrint ( eLogDebug , " I2PTunnel: new connection " ) ;
2015-01-08 05:28:54 +03:00
auto connection = std : : make_shared < I2PTunnelConnection > ( GetOwner ( ) , m_Socket , stream ) ;
GetOwner ( ) - > AddHandler ( connection ) ;
connection - > I2PConnect ( ) ;
Done ( shared_from_this ( ) ) ;
}
else
{
2015-12-18 15:12:46 +03:00
LogPrint ( eLogError , " I2PTunnel: Client Tunnel Issue when creating the stream, check the previous warnings for more info. " ) ;
2015-01-08 05:28:54 +03:00
Terminate ( ) ;
}
}
void I2PClientTunnelHandler : : Terminate ( )
{
if ( Kill ( ) ) return ;
if ( m_Socket )
{
m_Socket - > close ( ) ;
m_Socket = nullptr ;
}
Done ( shared_from_this ( ) ) ;
}
2017-08-31 19:08:22 +03:00
I2PClientTunnel : : I2PClientTunnel ( const std : : string & name , const std : : string & destination ,
2017-10-04 20:15:29 +03:00
const std : : string & address , int port , std : : shared_ptr < ClientDestination > localDestination , int destinationPort ) :
2017-08-31 19:08:22 +03:00
TCPIPAcceptor ( address , port , localDestination ) , m_Name ( name ) , m_Destination ( destination ) ,
2019-03-28 16:57:34 +03:00
m_DestinationPort ( destinationPort )
2016-01-14 04:21:53 +03:00
{
2017-08-31 19:08:22 +03:00
}
2014-08-13 05:14:19 +04:00
2014-08-13 23:25:52 +04:00
void I2PClientTunnel : : Start ( )
{
2015-01-08 15:39:35 +03:00
TCPIPAcceptor : : Start ( ) ;
2019-03-28 16:57:34 +03:00
GetAddress ( ) ;
2014-08-13 23:25:52 +04:00
}
void I2PClientTunnel : : Stop ( )
{
2015-01-08 05:49:35 +03:00
TCPIPAcceptor : : Stop ( ) ;
2019-03-28 16:57:34 +03:00
m_Address = nullptr ;
2014-08-13 23:25:52 +04:00
}
2015-01-03 04:17:01 +03:00
/* HACK: maybe we should create a caching IdentHash provider in AddressBook */
2020-03-01 13:25:50 +03:00
std : : shared_ptr < const Address > I2PClientTunnel : : GetAddress ( )
2015-01-03 04:17:01 +03:00
{
2019-03-28 16:57:34 +03:00
if ( ! m_Address )
2015-01-03 04:17:01 +03:00
{
2019-03-28 16:57:34 +03:00
m_Address = i2p : : client : : context . GetAddressBook ( ) . GetAddress ( m_Destination ) ;
if ( ! m_Address )
2015-12-18 15:12:46 +03:00
LogPrint ( eLogWarning , " I2PTunnel: Remote destination " , m_Destination , " not found " ) ;
2015-01-03 04:17:01 +03:00
}
2019-03-28 16:57:34 +03:00
return m_Address ;
2015-01-03 04:17:01 +03:00
}
2015-04-06 21:41:07 +03:00
std : : shared_ptr < I2PServiceHandler > I2PClientTunnel : : CreateHandler ( std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > socket )
2014-08-13 05:14:19 +04:00
{
2019-03-28 16:57:34 +03:00
auto address = GetAddress ( ) ;
if ( address )
2020-03-01 13:25:50 +03:00
return std : : make_shared < I2PClientTunnelHandler > ( this , address , m_DestinationPort , socket ) ;
2014-08-13 05:14:19 +04:00
else
2015-01-08 05:49:35 +03:00
return nullptr ;
2014-10-15 20:07:06 +04:00
}
2017-08-31 19:08:22 +03:00
I2PServerTunnel : : I2PServerTunnel ( const std : : string & name , const std : : string & address ,
2017-10-04 20:15:29 +03:00
int port , std : : shared_ptr < ClientDestination > localDestination , int inport , bool gzip ) :
2017-01-13 00:17:11 +03:00
I2PService ( localDestination ) , m_IsUniqueLocal ( true ) , m_Name ( name ) , m_Address ( address ) , m_Port ( port ) , m_IsAccessList ( false )
2014-08-20 23:03:10 +04:00
{
2016-02-29 22:44:15 +03:00
m_PortDestination = localDestination - > CreateStreamingDestination ( inport > 0 ? inport : port , gzip ) ;
2014-08-20 23:03:10 +04:00
}
2016-07-28 18:16:29 +03:00
2014-08-20 23:03:10 +04:00
void I2PServerTunnel : : Start ( )
{
2017-08-31 19:08:22 +03:00
m_Endpoint . port ( m_Port ) ;
2015-06-02 20:18:41 +03:00
boost : : system : : error_code ec ;
auto addr = boost : : asio : : ip : : address : : from_string ( m_Address , ec ) ;
2017-08-31 19:08:22 +03:00
if ( ! ec )
2015-06-02 20:18:41 +03:00
{
m_Endpoint . address ( addr ) ;
Accept ( ) ;
}
else
{
auto resolver = std : : make_shared < boost : : asio : : ip : : tcp : : resolver > ( GetService ( ) ) ;
2017-08-31 19:08:22 +03:00
resolver - > async_resolve ( boost : : asio : : ip : : tcp : : resolver : : query ( m_Address , " " ) ,
std : : bind ( & I2PServerTunnel : : HandleResolve , this ,
2015-06-02 20:18:41 +03:00
std : : placeholders : : _1 , std : : placeholders : : _2 , resolver ) ) ;
2017-08-31 19:08:22 +03:00
}
2014-08-20 23:03:10 +04:00
}
void I2PServerTunnel : : Stop ( )
{
2015-01-07 21:09:59 +03:00
ClearHandlers ( ) ;
2017-08-31 19:08:22 +03:00
}
2014-08-20 23:03:10 +04:00
2017-08-31 19:08:22 +03:00
void I2PServerTunnel : : HandleResolve ( const boost : : system : : error_code & ecode , boost : : asio : : ip : : tcp : : resolver : : iterator it ,
2016-10-10 15:59:48 +03:00
std : : shared_ptr < boost : : asio : : ip : : tcp : : resolver > resolver )
2017-08-31 19:08:22 +03:00
{
2015-06-02 20:18:41 +03:00
if ( ! ecode )
2017-08-31 19:08:22 +03:00
{
2015-06-02 20:18:41 +03:00
auto addr = ( * it ) . endpoint ( ) . address ( ) ;
2015-12-18 15:12:46 +03:00
LogPrint ( eLogInfo , " I2PTunnel: server tunnel " , ( * it ) . host_name ( ) , " has been resolved to " , addr ) ;
2015-06-02 20:18:41 +03:00
m_Endpoint . address ( addr ) ;
2017-08-31 19:08:22 +03:00
Accept ( ) ;
}
2015-06-02 20:18:41 +03:00
else
2015-12-18 15:12:46 +03:00
LogPrint ( eLogError , " I2PTunnel: Unable to resolve server tunnel address: " , ecode . message ( ) ) ;
2015-06-02 20:18:41 +03:00
}
2015-03-16 21:52:42 +03:00
void I2PServerTunnel : : SetAccessList ( const std : : set < i2p : : data : : IdentHash > & accessList )
{
m_AccessList = accessList ;
2017-08-31 19:08:22 +03:00
m_IsAccessList = true ;
2015-03-16 21:52:42 +03:00
}
2014-08-20 23:03:10 +04:00
void I2PServerTunnel : : Accept ( )
{
2015-03-03 22:52:16 +03:00
if ( m_PortDestination )
m_PortDestination - > SetAcceptor ( std : : bind ( & I2PServerTunnel : : HandleAccept , this , std : : placeholders : : _1 ) ) ;
2017-08-31 19:08:22 +03:00
auto localDestination = GetLocalDestination ( ) ;
2014-10-01 18:58:28 +04:00
if ( localDestination )
2015-03-03 22:52:16 +03: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 18:58:28 +04:00
else
2015-12-18 15:12:46 +03:00
LogPrint ( eLogError , " I2PTunnel: Local destination not set for server tunnel " ) ;
2014-08-20 23:03:10 +04:00
}
2014-11-23 19:33:58 +03:00
void I2PServerTunnel : : HandleAccept ( std : : shared_ptr < i2p : : stream : : Stream > stream )
2014-08-20 23:03:10 +04:00
{
if ( stream )
2017-08-31 19:08:22 +03:00
{
2015-03-16 21:52:42 +03:00
if ( m_IsAccessList )
{
2015-11-03 17:15:49 +03:00
if ( ! m_AccessList . count ( stream - > GetRemoteIdentity ( ) - > GetIdentHash ( ) ) )
2015-03-16 21:52:42 +03:00
{
2015-12-18 15:12:46 +03:00
LogPrint ( eLogWarning , " I2PTunnel: Address " , stream - > GetRemoteIdentity ( ) - > GetIdentHash ( ) . ToBase32 ( ) , " is not in white list. Incoming connection dropped " ) ;
2015-03-16 21:52:42 +03:00
stream - > Close ( ) ;
return ;
}
}
2017-01-13 21:47:51 +03:00
// new connection
auto conn = CreateI2PConnection ( stream ) ;
AddHandler ( conn ) ;
conn - > Connect ( m_IsUniqueLocal ) ;
2017-08-31 19:08:22 +03:00
}
2014-08-20 23:03:10 +04:00
}
2015-05-20 23:00:09 +03:00
2017-01-13 21:47:51 +03:00
std : : shared_ptr < I2PTunnelConnection > I2PServerTunnel : : CreateI2PConnection ( std : : shared_ptr < i2p : : stream : : Stream > stream )
2015-06-02 20:03:22 +03:00
{
2017-01-13 21:47:51 +03:00
return std : : make_shared < I2PTunnelConnection > ( this , stream , std : : make_shared < boost : : asio : : ip : : tcp : : socket > ( GetService ( ) ) , GetEndpoint ( ) ) ;
2017-08-31 19:08:22 +03:00
2015-06-02 20:03:22 +03:00
}
2017-08-31 19:08:22 +03:00
I2PServerTunnelHTTP : : I2PServerTunnelHTTP ( const std : : string & name , const std : : string & address ,
2017-10-04 20:15:29 +03:00
int port , std : : shared_ptr < ClientDestination > localDestination ,
const std : : string & host , int inport , bool gzip ) :
2017-08-31 19:08:22 +03:00
I2PServerTunnel ( name , address , port , localDestination , inport , gzip ) ,
2016-11-02 17:12:54 +03:00
m_Host ( host )
2015-06-02 20:03:22 +03:00
{
}
2017-01-13 21:47:51 +03:00
std : : shared_ptr < I2PTunnelConnection > I2PServerTunnelHTTP : : CreateI2PConnection ( std : : shared_ptr < i2p : : stream : : Stream > stream )
2015-05-20 23:00:09 +03:00
{
2017-08-31 19:08:22 +03:00
return std : : make_shared < I2PServerTunnelConnectionHTTP > ( this , stream ,
2016-02-26 04:32:05 +03:00
std : : make_shared < boost : : asio : : ip : : tcp : : socket > ( GetService ( ) ) , GetEndpoint ( ) , m_Host ) ;
2015-05-20 23:00:09 +03:00
}
2016-02-22 22:33:21 +03:00
2017-10-04 20:15:29 +03:00
I2PServerTunnelIRC : : I2PServerTunnelIRC ( const std : : string & name , const std : : string & address ,
int port , std : : shared_ptr < ClientDestination > localDestination ,
const std : : string & webircpass , int inport , bool gzip ) :
I2PServerTunnel ( name , address , port , localDestination , inport , gzip ) ,
m_WebircPass ( webircpass )
{
}
std : : shared_ptr < I2PTunnelConnection > I2PServerTunnelIRC : : CreateI2PConnection ( std : : shared_ptr < i2p : : stream : : Stream > stream )
{
return std : : make_shared < I2PTunnelConnectionIRC > ( this , stream , std : : make_shared < boost : : asio : : ip : : tcp : : socket > ( GetService ( ) ) , GetEndpoint ( ) , this - > m_WebircPass ) ;
}
void I2PUDPServerTunnel : : HandleRecvFromI2P ( const i2p : : data : : IdentityEx & from , uint16_t fromPort , uint16_t toPort , const uint8_t * buf , size_t len )
{
2020-06-16 03:10:47 +03:00
if ( ! m_LastSession | | m_LastSession - > Identity . GetLL ( ) [ 0 ] ! = from . GetIdentHash ( ) . GetLL ( ) [ 0 ] | | fromPort ! = m_LastSession - > RemotePort )
2020-06-10 04:48:47 +03:00
{
std : : lock_guard < std : : mutex > lock ( m_SessionsMutex ) ;
m_LastSession = ObtainUDPSession ( from , toPort , fromPort ) ;
}
m_LastSession - > IPSocket . send_to ( boost : : asio : : buffer ( buf , len ) , m_RemoteEndpoint ) ;
m_LastSession - > LastActivity = i2p : : util : : GetMillisecondsSinceEpoch ( ) ;
2017-10-04 20:15:29 +03:00
}
2020-06-10 04:48:47 +03:00
void I2PUDPServerTunnel : : HandleRecvFromI2PRaw ( uint16_t , uint16_t , const uint8_t * buf , size_t len )
{
if ( m_LastSession )
{
m_LastSession - > IPSocket . send_to ( boost : : asio : : buffer ( buf , len ) , m_RemoteEndpoint ) ;
m_LastSession - > LastActivity = i2p : : util : : GetMillisecondsSinceEpoch ( ) ;
}
}
2017-10-04 20:15:29 +03:00
void I2PUDPServerTunnel : : ExpireStale ( const uint64_t delta ) {
std : : lock_guard < std : : mutex > lock ( m_SessionsMutex ) ;
uint64_t now = i2p : : util : : GetMillisecondsSinceEpoch ( ) ;
2016-12-12 23:50:36 +03:00
auto itr = m_Sessions . begin ( ) ;
while ( itr ! = m_Sessions . end ( ) ) {
if ( now - ( * itr ) - > LastActivity > = delta )
itr = m_Sessions . erase ( itr ) ;
else
+ + itr ;
}
2017-10-04 20:15:29 +03:00
}
2016-11-17 18:36:27 +03:00
void I2PUDPClientTunnel : : ExpireStale ( const uint64_t delta ) {
std : : lock_guard < std : : mutex > lock ( m_SessionsMutex ) ;
2017-10-04 20:15:29 +03:00
uint64_t now = i2p : : util : : GetMillisecondsSinceEpoch ( ) ;
2016-11-17 18:36:27 +03:00
std : : vector < uint16_t > removePorts ;
for ( const auto & s : m_Sessions ) {
2020-06-07 23:24:11 +03:00
if ( now - s . second - > second > = delta )
2016-11-17 18:36:27 +03:00
removePorts . push_back ( s . first ) ;
}
for ( auto port : removePorts ) {
m_Sessions . erase ( port ) ;
}
2017-10-04 20:15:29 +03:00
}
2017-08-31 19:08:22 +03:00
2016-12-23 15:27:34 +03:00
UDPSessionPtr I2PUDPServerTunnel : : ObtainUDPSession ( const i2p : : data : : IdentityEx & from , uint16_t localPort , uint16_t remotePort )
2017-10-04 20:15:29 +03:00
{
auto ih = from . GetIdentHash ( ) ;
for ( auto & s : m_Sessions )
{
2020-06-16 03:10:47 +03:00
if ( s - > Identity . GetLL ( ) [ 0 ] = = ih . GetLL ( ) [ 0 ] & & remotePort = = s - > RemotePort )
2017-10-04 20:15:29 +03:00
{
/** found existing session */
LogPrint ( eLogDebug , " UDPServer: found session " , s - > IPSocket . local_endpoint ( ) , " " , ih . ToBase32 ( ) ) ;
return s ;
}
}
2016-12-25 16:56:47 +03:00
boost : : asio : : ip : : address addr ;
/** create new udp session */
2017-08-31 19:08:22 +03:00
if ( m_IsUniqueLocal & & m_LocalAddress . is_loopback ( ) )
2017-01-13 00:17:11 +03:00
{
2016-12-25 16:56:47 +03:00
auto ident = from . GetIdentHash ( ) ;
addr = GetLoopbackAddressFor ( ident ) ;
2017-08-31 19:08:22 +03:00
}
else
2016-12-25 16:56:47 +03:00
addr = m_LocalAddress ;
boost : : asio : : ip : : udp : : endpoint ep ( addr , 0 ) ;
2017-10-04 20:15:29 +03:00
m_Sessions . push_back ( std : : make_shared < UDPSession > ( ep , m_LocalDest , m_RemoteEndpoint , & ih , localPort , remotePort ) ) ;
2016-11-17 18:36:27 +03:00
auto & back = m_Sessions . back ( ) ;
return back ;
2017-10-04 20:15:29 +03:00
}
2016-08-21 22:02:17 +03:00
2017-10-04 20:15:29 +03:00
UDPSession : : UDPSession ( boost : : asio : : ip : : udp : : endpoint localEndpoint ,
const std : : shared_ptr < i2p : : client : : ClientDestination > & localDestination ,
boost : : asio : : ip : : udp : : endpoint endpoint , const i2p : : data : : IdentHash * to ,
uint16_t ourPort , uint16_t theirPort ) :
m_Destination ( localDestination - > GetDatagramDestination ( ) ) ,
2016-09-04 00:53:46 +03:00
IPSocket ( localDestination - > GetService ( ) , localEndpoint ) ,
SendEndpoint ( endpoint ) ,
LastActivity ( i2p : : util : : GetMillisecondsSinceEpoch ( ) ) ,
LocalPort ( ourPort ) ,
RemotePort ( theirPort )
{
2020-06-12 23:06:07 +03:00
IPSocket . set_option ( boost : : asio : : socket_base : : receive_buffer_size ( I2P_UDP_MAX_MTU ) ) ;
2016-10-09 17:55:55 +03:00
memcpy ( Identity , to - > data ( ) , 32 ) ;
2016-09-04 00:53:46 +03:00
Receive ( ) ;
}
2016-08-21 22:02:17 +03:00
2016-09-04 00:53:46 +03:00
void UDPSession : : Receive ( ) {
LogPrint ( eLogDebug , " UDPSession: Receive " ) ;
IPSocket . async_receive_from ( boost : : asio : : buffer ( m_Buffer , I2P_UDP_MAX_MTU ) ,
FromEndpoint , std : : bind ( & UDPSession : : HandleReceived , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) ) ;
}
2017-08-31 19:08:22 +03:00
2016-09-04 00:53:46 +03:00
void UDPSession : : HandleReceived ( const boost : : system : : error_code & ecode , std : : size_t len )
{
if ( ! ecode )
{
LogPrint ( eLogDebug , " UDPSession: forward " , len , " B from " , FromEndpoint ) ;
2020-07-25 03:44:01 +03:00
auto ts = i2p : : util : : GetMillisecondsSinceEpoch ( ) ;
2020-06-12 05:04:32 +03:00
auto session = m_Destination - > GetSession ( Identity ) ;
2020-07-25 03:44:01 +03:00
if ( ts > LastActivity + I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL )
m_Destination - > SendDatagram ( session , m_Buffer , len , LocalPort , RemotePort ) ;
else
m_Destination - > SendRawDatagram ( session , m_Buffer , len , LocalPort , RemotePort ) ;
2020-06-12 05:04:32 +03:00
size_t numPackets = 0 ;
while ( numPackets < i2p : : datagram : : DATAGRAM_SEND_QUEUE_MAX_SIZE )
{
boost : : system : : error_code ec ;
size_t moreBytes = IPSocket . available ( ec ) ;
if ( ec | | ! moreBytes ) break ;
len = IPSocket . receive_from ( boost : : asio : : buffer ( m_Buffer , I2P_UDP_MAX_MTU ) , FromEndpoint , 0 , ec ) ;
m_Destination - > SendRawDatagram ( session , m_Buffer , len , LocalPort , RemotePort ) ;
numPackets + + ;
}
if ( numPackets > 0 )
LogPrint ( eLogDebug , " UDPSession: forward more " , numPackets , " packets B from " , FromEndpoint ) ;
m_Destination - > FlushSendQueue ( session ) ;
2020-07-25 03:44:01 +03:00
LastActivity = ts ;
2016-09-04 00:53:46 +03:00
Receive ( ) ;
2020-06-12 05:04:32 +03:00
}
else
2016-09-04 00:53:46 +03:00
LogPrint ( eLogError , " UDPSession: " , ecode . message ( ) ) ;
}
2016-08-22 20:54:00 +03:00
2016-09-04 00:53:46 +03:00
I2PUDPServerTunnel : : I2PUDPServerTunnel ( const std : : string & name , std : : shared_ptr < i2p : : client : : ClientDestination > localDestination ,
2020-05-18 19:01:13 +03:00
boost : : asio : : ip : : address localAddress , boost : : asio : : ip : : udp : : endpoint forwardTo , uint16_t port , bool gzip ) :
2017-01-13 00:17:11 +03:00
m_IsUniqueLocal ( true ) ,
2016-09-04 00:53:46 +03:00
m_Name ( name ) ,
m_LocalAddress ( localAddress ) ,
m_RemoteEndpoint ( forwardTo )
{
m_LocalDest = localDestination ;
m_LocalDest - > Start ( ) ;
2020-05-18 19:01:13 +03:00
auto dgram = m_LocalDest - > CreateDatagramDestination ( gzip ) ;
2016-09-04 00:53:46 +03:00
dgram - > SetReceiver ( std : : bind ( & I2PUDPServerTunnel : : HandleRecvFromI2P , this , std : : placeholders : : _1 , std : : placeholders : : _2 , std : : placeholders : : _3 , std : : placeholders : : _4 , std : : placeholders : : _5 ) ) ;
2020-06-10 04:48:47 +03:00
dgram - > SetRawReceiver ( std : : bind ( & I2PUDPServerTunnel : : HandleRecvFromI2PRaw , this , std : : placeholders : : _1 , std : : placeholders : : _2 , std : : placeholders : : _3 , std : : placeholders : : _4 ) ) ;
2016-09-04 00:53:46 +03:00
}
2016-08-21 22:02:17 +03:00
2016-09-04 00:53:46 +03:00
I2PUDPServerTunnel : : ~ I2PUDPServerTunnel ( )
{
auto dgram = m_LocalDest - > GetDatagramDestination ( ) ;
if ( dgram ) dgram - > ResetReceiver ( ) ;
2017-08-31 19:08:22 +03:00
2016-09-04 00:53:46 +03:00
LogPrint ( eLogInfo , " UDPServer: done " ) ;
}
2016-08-21 22:02:17 +03:00
2016-09-04 00:53:46 +03:00
void I2PUDPServerTunnel : : Start ( ) {
m_LocalDest - > Start ( ) ;
}
2016-09-03 20:58:34 +03:00
2016-09-04 00:53:46 +03:00
std : : vector < std : : shared_ptr < DatagramSessionInfo > > I2PUDPServerTunnel : : GetSessions ( )
2016-09-03 20:58:34 +03:00
{
2016-09-04 00:53:46 +03:00
std : : vector < std : : shared_ptr < DatagramSessionInfo > > sessions ;
2016-09-03 20:58:34 +03:00
std : : lock_guard < std : : mutex > lock ( m_SessionsMutex ) ;
2016-12-23 15:27:34 +03:00
for ( UDPSessionPtr s : m_Sessions )
2016-09-03 20:58:34 +03:00
{
2016-11-17 19:37:48 +03:00
if ( ! s - > m_Destination ) continue ;
auto info = s - > m_Destination - > GetInfoForRemote ( s - > Identity ) ;
2016-09-03 20:58:34 +03:00
if ( ! info ) continue ;
2016-09-04 00:53:46 +03:00
auto sinfo = std : : make_shared < DatagramSessionInfo > ( ) ;
sinfo - > Name = m_Name ;
sinfo - > LocalIdent = std : : make_shared < i2p : : data : : IdentHash > ( m_LocalDest - > GetIdentHash ( ) . data ( ) ) ;
2016-11-17 19:37:48 +03:00
sinfo - > RemoteIdent = std : : make_shared < i2p : : data : : IdentHash > ( s - > Identity . data ( ) ) ;
2016-09-04 00:53:46 +03:00
sinfo - > CurrentIBGW = info - > IBGW ;
sinfo - > CurrentOBEP = info - > OBEP ;
sessions . push_back ( sinfo ) ;
2016-09-03 20:58:34 +03:00
}
return sessions ;
}
2017-08-31 19:08:22 +03:00
2016-09-04 00:53:46 +03:00
I2PUDPClientTunnel : : I2PUDPClientTunnel ( const std : : string & name , const std : : string & remoteDest ,
boost : : asio : : ip : : udp : : endpoint localEndpoint ,
std : : shared_ptr < i2p : : client : : ClientDestination > localDestination ,
2020-05-18 19:01:13 +03:00
uint16_t remotePort , bool gzip ) :
2016-09-04 00:53:46 +03:00
m_Name ( name ) ,
m_RemoteDest ( remoteDest ) ,
m_LocalDest ( localDestination ) ,
m_LocalEndpoint ( localEndpoint ) ,
m_RemoteIdent ( nullptr ) ,
m_ResolveThread ( nullptr ) ,
2016-11-17 18:36:27 +03:00
m_LocalSocket ( localDestination - > GetService ( ) , localEndpoint ) ,
2020-06-07 23:24:11 +03:00
RemotePort ( remotePort ) , m_LastPort ( 0 ) ,
2016-09-04 00:53:46 +03:00
m_cancel_resolve ( false )
{
2020-06-12 23:06:07 +03:00
m_LocalSocket . set_option ( boost : : asio : : socket_base : : receive_buffer_size ( I2P_UDP_MAX_MTU ) ) ;
2020-05-18 19:01:13 +03:00
auto dgram = m_LocalDest - > CreateDatagramDestination ( gzip ) ;
2016-09-04 00:53:46 +03:00
dgram - > SetReceiver ( std : : bind ( & I2PUDPClientTunnel : : HandleRecvFromI2P , this ,
2017-10-04 20:15:29 +03:00
std : : placeholders : : _1 , std : : placeholders : : _2 ,
std : : placeholders : : _3 , std : : placeholders : : _4 ,
std : : placeholders : : _5 ) ) ;
2020-06-12 05:04:32 +03:00
dgram - > SetRawReceiver ( std : : bind ( & I2PUDPClientTunnel : : HandleRecvFromI2PRaw , this ,
std : : placeholders : : _1 , std : : placeholders : : _2 , std : : placeholders : : _3 , std : : placeholders : : _4 ) ) ;
2016-09-04 00:53:46 +03:00
}
2016-08-21 22:02:17 +03:00
2016-09-04 00:53:46 +03:00
void I2PUDPClientTunnel : : Start ( ) {
m_LocalDest - > Start ( ) ;
if ( m_ResolveThread = = nullptr )
m_ResolveThread = new std : : thread ( std : : bind ( & I2PUDPClientTunnel : : TryResolving , this ) ) ;
2016-11-17 18:36:27 +03:00
RecvFromLocal ( ) ;
}
void I2PUDPClientTunnel : : RecvFromLocal ( )
{
m_LocalSocket . async_receive_from ( boost : : asio : : buffer ( m_RecvBuff , I2P_UDP_MAX_MTU ) ,
m_RecvEndpoint , std : : bind ( & I2PUDPClientTunnel : : HandleRecvFromLocal , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) ) ;
2016-09-04 00:53:46 +03:00
}
2016-08-21 22:02:17 +03:00
2016-11-17 18:36:27 +03:00
void I2PUDPClientTunnel : : HandleRecvFromLocal ( const boost : : system : : error_code & ec , std : : size_t transferred )
{
2016-11-17 19:13:40 +03:00
if ( ec ) {
LogPrint ( eLogError , " UDP Client: " , ec . message ( ) ) ;
return ;
}
2016-11-17 19:10:42 +03:00
if ( ! m_RemoteIdent ) {
LogPrint ( eLogWarning , " UDP Client: remote endpoint not resolved yet " ) ;
2016-11-17 19:13:40 +03:00
RecvFromLocal ( ) ;
2016-11-17 19:10:42 +03:00
return ; // drop, remote not resolved
}
2016-11-17 18:36:27 +03:00
auto remotePort = m_RecvEndpoint . port ( ) ;
2020-06-07 23:24:11 +03:00
if ( ! m_LastPort | | m_LastPort ! = remotePort )
{
auto itr = m_Sessions . find ( remotePort ) ;
if ( itr ! = m_Sessions . end ( ) )
m_LastSession = itr - > second ;
else
{
m_LastSession = std : : make_shared < UDPConvo > ( boost : : asio : : ip : : udp : : endpoint ( m_RecvEndpoint ) , 0 ) ;
m_Sessions . emplace ( remotePort , m_LastSession ) ;
}
m_LastPort = remotePort ;
}
2016-11-17 18:36:27 +03:00
// send off to remote i2p destination
2020-07-25 03:44:01 +03:00
auto ts = i2p : : util : : GetMillisecondsSinceEpoch ( ) ;
2016-11-17 19:10:42 +03:00
LogPrint ( eLogDebug , " UDP Client: send " , transferred , " to " , m_RemoteIdent - > ToBase32 ( ) , " : " , RemotePort ) ;
2020-06-10 02:20:24 +03:00
auto session = m_LocalDest - > GetDatagramDestination ( ) - > GetSession ( * m_RemoteIdent ) ;
2020-07-25 03:44:01 +03:00
if ( ts > m_LastSession - > second + I2P_UDP_REPLIABLE_DATAGRAM_INTERVAL )
m_LocalDest - > GetDatagramDestination ( ) - > SendDatagram ( session , m_RecvBuff , transferred , remotePort , RemotePort ) ;
else
m_LocalDest - > GetDatagramDestination ( ) - > SendRawDatagram ( session , m_RecvBuff , transferred , remotePort , RemotePort ) ;
2020-06-09 23:26:45 +03:00
size_t numPackets = 0 ;
while ( numPackets < i2p : : datagram : : DATAGRAM_SEND_QUEUE_MAX_SIZE )
{
boost : : system : : error_code ec ;
size_t moreBytes = m_LocalSocket . available ( ec ) ;
if ( ec | | ! moreBytes ) break ;
transferred = m_LocalSocket . receive_from ( boost : : asio : : buffer ( m_RecvBuff , I2P_UDP_MAX_MTU ) , m_RecvEndpoint , 0 , ec ) ;
remotePort = m_RecvEndpoint . port ( ) ;
// TODO: check remotePort
2020-06-10 04:48:47 +03:00
m_LocalDest - > GetDatagramDestination ( ) - > SendRawDatagram ( session , m_RecvBuff , transferred , remotePort , RemotePort ) ;
2020-06-09 23:26:45 +03:00
numPackets + + ;
}
if ( numPackets )
LogPrint ( eLogDebug , " UDP Client: sent " , numPackets , " more packets to " , m_RemoteIdent - > ToBase32 ( ) ) ;
2020-06-10 02:20:24 +03:00
m_LocalDest - > GetDatagramDestination ( ) - > FlushSendQueue ( session ) ;
2020-06-09 23:26:45 +03:00
2016-11-17 18:36:27 +03:00
// mark convo as active
2020-06-07 23:24:11 +03:00
if ( m_LastSession )
2020-07-25 03:44:01 +03:00
m_LastSession - > second = ts ;
2016-11-17 19:13:40 +03:00
RecvFromLocal ( ) ;
2016-11-17 18:36:27 +03:00
}
2017-08-31 19:08:22 +03:00
2016-09-04 00:53:46 +03:00
std : : vector < std : : shared_ptr < DatagramSessionInfo > > I2PUDPClientTunnel : : GetSessions ( )
2016-09-03 20:58:34 +03:00
{
2016-11-17 18:36:27 +03:00
// TODO: implement
2016-09-04 00:53:46 +03:00
std : : vector < std : : shared_ptr < DatagramSessionInfo > > infos ;
2016-09-03 20:58:34 +03:00
return infos ;
}
2017-08-31 19:08:22 +03:00
2016-09-04 00:53:46 +03:00
void I2PUDPClientTunnel : : TryResolving ( ) {
LogPrint ( eLogInfo , " UDP Tunnel: Trying to resolve " , m_RemoteDest ) ;
2016-08-22 05:11:41 +03:00
2019-03-28 19:19:19 +03:00
std : : shared_ptr < const Address > addr ;
while ( ! ( addr = context . GetAddressBook ( ) . GetAddress ( m_RemoteDest ) ) & & ! m_cancel_resolve )
2016-09-04 00:53:46 +03:00
{
LogPrint ( eLogWarning , " UDP Tunnel: failed to lookup " , m_RemoteDest ) ;
std : : this_thread : : sleep_for ( std : : chrono : : seconds ( 1 ) ) ;
}
if ( m_cancel_resolve )
{
LogPrint ( eLogError , " UDP Tunnel: lookup of " , m_RemoteDest , " was cancelled " ) ;
return ;
}
2019-03-28 19:19:19 +03:00
if ( ! addr | | ! addr - > IsIdentHash ( ) )
{
LogPrint ( eLogError , " UDP Tunnel: " , m_RemoteDest , " not found " ) ;
return ;
2020-03-01 13:25:50 +03:00
}
2019-03-28 19:19:19 +03:00
m_RemoteIdent = new i2p : : data : : IdentHash ;
* m_RemoteIdent = addr - > identHash ;
2016-12-25 00:31:28 +03:00
LogPrint ( eLogInfo , " UDP Tunnel: resolved " , m_RemoteDest , " to " , m_RemoteIdent - > ToBase32 ( ) ) ;
2016-09-04 00:53:46 +03:00
}
2016-08-21 22:02:17 +03:00
2016-10-10 15:59:48 +03:00
void I2PUDPClientTunnel : : HandleRecvFromI2P ( const i2p : : data : : IdentityEx & from , uint16_t fromPort , uint16_t toPort , const uint8_t * buf , size_t len )
2016-09-04 00:53:46 +03:00
{
if ( m_RemoteIdent & & from . GetIdentHash ( ) = = * m_RemoteIdent )
2020-06-12 05:04:32 +03:00
HandleRecvFromI2PRaw ( fromPort , toPort , buf , len ) ;
else
LogPrint ( eLogWarning , " UDP Client: unwarranted traffic from " , from . GetIdentHash ( ) . ToBase32 ( ) ) ;
}
void I2PUDPClientTunnel : : HandleRecvFromI2PRaw ( uint16_t fromPort , uint16_t toPort , const uint8_t * buf , size_t len )
{
auto itr = m_Sessions . find ( toPort ) ;
// found convo ?
if ( itr ! = m_Sessions . end ( ) )
2016-09-04 00:53:46 +03:00
{
2020-06-12 05:04:32 +03:00
// found convo
if ( len > 0 )
2016-09-04 00:53:46 +03:00
{
2020-06-12 05:04:32 +03:00
LogPrint ( eLogDebug , " UDP Client: got " , len , " B from " , m_RemoteIdent ? m_RemoteIdent - > ToBase32 ( ) : " " ) ;
m_LocalSocket . send_to ( boost : : asio : : buffer ( buf , len ) , itr - > second - > first ) ;
// mark convo as active
itr - > second - > second = i2p : : util : : GetMillisecondsSinceEpoch ( ) ;
2016-09-04 00:53:46 +03:00
}
}
else
2020-06-12 05:04:32 +03:00
LogPrint ( eLogWarning , " UDP Client: not tracking udp session using port " , ( int ) toPort ) ;
2016-09-04 00:53:46 +03:00
}
2020-06-12 05:04:32 +03:00
2016-09-04 00:53:46 +03:00
I2PUDPClientTunnel : : ~ I2PUDPClientTunnel ( ) {
auto dgram = m_LocalDest - > GetDatagramDestination ( ) ;
if ( dgram ) dgram - > ResetReceiver ( ) ;
2016-09-03 16:38:53 +03:00
2016-11-17 18:36:27 +03:00
m_Sessions . clear ( ) ;
2017-08-31 19:08:22 +03:00
2016-11-17 18:36:27 +03:00
if ( m_LocalSocket . is_open ( ) )
m_LocalSocket . close ( ) ;
2016-12-23 15:27:34 +03:00
2016-09-04 00:53:46 +03:00
m_cancel_resolve = true ;
2016-09-03 16:38:53 +03:00
2016-09-04 00:53:46 +03:00
if ( m_ResolveThread )
{
m_ResolveThread - > join ( ) ;
delete m_ResolveThread ;
m_ResolveThread = nullptr ;
}
if ( m_RemoteIdent ) delete m_RemoteIdent ;
}
2016-09-03 16:38:53 +03:00
}
}