@@ -47,6 +47,11 @@ static const float RECONNECT_TIMEOUT_EXP = 1.5;
4747 */
4848static const int MAX_LINE_LENGTH = 100000 ;
4949
50+ enum Tor_proto_version {
51+ TOR_NET_V2,
52+ TOR_NET_V3
53+ };
54+
5055/* ***** Low-level TorControlConnection ********/
5156
5257/* * Reply from Tor, can be single or multi-line */
@@ -422,6 +427,7 @@ class TorController
422427 struct event_base * base;
423428 std::string target;
424429 TorControlConnection conn;
430+ Tor_proto_version tor_version = TOR_NET_V2;
425431 std::string private_key;
426432 std::string service_id;
427433 bool reconnect;
@@ -463,12 +469,6 @@ TorController::TorController(struct event_base* _base, const std::string& _targe
463469 std::bind (&TorController::disconnected_cb, this , std::placeholders::_1) )) {
464470 LogPrintf (" tor: Initiating connection to Tor control port %s failed\n " , _target);
465471 }
466- // Read service private key if cached
467- std::pair<bool ,std::string> pkf = ReadBinaryFile (GetPrivateKeyFile ());
468- if (pkf.first ) {
469- LogPrint (BCLog::TOR, " tor: Reading cached private key from %s\n " , GetPrivateKeyFile ().string ());
470- private_key = pkf.second ;
471- }
472472}
473473
474474TorController::~TorController ()
@@ -485,7 +485,7 @@ TorController::~TorController()
485485void TorController::add_onion_cb (TorControlConnection& _conn, const TorControlReply& reply)
486486{
487487 if (reply.code == 250 ) {
488- LogPrint (BCLog::TOR, " tor: ADD_ONION successful\n " );
488+ LogPrint (BCLog::TOR, " tor: ADD_ONION %s successful\n " , tor_version == TOR_NET_V2 ? " V2 " : " V3 " );
489489 for (const std::string &s : reply.lines ) {
490490 std::map<std::string,std::string> m = ParseTorReplyMapping (s);
491491 std::map<std::string,std::string>::iterator i;
@@ -495,25 +495,49 @@ void TorController::add_onion_cb(TorControlConnection& _conn, const TorControlRe
495495 private_key = i->second ;
496496 }
497497 if (service_id.empty ()) {
498- LogPrintf (" tor: Error parsing ADD_ONION parameters:\n " );
498+ LogPrintf (" tor: Error parsing ADD_ONION %s parameters:\n " , tor_version == TOR_NET_V2 ? " V2 " : " V3 " );
499499 for (const std::string &s : reply.lines ) {
500500 LogPrintf (" %s\n " , SanitizeString (s));
501501 }
502- return ;
502+
503+ } else {
504+ service = LookupNumeric (std::string (service_id + " .onion" ), Params ().GetDefaultPort ());
505+ if (service_id.length () > 16 )
506+ tor_version = TOR_NET_V3;
507+ else
508+ tor_version = TOR_NET_V2;
509+ LogPrintf (" tor: Got service ID %s, created %s.onion, advertising service %s\n " , service_id, service_id, service.ToString ());
510+ if (WriteBinaryFile (GetPrivateKeyFile (), private_key)) {
511+ LogPrint (BCLog::TOR, " tor: Write cached service private key to %s\n " , GetPrivateKeyFile ().string ());
512+ } else {
513+ LogPrintf (" tor: Error writing service private key to %s\n " , GetPrivateKeyFile ().string ());
514+ }
515+ AddLocal (service, LOCAL_MANUAL);
516+ // ... onion requested - keep connection open
517+
518+ if (reply.code == 510 ) { // 510 Unrecognized command
519+ LogPrintf (" tor: Add onion failed with unrecognized command (You probably need to upgrade Tor)\n " );
520+ }
503521 }
504- service = LookupNumeric (std::string (service_id+" .onion" ), Params ().GetDefaultPort ());
505- LogPrintf (" tor: Got service ID %s, advertising service %s\n " , service_id, service.ToString ());
506- if (WriteBinaryFile (GetPrivateKeyFile (), private_key)) {
507- LogPrint (BCLog::TOR, " tor: Cached service private key to %s\n " , GetPrivateKeyFile ().string ());
508522 } else {
509- LogPrintf (" tor: Error writing service private key to %s \n " , GetPrivateKeyFile (). string () );
523+ LogPrintf (" tor: Add onion failed; error code %d \n " , reply. code );
510524 }
511- AddLocal (service, LOCAL_MANUAL);
512- // ... onion requested - keep connection open
513- } else if (reply.code == 510 ) { // 510 Unrecognized command
514- LogPrintf (" tor: Add onion failed with unrecognized command (You probably need to upgrade Tor)\n " );
515- } else {
516- LogPrintf (" tor: Add onion failed; error code %d\n " , reply.code );
525+ // Tor might deprecate v2-onions so we try to create from now on also v3 onions
526+ // Now we try to create the v3-service
527+ if (tor_version == TOR_NET_V2) {
528+ tor_version = TOR_NET_V3;
529+ private_key = " " ;
530+ std::pair<bool , std::string> pkf = ReadBinaryFile (GetPrivateKeyFile ());
531+ if (pkf.first ) {
532+ LogPrint (BCLog::TOR, " tor: Reading cached private key from %s\n " , GetPrivateKeyFile ().string ());
533+ private_key = pkf.second ;
534+ }
535+ if (private_key.empty ()) // No private key, generate one
536+ private_key = " NEW:ED25519-V3" ; // Explicitly request ED25519-V3
537+ // Request v3-hidden service, redirect port.
538+ // Note that the 'virtual' port is always the default port to avoid decloaking nodes using other ports.
539+ conn.Command (strprintf (" ADD_ONION %s Port=%i,127.0.0.1:%i" , private_key, Params ().GetDefaultPort (), GetListenPort ()),
540+ std::bind (&TorController::add_onion_cb, this , std::placeholders::_1, std::placeholders::_2));
517541 }
518542}
519543
@@ -522,7 +546,7 @@ void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply&
522546 if (reply.code == 250 ) {
523547 LogPrint (BCLog::TOR, " tor: Authentication successful\n " );
524548
525- // Now that we know Tor is running setup the proxy for onion addresses
549+ // Now that we know Tor is running, set up the proxy for onion addresses
526550 // if -onion isn't set to something else.
527551 if (gArgs .GetArg (" -onion" , " " ) == " " ) {
528552 CService resolved (LookupNumeric (" 127.0.0.1" , 9050 ));
@@ -531,13 +555,22 @@ void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply&
531555 SetReachable (NET_ONION, true );
532556 }
533557
534- // Finally - now create the service
558+ // Finaly we create the v2-service
559+ tor_version = TOR_NET_V2;
560+ private_key = " " ;
561+ std::pair<bool , std::string> pkf = ReadBinaryFile (GetPrivateKeyFile ());
562+ if (pkf.first ) {
563+ LogPrint (BCLog::TOR, " tor: Reading cached private key from %s\n " , GetPrivateKeyFile ().string ());
564+ private_key = pkf.second ;
565+ }
566+ tor_version = TOR_NET_V2;
535567 if (private_key.empty ()) // No private key, generate one
536568 private_key = " NEW:RSA1024" ; // Explicitly request RSA1024 - see issue #9214
537569 // Request onion service, redirect port.
538570 // Note that the 'virtual' port is always the default port to avoid decloaking nodes using other ports.
539571 _conn.Command (strprintf (" ADD_ONION %s Port=%i,127.0.0.1:%i" , private_key, Params ().GetDefaultPort (), GetListenPort ()),
540572 std::bind (&TorController::add_onion_cb, this , std::placeholders::_1, std::placeholders::_2));
573+
541574 } else {
542575 LogPrintf (" tor: Authentication failed\n " );
543576 }
@@ -718,7 +751,8 @@ void TorController::Reconnect()
718751
719752fs::path TorController::GetPrivateKeyFile ()
720753{
721- return GetDataDir () / " onion_private_key" ;
754+ if (tor_version == TOR_NET_V2) return GetDataDir () / " onion_private_key" ;
755+ return GetDataDir () / " onion_private_key_v3" ;
722756}
723757
724758void TorController::reconnect_cb (evutil_socket_t fd, short what, void *arg)
@@ -734,7 +768,6 @@ static std::thread torControlThread;
734768static void TorControlThread ()
735769{
736770 TorController ctrl (gBase , gArgs .GetArg (" -torcontrol" , DEFAULT_TOR_CONTROL));
737-
738771 event_base_dispatch (gBase );
739772}
740773
0 commit comments