@ -12,6 +12,7 @@
# include "hash.h"
# include "hash.h"
# include "sync.h"
# include "sync.h"
# include "uint256.h"
# include "uint256.h"
# include "random.h"
# include "util.h"
# include "util.h"
# include "utilstrencodings.h"
# include "utilstrencodings.h"
@ -38,7 +39,7 @@ using namespace std;
// Settings
// Settings
static proxyType proxyInfo [ NET_MAX ] ;
static proxyType proxyInfo [ NET_MAX ] ;
static CServic e nameProxy ;
static proxyTyp e nameProxy ;
static CCriticalSection cs_proxyInfos ;
static CCriticalSection cs_proxyInfos ;
int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT ;
int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT ;
bool fNameLookup = false ;
bool fNameLookup = false ;
@ -285,59 +286,100 @@ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSock
return len = = 0 ;
return len = = 0 ;
}
}
bool static Socks5 ( string strDest , int port , SOCKET & hSocket )
struct ProxyCredentials
{
std : : string username ;
std : : string password ;
} ;
/** Connect using SOCKS5 (as described in RFC1928) */
bool static Socks5 ( string strDest , int port , const ProxyCredentials * auth , SOCKET & hSocket )
{
{
LogPrintf ( " SOCKS5 connecting %s \n " , strDest ) ;
LogPrintf ( " SOCKS5 connecting %s \n " , strDest ) ;
if ( strDest . size ( ) > 255 )
if ( strDest . size ( ) > 255 ) {
{
CloseSocket ( hSocket ) ;
CloseSocket ( hSocket ) ;
return error ( " Hostname too long " ) ;
return error ( " Hostname too long " ) ;
}
}
char pszSocks5Init [ ] = " \5 \1 \0 " ;
// Accepted authentication methods
ssize_t nSize = sizeof ( pszSocks5Init ) - 1 ;
std : : vector < uint8_t > vSocks5Init ;
vSocks5Init . push_back ( 0x05 ) ;
ssize_t ret = send ( hSocket , pszSocks5Init , nSize , MSG_NOSIGNAL ) ;
if ( auth ) {
if ( ret ! = nSize )
vSocks5Init . push_back ( 0x02 ) ; // # METHODS
{
vSocks5Init . push_back ( 0x00 ) ; // X'00' NO AUTHENTICATION REQUIRED
vSocks5Init . push_back ( 0x02 ) ; // X'02' USERNAME/PASSWORD (RFC1929)
} else {
vSocks5Init . push_back ( 0x01 ) ; // # METHODS
vSocks5Init . push_back ( 0x00 ) ; // X'00' NO AUTHENTICATION REQUIRED
}
ssize_t ret = send ( hSocket , ( const char * ) begin_ptr ( vSocks5Init ) , vSocks5Init . size ( ) , MSG_NOSIGNAL ) ;
if ( ret ! = ( ssize_t ) vSocks5Init . size ( ) ) {
CloseSocket ( hSocket ) ;
CloseSocket ( hSocket ) ;
return error ( " Error sending to proxy " ) ;
return error ( " Error sending to proxy " ) ;
}
}
char pchRet1 [ 2 ] ;
char pchRet1 [ 2 ] ;
if ( ! InterruptibleRecv ( pchRet1 , 2 , SOCKS5_RECV_TIMEOUT , hSocket ) )
if ( ! InterruptibleRecv ( pchRet1 , 2 , SOCKS5_RECV_TIMEOUT , hSocket ) ) {
{
CloseSocket ( hSocket ) ;
CloseSocket ( hSocket ) ;
return error ( " Error reading proxy response " ) ;
return error ( " Error reading proxy response " ) ;
}
}
if ( pchRet1 [ 0 ] ! = 0x05 | | pchRet1 [ 1 ] ! = 0x00 )
if ( pchRet1 [ 0 ] ! = 0x05 ) {
{
CloseSocket ( hSocket ) ;
CloseSocket ( hSocket ) ;
return error ( " Proxy failed to initialize " ) ;
return error ( " Proxy failed to initialize " ) ;
}
}
string strSocks5 ( " \5 \1 " ) ;
if ( pchRet1 [ 1 ] = = 0x02 & & auth ) {
strSocks5 + = ' \000 ' ; strSocks5 + = ' \003 ' ;
// Perform username/password authentication (as described in RFC1929)
strSocks5 + = static_cast < char > ( std : : min ( ( int ) strDest . size ( ) , 255 ) ) ;
std : : vector < uint8_t > vAuth ;
strSocks5 + = strDest ;
vAuth . push_back ( 0x01 ) ;
strSocks5 + = static_cast < char > ( ( port > > 8 ) & 0xFF ) ;
if ( auth - > username . size ( ) > 255 | | auth - > password . size ( ) > 255 )
strSocks5 + = static_cast < char > ( ( port > > 0 ) & 0xFF ) ;
return error ( " Proxy username or password too long " ) ;
ret = send ( hSocket , strSocks5 . data ( ) , strSocks5 . size ( ) , MSG_NOSIGNAL ) ;
vAuth . push_back ( auth - > username . size ( ) ) ;
if ( ret ! = ( ssize_t ) strSocks5 . size ( ) )
vAuth . insert ( vAuth . end ( ) , auth - > username . begin ( ) , auth - > username . end ( ) ) ;
{
vAuth . push_back ( auth - > password . size ( ) ) ;
vAuth . insert ( vAuth . end ( ) , auth - > password . begin ( ) , auth - > password . end ( ) ) ;
ret = send ( hSocket , ( const char * ) begin_ptr ( vAuth ) , vAuth . size ( ) , MSG_NOSIGNAL ) ;
if ( ret ! = ( ssize_t ) vAuth . size ( ) ) {
CloseSocket ( hSocket ) ;
return error ( " Error sending authentication to proxy " ) ;
}
LogPrint ( " proxy " , " SOCKS5 sending proxy authentication %s:%s \n " , auth - > username , auth - > password ) ;
char pchRetA [ 2 ] ;
if ( ! InterruptibleRecv ( pchRetA , 2 , SOCKS5_RECV_TIMEOUT , hSocket ) ) {
CloseSocket ( hSocket ) ;
return error ( " Error reading proxy authentication response " ) ;
}
if ( pchRetA [ 0 ] ! = 0x01 | | pchRetA [ 1 ] ! = 0x00 ) {
CloseSocket ( hSocket ) ;
return error ( " Proxy authentication unsuccesful " ) ;
}
} else if ( pchRet1 [ 1 ] = = 0x00 ) {
// Perform no authentication
} else {
CloseSocket ( hSocket ) ;
return error ( " Proxy requested wrong authentication method %02x " , pchRet1 [ 1 ] ) ;
}
std : : vector < uint8_t > vSocks5 ;
vSocks5 . push_back ( 0x05 ) ; // VER protocol version
vSocks5 . push_back ( 0x01 ) ; // CMD CONNECT
vSocks5 . push_back ( 0x00 ) ; // RSV Reserved
vSocks5 . push_back ( 0x03 ) ; // ATYP DOMAINNAME
vSocks5 . push_back ( strDest . size ( ) ) ; // Length<=255 is checked at beginning of function
vSocks5 . insert ( vSocks5 . end ( ) , strDest . begin ( ) , strDest . end ( ) ) ;
vSocks5 . push_back ( ( port > > 8 ) & 0xFF ) ;
vSocks5 . push_back ( ( port > > 0 ) & 0xFF ) ;
ret = send ( hSocket , ( const char * ) begin_ptr ( vSocks5 ) , vSocks5 . size ( ) , MSG_NOSIGNAL ) ;
if ( ret ! = ( ssize_t ) vSocks5 . size ( ) ) {
CloseSocket ( hSocket ) ;
CloseSocket ( hSocket ) ;
return error ( " Error sending to proxy " ) ;
return error ( " Error sending to proxy " ) ;
}
}
char pchRet2 [ 4 ] ;
char pchRet2 [ 4 ] ;
if ( ! InterruptibleRecv ( pchRet2 , 4 , SOCKS5_RECV_TIMEOUT , hSocket ) )
if ( ! InterruptibleRecv ( pchRet2 , 4 , SOCKS5_RECV_TIMEOUT , hSocket ) ) {
{
CloseSocket ( hSocket ) ;
CloseSocket ( hSocket ) ;
return error ( " Error reading proxy response " ) ;
return error ( " Error reading proxy response " ) ;
}
}
if ( pchRet2 [ 0 ] ! = 0x05 )
if ( pchRet2 [ 0 ] ! = 0x05 ) {
{
CloseSocket ( hSocket ) ;
CloseSocket ( hSocket ) ;
return error ( " Proxy failed to accept request " ) ;
return error ( " Proxy failed to accept request " ) ;
}
}
if ( pchRet2 [ 1 ] ! = 0x00 )
if ( pchRet2 [ 1 ] ! = 0x00 ) {
{
CloseSocket ( hSocket ) ;
CloseSocket ( hSocket ) ;
switch ( pchRet2 [ 1 ] )
switch ( pchRet2 [ 1 ] )
{
{
@ -352,8 +394,7 @@ bool static Socks5(string strDest, int port, SOCKET& hSocket)
default : return error ( " Proxy error: unknown " ) ;
default : return error ( " Proxy error: unknown " ) ;
}
}
}
}
if ( pchRet2 [ 2 ] ! = 0x00 )
if ( pchRet2 [ 2 ] ! = 0x00 ) {
{
CloseSocket ( hSocket ) ;
CloseSocket ( hSocket ) ;
return error ( " Error: malformed proxy response " ) ;
return error ( " Error: malformed proxy response " ) ;
}
}
@ -375,13 +416,11 @@ bool static Socks5(string strDest, int port, SOCKET& hSocket)
}
}
default : CloseSocket ( hSocket ) ; return error ( " Error: malformed proxy response " ) ;
default : CloseSocket ( hSocket ) ; return error ( " Error: malformed proxy response " ) ;
}
}
if ( ! ret )
if ( ! ret ) {
{
CloseSocket ( hSocket ) ;
CloseSocket ( hSocket ) ;
return error ( " Error reading from proxy " ) ;
return error ( " Error reading from proxy " ) ;
}
}
if ( ! InterruptibleRecv ( pchRet3 , 2 , SOCKS5_RECV_TIMEOUT , hSocket ) )
if ( ! InterruptibleRecv ( pchRet3 , 2 , SOCKS5_RECV_TIMEOUT , hSocket ) ) {
{
CloseSocket ( hSocket ) ;
CloseSocket ( hSocket ) ;
return error ( " Error reading from proxy " ) ;
return error ( " Error reading from proxy " ) ;
}
}
@ -471,7 +510,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
return true ;
return true ;
}
}
bool SetProxy ( enum Network net , CService addrProxy ) {
bool SetProxy ( enum Network net , const proxyType & addrProxy ) {
assert ( net > = 0 & & net < NET_MAX ) ;
assert ( net > = 0 & & net < NET_MAX ) ;
if ( ! addrProxy . IsValid ( ) )
if ( ! addrProxy . IsValid ( ) )
return false ;
return false ;
@ -489,7 +528,7 @@ bool GetProxy(enum Network net, proxyType &proxyInfoOut) {
return true ;
return true ;
}
}
bool SetNameProxy ( CService addrProxy ) {
bool SetNameProxy ( const proxyType & addrProxy ) {
if ( ! addrProxy . IsValid ( ) )
if ( ! addrProxy . IsValid ( ) )
return false ;
return false ;
LOCK ( cs_proxyInfos ) ;
LOCK ( cs_proxyInfos ) ;
@ -497,7 +536,7 @@ bool SetNameProxy(CService addrProxy) {
return true ;
return true ;
}
}
bool GetNameProxy ( CServic e & nameProxyOut ) {
bool GetNameProxy ( proxyTyp e & nameProxyOut ) {
LOCK ( cs_proxyInfos ) ;
LOCK ( cs_proxyInfos ) ;
if ( ! nameProxy . IsValid ( ) )
if ( ! nameProxy . IsValid ( ) )
return false ;
return false ;
@ -513,37 +552,49 @@ bool HaveNameProxy() {
bool IsProxy ( const CNetAddr & addr ) {
bool IsProxy ( const CNetAddr & addr ) {
LOCK ( cs_proxyInfos ) ;
LOCK ( cs_proxyInfos ) ;
for ( int i = 0 ; i < NET_MAX ; i + + ) {
for ( int i = 0 ; i < NET_MAX ; i + + ) {
if ( addr = = ( CNetAddr ) proxyInfo [ i ] )
if ( addr = = ( CNetAddr ) proxyInfo [ i ] . proxy )
return true ;
return true ;
}
}
return false ;
return false ;
}
}
bool ConnectSocket ( const CService & addrDes t , SOCKET & hSocketRet , int nTimeout , bool * outProxyConnectionFailed )
static bool ConnectThroughProxy ( const proxyType & proxy , const std : : string strDest , int por t , SOCKET & hSocketRet , int nTimeout , bool * outProxyConnectionFailed )
{
{
proxyType proxy ;
if ( outProxyConnectionFailed )
* outProxyConnectionFailed = false ;
// no proxy needed (none set for target network)
if ( ! GetProxy ( addrDest . GetNetwork ( ) , proxy ) )
return ConnectSocketDirectly ( addrDest , hSocketRet , nTimeout ) ;
SOCKET hSocket = INVALID_SOCKET ;
SOCKET hSocket = INVALID_SOCKET ;
// first connect to proxy server
// first connect to proxy server
if ( ! ConnectSocketDirectly ( proxy , hSocket , nTimeout ) ) {
if ( ! ConnectSocketDirectly ( proxy . proxy , hSocket , nTimeout ) ) {
if ( outProxyConnectionFailed )
if ( outProxyConnectionFailed )
* outProxyConnectionFailed = true ;
* outProxyConnectionFailed = true ;
return false ;
return false ;
}
}
// do socks negotiation
// do socks negotiation
if ( ! Socks5 ( addrDest . ToStringIP ( ) , addrDest . GetPort ( ) , hSocket ) )
if ( proxy . randomize_credentials ) {
return false ;
ProxyCredentials random_auth ;
random_auth . username = strprintf ( " %i " , insecure_rand ( ) ) ;
random_auth . password = strprintf ( " %i " , insecure_rand ( ) ) ;
if ( ! Socks5 ( strDest , ( unsigned short ) port , & random_auth , hSocket ) )
return false ;
} else {
if ( ! Socks5 ( strDest , ( unsigned short ) port , 0 , hSocket ) )
return false ;
}
hSocketRet = hSocket ;
hSocketRet = hSocket ;
return true ;
return true ;
}
}
bool ConnectSocket ( const CService & addrDest , SOCKET & hSocketRet , int nTimeout , bool * outProxyConnectionFailed )
{
proxyType proxy ;
if ( outProxyConnectionFailed )
* outProxyConnectionFailed = false ;
if ( GetProxy ( addrDest . GetNetwork ( ) , proxy ) )
return ConnectThroughProxy ( proxy , addrDest . ToStringIP ( ) , addrDest . GetPort ( ) , hSocketRet , nTimeout , outProxyConnectionFailed ) ;
else // no proxy needed (none set for target network)
return ConnectSocketDirectly ( addrDest , hSocketRet , nTimeout ) ;
}
bool ConnectSocketByName ( CService & addr , SOCKET & hSocketRet , const char * pszDest , int portDefault , int nTimeout , bool * outProxyConnectionFailed )
bool ConnectSocketByName ( CService & addr , SOCKET & hSocketRet , const char * pszDest , int portDefault , int nTimeout , bool * outProxyConnectionFailed )
{
{
string strDest ;
string strDest ;
@ -554,9 +605,7 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest
SplitHostPort ( string ( pszDest ) , port , strDest ) ;
SplitHostPort ( string ( pszDest ) , port , strDest ) ;
SOCKET hSocket = INVALID_SOCKET ;
proxyType nameProxy ;
CService nameProxy ;
GetNameProxy ( nameProxy ) ;
GetNameProxy ( nameProxy ) ;
CService addrResolved ( CNetAddr ( strDest , fNameLookup & & ! HaveNameProxy ( ) ) , port ) ;
CService addrResolved ( CNetAddr ( strDest , fNameLookup & & ! HaveNameProxy ( ) ) , port ) ;
@ -569,18 +618,7 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest
if ( ! HaveNameProxy ( ) )
if ( ! HaveNameProxy ( ) )
return false ;
return false ;
// first connect to name proxy server
return ConnectThroughProxy ( nameProxy , strDest , port , hSocketRet , nTimeout , outProxyConnectionFailed ) ;
if ( ! ConnectSocketDirectly ( nameProxy , hSocket , nTimeout ) ) {
if ( outProxyConnectionFailed )
* outProxyConnectionFailed = true ;
return false ;
}
// do socks negotiation
if ( ! Socks5 ( strDest , ( unsigned short ) port , hSocket ) )
return false ;
hSocketRet = hSocket ;
return true ;
}
}
void CNetAddr : : Init ( )
void CNetAddr : : Init ( )