@@ -30,7 +30,7 @@ bool fNameLookup = DEFAULT_NAME_LOOKUP;
30
30
31
31
// Need ample time for negotiation for very slow proxies such as Tor
32
32
std::chrono::milliseconds g_socks5_recv_timeout = 20s;
33
- static std::atomic< bool > interruptSocks5Recv ( false ) ;
33
+ CThreadInterrupt g_socks5_interrupt ;
34
34
35
35
std::vector<CNetAddr> WrappedGetAddrInfo (const std::string& name, bool allow_lookup)
36
36
{
@@ -269,7 +269,7 @@ enum class IntrRecvError {
269
269
* IntrRecvError::OK only if all of the specified number of bytes were
270
270
* read.
271
271
*
272
- * @see This function can be interrupted by calling InterruptSocks5(bool ).
272
+ * @see This function can be interrupted by calling g_socks5_interrupt( ).
273
273
* Sockets can be made non-blocking with Sock::SetNonBlocking().
274
274
*/
275
275
static IntrRecvError InterruptibleRecv (uint8_t * data, size_t len, std::chrono::milliseconds timeout, const Sock& sock)
@@ -297,8 +297,9 @@ static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, std::chrono::m
297
297
return IntrRecvError::NetworkError;
298
298
}
299
299
}
300
- if (interruptSocks5Recv)
300
+ if (g_socks5_interrupt) {
301
301
return IntrRecvError::Interrupted;
302
+ }
302
303
curTime = Now<SteadyMilliseconds>();
303
304
}
304
305
return len == 0 ? IntrRecvError::OK : IntrRecvError::Timeout;
@@ -331,103 +332,93 @@ static std::string Socks5ErrorString(uint8_t err)
331
332
332
333
bool Socks5 (const std::string& strDest, uint16_t port, const ProxyCredentials* auth, const Sock& sock)
333
334
{
334
- IntrRecvError recvr;
335
- LogPrint (BCLog::NET, " SOCKS5 connecting %s\n " , strDest);
336
- if (strDest.size () > 255 ) {
337
- return error (" Hostname too long" );
338
- }
339
- // Construct the version identifier/method selection message
340
- std::vector<uint8_t > vSocks5Init;
341
- vSocks5Init.push_back (SOCKSVersion::SOCKS5); // We want the SOCK5 protocol
342
- if (auth) {
343
- vSocks5Init.push_back (0x02 ); // 2 method identifiers follow...
344
- vSocks5Init.push_back (SOCKS5Method::NOAUTH);
345
- vSocks5Init.push_back (SOCKS5Method::USER_PASS);
346
- } else {
347
- vSocks5Init.push_back (0x01 ); // 1 method identifier follows...
348
- vSocks5Init.push_back (SOCKS5Method::NOAUTH);
349
- }
350
- ssize_t ret = sock.Send (vSocks5Init.data (), vSocks5Init.size (), MSG_NOSIGNAL);
351
- if (ret != (ssize_t )vSocks5Init.size ()) {
352
- return error (" Error sending to proxy" );
353
- }
354
- uint8_t pchRet1[2 ];
355
- if (InterruptibleRecv (pchRet1, 2 , g_socks5_recv_timeout, sock) != IntrRecvError::OK) {
356
- LogPrintf (" Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n " , strDest, port);
357
- return false ;
358
- }
359
- if (pchRet1[0 ] != SOCKSVersion::SOCKS5) {
360
- return error (" Proxy failed to initialize" );
361
- }
362
- if (pchRet1[1 ] == SOCKS5Method::USER_PASS && auth) {
363
- // Perform username/password authentication (as described in RFC1929)
364
- std::vector<uint8_t > vAuth;
365
- vAuth.push_back (0x01 ); // Current (and only) version of user/pass subnegotiation
366
- if (auth->username .size () > 255 || auth->password .size () > 255 )
367
- return error (" Proxy username or password too long" );
368
- vAuth.push_back (auth->username .size ());
369
- vAuth.insert (vAuth.end (), auth->username .begin (), auth->username .end ());
370
- vAuth.push_back (auth->password .size ());
371
- vAuth.insert (vAuth.end (), auth->password .begin (), auth->password .end ());
372
- ret = sock.Send (vAuth.data (), vAuth.size (), MSG_NOSIGNAL);
373
- if (ret != (ssize_t )vAuth.size ()) {
374
- return error (" Error sending authentication to proxy" );
375
- }
376
- LogPrint (BCLog::PROXY, " SOCKS5 sending proxy authentication %s:%s\n " , auth->username , auth->password );
377
- uint8_t pchRetA[2 ];
378
- if (InterruptibleRecv (pchRetA, 2 , g_socks5_recv_timeout, sock) != IntrRecvError::OK) {
379
- return error (" Error reading proxy authentication response" );
335
+ try {
336
+ IntrRecvError recvr;
337
+ LogPrint (BCLog::NET, " SOCKS5 connecting %s\n " , strDest);
338
+ if (strDest.size () > 255 ) {
339
+ return error (" Hostname too long" );
380
340
}
381
- if (pchRetA[0 ] != 0x01 || pchRetA[1 ] != 0x00 ) {
382
- return error (" Proxy authentication unsuccessful" );
341
+ // Construct the version identifier/method selection message
342
+ std::vector<uint8_t > vSocks5Init;
343
+ vSocks5Init.push_back (SOCKSVersion::SOCKS5); // We want the SOCK5 protocol
344
+ if (auth) {
345
+ vSocks5Init.push_back (0x02 ); // 2 method identifiers follow...
346
+ vSocks5Init.push_back (SOCKS5Method::NOAUTH);
347
+ vSocks5Init.push_back (SOCKS5Method::USER_PASS);
348
+ } else {
349
+ vSocks5Init.push_back (0x01 ); // 1 method identifier follows...
350
+ vSocks5Init.push_back (SOCKS5Method::NOAUTH);
383
351
}
384
- } else if (pchRet1[1 ] == SOCKS5Method::NOAUTH) {
385
- // Perform no authentication
386
- } else {
387
- return error (" Proxy requested wrong authentication method %02x" , pchRet1[1 ]);
388
- }
389
- std::vector<uint8_t > vSocks5;
390
- vSocks5.push_back (SOCKSVersion::SOCKS5); // VER protocol version
391
- vSocks5.push_back (SOCKS5Command::CONNECT); // CMD CONNECT
392
- vSocks5.push_back (0x00 ); // RSV Reserved must be 0
393
- vSocks5.push_back (SOCKS5Atyp::DOMAINNAME); // ATYP DOMAINNAME
394
- vSocks5.push_back (strDest.size ()); // Length<=255 is checked at beginning of function
395
- vSocks5.insert (vSocks5.end (), strDest.begin (), strDest.end ());
396
- vSocks5.push_back ((port >> 8 ) & 0xFF );
397
- vSocks5.push_back ((port >> 0 ) & 0xFF );
398
- ret = sock.Send (vSocks5.data (), vSocks5.size (), MSG_NOSIGNAL);
399
- if (ret != (ssize_t )vSocks5.size ()) {
400
- return error (" Error sending to proxy" );
401
- }
402
- uint8_t pchRet2[4 ];
403
- if ((recvr = InterruptibleRecv (pchRet2, 4 , g_socks5_recv_timeout, sock)) != IntrRecvError::OK) {
404
- if (recvr == IntrRecvError::Timeout) {
405
- /* If a timeout happens here, this effectively means we timed out while connecting
406
- * to the remote node. This is very common for Tor, so do not print an
407
- * error message. */
352
+ sock.SendComplete (vSocks5Init, g_socks5_recv_timeout, g_socks5_interrupt);
353
+ uint8_t pchRet1[2 ];
354
+ if (InterruptibleRecv (pchRet1, 2 , g_socks5_recv_timeout, sock) != IntrRecvError::OK) {
355
+ LogPrintf (" Socks5() connect to %s:%d failed: InterruptibleRecv() timeout or other failure\n " , strDest, port);
408
356
return false ;
357
+ }
358
+ if (pchRet1[0 ] != SOCKSVersion::SOCKS5) {
359
+ return error (" Proxy failed to initialize" );
360
+ }
361
+ if (pchRet1[1 ] == SOCKS5Method::USER_PASS && auth) {
362
+ // Perform username/password authentication (as described in RFC1929)
363
+ std::vector<uint8_t > vAuth;
364
+ vAuth.push_back (0x01 ); // Current (and only) version of user/pass subnegotiation
365
+ if (auth->username .size () > 255 || auth->password .size () > 255 )
366
+ return error (" Proxy username or password too long" );
367
+ vAuth.push_back (auth->username .size ());
368
+ vAuth.insert (vAuth.end (), auth->username .begin (), auth->username .end ());
369
+ vAuth.push_back (auth->password .size ());
370
+ vAuth.insert (vAuth.end (), auth->password .begin (), auth->password .end ());
371
+ sock.SendComplete (vAuth, g_socks5_recv_timeout, g_socks5_interrupt);
372
+ LogPrint (BCLog::PROXY, " SOCKS5 sending proxy authentication %s:%s\n " , auth->username , auth->password );
373
+ uint8_t pchRetA[2 ];
374
+ if (InterruptibleRecv (pchRetA, 2 , g_socks5_recv_timeout, sock) != IntrRecvError::OK) {
375
+ return error (" Error reading proxy authentication response" );
376
+ }
377
+ if (pchRetA[0 ] != 0x01 || pchRetA[1 ] != 0x00 ) {
378
+ return error (" Proxy authentication unsuccessful" );
379
+ }
380
+ } else if (pchRet1[1 ] == SOCKS5Method::NOAUTH) {
381
+ // Perform no authentication
409
382
} else {
410
- return error (" Error while reading proxy response " );
383
+ return error (" Proxy requested wrong authentication method %02x " , pchRet1[ 1 ] );
411
384
}
412
- }
413
- if (pchRet2[0 ] != SOCKSVersion::SOCKS5) {
414
- return error (" Proxy failed to accept request" );
415
- }
416
- if (pchRet2[1 ] != SOCKS5Reply::SUCCEEDED) {
417
- // Failures to connect to a peer that are not proxy errors
418
- LogPrintf (" Socks5() connect to %s:%d failed: %s\n " , strDest, port, Socks5ErrorString (pchRet2[1 ]));
419
- return false ;
420
- }
421
- if (pchRet2[2 ] != 0x00 ) { // Reserved field must be 0
422
- return error (" Error: malformed proxy response" );
423
- }
424
- uint8_t pchRet3[256 ];
425
- switch (pchRet2[3 ])
426
- {
385
+ std::vector<uint8_t > vSocks5;
386
+ vSocks5.push_back (SOCKSVersion::SOCKS5); // VER protocol version
387
+ vSocks5.push_back (SOCKS5Command::CONNECT); // CMD CONNECT
388
+ vSocks5.push_back (0x00 ); // RSV Reserved must be 0
389
+ vSocks5.push_back (SOCKS5Atyp::DOMAINNAME); // ATYP DOMAINNAME
390
+ vSocks5.push_back (strDest.size ()); // Length<=255 is checked at beginning of function
391
+ vSocks5.insert (vSocks5.end (), strDest.begin (), strDest.end ());
392
+ vSocks5.push_back ((port >> 8 ) & 0xFF );
393
+ vSocks5.push_back ((port >> 0 ) & 0xFF );
394
+ sock.SendComplete (vSocks5, g_socks5_recv_timeout, g_socks5_interrupt);
395
+ uint8_t pchRet2[4 ];
396
+ if ((recvr = InterruptibleRecv (pchRet2, 4 , g_socks5_recv_timeout, sock)) != IntrRecvError::OK) {
397
+ if (recvr == IntrRecvError::Timeout) {
398
+ /* If a timeout happens here, this effectively means we timed out while connecting
399
+ * to the remote node. This is very common for Tor, so do not print an
400
+ * error message. */
401
+ return false ;
402
+ } else {
403
+ return error (" Error while reading proxy response" );
404
+ }
405
+ }
406
+ if (pchRet2[0 ] != SOCKSVersion::SOCKS5) {
407
+ return error (" Proxy failed to accept request" );
408
+ }
409
+ if (pchRet2[1 ] != SOCKS5Reply::SUCCEEDED) {
410
+ // Failures to connect to a peer that are not proxy errors
411
+ LogPrintf (" Socks5() connect to %s:%d failed: %s\n " , strDest, port, Socks5ErrorString (pchRet2[1 ]));
412
+ return false ;
413
+ }
414
+ if (pchRet2[2 ] != 0x00 ) { // Reserved field must be 0
415
+ return error (" Error: malformed proxy response" );
416
+ }
417
+ uint8_t pchRet3[256 ];
418
+ switch (pchRet2[3 ]) {
427
419
case SOCKS5Atyp::IPV4: recvr = InterruptibleRecv (pchRet3, 4 , g_socks5_recv_timeout, sock); break ;
428
420
case SOCKS5Atyp::IPV6: recvr = InterruptibleRecv (pchRet3, 16 , g_socks5_recv_timeout, sock); break ;
429
- case SOCKS5Atyp::DOMAINNAME:
430
- {
421
+ case SOCKS5Atyp::DOMAINNAME: {
431
422
recvr = InterruptibleRecv (pchRet3, 1 , g_socks5_recv_timeout, sock);
432
423
if (recvr != IntrRecvError::OK) {
433
424
return error (" Error reading from proxy" );
@@ -437,15 +428,18 @@ bool Socks5(const std::string& strDest, uint16_t port, const ProxyCredentials* a
437
428
break ;
438
429
}
439
430
default : return error (" Error: malformed proxy response" );
431
+ }
432
+ if (recvr != IntrRecvError::OK) {
433
+ return error (" Error reading from proxy" );
434
+ }
435
+ if (InterruptibleRecv (pchRet3, 2 , g_socks5_recv_timeout, sock) != IntrRecvError::OK) {
436
+ return error (" Error reading from proxy" );
437
+ }
438
+ LogPrint (BCLog::NET, " SOCKS5 connected %s\n " , strDest);
439
+ return true ;
440
+ } catch (const std::runtime_error& e) {
441
+ return error (" Error during SOCKS5 proxy handshake: %s" , e.what ());
440
442
}
441
- if (recvr != IntrRecvError::OK) {
442
- return error (" Error reading from proxy" );
443
- }
444
- if (InterruptibleRecv (pchRet3, 2 , g_socks5_recv_timeout, sock) != IntrRecvError::OK) {
445
- return error (" Error reading from proxy" );
446
- }
447
- LogPrint (BCLog::NET, " SOCKS5 connected %s\n " , strDest);
448
- return true ;
449
443
}
450
444
451
445
std::unique_ptr<Sock> CreateSockTCP (const CService& address_family)
@@ -678,11 +672,6 @@ bool LookupSubNet(const std::string& subnet_str, CSubNet& subnet_out)
678
672
return false ;
679
673
}
680
674
681
- void InterruptSocks5 (bool interrupt)
682
- {
683
- interruptSocks5Recv = interrupt;
684
- }
685
-
686
675
bool IsBadPort (uint16_t port)
687
676
{
688
677
/* Don't forget to update doc/p2p-bad-ports.md if you change this list. */
0 commit comments