From b2774fc0bed53dfaf98206d353d42c474c5bbb1a Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sat, 16 Feb 2019 16:40:00 +0000 Subject: torcontrol: Query Tor for correct -onion configuration --- src/torcontrol.cpp | 88 ++++++++++++++++++++++++++++++++++++++++++------------ src/torcontrol.h | 2 ++ 2 files changed, 71 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 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 diff --git a/src/torcontrol.h b/src/torcontrol.h index 4ace3edcb1..81475aee74 100644 --- a/src/torcontrol.h +++ b/src/torcontrol.h @@ -140,6 +140,8 @@ private: std::vector clientNonce; public: + /** Callback for GETINFO net/listeners/socks result */ + void get_socks_cb(TorControlConnection& conn, const TorControlReply& reply); /** Callback for ADD_ONION result */ void add_onion_cb(TorControlConnection& conn, const TorControlReply& reply); /** Callback for AUTHENTICATE result */ -- cgit v1.2.3