2019-05-16 08:17:05 +03:00
/*
2023-01-16 13:57:15 +03:00
* Copyright ( c ) 2013 - 2023 , The PurpleI2P Project
2019-05-16 08:17:05 +03:00
*
* This file is part of Purple i2pd project and licensed under BSD3
*
* See full license text in LICENSE file at top of project tree
*/
2015-01-07 02:15:38 +03:00
# include <cstring>
# include <cassert>
2015-01-07 21:09:59 +03:00
# include <string>
# include <atomic>
2016-06-23 03:00:00 +03:00
# include <memory>
# include <set>
# include <boost/asio.hpp>
2019-05-16 08:17:05 +03:00
# include <boost/algorithm/string/predicate.hpp>
2016-06-23 03:00:00 +03:00
# include <mutex>
# include "I2PService.h"
# include "Destination.h"
2014-03-18 02:31:29 +04:00
# include "HTTPProxy.h"
2015-02-07 20:34:25 +03:00
# include "util.h"
2015-01-07 02:15:38 +03:00
# include "Identity.h"
2015-01-07 21:09:59 +03:00
# include "Streaming.h"
2015-01-07 02:15:38 +03:00
# include "Destination.h"
# include "ClientContext.h"
# include "I2PEndian.h"
2015-01-07 21:09:59 +03:00
# include "I2PTunnel.h"
2016-03-11 13:30:50 +03:00
# include "Config.h"
2016-05-27 03:00:00 +03:00
# include "HTTP.h"
2021-05-23 06:06:04 +03:00
# include "I18N.h"
2014-03-18 02:31:29 +04:00
2016-06-23 03:00:00 +03:00
namespace i2p {
namespace proxy {
2022-05-20 20:49:26 +03:00
static const std : : vector < std : : string > jumporder = {
" reg.i2p " ,
" stats.i2p " ,
" identiguy.i2p " ,
2022-11-14 23:29:16 +03:00
" notbob.i2p "
2022-05-20 20:49:26 +03:00
} ;
static const std : : map < std : : string , std : : string > jumpservices = {
2021-01-27 06:48:35 +03:00
{ " reg.i2p " , " http://shx5vqsw7usdaunyzr2qmes2fq37oumybpudrd4jjj4e4vk4uusa.b32.i2p/jump/ " } ,
{ " identiguy.i2p " , " http://3mzmrus2oron5fxptw7hw2puho3bnqmw2hqy7nw64dsrrjwdilva.b32.i2p/cgi-bin/query?hostname= " } ,
{ " stats.i2p " , " http://7tbay5p4kzeekxvyvbf6v7eauazemsnnl2aoyqhg5jzpr5eke7tq.b32.i2p/cgi-bin/jump.cgi?a= " } ,
2022-11-14 23:29:16 +03:00
{ " notbob.i2p " , " http://nytzrhrjjfsutowojvxi7hphesskpqqr65wpistz6wa7cpajhp7a.b32.i2p/cgi-bin/jump.cgi?q= " }
2016-07-14 03:00:00 +03:00
} ;
static const char * pageHead =
" <head> \r \n "
2021-02-09 08:32:35 +03:00
" <meta name= \" viewport \" content= \" width=device-width, initial-scale=1.0 \" > \r \n "
2016-11-17 06:04:29 +03:00
" <title>I2Pd HTTP proxy</title> \r \n "
2016-07-14 03:00:00 +03:00
" <style type= \" text/css \" > \r \n "
" body { font: 100%/1.5em sans-serif; margin: 0; padding: 1.5em; background: #FAFAFA; color: #103456; } \r \n "
2021-02-09 08:32:35 +03:00
" h1 { font-size: 1.7em; color: #894C84; } \r \n "
" @media screen and (max-width: 980px) { h1 { font-size: 1.7em; text-align: center; color: #894C84; }} \r \n "
2016-07-14 03:00:00 +03:00
" </style> \r \n "
" </head> \r \n "
;
2016-06-27 04:30:00 +03:00
bool str_rmatch ( std : : string & str , const char * suffix ) {
auto pos = str . rfind ( suffix ) ;
if ( pos = = std : : string : : npos )
return false ; /* not found */
if ( str . length ( ) = = ( pos + std : : strlen ( suffix ) ) )
return true ; /* match */
return false ;
}
2016-06-23 03:00:00 +03:00
class HTTPReqHandler : public i2p : : client : : I2PServiceHandler , public std : : enable_shared_from_this < HTTPReqHandler >
2015-03-17 18:44:01 +03:00
{
2015-01-07 21:09:59 +03:00
private :
2016-07-01 03:00:00 +03:00
bool HandleRequest ( ) ;
2015-01-07 21:09:59 +03:00
void HandleSockRecv ( const boost : : system : : error_code & ecode , std : : size_t bytes_transfered ) ;
void Terminate ( ) ;
void AsyncSockRead ( ) ;
2017-11-16 01:13:42 +03:00
bool ExtractAddressHelper ( i2p : : http : : URL & url , std : : string & b64 , bool & confirm ) ;
2016-07-01 03:00:00 +03:00
void SanitizeHTTPRequest ( i2p : : http : : HTTPReq & req ) ;
2015-01-07 21:09:59 +03:00
void SentHTTPFailed ( const boost : : system : : error_code & ecode ) ;
void HandleStreamRequestComplete ( std : : shared_ptr < i2p : : stream : : Stream > stream ) ;
2016-07-14 03:00:00 +03:00
/* error helpers */
2021-05-23 06:06:04 +03:00
void GenericProxyError ( const std : : string & title , const std : : string & description ) ;
void GenericProxyInfo ( const std : : string & title , const std : : string & description ) ;
2022-10-09 22:13:49 +03:00
void HostNotFound ( std : : string & host ) ;
void SendProxyError ( std : : string & content ) ;
void SendRedirect ( std : : string & address ) ;
2015-01-07 21:09:59 +03:00
2019-04-25 23:06:14 +03:00
void ForwardToUpstreamProxy ( ) ;
void HandleUpstreamHTTPProxyConnect ( const boost : : system : : error_code & ec ) ;
void HandleUpstreamSocksProxyConnect ( const boost : : system : : error_code & ec ) ;
void HTTPConnect ( const std : : string & host , uint16_t port ) ;
void HandleHTTPConnectStreamRequestComplete ( std : : shared_ptr < i2p : : stream : : Stream > stream ) ;
2017-09-03 16:46:55 +03:00
2019-04-25 23:06:14 +03:00
void HandleSocksProxySendHandshake ( const boost : : system : : error_code & ec , std : : size_t bytes_transfered ) ;
void HandleSocksProxyReply ( const boost : : system : : error_code & ec , std : : size_t bytes_transfered ) ;
2017-09-03 16:46:55 +03:00
2019-04-25 23:06:14 +03:00
typedef std : : function < void ( boost : : asio : : ip : : tcp : : endpoint ) > ProxyResolvedHandler ;
2017-09-03 16:46:55 +03:00
2019-04-25 23:06:14 +03:00
void HandleUpstreamProxyResolved ( const boost : : system : : error_code & ecode , boost : : asio : : ip : : tcp : : resolver : : iterator itr , ProxyResolvedHandler handler ) ;
2016-11-20 17:25:56 +03:00
2019-04-25 23:06:14 +03:00
void SocksProxySuccess ( ) ;
void HandoverToUpstreamProxy ( ) ;
2017-09-03 16:46:55 +03:00
2016-07-01 03:00:00 +03:00
uint8_t m_recv_chunk [ 8192 ] ;
std : : string m_recv_buf ; // from client
std : : string m_send_buf ; // to upstream
2015-04-06 21:41:07 +03:00
std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > m_sock ;
2019-04-25 23:06:14 +03:00
std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > m_proxysock ;
boost : : asio : : ip : : tcp : : resolver m_proxy_resolver ;
std : : string m_OutproxyUrl ;
bool m_Addresshelper ;
i2p : : http : : URL m_ProxyURL ;
i2p : : http : : URL m_RequestURL ;
uint8_t m_socks_buf [ 255 + 8 ] ; // for socks request/response
2023-02-28 20:41:17 +03:00
int m_req_len ;
2019-04-25 23:06:14 +03:00
i2p : : http : : URL m_ClientRequestURL ;
i2p : : http : : HTTPReq m_ClientRequest ;
i2p : : http : : HTTPRes m_ClientResponse ;
std : : stringstream m_ClientRequestBuffer ;
2015-01-07 21:09:59 +03:00
public :
2015-03-17 18:44:01 +03:00
2016-06-23 03:00:00 +03:00
HTTPReqHandler ( HTTPProxy * parent , std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > sock ) :
2016-11-20 17:25:56 +03:00
I2PServiceHandler ( parent ) , m_sock ( sock ) ,
m_proxysock ( std : : make_shared < boost : : asio : : ip : : tcp : : socket > ( parent - > GetService ( ) ) ) ,
2017-10-27 15:42:54 +03:00
m_proxy_resolver ( parent - > GetService ( ) ) ,
2019-04-25 23:06:14 +03:00
m_OutproxyUrl ( parent - > GetOutproxyURL ( ) ) ,
m_Addresshelper ( parent - > GetHelperSupport ( ) ) { }
2016-06-23 03:00:00 +03:00
~ HTTPReqHandler ( ) { Terminate ( ) ; }
2016-07-01 03:00:00 +03:00
void Handle ( ) { AsyncSockRead ( ) ; } /* overload */
2015-01-07 21:09:59 +03:00
} ;
2016-06-23 03:00:00 +03:00
void HTTPReqHandler : : AsyncSockRead ( )
2015-01-07 02:15:38 +03:00
{
2021-11-27 22:53:53 +03:00
LogPrint ( eLogDebug , " HTTPProxy: Async sock read " ) ;
2016-06-27 16:00:00 +03:00
if ( ! m_sock ) {
2021-11-27 22:53:53 +03:00
LogPrint ( eLogError , " HTTPProxy: No socket for read " ) ;
2016-06-27 16:00:00 +03:00
return ;
2015-01-07 02:15:38 +03:00
}
2016-07-01 03:00:00 +03:00
m_sock - > async_read_some ( boost : : asio : : buffer ( m_recv_chunk , sizeof ( m_recv_chunk ) ) ,
2019-04-25 23:06:14 +03:00
std : : bind ( & HTTPReqHandler : : HandleSockRecv , shared_from_this ( ) ,
std : : placeholders : : _1 , std : : placeholders : : _2 ) ) ;
2015-01-07 02:15:38 +03:00
}
2016-06-23 03:00:00 +03:00
void HTTPReqHandler : : Terminate ( ) {
2015-01-07 21:09:59 +03:00
if ( Kill ( ) ) return ;
2017-09-03 16:46:55 +03:00
if ( m_sock )
2015-04-06 21:41:07 +03:00
{
2021-11-27 22:53:53 +03:00
LogPrint ( eLogDebug , " HTTPProxy: Close sock " ) ;
2015-01-07 02:15:38 +03:00
m_sock - > close ( ) ;
m_sock = nullptr ;
2014-03-18 02:31:29 +04:00
}
2016-11-20 17:25:56 +03:00
if ( m_proxysock )
{
2021-11-27 22:53:53 +03:00
LogPrint ( eLogDebug , " HTTPProxy: Close proxysock " ) ;
2016-11-20 17:25:56 +03:00
if ( m_proxysock - > is_open ( ) )
m_proxysock - > close ( ) ;
m_proxysock = nullptr ;
}
2015-01-07 21:09:59 +03:00
Done ( shared_from_this ( ) ) ;
2015-01-07 02:15:38 +03:00
}
2021-05-23 06:06:04 +03:00
void HTTPReqHandler : : GenericProxyError ( const std : : string & title , const std : : string & description ) {
2016-07-14 03:00:00 +03:00
std : : stringstream ss ;
2021-05-23 06:06:04 +03:00
ss < < " <h1> " < < tr ( " Proxy error " ) < < " : " < < title < < " </h1> \r \n " ;
2016-07-14 03:00:00 +03:00
ss < < " <p> " < < description < < " </p> \r \n " ;
std : : string content = ss . str ( ) ;
SendProxyError ( content ) ;
2016-08-05 21:23:54 +03:00
}
2016-07-14 03:00:00 +03:00
2021-05-23 06:06:04 +03:00
void HTTPReqHandler : : GenericProxyInfo ( const std : : string & title , const std : : string & description ) {
2016-11-17 06:04:29 +03:00
std : : stringstream ss ;
2021-05-23 06:06:04 +03:00
ss < < " <h1> " < < tr ( " Proxy info " ) < < " : " < < title < < " </h1> \r \n " ;
2016-11-17 06:04:29 +03:00
ss < < " <p> " < < description < < " </p> \r \n " ;
std : : string content = ss . str ( ) ;
SendProxyError ( content ) ;
}
2022-10-09 22:13:49 +03:00
void HTTPReqHandler : : HostNotFound ( std : : string & host ) {
2016-07-14 03:00:00 +03:00
std : : stringstream ss ;
2021-05-23 06:06:04 +03:00
ss < < " <h1> " < < tr ( " Proxy error: Host not found " ) < < " </h1> \r \n "
< < " <p> " < < tr ( " Remote host not found in router's addressbook " ) < < " </p> \r \n "
< < " <p> " < < tr ( " You may try to find this host on jump services below " ) < < " :</p> \r \n "
2016-07-14 03:00:00 +03:00
< < " <ul> \r \n " ;
2022-05-20 21:04:41 +03:00
for ( const auto & jump : jumporder )
{
auto js = jumpservices . find ( jump ) ;
if ( js ! = jumpservices . end ( ) )
2022-05-24 14:09:24 +03:00
ss < < " <li><a href= \" " < < js - > second < < host < < " \" > " < < js - > first < < " </a></li> \r \n " ;
2016-07-14 03:00:00 +03:00
}
ss < < " </ul> \r \n " ;
std : : string content = ss . str ( ) ;
SendProxyError ( content ) ;
2016-08-05 21:23:54 +03:00
}
2015-01-07 02:15:38 +03:00
2022-10-09 22:13:49 +03:00
void HTTPReqHandler : : SendProxyError ( std : : string & content )
2016-03-11 13:30:50 +03:00
{
2016-06-27 04:30:00 +03:00
i2p : : http : : HTTPRes res ;
2016-07-14 03:00:00 +03:00
res . code = 500 ;
res . add_header ( " Content-Type " , " text/html; charset=UTF-8 " ) ;
2016-07-01 03:00:00 +03:00
res . add_header ( " Connection " , " close " ) ;
2016-07-14 03:00:00 +03:00
std : : stringstream ss ;
ss < < " <html> \r \n " < < pageHead
< < " <body> " < < content < < " </body> \r \n "
< < " </html> \r \n " ;
res . body = ss . str ( ) ;
2016-06-27 04:30:00 +03:00
std : : string response = res . to_string ( ) ;
2016-11-20 17:25:56 +03:00
boost : : asio : : async_write ( * m_sock , boost : : asio : : buffer ( response ) , boost : : asio : : transfer_all ( ) ,
2020-03-01 13:25:50 +03:00
std : : bind ( & HTTPReqHandler : : SentHTTPFailed , shared_from_this ( ) , std : : placeholders : : _1 ) ) ;
2016-06-10 21:01:39 +03:00
}
2016-05-27 03:00:00 +03:00
2022-10-09 22:13:49 +03:00
void HTTPReqHandler : : SendRedirect ( std : : string & address )
{
i2p : : http : : HTTPRes res ;
res . code = 302 ;
res . add_header ( " Location " , address ) ;
res . add_header ( " Connection " , " close " ) ;
std : : string response = res . to_string ( ) ;
boost : : asio : : async_write ( * m_sock , boost : : asio : : buffer ( response ) , boost : : asio : : transfer_all ( ) ,
std : : bind ( & HTTPReqHandler : : SentHTTPFailed , shared_from_this ( ) , std : : placeholders : : _1 ) ) ;
}
2017-11-16 01:13:42 +03:00
bool HTTPReqHandler : : ExtractAddressHelper ( i2p : : http : : URL & url , std : : string & b64 , bool & confirm )
2015-03-17 18:44:01 +03:00
{
2017-11-16 01:13:42 +03:00
confirm = false ;
2016-07-01 03:00:00 +03:00
const char * param = " i2paddresshelper= " ;
std : : size_t pos = url . query . find ( param ) ;
std : : size_t len = std : : strlen ( param ) ;
std : : map < std : : string , std : : string > params ;
2017-11-16 01:13:42 +03:00
2016-07-01 03:00:00 +03:00
if ( pos = = std : : string : : npos )
return false ; /* not found */
if ( ! url . parse_query ( params ) )
return false ;
std : : string value = params [ " i2paddresshelper " ] ;
len + = value . length ( ) ;
b64 = i2p : : http : : UrlDecode ( value ) ;
2023-02-14 21:51:14 +03:00
2017-11-16 01:13:42 +03:00
// if we need update exists, request formed with update param
2023-02-14 21:51:14 +03:00
if ( params [ " update " ] = = " true " )
{
len + = std : : strlen ( " &update=true " ) ;
confirm = true ;
}
// if helper is not only one query option and it placed after user's query
if ( pos ! = 0 & & url . query [ pos - 1 ] = = ' & ' )
{
pos - - ;
len + + ;
}
// if helper is not only one query option and it placed before user's query
else if ( pos = = 0 & & url . query . length ( ) > len & & url . query [ len ] = = ' & ' )
{
// we don't touch the '?' but remove the trailing '&'
len + + ;
}
else
{
// there is no more query options, resetting hasquery flag
url . hasquery = false ;
}
// reset hasquery flag and remove addresshelper from URL
2021-05-23 13:16:52 +03:00
url . query . replace ( pos , len , " " ) ;
2016-07-01 03:00:00 +03:00
return true ;
2016-05-27 03:00:00 +03:00
}
2016-07-01 03:00:00 +03:00
void HTTPReqHandler : : SanitizeHTTPRequest ( i2p : : http : : HTTPReq & req )
{
/* drop common headers */
2017-02-05 06:39:54 +03:00
req . RemoveHeader ( " Via " ) ;
2017-08-24 22:13:15 +03:00
req . RemoveHeader ( " From " ) ;
2017-09-03 16:46:55 +03:00
req . RemoveHeader ( " Forwarded " ) ;
2022-10-23 21:33:52 +03:00
req . RemoveHeader ( " DNT " ) ; // Useless DoNotTrack flag
2017-08-24 22:13:15 +03:00
req . RemoveHeader ( " Accept " , " Accept-Encoding " ) ; // Accept*, but Accept-Encoding
2016-07-01 03:00:00 +03:00
/* drop proxy-disclosing headers */
2017-02-05 06:39:54 +03:00
req . RemoveHeader ( " X-Forwarded " ) ;
2019-05-16 08:17:05 +03:00
req . RemoveHeader ( " Proxy- " ) ; // Proxy-*
2016-07-01 03:00:00 +03:00
/* replace headers */
2017-02-05 06:39:54 +03:00
req . UpdateHeader ( " User-Agent " , " MYOB/6.66 (AN/ON) " ) ;
2019-05-16 08:17:05 +03:00
2022-12-22 20:55:51 +03:00
/**
* i2pd PR # 1816 :
* Android Webview send this with the value set to the application ID , so we drop it ,
* but only if it does not belong to an AJAX request ( * HttpRequest , like XMLHttpRequest ) .
*/
if ( req . GetHeader ( " X-Requested-With " ) ! = " " ) {
auto h = req . GetHeader ( " X-Requested-With " ) ;
auto x = h . find ( " HttpRequest " ) ;
if ( x = = std : : string : : npos ) // not found
req . RemoveHeader ( " X-Requested-With " ) ;
}
2019-05-16 08:17:05 +03:00
/**
* according to i2p ticket # 1862 :
2022-05-27 20:29:59 +03:00
* leave Referer if requested URL with same schema , host and port ,
2019-05-16 08:17:05 +03:00
* otherwise , drop it .
*/
2022-05-27 20:29:59 +03:00
if ( req . GetHeader ( " Referer " ) ! = " " ) {
2019-05-16 08:17:05 +03:00
i2p : : http : : URL reqURL ; reqURL . parse ( req . uri ) ;
2022-05-27 20:29:59 +03:00
i2p : : http : : URL refURL ; refURL . parse ( req . GetHeader ( " Referer " ) ) ;
2019-05-16 08:17:05 +03:00
if ( ! boost : : iequals ( reqURL . schema , refURL . schema ) | | ! boost : : iequals ( reqURL . host , refURL . host ) | | reqURL . port ! = refURL . port )
2022-05-27 20:29:59 +03:00
req . RemoveHeader ( " Referer " ) ;
2019-05-16 08:17:05 +03:00
}
2017-02-05 06:39:54 +03:00
/* add headers */
2019-02-12 19:20:54 +03:00
/* close connection, if not Connection: (U|u)pgrade (for websocket) */
2019-02-12 01:18:01 +03:00
auto h = req . GetHeader ( " Connection " ) ;
2019-04-25 23:06:14 +03:00
auto x = h . find ( " pgrade " ) ;
2019-02-12 19:20:54 +03:00
if ( ! ( x ! = std : : string : : npos & & std : : tolower ( h [ x - 1 ] ) = = ' u ' ) )
req . UpdateHeader ( " Connection " , " close " ) ;
2016-07-01 03:00:00 +03:00
}
2016-07-01 03:00:00 +03:00
/**
* @ brief Try to parse request from @ a m_recv_buf
* If parsing success , rebuild request and store to @ a m_send_buf
* with remaining data tail
* @ return true on processed request or false if more data needed
*/
bool HTTPReqHandler : : HandleRequest ( )
2016-06-10 21:01:39 +03:00
{
2016-11-20 20:13:11 +03:00
m_req_len = m_ClientRequest . parse ( m_recv_buf ) ;
2016-07-01 03:00:00 +03:00
2016-11-20 20:13:11 +03:00
if ( m_req_len = = 0 )
2016-07-01 03:00:00 +03:00
return false ; /* need more data */
2016-11-20 20:13:11 +03:00
if ( m_req_len < 0 ) {
2021-11-27 22:53:53 +03:00
LogPrint ( eLogError , " HTTPProxy: Unable to parse request " ) ;
2021-05-23 06:06:04 +03:00
GenericProxyError ( tr ( " Invalid request " ) , tr ( " Proxy unable to parse your request " ) ) ;
2016-07-01 03:00:00 +03:00
return true ; /* parse error */
2016-07-01 03:00:00 +03:00
}
2016-07-01 03:00:00 +03:00
2016-07-01 03:00:00 +03:00
/* parsing success, now let's look inside request */
2021-11-27 22:53:53 +03:00
LogPrint ( eLogDebug , " HTTPProxy: Requested: " , m_ClientRequest . uri ) ;
2016-11-20 20:13:11 +03:00
m_RequestURL . parse ( m_ClientRequest . uri ) ;
2017-11-16 01:13:42 +03:00
bool m_Confirm ;
2016-07-01 03:00:00 +03:00
2019-04-02 20:11:49 +03:00
std : : string jump ;
if ( ExtractAddressHelper ( m_RequestURL , jump , m_Confirm ) )
2017-04-11 21:36:28 +03:00
{
2019-04-25 23:06:14 +03:00
if ( ! m_Addresshelper )
2017-04-11 21:36:28 +03:00
{
2021-11-27 22:53:53 +03:00
LogPrint ( eLogWarning , " HTTPProxy: Addresshelper request rejected " ) ;
2023-01-19 07:46:54 +03:00
GenericProxyError ( tr ( " Invalid request " ) , tr ( " Addresshelper is not supported " ) ) ;
2017-09-03 16:46:55 +03:00
return true ;
2017-04-11 21:36:28 +03:00
}
2022-10-09 22:13:49 +03:00
if ( i2p : : client : : context . GetAddressBook ( ) . RecordExists ( m_RequestURL . host , jump ) )
{
std : : string full_url = m_RequestURL . to_string ( ) ;
SendRedirect ( full_url ) ;
return true ;
}
else if ( ! i2p : : client : : context . GetAddressBook ( ) . FindAddress ( m_RequestURL . host ) | | m_Confirm )
2017-11-16 01:13:42 +03:00
{
2023-01-16 16:16:16 +03:00
const std : : string referer_raw = m_ClientRequest . GetHeader ( " Referer " ) ;
i2p : : http : : URL referer_url ;
if ( ! referer_raw . empty ( ) )
2023-01-16 13:31:13 +03:00
{
2023-01-16 16:16:16 +03:00
referer_url . parse ( referer_raw ) ;
}
if ( m_RequestURL . host ! = referer_url . host )
{
2023-01-19 07:46:54 +03:00
if ( m_Confirm ) // Attempt to forced overwriting by link with "&update=true" from harmful URL
2023-01-16 13:31:13 +03:00
{
2023-01-16 13:56:36 +03:00
LogPrint ( eLogWarning , " HTTPProxy: Address update from addresshelper rejected for " , m_RequestURL . host , " (referer is " , m_RequestURL . host . empty ( ) ? " empty " : " harmful " , " ) " ) ;
2023-01-16 13:31:13 +03:00
std : : string full_url = m_RequestURL . to_string ( ) ;
std : : stringstream ss ;
2023-01-19 07:46:54 +03:00
ss < < tr ( " Host %s is <font color=red>already in router's addressbook</font>. <b>Be careful: source of this URL may be harmful!</b> Click here to update record: <a href= \" %s%s%s&update=true \" >Continue</a>. " ,
2023-01-19 08:33:03 +03:00
m_RequestURL . host . c_str ( ) , full_url . c_str ( ) , ( full_url . find ( ' ? ' ) ! = std : : string : : npos ? " &i2paddresshelper= " : " ?i2paddresshelper= " ) , jump . c_str ( ) ) ;
2023-01-16 13:31:13 +03:00
GenericProxyInfo ( tr ( " Addresshelper forced update rejected " ) , ss . str ( ) ) ;
}
2023-01-19 07:46:54 +03:00
else // Preventing unauthorized additions to the address book
2023-01-16 16:16:16 +03:00
{
LogPrint ( eLogDebug , " HTTPProxy: Adding address from addresshelper for " , m_RequestURL . host , " (generate refer-base page) " ) ;
std : : string full_url = m_RequestURL . to_string ( ) ;
std : : stringstream ss ;
2023-01-19 07:46:54 +03:00
ss < < tr ( " To add host <b>%s</b> in router's addressbook, click here: <a href= \" %s%s%s \" >Continue</a>. " ,
2023-01-19 08:33:03 +03:00
m_RequestURL . host . c_str ( ) , full_url . c_str ( ) , ( full_url . find ( ' ? ' ) ! = std : : string : : npos ? " &i2paddresshelper= " : " ?i2paddresshelper= " ) , jump . c_str ( ) ) ;
2023-01-16 16:16:16 +03:00
GenericProxyInfo ( tr ( " Addresshelper request " ) , ss . str ( ) ) ;
}
return true ; /* request processed */
2023-01-16 13:31:13 +03:00
}
2019-04-02 20:11:49 +03:00
i2p : : client : : context . GetAddressBook ( ) . InsertAddress ( m_RequestURL . host , jump ) ;
2021-11-27 22:53:53 +03:00
LogPrint ( eLogInfo , " HTTPProxy: Added address from addresshelper for " , m_RequestURL . host ) ;
2017-11-16 01:13:42 +03:00
std : : string full_url = m_RequestURL . to_string ( ) ;
std : : stringstream ss ;
2023-01-19 08:33:03 +03:00
ss < < tr ( " Host %s added to router's addressbook from helper. Click here to proceed: <a href= \" %s \" >Continue</a>. " ,
m_RequestURL . host . c_str ( ) , full_url . c_str ( ) ) ;
2023-01-16 16:16:16 +03:00
GenericProxyInfo ( tr ( " Addresshelper adding " ) , ss . str ( ) ) ;
2017-11-16 01:13:42 +03:00
return true ; /* request processed */
}
else
{
2021-05-23 06:06:04 +03:00
std : : string full_url = m_RequestURL . to_string ( ) ;
2017-11-16 01:13:42 +03:00
std : : stringstream ss ;
2023-01-19 07:46:54 +03:00
ss < < tr ( " Host %s is <font color=red>already in router's addressbook</font>. Click here to update record: <a href= \" %s%s%s&update=true \" >Continue</a>. " ,
2023-01-19 08:33:03 +03:00
m_RequestURL . host . c_str ( ) , full_url . c_str ( ) , ( full_url . find ( ' ? ' ) ! = std : : string : : npos ? " &i2paddresshelper= " : " ?i2paddresshelper= " ) , jump . c_str ( ) ) ;
2023-01-16 16:16:16 +03:00
GenericProxyInfo ( tr ( " Addresshelper update " ) , ss . str ( ) ) ;
2017-11-16 01:13:42 +03:00
return true ; /* request processed */
}
2016-07-01 03:00:00 +03:00
}
2017-09-03 16:46:55 +03:00
std : : string dest_host ;
uint16_t dest_port ;
bool useConnect = false ;
if ( m_ClientRequest . method = = " CONNECT " )
2017-02-05 06:39:54 +03:00
{
2017-09-03 16:46:55 +03:00
std : : string uri ( m_ClientRequest . uri ) ;
auto pos = uri . find ( " : " ) ;
if ( pos = = std : : string : : npos | | pos = = uri . size ( ) - 1 )
{
2023-01-19 07:46:54 +03:00
GenericProxyError ( tr ( " Invalid request " ) , tr ( " Invalid request URI " ) ) ;
2017-09-03 16:46:55 +03:00
return true ;
}
else
{
useConnect = true ;
dest_port = std : : stoi ( uri . substr ( pos + 1 ) ) ;
dest_host = uri . substr ( 0 , pos ) ;
}
}
2017-02-05 06:39:54 +03:00
else
2017-09-03 16:46:55 +03:00
{
SanitizeHTTPRequest ( m_ClientRequest ) ;
dest_host = m_RequestURL . host ;
dest_port = m_RequestURL . port ;
/* always set port, even if missing in request */
if ( ! dest_port )
dest_port = ( m_RequestURL . schema = = " https " ) ? 443 : 80 ;
/* detect dest_host, set proper 'Host' header in upstream request */
if ( dest_host ! = " " )
2017-02-05 06:39:54 +03:00
{
2017-09-03 16:46:55 +03:00
/* absolute url, replace 'Host' header */
std : : string h = dest_host ;
if ( dest_port ! = 0 & & dest_port ! = 80 )
h + = " : " + std : : to_string ( dest_port ) ;
m_ClientRequest . UpdateHeader ( " Host " , h ) ;
}
else
2017-02-05 06:39:54 +03:00
{
2017-09-03 16:46:55 +03:00
auto h = m_ClientRequest . GetHeader ( " Host " ) ;
if ( h . length ( ) > 0 )
{
/* relative url and 'Host' header provided. transparent proxy mode? */
i2p : : http : : URL u ;
std : : string t = " http:// " + h ;
u . parse ( t ) ;
dest_host = u . host ;
dest_port = u . port ;
}
else
{
/* relative url and missing 'Host' header */
2021-05-23 06:06:04 +03:00
GenericProxyError ( tr ( " Invalid request " ) , tr ( " Can't detect destination host from request " ) ) ;
2017-09-03 16:46:55 +03:00
return true ;
}
2017-02-05 06:39:54 +03:00
}
2017-09-03 16:46:55 +03:00
}
2016-07-01 03:00:00 +03:00
/* check dest_host really exists and inside I2P network */
if ( str_rmatch ( dest_host , " .i2p " ) ) {
2019-03-28 19:19:19 +03:00
if ( ! i2p : : client : : context . GetAddressBook ( ) . GetAddress ( dest_host ) ) {
2016-07-14 03:00:00 +03:00
HostNotFound ( dest_host ) ;
2016-07-01 03:00:00 +03:00
return true ; /* request processed */
2016-03-26 09:45:37 +03:00
}
2016-07-01 03:00:00 +03:00
} else {
2017-10-27 15:42:54 +03:00
if ( m_OutproxyUrl . size ( ) ) {
2021-11-27 22:53:53 +03:00
LogPrint ( eLogDebug , " HTTPProxy: Using outproxy " , m_OutproxyUrl ) ;
2017-10-27 15:42:54 +03:00
if ( m_ProxyURL . parse ( m_OutproxyUrl ) )
2016-11-20 17:25:56 +03:00
ForwardToUpstreamProxy ( ) ;
else
2023-01-19 07:46:54 +03:00
GenericProxyError ( tr ( " Outproxy failure " ) , tr ( " Bad outproxy settings " ) ) ;
2016-11-20 17:25:56 +03:00
} else {
2021-11-27 22:53:53 +03:00
LogPrint ( eLogWarning , " HTTPProxy: Outproxy failure for " , dest_host , " : no outproxy enabled " ) ;
2023-01-19 08:33:03 +03:00
std : : stringstream ss ; ss < < tr ( " Host %s is not inside I2P network, but outproxy is not enabled " , dest_host . c_str ( ) ) ;
2021-05-23 06:06:04 +03:00
GenericProxyError ( tr ( " Outproxy failure " ) , ss . str ( ) ) ;
2016-11-20 17:25:56 +03:00
}
2016-07-01 03:00:00 +03:00
return true ;
2016-03-11 13:30:50 +03:00
}
2017-09-03 16:46:55 +03:00
if ( useConnect )
{
HTTPConnect ( dest_host , dest_port ) ;
return true ;
}
2016-06-10 21:01:39 +03:00
2016-07-01 03:00:00 +03:00
/* make relative url */
2016-11-20 17:25:56 +03:00
m_RequestURL . schema = " " ;
m_RequestURL . host = " " ;
2016-11-20 20:13:11 +03:00
m_ClientRequest . uri = m_RequestURL . to_string ( ) ;
2016-06-03 03:00:00 +03:00
2016-07-01 03:00:00 +03:00
/* drop original request from recv buffer */
2016-11-20 20:13:11 +03:00
m_recv_buf . erase ( 0 , m_req_len ) ;
2016-07-01 03:00:00 +03:00
/* build new buffer from modified request and data from original request */
2016-11-20 20:13:11 +03:00
m_send_buf = m_ClientRequest . to_string ( ) ;
2016-07-01 03:00:00 +03:00
m_send_buf . append ( m_recv_buf ) ;
/* connect to destination */
2021-11-27 22:53:53 +03:00
LogPrint ( eLogDebug , " HTTPProxy: Connecting to host " , dest_host , " : " , dest_port ) ;
2016-07-01 03:00:00 +03:00
GetOwner ( ) - > CreateStream ( std : : bind ( & HTTPReqHandler : : HandleStreamRequestComplete ,
shared_from_this ( ) , std : : placeholders : : _1 ) , dest_host , dest_port ) ;
2015-01-07 02:15:38 +03:00
return true ;
}
2016-11-20 17:25:56 +03:00
void HTTPReqHandler : : ForwardToUpstreamProxy ( )
{
2021-11-27 22:53:53 +03:00
LogPrint ( eLogDebug , " HTTPProxy: Forwarded to upstream " ) ;
2016-11-20 20:13:11 +03:00
2022-07-27 00:37:48 +03:00
/* build http request */
2016-11-20 20:13:11 +03:00
m_ClientRequestURL = m_RequestURL ;
LogPrint ( eLogDebug , " HTTPProxy: " , m_ClientRequestURL . host ) ;
m_ClientRequestURL . schema = " " ;
m_ClientRequestURL . host = " " ;
2018-07-10 12:39:21 +03:00
std : : string origURI = m_ClientRequest . uri ; // TODO: what do we need to change uri for?
2016-11-20 20:13:11 +03:00
m_ClientRequest . uri = m_ClientRequestURL . to_string ( ) ;
2022-07-27 00:37:48 +03:00
/* update User-Agent to ESR version of Firefox, same as Tor Browser below version 8, for non-HTTPS connections */
2018-11-27 19:56:35 +03:00
if ( m_ClientRequest . method ! = " CONNECT " )
2019-02-12 00:51:47 +03:00
m_ClientRequest . UpdateHeader ( " User-Agent " , " Mozilla/5.0 (Windows NT 6.1; rv:60.0) Gecko/20100101 Firefox/60.0 " ) ;
2018-11-27 19:56:35 +03:00
2016-11-20 20:13:11 +03:00
m_ClientRequest . write ( m_ClientRequestBuffer ) ;
m_ClientRequestBuffer < < m_recv_buf . substr ( m_req_len ) ;
2019-04-25 23:06:14 +03:00
2022-07-27 00:37:48 +03:00
/* assume http if empty schema */
2019-04-25 23:06:14 +03:00
if ( m_ProxyURL . schema = = " " | | m_ProxyURL . schema = = " http " )
2018-04-06 22:23:56 +03:00
{
2022-07-27 00:37:48 +03:00
/* handle upstream http proxy */
2016-11-20 17:25:56 +03:00
if ( ! m_ProxyURL . port ) m_ProxyURL . port = 80 ;
2017-10-27 15:42:54 +03:00
if ( m_ProxyURL . is_i2p ( ) )
{
2018-04-13 23:29:49 +03:00
m_ClientRequest . uri = origURI ;
2021-03-11 06:47:31 +03:00
auto auth = i2p : : http : : CreateBasicAuthorizationString ( m_ProxyURL . user , m_ProxyURL . pass ) ;
if ( ! auth . empty ( ) )
2018-04-13 22:40:25 +03:00
{
2022-07-27 00:37:48 +03:00
/* remove existing authorization if any */
2018-04-13 22:40:25 +03:00
m_ClientRequest . RemoveHeader ( " Proxy- " ) ;
2022-07-27 00:37:48 +03:00
/* add own http proxy authorization */
2021-03-11 06:47:31 +03:00
m_ClientRequest . AddHeader ( " Proxy-Authorization " , auth ) ;
2018-04-13 22:40:25 +03:00
}
m_send_buf = m_ClientRequest . to_string ( ) ;
m_recv_buf . erase ( 0 , m_req_len ) ;
m_send_buf . append ( m_recv_buf ) ;
2017-10-27 15:42:54 +03:00
GetOwner ( ) - > CreateStream ( std : : bind ( & HTTPReqHandler : : HandleStreamRequestComplete ,
shared_from_this ( ) , std : : placeholders : : _1 ) , m_ProxyURL . host , m_ProxyURL . port ) ;
}
else
{
boost : : asio : : ip : : tcp : : resolver : : query q ( m_ProxyURL . host , std : : to_string ( m_ProxyURL . port ) ) ;
m_proxy_resolver . async_resolve ( q , std : : bind ( & HTTPReqHandler : : HandleUpstreamProxyResolved , this , std : : placeholders : : _1 , std : : placeholders : : _2 , [ & ] ( boost : : asio : : ip : : tcp : : endpoint ep ) {
m_proxysock - > async_connect ( ep , std : : bind ( & HTTPReqHandler : : HandleUpstreamHTTPProxyConnect , this , std : : placeholders : : _1 ) ) ;
} ) ) ;
}
2019-04-25 23:06:14 +03:00
}
else if ( m_ProxyURL . schema = = " socks " )
2018-04-06 22:23:56 +03:00
{
2022-07-27 00:37:48 +03:00
/* handle upstream socks proxy */
2016-11-20 17:25:56 +03:00
if ( ! m_ProxyURL . port ) m_ProxyURL . port = 9050 ; // default to tor default if not specified
boost : : asio : : ip : : tcp : : resolver : : query q ( m_ProxyURL . host , std : : to_string ( m_ProxyURL . port ) ) ;
m_proxy_resolver . async_resolve ( q , std : : bind ( & HTTPReqHandler : : HandleUpstreamProxyResolved , this , std : : placeholders : : _1 , std : : placeholders : : _2 , [ & ] ( boost : : asio : : ip : : tcp : : endpoint ep ) {
2020-03-01 13:25:50 +03:00
m_proxysock - > async_connect ( ep , std : : bind ( & HTTPReqHandler : : HandleUpstreamSocksProxyConnect , this , std : : placeholders : : _1 ) ) ;
2016-11-20 17:25:56 +03:00
} ) ) ;
2019-04-25 23:06:14 +03:00
}
else
2018-04-06 22:23:56 +03:00
{
2022-07-27 00:37:48 +03:00
/* unknown type, complain */
2023-01-19 07:46:54 +03:00
GenericProxyError ( tr ( " Unknown outproxy URL " ) , m_ProxyURL . to_string ( ) ) ;
2016-11-20 17:25:56 +03:00
}
}
void HTTPReqHandler : : HandleUpstreamProxyResolved ( const boost : : system : : error_code & ec , boost : : asio : : ip : : tcp : : resolver : : iterator it , ProxyResolvedHandler handler )
{
2023-01-19 07:46:54 +03:00
if ( ec ) GenericProxyError ( tr ( " Cannot resolve upstream proxy " ) , ec . message ( ) ) ;
2017-09-03 16:46:55 +03:00
else handler ( * it ) ;
2016-11-20 17:25:56 +03:00
}
void HTTPReqHandler : : HandleUpstreamSocksProxyConnect ( const boost : : system : : error_code & ec )
{
if ( ! ec ) {
if ( m_RequestURL . host . size ( ) > 255 ) {
2023-01-19 07:46:54 +03:00
GenericProxyError ( tr ( " Hostname is too long " ) , m_RequestURL . host ) ;
2016-11-20 17:25:56 +03:00
return ;
}
uint16_t port = m_RequestURL . port ;
2016-11-20 20:13:11 +03:00
if ( ! port ) port = 80 ;
2021-11-27 22:53:53 +03:00
LogPrint ( eLogDebug , " HTTPProxy: Connected to SOCKS upstream " ) ;
2016-11-20 20:13:11 +03:00
std : : string host = m_RequestURL . host ;
std : : size_t reqsize = 0 ;
m_socks_buf [ 0 ] = ' \x04 ' ;
m_socks_buf [ 1 ] = 1 ;
htobe16buf ( m_socks_buf + 2 , port ) ;
m_socks_buf [ 4 ] = 0 ;
m_socks_buf [ 5 ] = 0 ;
m_socks_buf [ 6 ] = 0 ;
m_socks_buf [ 7 ] = 1 ;
// user id
m_socks_buf [ 8 ] = ' i ' ;
m_socks_buf [ 9 ] = ' 2 ' ;
m_socks_buf [ 10 ] = ' p ' ;
m_socks_buf [ 11 ] = ' d ' ;
m_socks_buf [ 12 ] = 0 ;
reqsize + = 13 ;
memcpy ( m_socks_buf + reqsize , host . c_str ( ) , host . size ( ) ) ;
reqsize + = host . size ( ) ;
m_socks_buf [ + + reqsize ] = 0 ;
boost : : asio : : async_write ( * m_proxysock , boost : : asio : : buffer ( m_socks_buf , reqsize ) , boost : : asio : : transfer_all ( ) , std : : bind ( & HTTPReqHandler : : HandleSocksProxySendHandshake , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) ) ;
2023-01-19 07:46:54 +03:00
} else GenericProxyError ( tr ( " Cannot connect to upstream SOCKS proxy " ) , ec . message ( ) ) ;
2016-11-20 17:25:56 +03:00
}
void HTTPReqHandler : : HandleSocksProxySendHandshake ( const boost : : system : : error_code & ec , std : : size_t bytes_transferred )
{
2021-11-27 22:53:53 +03:00
LogPrint ( eLogDebug , " HTTPProxy: Upstream SOCKS handshake sent " ) ;
2023-01-19 07:46:54 +03:00
if ( ec ) GenericProxyError ( tr ( " Cannot negotiate with SOCKS proxy " ) , ec . message ( ) ) ;
2016-11-20 17:25:56 +03:00
else m_proxysock - > async_read_some ( boost : : asio : : buffer ( m_socks_buf , 8 ) , std : : bind ( & HTTPReqHandler : : HandleSocksProxyReply , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) ) ;
}
void HTTPReqHandler : : HandoverToUpstreamProxy ( )
{
2021-11-27 22:53:53 +03:00
LogPrint ( eLogDebug , " HTTPProxy: Handover to SOCKS proxy " ) ;
2016-11-20 20:13:11 +03:00
auto connection = std : : make_shared < i2p : : client : : TCPIPPipe > ( GetOwner ( ) , m_proxysock , m_sock ) ;
m_sock = nullptr ;
m_proxysock = nullptr ;
GetOwner ( ) - > AddHandler ( connection ) ;
connection - > Start ( ) ;
Terminate ( ) ;
2016-11-20 17:25:56 +03:00
}
2017-09-03 16:46:55 +03:00
void HTTPReqHandler : : HTTPConnect ( const std : : string & host , uint16_t port )
{
2017-09-03 18:13:43 +03:00
LogPrint ( eLogDebug , " HTTPProxy: CONNECT " , host , " : " , port ) ;
2017-09-03 16:46:55 +03:00
std : : string hostname ( host ) ;
if ( str_rmatch ( hostname , " .i2p " ) )
GetOwner ( ) - > CreateStream ( std : : bind ( & HTTPReqHandler : : HandleHTTPConnectStreamRequestComplete ,
2019-04-25 23:06:14 +03:00
shared_from_this ( ) , std : : placeholders : : _1 ) , host , port ) ;
2017-09-03 16:46:55 +03:00
else
ForwardToUpstreamProxy ( ) ;
}
void HTTPReqHandler : : HandleHTTPConnectStreamRequestComplete ( std : : shared_ptr < i2p : : stream : : Stream > stream )
{
if ( stream )
{
2017-09-03 18:13:43 +03:00
m_ClientResponse . code = 200 ;
m_ClientResponse . status = " OK " ;
2017-09-03 16:46:55 +03:00
m_send_buf = m_ClientResponse . to_string ( ) ;
2017-09-03 18:13:43 +03:00
m_sock - > send ( boost : : asio : : buffer ( m_send_buf ) ) ;
auto connection = std : : make_shared < i2p : : client : : I2PTunnelConnection > ( GetOwner ( ) , m_sock , stream ) ;
GetOwner ( ) - > AddHandler ( connection ) ;
connection - > I2PConnect ( ) ;
m_sock = nullptr ;
Terminate ( ) ;
2017-09-03 16:46:55 +03:00
}
else
{
2023-01-19 07:46:54 +03:00
GenericProxyError ( tr ( " CONNECT error " ) , tr ( " Failed to connect " ) ) ;
2017-09-03 16:46:55 +03:00
}
}
2016-11-20 17:25:56 +03:00
void HTTPReqHandler : : SocksProxySuccess ( )
{
2016-11-20 20:13:11 +03:00
if ( m_ClientRequest . method = = " CONNECT " ) {
m_ClientResponse . code = 200 ;
m_send_buf = m_ClientResponse . to_string ( ) ;
2020-03-01 13:25:50 +03:00
boost : : asio : : async_write ( * m_sock , boost : : asio : : buffer ( m_send_buf ) , boost : : asio : : transfer_all ( ) , [ & ] ( const boost : : system : : error_code & ec , std : : size_t transferred )
{
2023-01-19 07:46:54 +03:00
if ( ec ) GenericProxyError ( tr ( " SOCKS proxy error " ) , ec . message ( ) ) ;
2016-11-20 20:13:11 +03:00
else HandoverToUpstreamProxy ( ) ;
} ) ;
} else {
m_send_buf = m_ClientRequestBuffer . str ( ) ;
2021-11-27 22:53:53 +03:00
LogPrint ( eLogDebug , " HTTPProxy: Send " , m_send_buf . size ( ) , " bytes " ) ;
2020-03-01 13:25:50 +03:00
boost : : asio : : async_write ( * m_proxysock , boost : : asio : : buffer ( m_send_buf ) , boost : : asio : : transfer_all ( ) , [ & ] ( const boost : : system : : error_code & ec , std : : size_t transferred )
{
2023-01-19 07:46:54 +03:00
if ( ec ) GenericProxyError ( tr ( " Failed to send request to upstream " ) , ec . message ( ) ) ;
2016-11-20 20:13:11 +03:00
else HandoverToUpstreamProxy ( ) ;
} ) ;
}
2016-11-20 17:25:56 +03:00
}
2017-09-03 16:46:55 +03:00
2016-11-20 17:25:56 +03:00
void HTTPReqHandler : : HandleSocksProxyReply ( const boost : : system : : error_code & ec , std : : size_t bytes_transferred )
{
if ( ! ec )
{
if ( m_socks_buf [ 1 ] = = 90 ) {
// success
SocksProxySuccess ( ) ;
} else {
std : : stringstream ss ;
2016-11-20 20:13:11 +03:00
ss < < " error code: " ;
2016-11-20 17:25:56 +03:00
ss < < ( int ) m_socks_buf [ 1 ] ;
std : : string msg = ss . str ( ) ;
2023-01-19 07:46:54 +03:00
GenericProxyError ( tr ( " SOCKS proxy error " ) , msg ) ;
2016-11-20 17:25:56 +03:00
}
}
2023-01-19 07:46:54 +03:00
else GenericProxyError ( tr ( " No reply from SOCKS proxy " ) , ec . message ( ) ) ;
2016-11-20 17:25:56 +03:00
}
2017-09-03 16:46:55 +03:00
2016-11-20 17:25:56 +03:00
void HTTPReqHandler : : HandleUpstreamHTTPProxyConnect ( const boost : : system : : error_code & ec )
{
if ( ! ec ) {
2021-11-27 22:53:53 +03:00
LogPrint ( eLogDebug , " HTTPProxy: Connected to http upstream " ) ;
2023-01-19 07:46:54 +03:00
GenericProxyError ( tr ( " Cannot connect " ) , tr ( " HTTP out proxy not implemented " ) ) ;
} else GenericProxyError ( tr ( " Cannot connect to upstream HTTP proxy " ) , ec . message ( ) ) ;
2016-11-20 17:25:56 +03:00
}
2017-09-03 16:46:55 +03:00
2016-07-01 03:00:00 +03:00
/* will be called after some data received from client */
2016-06-23 03:00:00 +03:00
void HTTPReqHandler : : HandleSockRecv ( const boost : : system : : error_code & ecode , std : : size_t len )
2015-01-07 02:15:38 +03:00
{
2021-11-27 22:53:53 +03:00
LogPrint ( eLogDebug , " HTTPProxy: Sock recv: " , len , " bytes, recv buf: " , m_recv_buf . length ( ) , " , send buf: " , m_send_buf . length ( ) ) ;
2017-09-03 16:46:55 +03:00
if ( ecode )
2015-03-17 18:44:01 +03:00
{
2021-11-27 22:53:53 +03:00
LogPrint ( eLogWarning , " HTTPProxy: Sock recv got error: " , ecode ) ;
2016-02-11 03:00:00 +03:00
Terminate ( ) ;
2015-01-07 02:15:38 +03:00
return ;
}
2016-07-01 03:00:00 +03:00
m_recv_buf . append ( reinterpret_cast < const char * > ( m_recv_chunk ) , len ) ;
if ( HandleRequest ( ) ) {
m_recv_buf . clear ( ) ;
return ;
2016-06-04 03:00:00 +03:00
}
2016-07-01 03:00:00 +03:00
AsyncSockRead ( ) ;
2015-01-07 02:15:38 +03:00
}
2016-06-23 03:00:00 +03:00
void HTTPReqHandler : : SentHTTPFailed ( const boost : : system : : error_code & ecode )
2015-01-07 02:15:38 +03:00
{
2016-02-11 03:00:00 +03:00
if ( ecode )
LogPrint ( eLogError , " HTTPProxy: Closing socket after sending failure because: " , ecode . message ( ) ) ;
Terminate ( ) ;
2015-01-07 02:15:38 +03:00
}
2016-06-23 03:00:00 +03:00
void HTTPReqHandler : : HandleStreamRequestComplete ( std : : shared_ptr < i2p : : stream : : Stream > stream )
2015-01-07 02:15:38 +03:00
{
2016-06-27 16:00:00 +03:00
if ( ! stream ) {
2021-11-27 22:53:53 +03:00
LogPrint ( eLogError , " HTTPProxy: Error when creating the stream, check the previous warnings for more info " ) ;
2021-05-23 06:06:04 +03:00
GenericProxyError ( tr ( " Host is down " ) , tr ( " Can't create connection to requested host, it may be down. Please try again later. " ) ) ;
2016-06-27 16:00:00 +03:00
return ;
2015-01-07 02:15:38 +03:00
}
2016-06-27 16:00:00 +03:00
if ( Kill ( ) )
return ;
2016-07-01 03:00:00 +03:00
LogPrint ( eLogDebug , " HTTPProxy: Created new I2PTunnel stream, sSID= " , stream - > GetSendStreamID ( ) , " , rSID= " , stream - > GetRecvStreamID ( ) ) ;
2017-02-07 05:39:15 +03:00
auto connection = std : : make_shared < i2p : : client : : I2PClientTunnelConnectionHTTP > ( GetOwner ( ) , m_sock , stream ) ;
2016-06-27 16:00:00 +03:00
GetOwner ( ) - > AddHandler ( connection ) ;
2016-07-01 03:00:00 +03:00
connection - > I2PConnect ( reinterpret_cast < const uint8_t * > ( m_send_buf . data ( ) ) , m_send_buf . length ( ) ) ;
2016-06-27 16:00:00 +03:00
Done ( shared_from_this ( ) ) ;
2015-01-07 02:15:38 +03:00
}
2023-06-12 05:10:32 +03:00
HTTPProxy : : HTTPProxy ( const std : : string & name , const std : : string & address , uint16_t port , const std : : string & outproxy , bool addresshelper , std : : shared_ptr < i2p : : client : : ClientDestination > localDestination ) :
2019-04-25 23:06:14 +03:00
TCPIPAcceptor ( address , port , localDestination ? localDestination : i2p : : client : : context . GetSharedLocalDestination ( ) ) ,
m_Name ( name ) , m_OutproxyUrl ( outproxy ) , m_Addresshelper ( addresshelper )
2015-01-17 17:42:44 +03:00
{
}
2017-09-03 16:46:55 +03:00
2016-06-23 03:00:00 +03:00
std : : shared_ptr < i2p : : client : : I2PServiceHandler > HTTPProxy : : CreateHandler ( std : : shared_ptr < boost : : asio : : ip : : tcp : : socket > socket )
2015-01-07 02:15:38 +03:00
{
2016-06-23 03:00:00 +03:00
return std : : make_shared < HTTPReqHandler > ( this , socket ) ;
2014-03-30 02:16:23 +04:00
}
2016-06-23 03:00:00 +03:00
} // http
} // i2p