mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-25 10:43:19 -03:00
Merge #19991: net: Use alternative port for incoming Tor connections
96571b3d4c
doc: Update onion service target port numbers in tor.md (Hennadii Stepanov)bb145c9050
net: Extend -bind config option with optional network type (Hennadii Stepanov)92bd3c1da4
net, refactor: Move AddLocal call one level up (Hennadii Stepanov)57f17e57c8
net: Pass onion service target to Tor controller (Hennadii Stepanov)e3f07851f0
refactor: Rename TorController::target to m_tor_control_center (Hennadii Stepanov)fdd3ae4d26
net, refactor: Refactor CBaseChainParams::RPCPort function (Hennadii Stepanov)a5266d4546
net: Add alternative port for onion service (Hennadii Stepanov)b3273cf403
net: Use network byte order for in_addr.s_addr (Hennadii Stepanov) Pull request description: This PR adds ability to label incoming Tor connections as different from normal localhost connections. Closes #8973. Closes #16693. Default onion service target ports are: - 8334 on mainnnet - 18334 on testnet - 38334 on signet - 18445 on regtest To set the onion service target socket manually the extended `-bind` config option could be used: ``` $ src/bitcoind -help | grep -A 6 -e '-bind' -bind=<addr>[:<port>][=onion] Bind to given address and always listen on it (default: 0.0.0.0). Use [host]:port notation for IPv6. Append =onion to tag any incoming connections to that address and port as incoming Tor connections (default: 127.0.0.1:8334=onion, testnet: 127.0.0.1:18334=onion, signet: 127.0.0.1:38334=onion, regtest: 127.0.0.1:18445=onion) ``` Since [pr19991.02 update](https://github.com/bitcoin/bitcoin/pull/19991#issuecomment-698882284) this PR is an alternative to #19043. ACKs for top commit: Sjors: re-utACK96571b3d4c
vasild: ACK96571b3d4
laanwj: Re-ACK96571b3d4c
Tree-SHA512: cb0eade80f4b3395f405f775e1b89c086a1f09d5a4464df6cb4faf808d9c2245474e1720b2b538f203f6c1996507f69b09f5a6e35ea42633c10e22bd733d4438
This commit is contained in:
commit
df2129a234
8 changed files with 126 additions and 57 deletions
|
@ -45,11 +45,12 @@ config file): *Needed for Tor version 0.2.7.0 and older versions of Tor only. Fo
|
||||||
versions of Tor see [Section 3](#3-automatically-listen-on-tor).*
|
versions of Tor see [Section 3](#3-automatically-listen-on-tor).*
|
||||||
|
|
||||||
HiddenServiceDir /var/lib/tor/bitcoin-service/
|
HiddenServiceDir /var/lib/tor/bitcoin-service/
|
||||||
HiddenServicePort 8333 127.0.0.1:8333
|
HiddenServicePort 8333 127.0.0.1:8334
|
||||||
HiddenServicePort 18333 127.0.0.1:18333
|
HiddenServicePort 18333 127.0.0.1:18334
|
||||||
|
|
||||||
The directory can be different of course, but (both) port numbers should be equal to
|
The directory can be different of course, but virtual port numbers should be equal to
|
||||||
your bitcoind's P2P listen port (8333 by default).
|
your bitcoind's P2P listen port (8333 by default), and target addresses and ports
|
||||||
|
should be equal to binding address and port for inbound Tor connections (127.0.0.1:8334 by default).
|
||||||
|
|
||||||
-externalip=X You can tell bitcoin about its publicly reachable address using
|
-externalip=X You can tell bitcoin about its publicly reachable address using
|
||||||
this option, and this can be a .onion address. Given the above
|
this option, and this can be a .onion address. Given the above
|
||||||
|
|
|
@ -37,16 +37,20 @@ const CBaseChainParams& BaseParams()
|
||||||
return *globalChainBaseParams;
|
return *globalChainBaseParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Port numbers for incoming Tor connections (8334, 18334, 38334, 18445) have
|
||||||
|
* been chosen arbitrarily to keep ranges of used ports tight.
|
||||||
|
*/
|
||||||
std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain)
|
std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain)
|
||||||
{
|
{
|
||||||
if (chain == CBaseChainParams::MAIN) {
|
if (chain == CBaseChainParams::MAIN) {
|
||||||
return MakeUnique<CBaseChainParams>("", 8332);
|
return MakeUnique<CBaseChainParams>("", 8332, 8334);
|
||||||
} else if (chain == CBaseChainParams::TESTNET) {
|
} else if (chain == CBaseChainParams::TESTNET) {
|
||||||
return MakeUnique<CBaseChainParams>("testnet3", 18332);
|
return MakeUnique<CBaseChainParams>("testnet3", 18332, 18334);
|
||||||
} else if (chain == CBaseChainParams::SIGNET) {
|
} else if (chain == CBaseChainParams::SIGNET) {
|
||||||
return MakeUnique<CBaseChainParams>("signet", 38332);
|
return MakeUnique<CBaseChainParams>("signet", 38332, 38334);
|
||||||
} else if (chain == CBaseChainParams::REGTEST) {
|
} else if (chain == CBaseChainParams::REGTEST) {
|
||||||
return MakeUnique<CBaseChainParams>("regtest", 18443);
|
return MakeUnique<CBaseChainParams>("regtest", 18443, 18445);
|
||||||
}
|
}
|
||||||
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
|
throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,13 +26,16 @@ public:
|
||||||
///@}
|
///@}
|
||||||
|
|
||||||
const std::string& DataDir() const { return strDataDir; }
|
const std::string& DataDir() const { return strDataDir; }
|
||||||
int RPCPort() const { return nRPCPort; }
|
uint16_t RPCPort() const { return m_rpc_port; }
|
||||||
|
uint16_t OnionServiceTargetPort() const { return m_onion_service_target_port; }
|
||||||
|
|
||||||
CBaseChainParams() = delete;
|
CBaseChainParams() = delete;
|
||||||
CBaseChainParams(const std::string& data_dir, int rpc_port) : nRPCPort(rpc_port), strDataDir(data_dir) {}
|
CBaseChainParams(const std::string& data_dir, uint16_t rpc_port, uint16_t onion_service_target_port)
|
||||||
|
: m_rpc_port(rpc_port), m_onion_service_target_port(onion_service_target_port), strDataDir(data_dir) {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int nRPCPort;
|
const uint16_t m_rpc_port;
|
||||||
|
const uint16_t m_onion_service_target_port;
|
||||||
std::string strDataDir;
|
std::string strDataDir;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
41
src/init.cpp
41
src/init.cpp
|
@ -442,7 +442,7 @@ void SetupServerArgs(NodeContext& node)
|
||||||
argsman.AddArg("-addnode=<ip>", "Add a node to connect to and attempt to keep the connection open (see the `addnode` RPC command help for more info). This option can be specified multiple times to add multiple nodes.", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-addnode=<ip>", "Add a node to connect to and attempt to keep the connection open (see the `addnode` RPC command help for more info). This option can be specified multiple times to add multiple nodes.", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-asmap=<file>", strprintf("Specify asn mapping used for bucketing of the peers (default: %s). Relative paths will be prefixed by the net-specific datadir location.", DEFAULT_ASMAP_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-asmap=<file>", strprintf("Specify asn mapping used for bucketing of the peers (default: %s). Relative paths will be prefixed by the net-specific datadir location.", DEFAULT_ASMAP_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-bantime=<n>", strprintf("Default duration (in seconds) of manually configured bans (default: %u)", DEFAULT_MISBEHAVING_BANTIME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-bantime=<n>", strprintf("Default duration (in seconds) of manually configured bans (default: %u)", DEFAULT_MISBEHAVING_BANTIME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-bind=<addr>", "Bind to given address and always listen on it. Use [host]:port notation for IPv6", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-bind=<addr>[:<port>][=onion]", strprintf("Bind to given address and always listen on it (default: 0.0.0.0). Use [host]:port notation for IPv6. Append =onion to tag any incoming connections to that address and port as incoming Tor connections (default: 127.0.0.1:%u=onion, testnet: 127.0.0.1:%u=onion, signet: 127.0.0.1:%u=onion, regtest: 127.0.0.1:%u=onion)", defaultBaseParams->OnionServiceTargetPort(), testnetBaseParams->OnionServiceTargetPort(), signetBaseParams->OnionServiceTargetPort(), regtestBaseParams->OnionServiceTargetPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-connect=<ip>", "Connect only to the specified node; -noconnect disables automatic connections (the rules for this peer are the same as for -addnode). This option can be specified multiple times to connect to multiple nodes.", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-connect=<ip>", "Connect only to the specified node; -noconnect disables automatic connections (the rules for this peer are the same as for -addnode). This option can be specified multiple times to connect to multiple nodes.", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-discover", "Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-discover", "Discover own IP addresses (default: 1 when listening and no -externalip or -proxy)", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
argsman.AddArg("-dns", strprintf("Allow DNS lookups for -addnode, -seednode and -connect (default: %u)", DEFAULT_NAME_LOOKUP), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
argsman.AddArg("-dns", strprintf("Allow DNS lookups for -addnode, -seednode and -connect (default: %u)", DEFAULT_NAME_LOOKUP), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION);
|
||||||
|
@ -1918,9 +1918,6 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
|
||||||
}
|
}
|
||||||
LogPrintf("nBestHeight = %d\n", chain_active_height);
|
LogPrintf("nBestHeight = %d\n", chain_active_height);
|
||||||
|
|
||||||
if (args.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION))
|
|
||||||
StartTorControl();
|
|
||||||
|
|
||||||
Discover();
|
Discover();
|
||||||
|
|
||||||
// Map ports with UPnP
|
// Map ports with UPnP
|
||||||
|
@ -1947,13 +1944,39 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA
|
||||||
connOptions.nMaxOutboundLimit = nMaxOutboundLimit;
|
connOptions.nMaxOutboundLimit = nMaxOutboundLimit;
|
||||||
connOptions.m_peer_connect_timeout = peer_connect_timeout;
|
connOptions.m_peer_connect_timeout = peer_connect_timeout;
|
||||||
|
|
||||||
for (const std::string& strBind : args.GetArgs("-bind")) {
|
for (const std::string& bind_arg : args.GetArgs("-bind")) {
|
||||||
CService addrBind;
|
CService bind_addr;
|
||||||
if (!Lookup(strBind, addrBind, GetListenPort(), false)) {
|
const size_t index = bind_arg.rfind('=');
|
||||||
return InitError(ResolveErrMsg("bind", strBind));
|
if (index == std::string::npos) {
|
||||||
|
if (Lookup(bind_arg, bind_addr, GetListenPort(), false)) {
|
||||||
|
connOptions.vBinds.push_back(bind_addr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const std::string network_type = bind_arg.substr(index + 1);
|
||||||
|
if (network_type == "onion") {
|
||||||
|
const std::string truncated_bind_arg = bind_arg.substr(0, index);
|
||||||
|
if (Lookup(truncated_bind_arg, bind_addr, BaseParams().OnionServiceTargetPort(), false)) {
|
||||||
|
connOptions.onion_binds.push_back(bind_addr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
connOptions.vBinds.push_back(addrBind);
|
return InitError(ResolveErrMsg("bind", bind_arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (connOptions.onion_binds.empty()) {
|
||||||
|
connOptions.onion_binds.push_back(DefaultOnionServiceTarget());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) {
|
||||||
|
const auto bind_addr = connOptions.onion_binds.front();
|
||||||
|
if (connOptions.onion_binds.size() > 1) {
|
||||||
|
InitWarning(strprintf(_("More than one onion bind address is provided. Using %s for the automatically created Tor onion service."), bind_addr.ToStringIPPort()));
|
||||||
|
}
|
||||||
|
StartTorControl(bind_addr);
|
||||||
|
}
|
||||||
|
|
||||||
for (const std::string& strBind : args.GetArgs("-whitebind")) {
|
for (const std::string& strBind : args.GetArgs("-whitebind")) {
|
||||||
NetWhitebindPermissions whitebind;
|
NetWhitebindPermissions whitebind;
|
||||||
bilingual_str error;
|
bilingual_str error;
|
||||||
|
|
28
src/net.cpp
28
src/net.cpp
|
@ -83,6 +83,11 @@ enum BindFlags {
|
||||||
BF_NONE = 0,
|
BF_NONE = 0,
|
||||||
BF_EXPLICIT = (1U << 0),
|
BF_EXPLICIT = (1U << 0),
|
||||||
BF_REPORT_ERROR = (1U << 1),
|
BF_REPORT_ERROR = (1U << 1),
|
||||||
|
/**
|
||||||
|
* Do not call AddLocal() for our special addresses, e.g., for incoming
|
||||||
|
* Tor connections, to prevent gossiping them over the network.
|
||||||
|
*/
|
||||||
|
BF_DONT_ADVERTISE = (1U << 2),
|
||||||
};
|
};
|
||||||
|
|
||||||
// The set of sockets cannot be modified while waiting
|
// The set of sockets cannot be modified while waiting
|
||||||
|
@ -2241,10 +2246,6 @@ bool CConnman::BindListenPort(const CService& addrBind, bilingual_str& strError,
|
||||||
}
|
}
|
||||||
|
|
||||||
vhListenSocket.push_back(ListenSocket(hListenSocket, permissions));
|
vhListenSocket.push_back(ListenSocket(hListenSocket, permissions));
|
||||||
|
|
||||||
if (addrBind.IsRoutable() && fDiscover && (permissions & PF_NOBAN) == 0)
|
|
||||||
AddLocal(addrBind, LOCAL_BIND);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2338,10 +2339,18 @@ bool CConnman::Bind(const CService &addr, unsigned int flags, NetPermissionFlags
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (addr.IsRoutable() && fDiscover && !(flags & BF_DONT_ADVERTISE) && !(permissions & PF_NOBAN)) {
|
||||||
|
AddLocal(addr, LOCAL_BIND);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CConnman::InitBinds(const std::vector<CService>& binds, const std::vector<NetWhitebindPermissions>& whiteBinds)
|
bool CConnman::InitBinds(
|
||||||
|
const std::vector<CService>& binds,
|
||||||
|
const std::vector<NetWhitebindPermissions>& whiteBinds,
|
||||||
|
const std::vector<CService>& onion_binds)
|
||||||
{
|
{
|
||||||
bool fBound = false;
|
bool fBound = false;
|
||||||
for (const auto& addrBind : binds) {
|
for (const auto& addrBind : binds) {
|
||||||
|
@ -2352,11 +2361,16 @@ bool CConnman::InitBinds(const std::vector<CService>& binds, const std::vector<N
|
||||||
}
|
}
|
||||||
if (binds.empty() && whiteBinds.empty()) {
|
if (binds.empty() && whiteBinds.empty()) {
|
||||||
struct in_addr inaddr_any;
|
struct in_addr inaddr_any;
|
||||||
inaddr_any.s_addr = INADDR_ANY;
|
inaddr_any.s_addr = htonl(INADDR_ANY);
|
||||||
struct in6_addr inaddr6_any = IN6ADDR_ANY_INIT;
|
struct in6_addr inaddr6_any = IN6ADDR_ANY_INIT;
|
||||||
fBound |= Bind(CService(inaddr6_any, GetListenPort()), BF_NONE, NetPermissionFlags::PF_NONE);
|
fBound |= Bind(CService(inaddr6_any, GetListenPort()), BF_NONE, NetPermissionFlags::PF_NONE);
|
||||||
fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE, NetPermissionFlags::PF_NONE);
|
fBound |= Bind(CService(inaddr_any, GetListenPort()), !fBound ? BF_REPORT_ERROR : BF_NONE, NetPermissionFlags::PF_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto& addr_bind : onion_binds) {
|
||||||
|
fBound |= Bind(addr_bind, BF_EXPLICIT | BF_DONT_ADVERTISE, NetPermissionFlags::PF_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
return fBound;
|
return fBound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2375,7 +2389,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions)
|
||||||
nMaxOutboundCycleStartTime = 0;
|
nMaxOutboundCycleStartTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fListen && !InitBinds(connOptions.vBinds, connOptions.vWhiteBinds)) {
|
if (fListen && !InitBinds(connOptions.vBinds, connOptions.vWhiteBinds, connOptions.onion_binds)) {
|
||||||
if (clientInterface) {
|
if (clientInterface) {
|
||||||
clientInterface->ThreadSafeMessageBox(
|
clientInterface->ThreadSafeMessageBox(
|
||||||
_("Failed to listen on any port. Use -listen=0 if you want this."),
|
_("Failed to listen on any port. Use -listen=0 if you want this."),
|
||||||
|
|
|
@ -220,6 +220,7 @@ public:
|
||||||
std::vector<NetWhitelistPermissions> vWhitelistedRange;
|
std::vector<NetWhitelistPermissions> vWhitelistedRange;
|
||||||
std::vector<NetWhitebindPermissions> vWhiteBinds;
|
std::vector<NetWhitebindPermissions> vWhiteBinds;
|
||||||
std::vector<CService> vBinds;
|
std::vector<CService> vBinds;
|
||||||
|
std::vector<CService> onion_binds;
|
||||||
bool m_use_addrman_outgoing = true;
|
bool m_use_addrman_outgoing = true;
|
||||||
std::vector<std::string> m_specified_outgoing;
|
std::vector<std::string> m_specified_outgoing;
|
||||||
std::vector<std::string> m_added_nodes;
|
std::vector<std::string> m_added_nodes;
|
||||||
|
@ -417,7 +418,11 @@ private:
|
||||||
|
|
||||||
bool BindListenPort(const CService& bindAddr, bilingual_str& strError, NetPermissionFlags permissions);
|
bool BindListenPort(const CService& bindAddr, bilingual_str& strError, NetPermissionFlags permissions);
|
||||||
bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions);
|
bool Bind(const CService& addr, unsigned int flags, NetPermissionFlags permissions);
|
||||||
bool InitBinds(const std::vector<CService>& binds, const std::vector<NetWhitebindPermissions>& whiteBinds);
|
bool InitBinds(
|
||||||
|
const std::vector<CService>& binds,
|
||||||
|
const std::vector<NetWhitebindPermissions>& whiteBinds,
|
||||||
|
const std::vector<CService>& onion_binds);
|
||||||
|
|
||||||
void ThreadOpenAddedConnections();
|
void ThreadOpenAddedConnections();
|
||||||
void AddAddrFetch(const std::string& strDest);
|
void AddAddrFetch(const std::string& strDest);
|
||||||
void ProcessAddrFetch();
|
void ProcessAddrFetch();
|
||||||
|
|
|
@ -3,13 +3,16 @@
|
||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
#include <chainparams.h>
|
|
||||||
#include <torcontrol.h>
|
#include <torcontrol.h>
|
||||||
#include <util/strencodings.h>
|
|
||||||
#include <netbase.h>
|
#include <chainparams.h>
|
||||||
#include <net.h>
|
#include <chainparamsbase.h>
|
||||||
#include <util/system.h>
|
|
||||||
#include <crypto/hmac_sha256.h>
|
#include <crypto/hmac_sha256.h>
|
||||||
|
#include <net.h>
|
||||||
|
#include <netaddress.h>
|
||||||
|
#include <netbase.h>
|
||||||
|
#include <util/strencodings.h>
|
||||||
|
#include <util/system.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
|
@ -81,12 +84,12 @@ public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Connect to a Tor control port.
|
* Connect to a Tor control port.
|
||||||
* target is address of the form host:port.
|
* tor_control_center is address of the form host:port.
|
||||||
* connected is the handler that is called when connection is successfully established.
|
* connected is the handler that is called when connection is successfully established.
|
||||||
* disconnected is a handler that is called when the connection is broken.
|
* disconnected is a handler that is called when the connection is broken.
|
||||||
* Return true on success.
|
* Return true on success.
|
||||||
*/
|
*/
|
||||||
bool Connect(const std::string &target, const ConnectionCB& connected, const ConnectionCB& disconnected);
|
bool Connect(const std::string& tor_control_center, const ConnectionCB& connected, const ConnectionCB& disconnected);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disconnect from Tor control port.
|
* Disconnect from Tor control port.
|
||||||
|
@ -193,16 +196,16 @@ void TorControlConnection::eventcb(struct bufferevent *bev, short what, void *ct
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TorControlConnection::Connect(const std::string &target, const ConnectionCB& _connected, const ConnectionCB& _disconnected)
|
bool TorControlConnection::Connect(const std::string& tor_control_center, const ConnectionCB& _connected, const ConnectionCB& _disconnected)
|
||||||
{
|
{
|
||||||
if (b_conn)
|
if (b_conn)
|
||||||
Disconnect();
|
Disconnect();
|
||||||
// Parse target address:port
|
// Parse tor_control_center address:port
|
||||||
struct sockaddr_storage connect_to_addr;
|
struct sockaddr_storage connect_to_addr;
|
||||||
int connect_to_addrlen = sizeof(connect_to_addr);
|
int connect_to_addrlen = sizeof(connect_to_addr);
|
||||||
if (evutil_parse_sockaddr_port(target.c_str(),
|
if (evutil_parse_sockaddr_port(tor_control_center.c_str(),
|
||||||
(struct sockaddr*)&connect_to_addr, &connect_to_addrlen)<0) {
|
(struct sockaddr*)&connect_to_addr, &connect_to_addrlen)<0) {
|
||||||
LogPrintf("tor: Error parsing socket address %s\n", target);
|
LogPrintf("tor: Error parsing socket address %s\n", tor_control_center);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,9 +218,9 @@ bool TorControlConnection::Connect(const std::string &target, const ConnectionCB
|
||||||
this->connected = _connected;
|
this->connected = _connected;
|
||||||
this->disconnected = _disconnected;
|
this->disconnected = _disconnected;
|
||||||
|
|
||||||
// Finally, connect to target
|
// Finally, connect to tor_control_center
|
||||||
if (bufferevent_socket_connect(b_conn, (struct sockaddr*)&connect_to_addr, connect_to_addrlen) < 0) {
|
if (bufferevent_socket_connect(b_conn, (struct sockaddr*)&connect_to_addr, connect_to_addrlen) < 0) {
|
||||||
LogPrintf("tor: Error connecting to address %s\n", target);
|
LogPrintf("tor: Error connecting to address %s\n", tor_control_center);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -410,7 +413,7 @@ static bool WriteBinaryFile(const fs::path &filename, const std::string &data)
|
||||||
class TorController
|
class TorController
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TorController(struct event_base* base, const std::string& target);
|
TorController(struct event_base* base, const std::string& tor_control_center, const CService& target);
|
||||||
~TorController();
|
~TorController();
|
||||||
|
|
||||||
/** Get name of file to store private key in */
|
/** Get name of file to store private key in */
|
||||||
|
@ -420,7 +423,7 @@ public:
|
||||||
void Reconnect();
|
void Reconnect();
|
||||||
private:
|
private:
|
||||||
struct event_base* base;
|
struct event_base* base;
|
||||||
std::string target;
|
const std::string m_tor_control_center;
|
||||||
TorControlConnection conn;
|
TorControlConnection conn;
|
||||||
std::string private_key;
|
std::string private_key;
|
||||||
std::string service_id;
|
std::string service_id;
|
||||||
|
@ -428,6 +431,7 @@ private:
|
||||||
struct event *reconnect_ev;
|
struct event *reconnect_ev;
|
||||||
float reconnect_timeout;
|
float reconnect_timeout;
|
||||||
CService service;
|
CService service;
|
||||||
|
const CService m_target;
|
||||||
/** Cookie for SAFECOOKIE auth */
|
/** Cookie for SAFECOOKIE auth */
|
||||||
std::vector<uint8_t> cookie;
|
std::vector<uint8_t> cookie;
|
||||||
/** ClientNonce for SAFECOOKIE auth */
|
/** ClientNonce for SAFECOOKIE auth */
|
||||||
|
@ -450,18 +454,19 @@ private:
|
||||||
static void reconnect_cb(evutil_socket_t fd, short what, void *arg);
|
static void reconnect_cb(evutil_socket_t fd, short what, void *arg);
|
||||||
};
|
};
|
||||||
|
|
||||||
TorController::TorController(struct event_base* _base, const std::string& _target):
|
TorController::TorController(struct event_base* _base, const std::string& tor_control_center, const CService& target):
|
||||||
base(_base),
|
base(_base),
|
||||||
target(_target), conn(base), reconnect(true), reconnect_ev(0),
|
m_tor_control_center(tor_control_center), conn(base), reconnect(true), reconnect_ev(0),
|
||||||
reconnect_timeout(RECONNECT_TIMEOUT_START)
|
reconnect_timeout(RECONNECT_TIMEOUT_START),
|
||||||
|
m_target(target)
|
||||||
{
|
{
|
||||||
reconnect_ev = event_new(base, -1, 0, reconnect_cb, this);
|
reconnect_ev = event_new(base, -1, 0, reconnect_cb, this);
|
||||||
if (!reconnect_ev)
|
if (!reconnect_ev)
|
||||||
LogPrintf("tor: Failed to create event for reconnection: out of memory?\n");
|
LogPrintf("tor: Failed to create event for reconnection: out of memory?\n");
|
||||||
// Start connection attempts immediately
|
// Start connection attempts immediately
|
||||||
if (!conn.Connect(_target, std::bind(&TorController::connected_cb, this, std::placeholders::_1),
|
if (!conn.Connect(m_tor_control_center, std::bind(&TorController::connected_cb, this, std::placeholders::_1),
|
||||||
std::bind(&TorController::disconnected_cb, this, std::placeholders::_1) )) {
|
std::bind(&TorController::disconnected_cb, this, std::placeholders::_1) )) {
|
||||||
LogPrintf("tor: Initiating connection to Tor control port %s failed\n", _target);
|
LogPrintf("tor: Initiating connection to Tor control port %s failed\n", m_tor_control_center);
|
||||||
}
|
}
|
||||||
// Read service private key if cached
|
// Read service private key if cached
|
||||||
std::pair<bool,std::string> pkf = ReadBinaryFile(GetPrivateKeyFile());
|
std::pair<bool,std::string> pkf = ReadBinaryFile(GetPrivateKeyFile());
|
||||||
|
@ -536,7 +541,7 @@ void TorController::auth_cb(TorControlConnection& _conn, const TorControlReply&
|
||||||
private_key = "NEW:RSA1024"; // Explicitly request RSA1024 - see issue #9214
|
private_key = "NEW:RSA1024"; // Explicitly request RSA1024 - see issue #9214
|
||||||
// Request onion service, redirect port.
|
// Request onion service, redirect port.
|
||||||
// Note that the 'virtual' port is always the default port to avoid decloaking nodes using other ports.
|
// Note that the 'virtual' port is always the default port to avoid decloaking nodes using other ports.
|
||||||
_conn.Command(strprintf("ADD_ONION %s Port=%i,127.0.0.1:%i", private_key, Params().GetDefaultPort(), GetListenPort()),
|
_conn.Command(strprintf("ADD_ONION %s Port=%i,%s", private_key, Params().GetDefaultPort(), m_target.ToStringIPPort()),
|
||||||
std::bind(&TorController::add_onion_cb, this, std::placeholders::_1, std::placeholders::_2));
|
std::bind(&TorController::add_onion_cb, this, std::placeholders::_1, std::placeholders::_2));
|
||||||
} else {
|
} else {
|
||||||
LogPrintf("tor: Authentication failed\n");
|
LogPrintf("tor: Authentication failed\n");
|
||||||
|
@ -696,7 +701,7 @@ void TorController::disconnected_cb(TorControlConnection& _conn)
|
||||||
if (!reconnect)
|
if (!reconnect)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LogPrint(BCLog::TOR, "tor: Not connected to Tor control port %s, trying to reconnect\n", target);
|
LogPrint(BCLog::TOR, "tor: Not connected to Tor control port %s, trying to reconnect\n", m_tor_control_center);
|
||||||
|
|
||||||
// Single-shot timer for reconnect. Use exponential backoff.
|
// Single-shot timer for reconnect. Use exponential backoff.
|
||||||
struct timeval time = MillisToTimeval(int64_t(reconnect_timeout * 1000.0));
|
struct timeval time = MillisToTimeval(int64_t(reconnect_timeout * 1000.0));
|
||||||
|
@ -710,9 +715,9 @@ void TorController::Reconnect()
|
||||||
/* Try to reconnect and reestablish if we get booted - for example, Tor
|
/* Try to reconnect and reestablish if we get booted - for example, Tor
|
||||||
* may be restarting.
|
* may be restarting.
|
||||||
*/
|
*/
|
||||||
if (!conn.Connect(target, std::bind(&TorController::connected_cb, this, std::placeholders::_1),
|
if (!conn.Connect(m_tor_control_center, std::bind(&TorController::connected_cb, this, std::placeholders::_1),
|
||||||
std::bind(&TorController::disconnected_cb, this, std::placeholders::_1) )) {
|
std::bind(&TorController::disconnected_cb, this, std::placeholders::_1) )) {
|
||||||
LogPrintf("tor: Re-initiating connection to Tor control port %s failed\n", target);
|
LogPrintf("tor: Re-initiating connection to Tor control port %s failed\n", m_tor_control_center);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -731,14 +736,14 @@ void TorController::reconnect_cb(evutil_socket_t fd, short what, void *arg)
|
||||||
static struct event_base *gBase;
|
static struct event_base *gBase;
|
||||||
static std::thread torControlThread;
|
static std::thread torControlThread;
|
||||||
|
|
||||||
static void TorControlThread()
|
static void TorControlThread(CService onion_service_target)
|
||||||
{
|
{
|
||||||
TorController ctrl(gBase, gArgs.GetArg("-torcontrol", DEFAULT_TOR_CONTROL));
|
TorController ctrl(gBase, gArgs.GetArg("-torcontrol", DEFAULT_TOR_CONTROL), onion_service_target);
|
||||||
|
|
||||||
event_base_dispatch(gBase);
|
event_base_dispatch(gBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartTorControl()
|
void StartTorControl(CService onion_service_target)
|
||||||
{
|
{
|
||||||
assert(!gBase);
|
assert(!gBase);
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
@ -752,7 +757,9 @@ void StartTorControl()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
torControlThread = std::thread(std::bind(&TraceThread<void (*)()>, "torcontrol", &TorControlThread));
|
torControlThread = std::thread(&TraceThread<std::function<void()>>, "torcontrol", [onion_service_target] {
|
||||||
|
TorControlThread(onion_service_target);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterruptTorControl()
|
void InterruptTorControl()
|
||||||
|
@ -773,3 +780,10 @@ void StopTorControl()
|
||||||
gBase = nullptr;
|
gBase = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CService DefaultOnionServiceTarget()
|
||||||
|
{
|
||||||
|
struct in_addr onion_service_target;
|
||||||
|
onion_service_target.s_addr = htonl(INADDR_LOOPBACK);
|
||||||
|
return {onion_service_target, BaseParams().OnionServiceTargetPort()};
|
||||||
|
}
|
||||||
|
|
|
@ -8,12 +8,17 @@
|
||||||
#ifndef BITCOIN_TORCONTROL_H
|
#ifndef BITCOIN_TORCONTROL_H
|
||||||
#define BITCOIN_TORCONTROL_H
|
#define BITCOIN_TORCONTROL_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class CService;
|
||||||
|
|
||||||
extern const std::string DEFAULT_TOR_CONTROL;
|
extern const std::string DEFAULT_TOR_CONTROL;
|
||||||
static const bool DEFAULT_LISTEN_ONION = true;
|
static const bool DEFAULT_LISTEN_ONION = true;
|
||||||
|
|
||||||
void StartTorControl();
|
void StartTorControl(CService onion_service_target);
|
||||||
void InterruptTorControl();
|
void InterruptTorControl();
|
||||||
void StopTorControl();
|
void StopTorControl();
|
||||||
|
|
||||||
|
CService DefaultOnionServiceTarget();
|
||||||
|
|
||||||
#endif /* BITCOIN_TORCONTROL_H */
|
#endif /* BITCOIN_TORCONTROL_H */
|
||||||
|
|
Loading…
Add table
Reference in a new issue