From 1e2d011705432396e45440d2e39a2cff34208320 Mon Sep 17 00:00:00 2001 From: XMRig Date: Tue, 18 Feb 2020 02:16:21 +0700 Subject: [PATCH] Initial SOCKS5 implementation. --- src/base/base.cmake | 4 ++ src/base/net/stratum/Client.cpp | 37 ++++++++++- src/base/net/stratum/Client.h | 6 +- src/base/net/stratum/Pool.cpp | 12 ++-- src/base/net/stratum/Pool.h | 5 +- src/base/net/stratum/ProxyUrl.cpp | 62 ++++++++++++++++++ src/base/net/stratum/ProxyUrl.h | 46 +++++++++++++ src/base/net/stratum/Socks5.cpp | 103 ++++++++++++++++++++++++++++++ src/base/net/stratum/Socks5.h | 60 +++++++++++++++++ src/base/net/stratum/Url.cpp | 11 +++- src/base/net/stratum/Url.h | 10 +-- 11 files changed, 339 insertions(+), 17 deletions(-) create mode 100644 src/base/net/stratum/ProxyUrl.cpp create mode 100644 src/base/net/stratum/ProxyUrl.h create mode 100644 src/base/net/stratum/Socks5.cpp create mode 100644 src/base/net/stratum/Socks5.h diff --git a/src/base/base.cmake b/src/base/base.cmake index 85ee71313..47996f33f 100644 --- a/src/base/base.cmake +++ b/src/base/base.cmake @@ -40,6 +40,8 @@ set(HEADERS_BASE src/base/net/stratum/NetworkState.h src/base/net/stratum/Pool.h src/base/net/stratum/Pools.h + src/base/net/stratum/ProxyUrl.h + src/base/net/stratum/Socks5.h src/base/net/stratum/strategies/FailoverStrategy.h src/base/net/stratum/strategies/SinglePoolStrategy.h src/base/net/stratum/strategies/StrategyProxy.h @@ -82,6 +84,8 @@ set(SOURCES_BASE src/base/net/stratum/NetworkState.cpp src/base/net/stratum/Pool.cpp src/base/net/stratum/Pools.cpp + src/base/net/stratum/ProxyUrl.cpp + src/base/net/stratum/Socks5.cpp src/base/net/stratum/strategies/FailoverStrategy.cpp src/base/net/stratum/strategies/SinglePoolStrategy.cpp src/base/net/stratum/Url.cpp diff --git a/src/base/net/stratum/Client.cpp b/src/base/net/stratum/Client.cpp index 42c755f5c..b4e910b2a 100644 --- a/src/base/net/stratum/Client.cpp +++ b/src/base/net/stratum/Client.cpp @@ -44,6 +44,7 @@ #include "base/kernel/interfaces/IClientListener.h" #include "base/net/dns/Dns.h" #include "base/net/stratum/Client.h" +#include "base/net/stratum/Socks5.h" #include "base/tools/Buffer.h" #include "base/tools/Chrono.h" #include "net/JobResult.h" @@ -235,6 +236,13 @@ int64_t xmrig::Client::submit(const JobResult &result) void xmrig::Client::connect() { + if (m_pool.proxy().isValid()) { + m_socks5 = new Socks5(this); + resolve(m_pool.proxy().host()); + + return; + } + # ifdef XMRIG_FEATURE_TLS if (m_pool.isTLS()) { m_tls = new Tls(this); @@ -305,10 +313,10 @@ void xmrig::Client::onResolved(const Dns &dns, int status) return reconnect(); } - const DnsRecord &record = dns.get(); + const auto &record = dns.get(); m_ip = record.ip(); - connect(record.addr(m_pool.port())); + connect(record.addr(m_socks5 ? m_pool.proxy().port() : m_pool.port())); } @@ -607,6 +615,10 @@ void xmrig::Client::connect(sockaddr *addr) void xmrig::Client::handshake() { + if (m_socks5) { + return m_socks5->handshake(); + } + # ifdef XMRIG_FEATURE_TLS if (isTLS()) { m_expire = Chrono::steadyMSecs() + kResponseTimeout; @@ -849,6 +861,27 @@ void xmrig::Client::read(ssize_t nread) m_recvBuf.nread(size); + if (m_socks5) { + if (m_socks5->read(m_recvBuf.base(), m_recvBuf.pos())) { + m_recvBuf.reset(); + } + + if (m_socks5->isReady()) { + delete m_socks5; + m_socks5 = nullptr; + +# ifdef XMRIG_FEATURE_TLS + if (m_pool.isTLS() && !m_tls) { + m_tls = new Tls(this); + } +# endif + + handshake(); + } + + return; + } + # ifdef XMRIG_FEATURE_TLS if (isTLS()) { LOG_DEBUG("[%s] TLS received (%d bytes)", url(), static_cast(nread)); diff --git a/src/base/net/stratum/Client.h b/src/base/net/stratum/Client.h index ec90dd857..e26eaa7b7 100644 --- a/src/base/net/stratum/Client.h +++ b/src/base/net/stratum/Client.h @@ -5,9 +5,9 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2019 SChernykh * Copyright 2019 jtgrassie - * Copyright 2016-2019 XMRig , + * Copyright 2018-2020 SChernykh + * Copyright 2016-2020 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -88,6 +88,7 @@ protected: inline void onLine(char *line, size_t size) override { parse(line, size); } private: + class Socks5; class Tls; bool close(); @@ -128,6 +129,7 @@ private: const char *m_agent; Dns *m_dns; RecvBuf m_recvBuf; + Socks5 *m_socks5 = nullptr; std::bitset m_extensions; std::vector m_sendBuf; String m_rpcId; diff --git a/src/base/net/stratum/Pool.cpp b/src/base/net/stratum/Pool.cpp index 78dd2554c..e112feca3 100644 --- a/src/base/net/stratum/Pool.cpp +++ b/src/base/net/stratum/Pool.cpp @@ -63,6 +63,7 @@ const char *Pool::kNicehash = "nicehash"; const char *Pool::kPass = "pass"; const char *Pool::kRigId = "rig-id"; const char *Pool::kSelfSelect = "self-select"; +const char *Pool::kSOCKS5 = "socks5"; const char *Pool::kTls = "tls"; const char *Pool::kUrl = "url"; const char *Pool::kUser = "user"; @@ -96,6 +97,7 @@ xmrig::Pool::Pool(const rapidjson::Value &object) : m_algorithm = Json::getString(object, kAlgo); m_coin = Json::getString(object, kCoin); m_daemon = Json::getString(object, kSelfSelect); + m_proxy = Json::getValue(object, kSOCKS5); m_flags.set(FLAG_ENABLED, Json::getBool(object, kEnabled, true)); m_flags.set(FLAG_NICEHASH, Json::getBool(object, kNicehash)); @@ -173,6 +175,7 @@ bool xmrig::Pool::isEqual(const Pool &other) const && m_user == other.m_user && m_pollInterval == other.m_pollInterval && m_daemon == other.m_daemon + && m_proxy == other.m_proxy ); } @@ -232,10 +235,11 @@ rapidjson::Value xmrig::Pool::toJSON(rapidjson::Document &doc) const } } - obj.AddMember(StringRef(kEnabled), m_flags.test(FLAG_ENABLED), allocator); - obj.AddMember(StringRef(kTls), isTLS(), allocator); - obj.AddMember(StringRef(kFingerprint), m_fingerprint.toJSON(), allocator); - obj.AddMember(StringRef(kDaemon), m_mode == MODE_DAEMON, allocator); + obj.AddMember(StringRef(kEnabled), m_flags.test(FLAG_ENABLED), allocator); + obj.AddMember(StringRef(kTls), isTLS(), allocator); + obj.AddMember(StringRef(kFingerprint), m_fingerprint.toJSON(), allocator); + obj.AddMember(StringRef(kDaemon), m_mode == MODE_DAEMON, allocator); + obj.AddMember(StringRef(kSOCKS5), m_proxy.toJSON(doc), allocator); if (m_mode == MODE_DAEMON) { obj.AddMember(StringRef(kDaemonPollInterval), m_pollInterval, allocator); diff --git a/src/base/net/stratum/Pool.h b/src/base/net/stratum/Pool.h index 782ae4492..0272ef077 100644 --- a/src/base/net/stratum/Pool.h +++ b/src/base/net/stratum/Pool.h @@ -31,7 +31,7 @@ #include -#include "base/net/stratum/Url.h" +#include "base/net/stratum/ProxyUrl.h" #include "crypto/common/Coin.h" #include "rapidjson/fwd.h" @@ -66,6 +66,7 @@ public: static const char *kPass; static const char *kRigId; static const char *kSelfSelect; + static const char *kSOCKS5; static const char *kTls; static const char *kUrl; static const char *kUser; @@ -91,6 +92,7 @@ public: inline bool isValid() const { return m_url.isValid(); } inline const Algorithm &algorithm() const { return m_algorithm; } inline const Coin &coin() const { return m_coin; } + inline const ProxyUrl &proxy() const { return m_proxy; } inline const String &fingerprint() const { return m_fingerprint; } inline const String &host() const { return m_url.host(); } inline const String &password() const { return !m_password.isNull() ? m_password : kDefaultPassword; } @@ -135,6 +137,7 @@ private: Coin m_coin; int m_keepAlive = 0; Mode m_mode = MODE_POOL; + ProxyUrl m_proxy; std::bitset m_flags = 0; String m_fingerprint; String m_password; diff --git a/src/base/net/stratum/ProxyUrl.cpp b/src/base/net/stratum/ProxyUrl.cpp new file mode 100644 index 000000000..5b0ff281b --- /dev/null +++ b/src/base/net/stratum/ProxyUrl.cpp @@ -0,0 +1,62 @@ +/* XMRig + * Copyright 2018-2020 SChernykh + * Copyright 2016-2020 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "base/net/stratum/ProxyUrl.h" +#include "rapidjson/document.h" + + +namespace xmrig { + +static const String kLocalhost = "127.0.0.1"; + +} // namespace xmrig + + +xmrig::ProxyUrl::ProxyUrl(const rapidjson::Value &value) +{ + m_port = 0; + + if (value.IsString()) { + parse(value.GetString()); + } + else if (value.IsUint()) { + m_port = value.GetUint(); + } +} + + +const xmrig::String &xmrig::ProxyUrl::host() const +{ + return m_host.isNull() && isValid() ? kLocalhost : m_host; +} + + +rapidjson::Value xmrig::ProxyUrl::toJSON(rapidjson::Document &doc) const +{ + using namespace rapidjson; + if (!isValid()) { + return Value(kNullType); + } + + if (!m_host.isNull()) { + return m_url.toJSON(doc); + } + + return Value(m_port); +} diff --git a/src/base/net/stratum/ProxyUrl.h b/src/base/net/stratum/ProxyUrl.h new file mode 100644 index 000000000..0604dd9dd --- /dev/null +++ b/src/base/net/stratum/ProxyUrl.h @@ -0,0 +1,46 @@ +/* XMRig + * Copyright 2018-2020 SChernykh + * Copyright 2016-2020 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_PROXYURL_H +#define XMRIG_PROXYURL_H + + +#include "base/net/stratum/Url.h" + + +namespace xmrig { + + +class ProxyUrl : public Url +{ +public: + inline ProxyUrl() { m_port = 0; } + + ProxyUrl(const rapidjson::Value &value); + + inline bool isValid() const { return m_port > 0 && (m_scheme == UNSPECIFIED || m_scheme == SOCKS5); } + + const String &host() const; + rapidjson::Value toJSON(rapidjson::Document &doc) const; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_PROXYURL_H */ diff --git a/src/base/net/stratum/Socks5.cpp b/src/base/net/stratum/Socks5.cpp new file mode 100644 index 000000000..94fce6f36 --- /dev/null +++ b/src/base/net/stratum/Socks5.cpp @@ -0,0 +1,103 @@ +/* XMRig + * Copyright 2018-2020 SChernykh + * Copyright 2016-2020 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include "base/net/stratum/Socks5.h" + + +xmrig::Client::Socks5::Socks5(Client *client) : + m_client(client) +{ +} + + +bool xmrig::Client::Socks5::read(const char *data, size_t size) +{ + if (size < m_nextSize) { + return false; + } + + if (data[0] == 0x05 && data[1] == 0x00) { + if (m_state == SentInitialHandshake) { + connect(); + } + else { + m_state = Ready; + } + } + else { + m_client->close(); + } + + return true; +} + + +void xmrig::Client::Socks5::handshake() +{ + m_nextSize = 2; + m_state = SentInitialHandshake; + + char buf[3] = { 0x05, 0x01, 0x00 }; + + m_client->write(uv_buf_init(buf, sizeof (buf))); +} + + +bool xmrig::Client::Socks5::isIPv4(const String &) const +{ + return false; +} + + +bool xmrig::Client::Socks5::isIPv6(const String &) const +{ + return false; +} + + +void xmrig::Client::Socks5::connect() +{ + m_nextSize = 5; + m_state = SentFinalHandshake; + + const auto &host = m_client->pool().host(); + std::vector buf; + + if (isIPv4(host)) { + + } + else if (isIPv6(host)) { + + } + else { + buf.resize(host.size() + 7); + buf[3] = 0x03; + buf[4] = static_cast(host.size()); + memcpy(buf.data() + 5, host.data(), host.size()); + } + + buf[0] = 0x05; + buf[1] = 0x01; + buf[2] = 0x00; + + const uint16_t port = htons(m_client->pool().port()); + memcpy(buf.data() + (buf.size() - sizeof(port)), &port, sizeof(port)); + + m_client->write(uv_buf_init(reinterpret_cast(buf.data()), buf.size())); +} diff --git a/src/base/net/stratum/Socks5.h b/src/base/net/stratum/Socks5.h new file mode 100644 index 000000000..927a7fc04 --- /dev/null +++ b/src/base/net/stratum/Socks5.h @@ -0,0 +1,60 @@ +/* XMRig + * Copyright 2018-2020 SChernykh + * Copyright 2016-2020 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_SOCKS5_H +#define XMRIG_SOCKS5_H + + +#include "base/net/stratum/Client.h" + + +namespace xmrig { + + +class Client::Socks5 +{ +public: + Socks5(Client *client); + + inline bool isReady() const { return m_state == Ready; } + + bool read(const char *data, size_t size); + void handshake(); + +private: + enum State { + Created, + SentInitialHandshake, + SentFinalHandshake, + Ready + }; + + bool isIPv4(const String &host) const; + bool isIPv6(const String &host) const; + void connect(); + + Client *m_client; + size_t m_nextSize = 0; + State m_state = Created; +}; + + +} /* namespace xmrig */ + + +#endif /* XMRIG_SOCKS5_H */ diff --git a/src/base/net/stratum/Url.cpp b/src/base/net/stratum/Url.cpp index 3de6bc9b8..5e2bdb9ac 100644 --- a/src/base/net/stratum/Url.cpp +++ b/src/base/net/stratum/Url.cpp @@ -4,10 +4,10 @@ * Copyright 2014 Lucas Jones * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee - * Copyright 2017-2019 XMR-Stak , - * Copyright 2018-2019 SChernykh + * Copyright 2017-2018 XMR-Stak , * Copyright 2019 Howard Chu - * Copyright 2016-2019 XMRig , + * Copyright 2018-2020 SChernykh + * Copyright 2016-2020 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -42,6 +42,7 @@ namespace xmrig { static const char kStratumTcp[] = "stratum+tcp://"; static const char kStratumSsl[] = "stratum+ssl://"; +static const char kSOCKS5[] = "socks5://"; #ifdef XMRIG_FEATURE_HTTP static const char kDaemonHttp[] = "daemon+http://"; @@ -97,6 +98,10 @@ bool xmrig::Url::parse(const char *url) m_scheme = STRATUM; m_tls = true; } + else if (strncasecmp(url, kSOCKS5, sizeof(kSOCKS5) - 1) == 0) { + m_scheme = SOCKS5; + m_tls = false; + } # ifdef XMRIG_FEATURE_HTTP else if (strncasecmp(url, kDaemonHttps, sizeof(kDaemonHttps) - 1) == 0) { m_scheme = DAEMON; diff --git a/src/base/net/stratum/Url.h b/src/base/net/stratum/Url.h index 23fd750e9..647612c11 100644 --- a/src/base/net/stratum/Url.h +++ b/src/base/net/stratum/Url.h @@ -5,9 +5,9 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2017-2018 XMR-Stak , - * Copyright 2018-2019 SChernykh * Copyright 2019 Howard Chu - * Copyright 2016-2019 XMRig , + * Copyright 2018-2020 SChernykh + * Copyright 2016-2020 XMRig , * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,7 +39,8 @@ public: enum Scheme { UNSPECIFIED, STRATUM, - DAEMON + DAEMON, + SOCKS5 }; Url() = default; @@ -57,9 +58,8 @@ public: inline bool operator==(const Url &other) const { return isEqual(other); } bool isEqual(const Url &other) const; - rapidjson::Value toJSON(rapidjson::Document &doc) const; -private: +protected: bool parse(const char *url); bool parseIPv6(const char *addr);