merge bitcoin#15423: Query Tor for correct -onion configuration

This commit is contained in:
Kittywhiskers Van Gogh 2019-02-16 16:40:00 +00:00
parent 74dceb3c5c
commit 092a11e2d1
No known key found for this signature in database
GPG Key ID: 30CD0C065E5C4AAD
2 changed files with 71 additions and 19 deletions

View File

@ -48,6 +48,7 @@ static const float RECONNECT_TIMEOUT_EXP = 1.5;
* this is belt-and-suspenders sanity limit to prevent memory exhaustion. * this is belt-and-suspenders sanity limit to prevent memory exhaustion.
*/ */
static const int MAX_LINE_LENGTH = 100000; static const int MAX_LINE_LENGTH = 100000;
static const uint16_t DEFAULT_TOR_SOCKS_PORT = 9050;
/****** Low-level TorControlConnection ********/ /****** Low-level TorControlConnection ********/
@ -333,6 +334,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 = SplitString(port_list_str, ' ');
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.ToStringAddrPort());
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) void TorController::add_onion_cb(TorControlConnection& _conn, const TorControlReply& reply)
{ {
if (reply.code == 250) { if (reply.code == 250) {
@ -376,25 +444,7 @@ void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply&
// Now that we know Tor is running setup the proxy for onion addresses // Now that we know Tor is running setup the proxy for onion addresses
// if -onion isn't set to something else. // if -onion isn't set to something else.
if (gArgs.GetArg("-onion", "") == "") { if (gArgs.GetArg("-onion", "") == "") {
CService resolved(LookupNumeric("127.0.0.1", 9050)); _conn.Command("GETINFO net/listeners/socks", std::bind(&TorController::get_socks_cb, this, std::placeholders::_1, std::placeholders::_2));
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);
}
} }
// Finally - now create the service // Finally - now create the service

View File

@ -140,6 +140,8 @@ private:
std::vector<uint8_t> clientNonce; std::vector<uint8_t> clientNonce;
public: public:
/** Callback for GETINFO net/listeners/socks result */
void get_socks_cb(TorControlConnection& conn, const TorControlReply& reply);
/** Callback for ADD_ONION result */ /** Callback for ADD_ONION result */
void add_onion_cb(TorControlConnection& conn, const TorControlReply& reply); void add_onion_cb(TorControlConnection& conn, const TorControlReply& reply);
/** Callback for AUTHENTICATE result */ /** Callback for AUTHENTICATE result */