diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -643,11 +643,18 @@ "configured bans (default: %u)", DEFAULT_MISBEHAVING_BANTIME), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-bind=", - "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=[:][=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, regtest: 127.0.0.1:%u=onion)", + defaultBaseParams->OnionServiceTargetPort(), + testnetBaseParams->OnionServiceTargetPort(), + regtestBaseParams->OnionServiceTargetPort()), + ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, + OptionsCategory::CONNECTION); argsman.AddArg( "-connect=", "Connect only to the specified node(s); -connect=0 disables automatic " @@ -2977,10 +2984,6 @@ } LogPrintf("nBestHeight = %d\n", chain_active_height); - if (args.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) { - StartTorControl(DefaultOnionServiceTarget()); - } - Discover(); // Map ports with UPnP @@ -3012,12 +3015,42 @@ connOptions.nMaxOutboundLimit = nMaxOutboundLimit; connOptions.m_peer_connect_timeout = peer_connect_timeout; - for (const std::string &strBind : args.GetArgs("-bind")) { - CService addrBind; - if (!Lookup(strBind, addrBind, GetListenPort(), false)) { - return InitError(ResolveErrMsg("bind", strBind)); + for (const std::string &bind_arg : args.GetArgs("-bind")) { + CService bind_addr; + const size_t index = bind_arg.rfind('='); + 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; + } + } + } + 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())); } - connOptions.vBinds.push_back(addrBind); + StartTorControl(bind_addr); } for (const std::string &strBind : args.GetArgs("-whitebind")) { diff --git a/src/net.h b/src/net.h --- a/src/net.h +++ b/src/net.h @@ -245,6 +245,7 @@ std::vector vWhitelistedRange; std::vector vWhiteBinds; std::vector vBinds; + std::vector onion_binds; bool m_use_addrman_outgoing = true; std::vector m_specified_outgoing; std::vector m_added_nodes; @@ -465,7 +466,9 @@ bool Bind(const CService &addr, unsigned int flags, NetPermissionFlags permissions); bool InitBinds(const std::vector &binds, - const std::vector &whiteBinds); + const std::vector &whiteBinds, + const std::vector &onion_binds); + void ThreadOpenAddedConnections(); void AddAddrFetch(const std::string &strDest); void ProcessAddrFetch(); diff --git a/src/net.cpp b/src/net.cpp --- a/src/net.cpp +++ b/src/net.cpp @@ -95,6 +95,11 @@ BF_NONE = 0, BF_EXPLICIT = (1U << 0), 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 @@ -2610,16 +2615,17 @@ return false; } - if (addr.IsRoutable() && fDiscover && (permissions & PF_NOBAN) == 0) { + if (addr.IsRoutable() && fDiscover && !(flags & BF_DONT_ADVERTISE) && + !(permissions & PF_NOBAN)) { AddLocal(addr, LOCAL_BIND); } return true; } -bool CConnman::InitBinds( - const std::vector &binds, - const std::vector &whiteBinds) { +bool CConnman::InitBinds(const std::vector &binds, + const std::vector &whiteBinds, + const std::vector &onion_binds) { bool fBound = false; for (const auto &addrBind : binds) { fBound |= Bind(addrBind, (BF_EXPLICIT | BF_REPORT_ERROR), @@ -2639,6 +2645,12 @@ !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; } @@ -2656,7 +2668,8 @@ nMaxOutboundCycleStartTime = 0; } - if (fListen && !InitBinds(connOptions.vBinds, connOptions.vWhiteBinds)) { + if (fListen && !InitBinds(connOptions.vBinds, connOptions.vWhiteBinds, + connOptions.onion_binds)) { if (clientInterface) { clientInterface->ThreadSafeMessageBox( _("Failed to listen on any port. Use -listen=0 if you want "