Added SOCKS5 proxy type command line parameter

- Auto-detect by default, based on the port number
- Don't run TOR-specific code if it's not the TOR proxy
This commit is contained in:
SChernykh
2026-02-10 21:15:30 +01:00
parent cf1c88b907
commit 6d6c12c1e8
13 changed files with 99 additions and 21 deletions
+1
View File
@@ -29,6 +29,7 @@
--no-autodiff Disable automatic difficulty adjustment for miners connected to stratum (WARNING: incompatible with Nicehash and MRR) --no-autodiff Disable automatic difficulty adjustment for miners connected to stratum (WARNING: incompatible with Nicehash and MRR)
--rpc-login Specify username[:password] required for Monero RPC server --rpc-login Specify username[:password] required for Monero RPC server
--socks5 Specify IP:port of a SOCKS5 proxy to use for outgoing connections --socks5 Specify IP:port of a SOCKS5 proxy to use for outgoing connections
--socks5-proxy-type The type of SOCKS5 proxy. Can be one of the following values: auto, plain, tor. Default is auto (auto-detect by the port number)
--no-dns Disable DNS queries, use only IP addresses to connect to peers (seed node DNS will be unavailable too) --no-dns Disable DNS queries, use only IP addresses to connect to peers (seed node DNS will be unavailable too)
--p2p-external-port Port number that your router uses for mapping to your local p2p port. Use it if you are behind a NAT and still want to accept incoming connections --p2p-external-port Port number that your router uses for mapping to your local p2p port. Use it if you are behind a NAT and still want to accept incoming connections
--no-upnp Disable UPnP port forwarding --no-upnp Disable UPnP port forwarding
+1 -1
View File
@@ -35,7 +35,7 @@ static constexpr int DEFAULT_BACKLOG = 1;
namespace p2pool { namespace p2pool {
ConsoleCommands::ConsoleCommands(p2pool* pool) ConsoleCommands::ConsoleCommands(p2pool* pool)
: TCPServer(DEFAULT_BACKLOG, ConsoleClient::allocate, std::string()) : TCPServer(DEFAULT_BACKLOG, ConsoleClient::allocate, std::string(), Params::ProxyType::INVALID)
, m_pool(pool) , m_pool(pool)
, m_tty{} , m_tty{}
, m_stdin_pipe{} , m_stdin_pipe{}
+1
View File
@@ -89,6 +89,7 @@ void p2pool_usage()
"--no-autodiff Disable automatic difficulty adjustment for miners connected to stratum (WARNING: incompatible with Nicehash and MRR)\n" "--no-autodiff Disable automatic difficulty adjustment for miners connected to stratum (WARNING: incompatible with Nicehash and MRR)\n"
"--rpc-login Specify username[:password] required for Monero RPC server\n" "--rpc-login Specify username[:password] required for Monero RPC server\n"
"--socks5 Specify IP:port of a SOCKS5 proxy to use for outgoing connections\n" "--socks5 Specify IP:port of a SOCKS5 proxy to use for outgoing connections\n"
"--socks5-proxy-type The type of SOCKS5 proxy. Can be one of the following values: auto, plain, tor. Default is auto (auto-detect by the port number)\n"
"--no-dns Disable DNS queries, use only IP addresses to connect to peers (seed node DNS will be unavailable too)\n" "--no-dns Disable DNS queries, use only IP addresses to connect to peers (seed node DNS will be unavailable too)\n"
"--p2p-external-port Port number that your router uses for mapping to your local p2p port. Use it if you are behind a NAT and still want to accept incoming connections\n" "--p2p-external-port Port number that your router uses for mapping to your local p2p port. Use it if you are behind a NAT and still want to accept incoming connections\n"
#ifdef WITH_UPNP #ifdef WITH_UPNP
+3 -3
View File
@@ -42,7 +42,7 @@ MergeMiningClientTari::MergeMiningClientTari(p2pool* pool, std::string host, con
, m_auxWallet(wallet) , m_auxWallet(wallet)
, m_pool(pool) , m_pool(pool)
, m_tariJobParams{} , m_tariJobParams{}
, m_server(new TariServer(pool->params().m_socks5Proxy)) , m_server(new TariServer(pool->params().m_socks5Proxy, pool->params().m_socks5ProxyType))
, m_hostStr(host) , m_hostStr(host)
, m_workerStop(0) , m_workerStop(0)
, m_pushBlockStop(0) , m_pushBlockStop(0)
@@ -863,8 +863,8 @@ void MergeMiningClientTari::run()
// TariServer and TariClient are simply a proxy from a localhost TCP port to the external Tari node // TariServer and TariClient are simply a proxy from a localhost TCP port to the external Tari node
// This is needed for SOCKS5 proxy support (gRPC library doesn't support it natively) // This is needed for SOCKS5 proxy support (gRPC library doesn't support it natively)
MergeMiningClientTari::TariServer::TariServer(const std::string& socks5Proxy) MergeMiningClientTari::TariServer::TariServer(const std::string& socks5Proxy, Params::ProxyType socks5ProxyType)
: TCPServer(1, MergeMiningClientTari::TariClient::allocate, socks5Proxy) : TCPServer(1, MergeMiningClientTari::TariClient::allocate, socks5Proxy, socks5ProxyType)
, m_TariNodeIsV6(false) , m_TariNodeIsV6(false)
, m_TariNodeHost() , m_TariNodeHost()
, m_TariNodePort(0) , m_TariNodePort(0)
+1 -1
View File
@@ -83,7 +83,7 @@ private:
struct TariServer : public TCPServer struct TariServer : public TCPServer
{ {
explicit TariServer(const std::string& socks5Proxy); TariServer(const std::string& socks5Proxy, Params::ProxyType socks5ProxyType);
~TariServer() {} ~TariServer() {}
[[nodiscard]] bool start(); [[nodiscard]] bool start();
+23 -8
View File
@@ -64,7 +64,7 @@ static constexpr hash seed_onion_nodes[] = {
}; };
P2PServer::P2PServer(p2pool* pool) P2PServer::P2PServer(p2pool* pool)
: TCPServer(DEFAULT_BACKLOG, P2PClient::allocate, pool->params().m_socks5Proxy) : TCPServer(DEFAULT_BACKLOG, P2PClient::allocate, pool->params().m_socks5Proxy, pool->params().m_socks5ProxyType)
, m_pool(pool) , m_pool(pool)
, m_cache(pool->params().m_blockCache ? new BlockCache(pool->params()) : nullptr) , m_cache(pool->params().m_blockCache ? new BlockCache(pool->params()) : nullptr)
, m_cacheLoaded(false) , m_cacheLoaded(false)
@@ -426,14 +426,16 @@ void P2PServer::update_peer_connections()
uint32_t num_outgoing = m_numConnections - m_numIncomingConnections; uint32_t num_outgoing = m_numConnections - m_numIncomingConnections;
// Try to have at least N/2 outgoing onion connections // Try to have at least N/2 (or N if clearnet P2P is disabled) outgoing onion connections
if (!m_socks5Proxy.empty()) { if (!m_socks5Proxy.empty() && (m_socks5ProxyType == Params::ProxyType::TOR)) {
std::vector<hash> pubkeys = m_pool->side_chain().seen_onion_pubkeys(); std::vector<hash> pubkeys = m_pool->side_chain().seen_onion_pubkeys();
// Add seed nodes // Add seed nodes
pubkeys.insert(pubkeys.end(), seed_onion_nodes, seed_onion_nodes + array_size(seed_onion_nodes)); pubkeys.insert(pubkeys.end(), seed_onion_nodes, seed_onion_nodes + array_size(seed_onion_nodes));
for (uint32_t i = m_numOnionConnections, n = N / 2; (i < n) && !pubkeys.empty();) { const uint32_t n = m_pool->params().m_noClearnetP2P ? N : (N / 2);
for (uint32_t i = m_numOnionConnections; (i < n) && !pubkeys.empty();) {
const uint64_t k = get_random64() % pubkeys.size(); const uint64_t k = get_random64() % pubkeys.size();
const std::string addr = to_onion_v3(pubkeys[k]); const std::string addr = to_onion_v3(pubkeys[k]);
@@ -727,8 +729,21 @@ void P2PServer::load_peer_list()
} }
// Finally load peers from p2pool_peers.txt and p2pool_onion_peers.txt // Finally load peers from p2pool_peers.txt and p2pool_onion_peers.txt
for (size_t i = 0, n = (m_socks5Proxy.empty() ? 1 : 2); i < n; ++i) { std::vector<std::string> paths;
const std::string path = m_pool->params().m_dataDir + (i ? saved_onion_peer_list_file_name : saved_peer_list_file_name); paths.resize(Params::ProxyType::MAX);
paths[Params::ProxyType::PLAIN] = saved_peer_list_file_name;
if (!m_socks5Proxy.empty() && (m_socks5ProxyType == Params::ProxyType::TOR)) {
paths[Params::ProxyType::TOR] = saved_onion_peer_list_file_name;
}
for (int i = Params::ProxyType::PLAIN; i < Params::ProxyType::MAX; ++i) {
const std::string& path = paths[i];
if (path.empty()) {
continue;
}
std::ifstream f(path); std::ifstream f(path);
@@ -740,7 +755,7 @@ void P2PServer::load_peer_list()
std::getline(f, address); std::getline(f, address);
if (!address.empty()) { if (!address.empty()) {
if (i > 0) { if (i == Params::ProxyType::TOR) {
const hash h = from_onion_v3(address); const hash h = from_onion_v3(address);
if (!h.empty()) { if (!h.empty()) {
pubkeys.emplace_back(h); pubkeys.emplace_back(h);
@@ -756,7 +771,7 @@ void P2PServer::load_peer_list()
} }
f.close(); f.close();
if (i > 0) { if (i == Params::ProxyType::TOR) {
s.add_onion_pubkeys(pubkeys); s.add_onion_pubkeys(pubkeys);
} }
} }
+40
View File
@@ -238,6 +238,18 @@ Params::Params(const std::vector<std::vector<std::string>>& args)
ok = true; ok = true;
} }
if ((arg[0] == "socks5-proxy-type") && has1(arg)) {
const std::string s = tolower(arg[1]);
m_socks5ProxyType = ProxyType::INVALID;
if (s == "auto") m_socks5ProxyType = ProxyType::AUTO;
if (s == "plain") m_socks5ProxyType = ProxyType::PLAIN;
if (s == "tor") m_socks5ProxyType = ProxyType::TOR;
ok = m_socks5ProxyType != ProxyType::INVALID;
}
if (arg[0] == "no-dns") { if (arg[0] == "no-dns") {
m_dns = false; m_dns = false;
disable_resolve_host = true; disable_resolve_host = true;
@@ -426,6 +438,29 @@ Params::Params(const std::vector<std::vector<std::string>>& args)
else { else {
fixup_path(m_dataDir); fixup_path(m_dataDir);
} }
// Detect the proxy type
if (!m_socks5Proxy.empty() && (m_socks5ProxyType == ProxyType::AUTO)) {
m_socks5ProxyType = ProxyType::INVALID;
const size_t k = m_socks5Proxy.find_last_of(':');
if ((k != std::string::npos) && (k < m_socks5Proxy.length() - 1)) {
const uint32_t port = std::stoul(m_socks5Proxy.substr(k + 1), nullptr, 10);
if ((port > 0) && (port < 65536)) {
switch (port) {
case 9050:
m_socks5ProxyType = ProxyType::TOR;
break;
default:
m_socks5ProxyType = ProxyType::PLAIN;
break;
}
}
}
}
} }
bool Params::valid() const bool Params::valid() const
@@ -478,6 +513,11 @@ bool Params::valid() const
return false; return false;
} }
if (m_socks5ProxyType == ProxyType::INVALID) {
LOGERR(1, "Invalid SOCKS5 proxy type. Check the --socks5 parameter.");
return false;
}
return true; return true;
} }
+10
View File
@@ -108,7 +108,17 @@ struct Params
bool m_mini = false; bool m_mini = false;
bool m_nano = false; bool m_nano = false;
bool m_autoDiff = true; bool m_autoDiff = true;
std::string m_socks5Proxy; std::string m_socks5Proxy;
enum ProxyType {
INVALID = -1,
AUTO = 0,
PLAIN = 1,
TOR = 2,
MAX = 3,
} m_socks5ProxyType = ProxyType::AUTO;
bool m_dns = true; bool m_dns = true;
int32_t m_p2pExternalPort = 0; int32_t m_p2pExternalPort = 0;
#ifdef WITH_UPNP #ifdef WITH_UPNP
+1 -1
View File
@@ -44,7 +44,7 @@ static constexpr int32_t BAN_THRESHOLD_POINTS = -15;
namespace p2pool { namespace p2pool {
StratumServer::StratumServer(p2pool* pool) StratumServer::StratumServer(p2pool* pool)
: TCPServer(DEFAULT_BACKLOG, StratumClient::allocate, std::string()) : TCPServer(DEFAULT_BACKLOG, StratumClient::allocate, std::string(), Params::ProxyType::INVALID)
, m_pool(pool) , m_pool(pool)
, m_autoDiff(pool->params().m_autoDiff) , m_autoDiff(pool->params().m_autoDiff)
, m_enableFullValidation(pool->params().m_enableFullValidation) , m_enableFullValidation(pool->params().m_enableFullValidation)
+2 -1
View File
@@ -23,7 +23,7 @@ static thread_local const char* log_category_prefix = "TCPServer ";
namespace p2pool { namespace p2pool {
TCPServer::TCPServer(int default_backlog, allocate_client_callback allocate_new_client, const std::string& socks5Proxy) TCPServer::TCPServer(int default_backlog, allocate_client_callback allocate_new_client, const std::string& socks5Proxy, Params::ProxyType socks5ProxyType)
: m_allocateNewClient(allocate_new_client) : m_allocateNewClient(allocate_new_client)
, m_defaultBacklog(default_backlog) , m_defaultBacklog(default_backlog)
, m_loopThread{} , m_loopThread{}
@@ -32,6 +32,7 @@ TCPServer::TCPServer(int default_backlog, allocate_client_callback allocate_new_
, m_portMapping(0) , m_portMapping(0)
#endif #endif
, m_socks5Proxy(socks5Proxy) , m_socks5Proxy(socks5Proxy)
, m_socks5ProxyType(socks5ProxyType)
, m_socks5ProxyV6(false) , m_socks5ProxyV6(false)
, m_socks5ProxyIP{} , m_socks5ProxyIP{}
, m_socks5ProxyPort(-1) , m_socks5ProxyPort(-1)
+3 -1
View File
@@ -18,6 +18,7 @@
#pragma once #pragma once
#include "uv_util.h" #include "uv_util.h"
#include "params.h"
#ifdef WITH_TLS #ifdef WITH_TLS
#include "tls.h" #include "tls.h"
@@ -33,7 +34,7 @@ public:
struct Client; struct Client;
typedef Client* (*allocate_client_callback)(); typedef Client* (*allocate_client_callback)();
TCPServer(int default_backlog, allocate_client_callback allocate_new_client, const std::string& socks5Proxy); TCPServer(int default_backlog, allocate_client_callback allocate_new_client, const std::string& socks5Proxy, Params::ProxyType socks5ProxyType);
virtual ~TCPServer(); virtual ~TCPServer();
[[nodiscard]] bool connect_to_peer(bool is_v6, const char* ip, int port); [[nodiscard]] bool connect_to_peer(bool is_v6, const char* ip, int port);
@@ -191,6 +192,7 @@ protected:
#endif #endif
std::string m_socks5Proxy; std::string m_socks5Proxy;
Params::ProxyType m_socks5ProxyType;
bool m_socks5ProxyV6; bool m_socks5ProxyV6;
raw_ip m_socks5ProxyIP; raw_ip m_socks5ProxyIP;
int m_socks5ProxyPort; int m_socks5ProxyPort;
+1 -5
View File
@@ -1014,12 +1014,8 @@ hash from_onion_v3(const std::string& address)
return {}; return {};
} }
// Convert address to lowercase
std::string s = address;
std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
// Checksum validation // Checksum validation
if (to_onion_v3(result) != s) { if (to_onion_v3(result) != tolower(address)) {
LOGWARN(3, "Invalid onion address \"" << address << "\": checksum failed"); LOGWARN(3, "Invalid onion address \"" << address << "\": checksum failed");
return {}; return {};
} }
+12
View File
@@ -395,6 +395,18 @@ FORCEINLINE void secure_zero_memory(T& value)
secure_zero_memory(&value, sizeof(T)); secure_zero_memory(&value, sizeof(T));
} }
FORCEINLINE std::string tolower(const std::string& s)
{
std::string result;
result.reserve(s.size() + 1);
for (char c : s) {
result.push_back(static_cast<char>(std::tolower(c)));
}
return result;
}
std::string to_onion_v3(const hash& pubkey); std::string to_onion_v3(const hash& pubkey);
hash from_onion_v3(const std::string& address); hash from_onion_v3(const std::string& address);