1212#include " hash.h"
1313#include " sync.h"
1414#include " uint256.h"
15+ #include " random.h"
1516#include " util.h"
1617#include " utilstrencodings.h"
1718
@@ -38,7 +39,7 @@ using namespace std;
3839
3940// Settings
4041static proxyType proxyInfo[NET_MAX];
41- static CService nameProxy;
42+ static proxyType nameProxy;
4243static CCriticalSection cs_proxyInfos;
4344int nConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
4445bool fNameLookup = false ;
@@ -285,59 +286,100 @@ bool static InterruptibleRecv(char* data, size_t len, int timeout, SOCKET& hSock
285286 return len == 0 ;
286287}
287288
288- bool static Socks5 (string strDest, int port, SOCKET& hSocket)
289+ struct ProxyCredentials
290+ {
291+ std::string username;
292+ std::string password;
293+ };
294+
295+ /* * Connect using SOCKS5 (as described in RFC1928) */
296+ bool static Socks5 (string strDest, int port, const ProxyCredentials *auth, SOCKET& hSocket)
289297{
290298 LogPrintf (" SOCKS5 connecting %s\n " , strDest);
291- if (strDest.size () > 255 )
292- {
299+ if (strDest.size () > 255 ) {
293300 CloseSocket (hSocket);
294301 return error (" Hostname too long" );
295302 }
296- char pszSocks5Init[] = " \5\1\0 " ;
297- ssize_t nSize = sizeof (pszSocks5Init) - 1 ;
298-
299- ssize_t ret = send (hSocket, pszSocks5Init, nSize, MSG_NOSIGNAL);
300- if (ret != nSize)
301- {
303+ // Accepted authentication methods
304+ std::vector<uint8_t > vSocks5Init;
305+ vSocks5Init.push_back (0x05 );
306+ if (auth) {
307+ vSocks5Init.push_back (0x02 ); // # METHODS
308+ vSocks5Init.push_back (0x00 ); // X'00' NO AUTHENTICATION REQUIRED
309+ vSocks5Init.push_back (0x02 ); // X'02' USERNAME/PASSWORD (RFC1929)
310+ } else {
311+ vSocks5Init.push_back (0x01 ); // # METHODS
312+ vSocks5Init.push_back (0x00 ); // X'00' NO AUTHENTICATION REQUIRED
313+ }
314+ ssize_t ret = send (hSocket, (const char *)begin_ptr (vSocks5Init), vSocks5Init.size (), MSG_NOSIGNAL);
315+ if (ret != (ssize_t )vSocks5Init.size ()) {
302316 CloseSocket (hSocket);
303317 return error (" Error sending to proxy" );
304318 }
305319 char pchRet1[2 ];
306- if (!InterruptibleRecv (pchRet1, 2 , SOCKS5_RECV_TIMEOUT, hSocket))
307- {
320+ if (!InterruptibleRecv (pchRet1, 2 , SOCKS5_RECV_TIMEOUT, hSocket)) {
308321 CloseSocket (hSocket);
309322 return error (" Error reading proxy response" );
310323 }
311- if (pchRet1[0 ] != 0x05 || pchRet1[1 ] != 0x00 )
312- {
324+ if (pchRet1[0 ] != 0x05 ) {
313325 CloseSocket (hSocket);
314326 return error (" Proxy failed to initialize" );
315327 }
316- string strSocks5 (" \5\1 " );
317- strSocks5 += ' \000 ' ; strSocks5 += ' \003 ' ;
318- strSocks5 += static_cast <char >(std::min ((int )strDest.size (), 255 ));
319- strSocks5 += strDest;
320- strSocks5 += static_cast <char >((port >> 8 ) & 0xFF );
321- strSocks5 += static_cast <char >((port >> 0 ) & 0xFF );
322- ret = send (hSocket, strSocks5.data (), strSocks5.size (), MSG_NOSIGNAL);
323- if (ret != (ssize_t )strSocks5.size ())
324- {
328+ if (pchRet1[1 ] == 0x02 && auth) {
329+ // Perform username/password authentication (as described in RFC1929)
330+ std::vector<uint8_t > vAuth;
331+ vAuth.push_back (0x01 );
332+ if (auth->username .size () > 255 || auth->password .size () > 255 )
333+ return error (" Proxy username or password too long" );
334+ vAuth.push_back (auth->username .size ());
335+ vAuth.insert (vAuth.end (), auth->username .begin (), auth->username .end ());
336+ vAuth.push_back (auth->password .size ());
337+ vAuth.insert (vAuth.end (), auth->password .begin (), auth->password .end ());
338+ ret = send (hSocket, (const char *)begin_ptr (vAuth), vAuth.size (), MSG_NOSIGNAL);
339+ if (ret != (ssize_t )vAuth.size ()) {
340+ CloseSocket (hSocket);
341+ return error (" Error sending authentication to proxy" );
342+ }
343+ LogPrint (" proxy" , " SOCKS5 sending proxy authentication %s:%s\n " , auth->username , auth->password );
344+ char pchRetA[2 ];
345+ if (!InterruptibleRecv (pchRetA, 2 , SOCKS5_RECV_TIMEOUT, hSocket)) {
346+ CloseSocket (hSocket);
347+ return error (" Error reading proxy authentication response" );
348+ }
349+ if (pchRetA[0 ] != 0x01 || pchRetA[1 ] != 0x00 ) {
350+ CloseSocket (hSocket);
351+ return error (" Proxy authentication unsuccesful" );
352+ }
353+ } else if (pchRet1[1 ] == 0x00 ) {
354+ // Perform no authentication
355+ } else {
356+ CloseSocket (hSocket);
357+ return error (" Proxy requested wrong authentication method %02x" , pchRet1[1 ]);
358+ }
359+ std::vector<uint8_t > vSocks5;
360+ vSocks5.push_back (0x05 ); // VER protocol version
361+ vSocks5.push_back (0x01 ); // CMD CONNECT
362+ vSocks5.push_back (0x00 ); // RSV Reserved
363+ vSocks5.push_back (0x03 ); // ATYP DOMAINNAME
364+ vSocks5.push_back (strDest.size ()); // Length<=255 is checked at beginning of function
365+ vSocks5.insert (vSocks5.end (), strDest.begin (), strDest.end ());
366+ vSocks5.push_back ((port >> 8 ) & 0xFF );
367+ vSocks5.push_back ((port >> 0 ) & 0xFF );
368+ ret = send (hSocket, (const char *)begin_ptr (vSocks5), vSocks5.size (), MSG_NOSIGNAL);
369+ if (ret != (ssize_t )vSocks5.size ()) {
325370 CloseSocket (hSocket);
326371 return error (" Error sending to proxy" );
327372 }
328373 char pchRet2[4 ];
329- if (!InterruptibleRecv (pchRet2, 4 , SOCKS5_RECV_TIMEOUT, hSocket))
330- {
374+ if (!InterruptibleRecv (pchRet2, 4 , SOCKS5_RECV_TIMEOUT, hSocket)) {
331375 CloseSocket (hSocket);
332376 return error (" Error reading proxy response" );
333377 }
334- if (pchRet2[0 ] != 0x05 )
335- {
378+ if (pchRet2[0 ] != 0x05 ) {
336379 CloseSocket (hSocket);
337380 return error (" Proxy failed to accept request" );
338381 }
339- if (pchRet2[1 ] != 0x00 )
340- {
382+ if (pchRet2[1 ] != 0x00 ) {
341383 CloseSocket (hSocket);
342384 switch (pchRet2[1 ])
343385 {
@@ -352,8 +394,7 @@ bool static Socks5(string strDest, int port, SOCKET& hSocket)
352394 default : return error (" Proxy error: unknown" );
353395 }
354396 }
355- if (pchRet2[2 ] != 0x00 )
356- {
397+ if (pchRet2[2 ] != 0x00 ) {
357398 CloseSocket (hSocket);
358399 return error (" Error: malformed proxy response" );
359400 }
@@ -375,13 +416,11 @@ bool static Socks5(string strDest, int port, SOCKET& hSocket)
375416 }
376417 default : CloseSocket (hSocket); return error (" Error: malformed proxy response" );
377418 }
378- if (!ret)
379- {
419+ if (!ret) {
380420 CloseSocket (hSocket);
381421 return error (" Error reading from proxy" );
382422 }
383- if (!InterruptibleRecv (pchRet3, 2 , SOCKS5_RECV_TIMEOUT, hSocket))
384- {
423+ if (!InterruptibleRecv (pchRet3, 2 , SOCKS5_RECV_TIMEOUT, hSocket)) {
385424 CloseSocket (hSocket);
386425 return error (" Error reading from proxy" );
387426 }
@@ -471,7 +510,7 @@ bool static ConnectSocketDirectly(const CService &addrConnect, SOCKET& hSocketRe
471510 return true ;
472511}
473512
474- bool SetProxy (enum Network net, CService addrProxy) {
513+ bool SetProxy (enum Network net, const proxyType & addrProxy) {
475514 assert (net >= 0 && net < NET_MAX);
476515 if (!addrProxy.IsValid ())
477516 return false ;
@@ -489,15 +528,15 @@ bool GetProxy(enum Network net, proxyType &proxyInfoOut) {
489528 return true ;
490529}
491530
492- bool SetNameProxy (CService addrProxy) {
531+ bool SetNameProxy (const proxyType & addrProxy) {
493532 if (!addrProxy.IsValid ())
494533 return false ;
495534 LOCK (cs_proxyInfos);
496535 nameProxy = addrProxy;
497536 return true ;
498537}
499538
500- bool GetNameProxy (CService &nameProxyOut) {
539+ bool GetNameProxy (proxyType &nameProxyOut) {
501540 LOCK (cs_proxyInfos);
502541 if (!nameProxy.IsValid ())
503542 return false ;
@@ -513,37 +552,49 @@ bool HaveNameProxy() {
513552bool IsProxy (const CNetAddr &addr) {
514553 LOCK (cs_proxyInfos);
515554 for (int i = 0 ; i < NET_MAX; i++) {
516- if (addr == (CNetAddr)proxyInfo[i])
555+ if (addr == (CNetAddr)proxyInfo[i]. proxy )
517556 return true ;
518557 }
519558 return false ;
520559}
521560
522- bool ConnectSocket (const CService &addrDest , SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed)
561+ static bool ConnectThroughProxy (const proxyType &proxy, const std::string strDest, int port , SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed)
523562{
524- proxyType proxy;
525- if (outProxyConnectionFailed)
526- *outProxyConnectionFailed = false ;
527- // no proxy needed (none set for target network)
528- if (!GetProxy (addrDest.GetNetwork (), proxy))
529- return ConnectSocketDirectly (addrDest, hSocketRet, nTimeout);
530-
531563 SOCKET hSocket = INVALID_SOCKET;
532-
533564 // first connect to proxy server
534- if (!ConnectSocketDirectly (proxy, hSocket, nTimeout)) {
565+ if (!ConnectSocketDirectly (proxy. proxy , hSocket, nTimeout)) {
535566 if (outProxyConnectionFailed)
536567 *outProxyConnectionFailed = true ;
537568 return false ;
538569 }
539570 // do socks negotiation
540- if (!Socks5 (addrDest.ToStringIP (), addrDest.GetPort (), hSocket))
541- return false ;
571+ if (proxy.randomize_credentials ) {
572+ ProxyCredentials random_auth;
573+ random_auth.username = strprintf (" %i" , insecure_rand ());
574+ random_auth.password = strprintf (" %i" , insecure_rand ());
575+ if (!Socks5 (strDest, (unsigned short )port, &random_auth, hSocket))
576+ return false ;
577+ } else {
578+ if (!Socks5 (strDest, (unsigned short )port, 0 , hSocket))
579+ return false ;
580+ }
542581
543582 hSocketRet = hSocket;
544583 return true ;
545584}
546585
586+ bool ConnectSocket (const CService &addrDest, SOCKET& hSocketRet, int nTimeout, bool *outProxyConnectionFailed)
587+ {
588+ proxyType proxy;
589+ if (outProxyConnectionFailed)
590+ *outProxyConnectionFailed = false ;
591+
592+ if (GetProxy (addrDest.GetNetwork (), proxy))
593+ return ConnectThroughProxy (proxy, addrDest.ToStringIP (), addrDest.GetPort (), hSocketRet, nTimeout, outProxyConnectionFailed);
594+ else // no proxy needed (none set for target network)
595+ return ConnectSocketDirectly (addrDest, hSocketRet, nTimeout);
596+ }
597+
547598bool ConnectSocketByName (CService &addr, SOCKET& hSocketRet, const char *pszDest, int portDefault, int nTimeout, bool *outProxyConnectionFailed)
548599{
549600 string strDest;
@@ -554,9 +605,7 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest
554605
555606 SplitHostPort (string (pszDest), port, strDest);
556607
557- SOCKET hSocket = INVALID_SOCKET;
558-
559- CService nameProxy;
608+ proxyType nameProxy;
560609 GetNameProxy (nameProxy);
561610
562611 CService addrResolved (CNetAddr (strDest, fNameLookup && !HaveNameProxy ()), port);
@@ -569,18 +618,7 @@ bool ConnectSocketByName(CService &addr, SOCKET& hSocketRet, const char *pszDest
569618
570619 if (!HaveNameProxy ())
571620 return false ;
572- // first connect to name proxy server
573- if (!ConnectSocketDirectly (nameProxy, hSocket, nTimeout)) {
574- if (outProxyConnectionFailed)
575- *outProxyConnectionFailed = true ;
576- return false ;
577- }
578- // do socks negotiation
579- if (!Socks5 (strDest, (unsigned short )port, hSocket))
580- return false ;
581-
582- hSocketRet = hSocket;
583- return true ;
621+ return ConnectThroughProxy (nameProxy, strDest, port, hSocketRet, nTimeout, outProxyConnectionFailed);
584622}
585623
586624void CNetAddr::Init ()
0 commit comments