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