aboutsummaryrefslogtreecommitdiff
path: root/src/torcontrol.cpp
diff options
context:
space:
mode:
authorLuke Dashjr <luke-jr+git@utopios.org>2019-02-16 16:40:00 +0000
committerLuke Dashjr <luke-jr+git@utopios.org>2022-03-15 01:33:52 +0000
commitb2774fc0bed53dfaf98206d353d42c474c5bbb1a (patch)
tree826f0b09630e36a064cbf07efa1b1e20af7e3483 /src/torcontrol.cpp
parent30308cc380a8176a5ec0e0bd2beed8b9c482ccf7 (diff)
downloadbitcoin-b2774fc0bed53dfaf98206d353d42c474c5bbb1a.tar.xz
torcontrol: Query Tor for correct -onion configuration
Diffstat (limited to 'src/torcontrol.cpp')
-rw-r--r--src/torcontrol.cpp88
1 files changed, 69 insertions, 19 deletions
diff --git a/src/torcontrol.cpp b/src/torcontrol.cpp
index 7ae384ceb3..a15094e5c8 100644
--- a/src/torcontrol.cpp
+++ b/src/torcontrol.cpp
@@ -53,6 +53,7 @@ static const float RECONNECT_TIMEOUT_EXP = 1.5;
* this is belt-and-suspenders sanity limit to prevent memory exhaustion.
*/
static const int MAX_LINE_LENGTH = 100000;
+static const uint16_t DEFAULT_TOR_SOCKS_PORT = 9050;
/****** Low-level TorControlConnection ********/
@@ -338,6 +339,73 @@ TorController::~TorController()
}
}
+void TorController::get_socks_cb(TorControlConnection& _conn, const TorControlReply& reply)
+{
+ // NOTE: We can only get here if -onion is unset
+ std::string socks_location;
+ if (reply.code == 250) {
+ for (const auto& line : reply.lines) {
+ if (0 == line.compare(0, 20, "net/listeners/socks=")) {
+ const std::string port_list_str = line.substr(20);
+ std::vector<std::string> port_list;
+ boost::split(port_list, port_list_str, boost::is_any_of(" "));
+ for (auto& portstr : port_list) {
+ if (portstr.empty()) continue;
+ if ((portstr[0] == '"' || portstr[0] == '\'') && portstr.size() >= 2 && (*portstr.rbegin() == portstr[0])) {
+ portstr = portstr.substr(1, portstr.size() - 2);
+ if (portstr.empty()) continue;
+ }
+ socks_location = portstr;
+ if (0 == portstr.compare(0, 10, "127.0.0.1:")) {
+ // Prefer localhost - ignore other ports
+ break;
+ }
+ }
+ }
+ }
+ if (!socks_location.empty()) {
+ LogPrint(BCLog::TOR, "tor: Get SOCKS port command yielded %s\n", socks_location);
+ } else {
+ LogPrintf("tor: Get SOCKS port command returned nothing\n");
+ }
+ } else if (reply.code == 510) { // 510 Unrecognized command
+ LogPrintf("tor: Get SOCKS port command failed with unrecognized command (You probably should upgrade Tor)\n");
+ } else {
+ LogPrintf("tor: Get SOCKS port command failed; error code %d\n", reply.code);
+ }
+
+ CService resolved;
+ Assume(!resolved.IsValid());
+ if (!socks_location.empty()) {
+ resolved = LookupNumeric(socks_location, DEFAULT_TOR_SOCKS_PORT);
+ }
+ if (!resolved.IsValid()) {
+ // Fallback to old behaviour
+ resolved = LookupNumeric("127.0.0.1", DEFAULT_TOR_SOCKS_PORT);
+ }
+
+ Assume(resolved.IsValid());
+ LogPrint(BCLog::TOR, "tor: Configuring onion proxy for %s\n", resolved.ToStringIPPort());
+ Proxy addrOnion = Proxy(resolved, true);
+ SetProxy(NET_ONION, addrOnion);
+
+ const auto onlynets = gArgs.GetArgs("-onlynet");
+
+ const bool onion_allowed_by_onlynet{
+ !gArgs.IsArgSet("-onlynet") ||
+ std::any_of(onlynets.begin(), onlynets.end(), [](const auto& n) {
+ return ParseNetwork(n) == NET_ONION;
+ })};
+
+ if (onion_allowed_by_onlynet) {
+ // If NET_ONION is reachable, then the below is a noop.
+ //
+ // If NET_ONION is not reachable, then none of -proxy or -onion was given.
+ // Since we are here, then -torcontrol and -torpassword were given.
+ SetReachable(NET_ONION, true);
+ }
+}
+
void TorController::add_onion_cb(TorControlConnection& _conn, const TorControlReply& reply)
{
if (reply.code == 250) {
@@ -381,25 +449,7 @@ void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply&
// Now that we know Tor is running setup the proxy for onion addresses
// if -onion isn't set to something else.
if (gArgs.GetArg("-onion", "") == "") {
- CService resolved(LookupNumeric("127.0.0.1", 9050));
- Proxy addrOnion = Proxy(resolved, true);
- SetProxy(NET_ONION, addrOnion);
-
- const auto onlynets = gArgs.GetArgs("-onlynet");
-
- const bool onion_allowed_by_onlynet{
- !gArgs.IsArgSet("-onlynet") ||
- std::any_of(onlynets.begin(), onlynets.end(), [](const auto& n) {
- return ParseNetwork(n) == NET_ONION;
- })};
-
- if (onion_allowed_by_onlynet) {
- // If NET_ONION is reachable, then the below is a noop.
- //
- // If NET_ONION is not reachable, then none of -proxy or -onion was given.
- // Since we are here, then -torcontrol and -torpassword were given.
- SetReachable(NET_ONION, true);
- }
+ _conn.Command("GETINFO net/listeners/socks", std::bind(&TorController::get_socks_cb, this, std::placeholders::_1, std::placeholders::_2));
}
// Finally - now create the service