Skip to content

Commit b2774fc

Browse files
committed
torcontrol: Query Tor for correct -onion configuration
1 parent 30308cc commit b2774fc

File tree

2 files changed

+71
-19
lines changed

2 files changed

+71
-19
lines changed

src/torcontrol.cpp

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ static const float RECONNECT_TIMEOUT_EXP = 1.5;
5353
* this is belt-and-suspenders sanity limit to prevent memory exhaustion.
5454
*/
5555
static const int MAX_LINE_LENGTH = 100000;
56+
static const uint16_t DEFAULT_TOR_SOCKS_PORT = 9050;
5657

5758
/****** Low-level TorControlConnection ********/
5859

@@ -338,6 +339,73 @@ TorController::~TorController()
338339
}
339340
}
340341

342+
void TorController::get_socks_cb(TorControlConnection& _conn, const TorControlReply& reply)
343+
{
344+
// NOTE: We can only get here if -onion is unset
345+
std::string socks_location;
346+
if (reply.code == 250) {
347+
for (const auto& line : reply.lines) {
348+
if (0 == line.compare(0, 20, "net/listeners/socks=")) {
349+
const std::string port_list_str = line.substr(20);
350+
std::vector<std::string> port_list;
351+
boost::split(port_list, port_list_str, boost::is_any_of(" "));
352+
for (auto& portstr : port_list) {
353+
if (portstr.empty()) continue;
354+
if ((portstr[0] == '"' || portstr[0] == '\'') && portstr.size() >= 2 && (*portstr.rbegin() == portstr[0])) {
355+
portstr = portstr.substr(1, portstr.size() - 2);
356+
if (portstr.empty()) continue;
357+
}
358+
socks_location = portstr;
359+
if (0 == portstr.compare(0, 10, "127.0.0.1:")) {
360+
// Prefer localhost - ignore other ports
361+
break;
362+
}
363+
}
364+
}
365+
}
366+
if (!socks_location.empty()) {
367+
LogPrint(BCLog::TOR, "tor: Get SOCKS port command yielded %s\n", socks_location);
368+
} else {
369+
LogPrintf("tor: Get SOCKS port command returned nothing\n");
370+
}
371+
} else if (reply.code == 510) { // 510 Unrecognized command
372+
LogPrintf("tor: Get SOCKS port command failed with unrecognized command (You probably should upgrade Tor)\n");
373+
} else {
374+
LogPrintf("tor: Get SOCKS port command failed; error code %d\n", reply.code);
375+
}
376+
377+
CService resolved;
378+
Assume(!resolved.IsValid());
379+
if (!socks_location.empty()) {
380+
resolved = LookupNumeric(socks_location, DEFAULT_TOR_SOCKS_PORT);
381+
}
382+
if (!resolved.IsValid()) {
383+
// Fallback to old behaviour
384+
resolved = LookupNumeric("127.0.0.1", DEFAULT_TOR_SOCKS_PORT);
385+
}
386+
387+
Assume(resolved.IsValid());
388+
LogPrint(BCLog::TOR, "tor: Configuring onion proxy for %s\n", resolved.ToStringIPPort());
389+
Proxy addrOnion = Proxy(resolved, true);
390+
SetProxy(NET_ONION, addrOnion);
391+
392+
const auto onlynets = gArgs.GetArgs("-onlynet");
393+
394+
const bool onion_allowed_by_onlynet{
395+
!gArgs.IsArgSet("-onlynet") ||
396+
std::any_of(onlynets.begin(), onlynets.end(), [](const auto& n) {
397+
return ParseNetwork(n) == NET_ONION;
398+
})};
399+
400+
if (onion_allowed_by_onlynet) {
401+
// If NET_ONION is reachable, then the below is a noop.
402+
//
403+
// If NET_ONION is not reachable, then none of -proxy or -onion was given.
404+
// Since we are here, then -torcontrol and -torpassword were given.
405+
SetReachable(NET_ONION, true);
406+
}
407+
}
408+
341409
void TorController::add_onion_cb(TorControlConnection& _conn, const TorControlReply& reply)
342410
{
343411
if (reply.code == 250) {
@@ -381,25 +449,7 @@ void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply&
381449
// Now that we know Tor is running setup the proxy for onion addresses
382450
// if -onion isn't set to something else.
383451
if (gArgs.GetArg("-onion", "") == "") {
384-
CService resolved(LookupNumeric("127.0.0.1", 9050));
385-
Proxy addrOnion = Proxy(resolved, true);
386-
SetProxy(NET_ONION, addrOnion);
387-
388-
const auto onlynets = gArgs.GetArgs("-onlynet");
389-
390-
const bool onion_allowed_by_onlynet{
391-
!gArgs.IsArgSet("-onlynet") ||
392-
std::any_of(onlynets.begin(), onlynets.end(), [](const auto& n) {
393-
return ParseNetwork(n) == NET_ONION;
394-
})};
395-
396-
if (onion_allowed_by_onlynet) {
397-
// If NET_ONION is reachable, then the below is a noop.
398-
//
399-
// If NET_ONION is not reachable, then none of -proxy or -onion was given.
400-
// Since we are here, then -torcontrol and -torpassword were given.
401-
SetReachable(NET_ONION, true);
402-
}
452+
_conn.Command("GETINFO net/listeners/socks", std::bind(&TorController::get_socks_cb, this, std::placeholders::_1, std::placeholders::_2));
403453
}
404454

405455
// Finally - now create the service

src/torcontrol.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ class TorController
140140
std::vector<uint8_t> clientNonce;
141141

142142
public:
143+
/** Callback for GETINFO net/listeners/socks result */
144+
void get_socks_cb(TorControlConnection& conn, const TorControlReply& reply);
143145
/** Callback for ADD_ONION result */
144146
void add_onion_cb(TorControlConnection& conn, const TorControlReply& reply);
145147
/** Callback for AUTHENTICATE result */

0 commit comments

Comments
 (0)