Skip to content

Commit cb8f28a

Browse files
committed
torcontrol: Create also a v3 ed25519-V3 service address.
If the Tor version supports this, from now on we also create also ED25519-V3 in torcontrol.
1 parent 4cde973 commit cb8f28a

File tree

1 file changed

+57
-24
lines changed

1 file changed

+57
-24
lines changed

src/torcontrol.cpp

Lines changed: 57 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ static const float RECONNECT_TIMEOUT_EXP = 1.5;
4747
*/
4848
static 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

474474
TorController::~TorController()
@@ -485,7 +485,7 @@ TorController::~TorController()
485485
void 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

719752
fs::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

724758
void TorController::reconnect_cb(evutil_socket_t fd, short what, void *arg)
@@ -734,7 +768,6 @@ static std::thread torControlThread;
734768
static void TorControlThread()
735769
{
736770
TorController ctrl(gBase, gArgs.GetArg("-torcontrol", DEFAULT_TOR_CONTROL));
737-
738771
event_base_dispatch(gBase);
739772
}
740773

0 commit comments

Comments
 (0)