xmrig使用加密tls协议进行挖矿——我去,居然使用了tls1.3进行通信,GG!
只需要在命令行加 --tls即可:
C:\Users\bonel\Desktop\xmrig-6.18.0-msvc-win64\xmrig-6.18.0>xmrig.exe -o pool.hashvault.pro:3333 -u 48edfHu7V9Z84YzzMa6fUueoELZ9ZRXq9VetWzYGzKt52XU5xvqgzYnDK9URnRoJMk1j8nLwEVsaSWJ4fhdUyZijBGUicoD -p x --tls * ABOUT XMRig/6.18.0 MSVC/2019 * LIBS libuv/1.44.1 OpenSSL/1.1.1o hwloc/2.7.1 * HUGE PAGES unavailable * 1GB PAGES unavailable * CPU 11th Gen Intel(R) Core(TM) i5-11400 @ 2.60GHz (1) 64-bit AES VM L2:1.5 MB L3:36.0 MB 3C/3T NUMA:1 * MEMORY 1.2/3.0 GB (38%) * MOTHERBOARD innotek GmbH - VirtualBox * DONATE 1% * ASSEMBLY auto:intel * POOL #1 pool.hashvault.pro:3333 algo auto * COMMANDS hashrate, pause, resume, results, connection * OPENCL disabled * CUDA disabled [2022-07-12 10:28:55.214] net use pool pool.hashvault.pro:3333 TLSv1.3 125.253.92.50 [2022-07-12 10:28:55.220] net fingerprint (SHA-256): "420c7850e09b7c0bdcf748a7da9eb3647daf8515718f36d9ccfdd6b9ff834b14" [2022-07-12 10:28:55.221] net new job from pool.hashvault.pro:3333 diff 72000 algo rx/0 height 2665379 (6 tx) [2022-07-12 10:28:55.222] cpu use argon2 implementation AVX2 [2022-07-12 10:28:55.222] msr to access MSR registers Administrator privileges required. [2022-07-12 10:28:55.222] msr FAILED TO APPLY MSR MOD, HASHRATE WILL BE LOW [2022-07-12 10:28:55.223] randomx init dataset algo rx/0 (3 threads) seed 6b9d4c7053de0009... [2022-07-12 10:28:55.223] randomx allocated 2336 MB (2080+256) huge pages 0% 0/1168 +JIT (0 ms) [2022-07-12 10:29:01.257] net new job from pool.hashvault.pro:3333 diff 116758 algo rx/0 height 2665379 (6 tx) [2022-07-12 10:29:01.785] signal Ctrl+C received, exiting [2022-07-12 10:29:07.345] randomx dataset ready (12119 ms) C:\Users\bonel\Desktop\xmrig-6.18.0-msvc-win64\xmrig-6.18.0>
看下矿池的IP:
C:\Users\bonelee>ping pool.hashvault.pro 正在 Ping pool.hashvault.pro [131.153.76.130] 具有 32 字节的数据: 来自 131.153.76.130 的回复: 字节=32 时间=235ms TTL=43 来自 131.153.76.130 的回复: 字节=32 时间=233ms TTL=43 131.153.76.130 的 Ping 统计信息: 数据包: 已发送 = 2,已接收 = 2,丢失 = 0 (0% 丢失), 往返行程的估计时间(以毫秒为单位): 最短 = 233ms,最长 = 235ms,平均 = 234ms Control-C
然后在挖矿过程中抓包,可以看到,在通信过程中完全使用了tls1.3的通信流量:
这下通过流量检测有些麻烦了!
补充,我又在挖矿过程中进行了一次抓包,
D:\share\xmrig-6.18.0-msvc-win64\xmrig-6.18.0>xmrig.exe -o pool.hashvault.pro:3333 -u 48edfHu7V9Z84YzzMa6fUueoELZ9ZRXq9VetWzYGzKt52XU5xvqgzYnDK9URnRoJMk1j8nLwEVsaSWJ4fhdUyZijBGUicoD -p x --tls * ABOUT XMRig/6.18.0 MSVC/2019 * LIBS libuv/1.44.1 OpenSSL/1.1.1o hwloc/2.7.1 * HUGE PAGES permission granted * 1GB PAGES unavailable * CPU 11th Gen Intel(R) Core(TM) i5-11400 @ 2.60GHz (1) 64-bit AES L2:3.0 MB L3:12.0 MB 6C/12T NUMA:1 * MEMORY 9.5/15.7 GB (60%) Controller0-ChannelA-DIMM0: 16 GB DDR4 @ 2933 MHz M378A2G43AB3-CWE Controller0-ChannelB-DIMM0: <empty> * MOTHERBOARD LENOVO - 3730 * DONATE 1% * ASSEMBLY auto:intel * POOL #1 pool.hashvault.pro:3333 algo auto * COMMANDS hashrate, pause, resume, results, connection * OPENCL disabled * CUDA disabled [2022-07-12 14:14:22.717] net use pool pool.hashvault.pro:3333 TLSv1.3 125.253.92.50 [2022-07-12 14:14:22.718] net fingerprint (SHA-256): "420c7850e09b7c0bdcf748a7da9eb3647daf8515718f36d9ccfdd6b9ff834b14" [2022-07-12 14:14:22.719] net new job from pool.hashvault.pro:3333 diff 72000 algo rx/0 height 2665490 (4 tx) [2022-07-12 14:14:22.719] cpu use argon2 implementation AVX-512F [2022-07-12 14:14:22.720] msr to access MSR registers Administrator privileges required. [2022-07-12 14:14:22.720] msr FAILED TO APPLY MSR MOD, HASHRATE WILL BE LOW [2022-07-12 14:14:22.721] randomx init dataset algo rx/0 (12 threads) seed 6b9d4c7053de0009... [2022-07-12 14:14:22.726] randomx allocated 2336 MB (2080+256) huge pages 0% 0/1168 +JIT (5 ms) [2022-07-12 14:14:26.652] randomx dataset ready (3926 ms) [2022-07-12 14:14:26.652] cpu use profile rx (6 threads) scratchpad 2048 KB [2022-07-12 14:14:26.677] cpu READY threads 6/6 (6) huge pages 0% 0/6 memory 12288 KB (24 ms) [2022-07-12 14:14:58.596] net new job from pool.hashvault.pro:3333 diff 72000 algo rx/0 height 2665491 (9 tx) [2022-07-12 14:15:07.586] cpu accepted (1/0) diff 72000 (274 ms) [2022-07-12 14:15:24.414] cpu accepted (2/0) diff 72000 (1621 ms) [2022-07-12 14:15:26.716] miner speed 10s/60s/15m 1020.2 n/a n/a H/s max 1092.4 H/s [2022-07-12 14:15:56.798] cpu accepted (3/0) diff 72000 (297 ms) [2022-07-12 14:16:01.720] net new job from pool.hashvault.pro:3333 diff 66120 algo rx/0 height 2665491 (9 tx) [2022-07-12 14:16:21.318] signal Ctrl+C received, exiting [2022-07-12 14:16:21.325] cpu stopped (7 ms) D:\share\xmrig-6.18.0-msvc-win64\xmrig-6.18.0>PING pool.hashvault.pro 正在 Ping pool.hashvault.pro [125.253.92.50] 具有 32 字节的数据: 来自 125.253.92.50 的回复: 字节=32 时间=148ms TTL=47 来自 125.253.92.50 的回复: 字节=32 时间=144ms TTL=47 125.253.92.50 的 Ping 统计信息: 数据包: 已发送 = 2,已接收 = 2,丢失 = 0 (0% 丢失), 往返行程的估计时间(以毫秒为单位): 最短 = 144ms,最长 = 148ms,平均 = 146ms Control-C ^C D:\share\xmrig-6.18.0-msvc-win64\xmrig-6.18.0>
虽然cmd里提示tls1.3,但是我看到却是tls1.2,咋回事?
我又试了几次,因为有动态dns,这次IP是131.153.76.130,不过还是tls1.3
又试了几次,还是tls1.3
源码分析,用的是网络通信client IClient:
/* XMRig * Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh> * Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com> * * 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 <http://www.gnu.org/licenses/>. */ #ifndef XMRIG_ICLIENT_H #define XMRIG_ICLIENT_H #include "3rdparty/rapidjson/fwd.h" #include "base/tools/Object.h" #include <functional> namespace xmrig { class Algorithm; class Job; class JobResult; class Pool; class ProxyUrl; class String; class IClient { public: XMRIG_DISABLE_COPY_MOVE(IClient) enum Extension { EXT_ALGO, EXT_NICEHASH, EXT_CONNECT, EXT_TLS, EXT_KEEPALIVE, EXT_MAX }; using Callback = std::function<void(const rapidjson::Value &result, bool success, uint64_t elapsed)>; IClient() = default; virtual ~IClient() = default; virtual bool disconnect() = 0; virtual bool hasExtension(Extension extension) const noexcept = 0; virtual bool isEnabled() const = 0; virtual bool isTLS() const = 0; virtual const char *mode() const = 0; virtual const char *tag() const = 0; virtual const char *tlsFingerprint() const = 0; virtual const char *tlsVersion() const = 0; virtual const Job &job() const = 0; virtual const Pool &pool() const = 0; virtual const String &ip() const = 0; virtual int id() const = 0; virtual int64_t send(const rapidjson::Value &obj, Callback callback) = 0; virtual int64_t send(const rapidjson::Value &obj) = 0; virtual int64_t sequence() const = 0; virtual int64_t submit(const JobResult &result) = 0; virtual void connect() = 0; virtual void connect(const Pool &pool) = 0; virtual void deleteLater() = 0; virtual void setAlgo(const Algorithm &algo) = 0; virtual void setEnabled(bool enabled) = 0; virtual void setPool(const Pool &pool) = 0; virtual void setProxy(const ProxyUrl &proxy) = 0; virtual void setQuiet(bool quiet) = 0; virtual void setRetries(int retries) = 0; virtual void setRetryPause(uint64_t ms) = 0; virtual void tick(uint64_t now) = 0; }; } /* namespace xmrig */ #endif // XMRIG_ICLIENT_H
然后看到baseclient继承自它,
/* XMRig * Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh> * Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com> * * 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 <http://www.gnu.org/licenses/>. */ #ifndef XMRIG_BASECLIENT_H #define XMRIG_BASECLIENT_H #include <map> #include "base/kernel/interfaces/IClient.h" #include "base/net/stratum/Job.h" #include "base/net/stratum/Pool.h" #include "base/tools/Chrono.h" namespace xmrig { class IClientListener; class SubmitResult; class BaseClient : public IClient { public: BaseClient(int id, IClientListener *listener); protected: inline bool isEnabled() const override { return m_enabled; } inline const char *tag() const override { return m_tag.c_str(); } inline const Job &job() const override { return m_job; } inline const Pool &pool() const override { return m_pool; } inline const String &ip() const override { return m_ip; } inline int id() const override { return m_id; } inline int64_t sequence() const override { return m_sequence; } inline void setAlgo(const Algorithm &algo) override { m_pool.setAlgo(algo); } inline void setEnabled(bool enabled) override { m_enabled = enabled; } inline void setProxy(const ProxyUrl &proxy) override { m_pool.setProxy(proxy); } inline void setQuiet(bool quiet) override { m_quiet = quiet; } inline void setRetries(int retries) override { m_retries = retries; } inline void setRetryPause(uint64_t ms) override { m_retryPause = ms; } void setPool(const Pool &pool) override; protected: enum SocketState { UnconnectedState, HostLookupState, ConnectingState, ConnectedState, ClosingState, ReconnectingState }; struct SendResult { inline SendResult(Callback &&callback) : callback(callback), ts(Chrono::steadyMSecs()) {} Callback callback; const uint64_t ts; }; inline bool isQuiet() const { return m_quiet || m_failures >= m_retries; } virtual bool handleResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error); bool handleSubmitResponse(int64_t id, const char *error = nullptr); bool m_quiet = false; IClientListener *m_listener; int m_id; int m_retries = 5; int64_t m_failures = 0; Job m_job; Pool m_pool; SocketState m_state = UnconnectedState; std::map<int64_t, SendResult> m_callbacks; std::map<int64_t, SubmitResult> m_results; std::string m_tag; String m_ip; String m_password; String m_rigId; String m_user; uint64_t m_retryPause = 5000; static int64_t m_sequence; private: bool m_enabled = true; }; } /* namespace xmrig */ #endif /* XMRIG_BASECLIENT_H */
真正有意义的client来了,setpool,login啥的都在里面
/* XMRig * Copyright (c) 2019 jtgrassie <https://github.com/jtgrassie> * Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh> * Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com> * * 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 <http://www.gnu.org/licenses/>. */ #ifndef XMRIG_CLIENT_H #define XMRIG_CLIENT_H #include <bitset> #include <map> #include <uv.h> #include <vector> #include "base/kernel/interfaces/IDnsListener.h" #include "base/kernel/interfaces/ILineListener.h" #include "base/net/stratum/BaseClient.h" #include "base/net/stratum/Job.h" #include "base/net/stratum/Pool.h" #include "base/net/stratum/SubmitResult.h" #include "base/net/tools/LineReader.h" #include "base/net/tools/Storage.h" #include "base/tools/Object.h" using BIO = struct bio_st; namespace xmrig { class DnsRequest; class IClientListener; class JobResult; class Client : public BaseClient, public IDnsListener, public ILineListener { public: XMRIG_DISABLE_COPY_MOVE_DEFAULT(Client) constexpr static uint64_t kConnectTimeout = 20 * 1000; constexpr static uint64_t kResponseTimeout = 20 * 1000; constexpr static size_t kMaxSendBufferSize = 1024 * 16; Client(int id, const char *agent, IClientListener *listener); ~Client() override; protected: bool disconnect() override; bool isTLS() const override; const char *tlsFingerprint() const override; const char *tlsVersion() const override; int64_t send(const rapidjson::Value &obj, Callback callback) override; int64_t send(const rapidjson::Value &obj) override; int64_t submit(const JobResult &result) override; void connect() override; void connect(const Pool &pool) override; void deleteLater() override; void tick(uint64_t now) override; void onResolved(const DnsRecords &records, int status, const char *error) override; inline bool hasExtension(Extension extension) const noexcept override { return m_extensions.test(extension); } inline const char *mode() const override { return "pool"; } inline void onLine(char *line, size_t size) override { parse(line, size); } inline const char *agent() const { return m_agent; } inline const char *url() const { return m_pool.url(); } inline const String &rpcId() const { return m_rpcId; } inline void setRpcId(const char *id) { m_rpcId = id; } inline void setPoolUrl(const char *url) { m_pool.setUrl(url); } virtual bool parseLogin(const rapidjson::Value &result, int *code); virtual void login(); virtual void parseNotification(const char* method, const rapidjson::Value& params, const rapidjson::Value& error); bool close(); virtual void onClose(); private: class Socks5; class Tls; bool parseJob(const rapidjson::Value ¶ms, int *code); bool send(BIO *bio); bool verifyAlgorithm(const Algorithm &algorithm, const char *algo) const; bool write(const uv_buf_t &buf); int resolve(const String &host); int64_t send(size_t size); void connect(const sockaddr *addr); void handshake(); void parse(char *line, size_t len); void parseExtensions(const rapidjson::Value &result); void parseResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error); void ping(); void read(ssize_t nread, const uv_buf_t *buf); void reconnect(); void setState(SocketState state); void startTimeout(); inline SocketState state() const { return m_state; } inline uv_stream_t *stream() const { return reinterpret_cast<uv_stream_t *>(m_socket); } inline void setExtension(Extension ext, bool enable) noexcept { m_extensions.set(ext, enable); } template<Extension ext> inline bool has() const noexcept { return m_extensions.test(ext); } static bool isCriticalError(const char *message); static void onClose(uv_handle_t *handle); static void onConnect(uv_connect_t *req, int status); static void onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf); static inline Client *getClient(void *data) { return m_storage.get(data); } const char *m_agent; LineReader m_reader; Socks5 *m_socks5 = nullptr; std::bitset<EXT_MAX> m_extensions; std::shared_ptr<DnsRequest> m_dns; std::vector<char> m_sendBuf; std::vector<char> m_tempBuf; String m_rpcId; Tls *m_tls = nullptr; uint64_t m_expire = 0; uint64_t m_jobs = 0; uint64_t m_keepAlive = 0; uintptr_t m_key = 0; uv_tcp_t *m_socket = nullptr; static Storage<Client> m_storage; }; template<> inline bool Client::has<Client::EXT_NICEHASH>() const noexcept { return m_extensions.test(EXT_NICEHASH) || m_pool.isNicehash(); } template<> inline bool Client::has<Client::EXT_KEEPALIVE>() const noexcept { return m_extensions.test(EXT_KEEPALIVE) || m_pool.keepAlive() > 0; } } /* namespace xmrig */ #endif /* XMRIG_CLIENT_H */
其中,m_tls就是负责加密传输:
/* XMRig * Copyright (c) 2019 jtgrassie <https://github.com/jtgrassie> * Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh> * Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com> * * 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 <http://www.gnu.org/licenses/>. */ #include <cassert> #include <cinttypes> #include <iterator> #include <cstdio> #include <cstring> #include <utility> #include <sstream> #ifdef XMRIG_FEATURE_TLS # include <openssl/ssl.h> # include <openssl/err.h> # include "base/net/stratum/Tls.h" #endif #include "base/net/stratum/Client.h" #include "3rdparty/rapidjson/document.h" #include "3rdparty/rapidjson/error/en.h" #include "3rdparty/rapidjson/stringbuffer.h" #include "3rdparty/rapidjson/writer.h" #include "base/io/json/Json.h" #include "base/io/json/JsonRequest.h" #include "base/io/log/Log.h" #include "base/kernel/interfaces/IClientListener.h" #include "base/net/dns/Dns.h" #include "base/net/dns/DnsRecords.h" #include "base/net/stratum/Socks5.h" #include "base/net/tools/NetBuffer.h" #include "base/tools/Chrono.h" #include "base/tools/Cvt.h" #include "base/tools/cryptonote/BlobReader.h" #include "net/JobResult.h" #ifdef _MSC_VER # define strncasecmp(x,y,z) _strnicmp(x,y,z) #endif namespace xmrig { Storage<Client> Client::m_storage; } /* namespace xmrig */ #ifdef APP_DEBUG static const char *states[] = { "unconnected", "host-lookup", "connecting", "connected", "closing", "reconnecting" }; #endif xmrig::Client::Client(int id, const char *agent, IClientListener *listener) : BaseClient(id, listener), m_agent(agent), m_sendBuf(1024), m_tempBuf(256) { m_reader.setListener(this); m_key = m_storage.add(this); } xmrig::Client::~Client() { delete m_socket; } bool xmrig::Client::disconnect() { m_keepAlive = 0; m_expire = 0; m_failures = -1; return close(); } bool xmrig::Client::isTLS() const { # ifdef XMRIG_FEATURE_TLS return m_pool.isTLS() && m_tls; # else return false; # endif } const char *xmrig::Client::tlsFingerprint() const { # ifdef XMRIG_FEATURE_TLS if (isTLS() && m_pool.fingerprint() == nullptr) { return m_tls->fingerprint(); } # endif return nullptr; } const char *xmrig::Client::tlsVersion() const { # ifdef XMRIG_FEATURE_TLS if (isTLS()) { return m_tls->version(); } # endif return nullptr; } int64_t xmrig::Client::send(const rapidjson::Value &obj, Callback callback) { assert(obj["id"] == sequence()); m_callbacks.insert({ sequence(), std::move(callback) }); return send(obj); } int64_t xmrig::Client::send(const rapidjson::Value &obj) { using namespace rapidjson; StringBuffer buffer(nullptr, 512); Writer<StringBuffer> writer(buffer); obj.Accept(writer); const size_t size = buffer.GetSize(); if (size > kMaxSendBufferSize) { LOG_ERR("%s " RED("send failed: ") RED_BOLD("\"max send buffer size exceeded: %zu\""), tag(), size); close(); return -1; } if (size > (m_sendBuf.size() - 2)) { m_sendBuf.resize(((size + 1) / 1024 + 1) * 1024); } memcpy(m_sendBuf.data(), buffer.GetString(), size); m_sendBuf[size] = '\n'; m_sendBuf[size + 1] = '\0'; return send(size + 1); } int64_t xmrig::Client::submit(const JobResult &result) { # ifndef XMRIG_PROXY_PROJECT if (result.clientId != m_rpcId || m_rpcId.isNull() || m_state != ConnectedState) { return -1; } # endif if (result.diff == 0) { close(); return -1; } using namespace rapidjson; # ifdef XMRIG_PROXY_PROJECT const char *nonce = result.nonce; const char *data = result.result; # else char *nonce = m_tempBuf.data(); char *data = m_tempBuf.data() + 16; char *signature = m_tempBuf.data() + 88; Cvt::toHex(nonce, sizeof(uint32_t) * 2 + 1, reinterpret_cast<const uint8_t *>(&result.nonce), sizeof(uint32_t)); Cvt::toHex(data, 65, result.result(), 32); if (result.minerSignature()) { Cvt::toHex(signature, 129, result.minerSignature(), 64); } # endif Document doc(kObjectType); auto &allocator = doc.GetAllocator(); Value params(kObjectType); params.AddMember("id", StringRef(m_rpcId.data()), allocator); params.AddMember("job_id", StringRef(result.jobId.data()), allocator); params.AddMember("nonce", StringRef(nonce), allocator); params.AddMember("result", StringRef(data), allocator); # ifndef XMRIG_PROXY_PROJECT if (result.minerSignature()) { params.AddMember("sig", StringRef(signature), allocator); } # else if (result.sig) { params.AddMember("sig", StringRef(result.sig), allocator); } # endif if (has<EXT_ALGO>() && result.algorithm.isValid()) { params.AddMember("algo", StringRef(result.algorithm.name()), allocator); } JsonRequest::create(doc, m_sequence, "submit", params); # ifdef XMRIG_PROXY_PROJECT m_results[m_sequence] = SubmitResult(m_sequence, result.diff, result.actualDiff(), result.id, 0); # else m_results[m_sequence] = SubmitResult(m_sequence, result.diff, result.actualDiff(), 0, result.backend); # endif return send(doc); } 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); } # endif resolve(m_pool.host()); } void xmrig::Client::connect(const Pool &pool) { setPool(pool); connect(); } void xmrig::Client::deleteLater() { if (!m_listener) { return; } m_listener = nullptr; if (!disconnect()) { m_storage.remove(m_key); } } void xmrig::Client::tick(uint64_t now) { if (m_state == ConnectedState) { if (m_expire && now > m_expire) { LOG_DEBUG_ERR("[%s] timeout", url()); close(); } else if (m_keepAlive && now > m_keepAlive) { ping(); } return; } if (m_state == ReconnectingState && m_expire && now > m_expire) { return connect(); } if (m_state == ConnectingState && m_expire && now > m_expire) { close(); } } void xmrig::Client::onResolved(const DnsRecords &records, int status, const char *error) { m_dns.reset(); assert(m_listener != nullptr); if (!m_listener) { return reconnect(); } if (status < 0 && records.isEmpty()) { if (!isQuiet()) { LOG_ERR("%s " RED("DNS error: ") RED_BOLD("\"%s\""), tag(), error); } return reconnect(); } const auto &record = records.get(); m_ip = record.ip(); connect(record.addr(m_socks5 ? m_pool.proxy().port() : m_pool.port())); } bool xmrig::Client::close() { if (m_state == ClosingState) { return m_socket != nullptr; } if (m_state == UnconnectedState || m_socket == nullptr) { return false; } setState(ClosingState); if (uv_is_closing(reinterpret_cast<uv_handle_t*>(m_socket)) == 0) { uv_close(reinterpret_cast<uv_handle_t*>(m_socket), Client::onClose); } return true; } bool xmrig::Client::parseJob(const rapidjson::Value ¶ms, int *code) { if (!params.IsObject()) { *code = 2; return false; } Job job(has<EXT_NICEHASH>(), m_pool.algorithm(), m_rpcId); if (!job.setId(params["job_id"].GetString())) { *code = 3; return false; } const char *algo = Json::getString(params, "algo"); const char *blobData = Json::getString(params, "blob"); if (algo) { job.setAlgorithm(algo); } else if (m_pool.coin().isValid()) { uint8_t blobVersion = 0; if (blobData) { Cvt::fromHex(&blobVersion, 1, blobData, 2); } job.setAlgorithm(m_pool.coin().algorithm(blobVersion)); } # ifdef XMRIG_FEATURE_HTTP if (m_pool.mode() == Pool::MODE_SELF_SELECT) { job.setExtraNonce(Json::getString(params, "extra_nonce")); job.setPoolWallet(Json::getString(params, "pool_wallet")); if (job.extraNonce().isNull() || job.poolWallet().isNull()) { *code = 4; return false; } } else # endif { if (!job.setBlob(blobData)) { *code = 4; return false; } } if (!job.setTarget(params["target"].GetString())) { *code = 5; return false; } job.setHeight(Json::getUint64(params, "height")); if (!verifyAlgorithm(job.algorithm(), algo)) { *code = 6; return false; } if (m_pool.mode() != Pool::MODE_SELF_SELECT && job.algorithm().family() == Algorithm::RANDOM_X && !job.setSeedHash(Json::getString(params, "seed_hash"))) { *code = 7; return false; } job.setSigKey(Json::getString(params, "sig_key")); m_job.setClientId(m_rpcId); if (m_job != job) { m_jobs++; m_job = std::move(job); return true; } if (m_jobs == 0) { // https://github.com/xmrig/xmrig/issues/459 return false; } if (!isQuiet()) { LOG_WARN("%s " YELLOW("duplicate job received, reconnect"), tag()); } close(); return false; } bool xmrig::Client::send(BIO *bio) { # ifdef XMRIG_FEATURE_TLS uv_buf_t buf; buf.len = BIO_get_mem_data(bio, &buf.base); // NOLINT(cppcoreguidelines-pro-type-cstyle-cast) if (buf.len == 0) { return true; } LOG_DEBUG("[%s] TLS send (%d bytes)", url(), static_cast<int>(buf.len)); bool result = false; if (state() == ConnectedState && uv_is_writable(stream())) { result = write(buf); } else { LOG_DEBUG_ERR("[%s] send failed, invalid state: %d", url(), m_state); } (void) BIO_reset(bio); return result; # else return false; # endif } bool xmrig::Client::verifyAlgorithm(const Algorithm &algorithm, const char *algo) const { if (!algorithm.isValid()) { if (!isQuiet()) { if (algo == nullptr) { LOG_ERR("%s " RED("unknown algorithm, make sure you set \"algo\" or \"coin\" option"), tag(), algo); } else { LOG_ERR("%s " RED("unsupported algorithm ") RED_BOLD("\"%s\" ") RED("detected, reconnect"), tag(), algo); } } return false; } bool ok = true; m_listener->onVerifyAlgorithm(this, algorithm, &ok); if (!ok && !isQuiet()) { LOG_ERR("%s " RED("incompatible/disabled algorithm ") RED_BOLD("\"%s\" ") RED("detected, reconnect"), tag(), algorithm.name()); } return ok; } bool xmrig::Client::write(const uv_buf_t &buf) { const int rc = uv_try_write(stream(), &buf, 1); if (static_cast<size_t>(rc) == buf.len) { return true; } if (!isQuiet()) { LOG_ERR("%s " RED("write error: ") RED_BOLD("\"%s\""), tag(), uv_strerror(rc)); } close(); return false; } int xmrig::Client::resolve(const String &host) { setState(HostLookupState); m_reader.reset(); if (m_failures == -1) { m_failures = 0; } m_dns = Dns::resolve(host, this); return 0; } int64_t xmrig::Client::send(size_t size) { LOG_DEBUG("[%s] send (%d bytes): \"%.*s\"", url(), size, static_cast<int>(size) - 1, m_sendBuf.data()); # ifdef XMRIG_FEATURE_TLS if (isTLS()) { if (!m_tls->send(m_sendBuf.data(), size)) { return -1; } } else # endif { if (state() != ConnectedState || !uv_is_writable(stream())) { LOG_DEBUG_ERR("[%s] send failed, invalid state: %d", url(), m_state); return -1; } uv_buf_t buf = uv_buf_init(m_sendBuf.data(), (unsigned int) size); if (!write(buf)) { return -1; } } m_expire = Chrono::steadyMSecs() + kResponseTimeout; return m_sequence++; } void xmrig::Client::connect(const sockaddr *addr) { setState(ConnectingState); auto req = new uv_connect_t; req->data = m_storage.ptr(m_key); m_socket = new uv_tcp_t; m_socket->data = m_storage.ptr(m_key); uv_tcp_init(uv_default_loop(), m_socket); uv_tcp_nodelay(m_socket, 1); # ifndef WIN32 uv_tcp_keepalive(m_socket, 1, 60); # endif uv_tcp_connect(req, m_socket, addr, onConnect); } void xmrig::Client::handshake() { if (m_socks5) { return m_socks5->handshake(); } # ifdef XMRIG_FEATURE_TLS if (isTLS()) { m_expire = Chrono::steadyMSecs() + kResponseTimeout; m_tls->handshake(); } else # endif { login(); } } bool xmrig::Client::parseLogin(const rapidjson::Value &result, int *code) { setRpcId(Json::getString(result, "id")); if (rpcId().isNull()) { *code = 1; return false; } parseExtensions(result); const bool rc = parseJob(result["job"], code); m_jobs = 0; return rc; } void xmrig::Client::login() { using namespace rapidjson; m_results.clear(); Document doc(kObjectType); auto &allocator = doc.GetAllocator(); Value params(kObjectType); params.AddMember("login", m_user.toJSON(), allocator); params.AddMember("pass", m_password.toJSON(), allocator); params.AddMember("agent", StringRef(m_agent), allocator); if (!m_rigId.isNull()) { params.AddMember("rigid", m_rigId.toJSON(), allocator); } m_listener->onLogin(this, doc, params); JsonRequest::create(doc, 1, "login", params); send(doc); } void xmrig::Client::onClose() { delete m_socket; m_socket = nullptr; setState(UnconnectedState); # ifdef XMRIG_FEATURE_TLS if (m_tls) { delete m_tls; m_tls = nullptr; } # endif reconnect(); } void xmrig::Client::parse(char *line, size_t len) { startTimeout(); LOG_DEBUG("[%s] received (%d bytes): \"%.*s\"", url(), len, static_cast<int>(len), line); if (len < 22 || line[0] != '{') { if (!isQuiet()) { LOG_ERR("%s " RED("JSON decode failed"), tag()); } return; } rapidjson::Document doc; if (doc.ParseInsitu(line).HasParseError()) { if (!isQuiet()) { LOG_ERR("%s " RED("JSON decode failed: ") RED_BOLD("\"%s\""), tag(), rapidjson::GetParseError_En(doc.GetParseError())); } return; } if (!doc.IsObject()) { return; } const auto &id = Json::getValue(doc, "id"); const auto &error = Json::getValue(doc, "error"); const char *method = Json::getString(doc, "method"); if (method && strcmp(method, "client.reconnect") == 0) { const auto ¶ms = Json::getValue(doc, "params"); if (!params.IsArray()) { LOG_ERR("%s " RED("invalid client.reconnect notification: params is not an array"), tag()); return; } auto arr = params.GetArray(); if (arr.Empty()) { LOG_ERR("%s " RED("invalid client.reconnect notification: params array is empty"), tag()); return; } if (arr.Size() != 2) { LOG_ERR("%s " RED("invalid client.reconnect notification: params array has wrong size"), tag()); return; } if (!arr[0].IsString()) { LOG_ERR("%s " RED("invalid client.reconnect notification: host is not a string"), tag()); return; } if (!arr[1].IsString()) { LOG_ERR("%s " RED("invalid client.reconnect notification: port is not a string"), tag()); return; } std::stringstream s; s << arr[0].GetString() << ":" << arr[1].GetString(); LOG_WARN("%s " YELLOW("client.reconnect to %s"), tag(), s.str().c_str()); setPoolUrl(s.str().c_str()); return reconnect(); } if (id.IsInt64()) { return parseResponse(id.GetInt64(), Json::getValue(doc, "result"), error); } if (!method) { return; } if (error.IsObject()) { if (!isQuiet()) { LOG_ERR("%s " RED("error: ") RED_BOLD("\"%s\"") RED(", code: ") RED_BOLD("%d"), tag(), Json::getString(error, "message"), Json::getInt(error, "code")); } return; } parseNotification(method, Json::getValue(doc, "params"), error); } void xmrig::Client::parseExtensions(const rapidjson::Value &result) { m_extensions.reset(); if (!result.HasMember("extensions")) { return; } const rapidjson::Value &extensions = result["extensions"]; if (!extensions.IsArray()) { return; } for (const rapidjson::Value &ext : extensions.GetArray()) { if (!ext.IsString()) { continue; } const char *name = ext.GetString(); if (strcmp(name, "algo") == 0) { setExtension(EXT_ALGO, true); } else if (strcmp(name, "nicehash") == 0) { setExtension(EXT_NICEHASH, true); } else if (strcmp(name, "connect") == 0) { setExtension(EXT_CONNECT, true); } else if (strcmp(name, "keepalive") == 0) { setExtension(EXT_KEEPALIVE, true); startTimeout(); } # ifdef XMRIG_FEATURE_TLS else if (strcmp(name, "tls") == 0) { setExtension(EXT_TLS, true); } # endif } } void xmrig::Client::parseNotification(const char *method, const rapidjson::Value ¶ms, const rapidjson::Value &) { if (strcmp(method, "job") == 0) { int code = -1; if (parseJob(params, &code)) { m_listener->onJobReceived(this, m_job, params); } else { close(); } return; } } void xmrig::Client::parseResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error) { if (handleResponse(id, result, error)) { return; } if (error.IsObject()) { const char *message = error["message"].GetString(); if (!handleSubmitResponse(id, message) && !isQuiet()) { LOG_ERR("%s " RED("error: ") RED_BOLD("\"%s\"") RED(", code: ") RED_BOLD("%d"), tag(), message, Json::getInt(error, "code")); } if (m_id == 1 || isCriticalError(message)) { close(); } return; } if (!result.IsObject()) { return; } if (id == 1) { int code = -1; if (!parseLogin(result, &code)) { if (!isQuiet()) { LOG_ERR("%s " RED("login error code: ") RED_BOLD("%d"), tag(), code); } close(); return; } m_failures = 0; m_listener->onLoginSuccess(this); if (m_job.isValid()) { m_listener->onJobReceived(this, m_job, result["job"]); } return; } handleSubmitResponse(id); } void xmrig::Client::ping() { send(snprintf(m_sendBuf.data(), m_sendBuf.size(), "{\"id\":%" PRId64 ",\"jsonrpc\":\"2.0\",\"method\":\"keepalived\",\"params\":{\"id\":\"%s\"}}\n", m_sequence, m_rpcId.data())); m_keepAlive = 0; } void xmrig::Client::read(ssize_t nread, const uv_buf_t *buf) { const auto size = static_cast<size_t>(nread); if (nread < 0) { if (!isQuiet()) { LOG_ERR("%s " RED("read error: ") RED_BOLD("\"%s\""), tag(), uv_strerror(static_cast<int>(nread))); } close(); return; } assert(m_listener != nullptr); if (!m_listener) { return reconnect(); } if (m_socks5) { m_socks5->read(buf->base, size); 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<int>(nread)); m_tls->read(buf->base, size); } else # endif { m_reader.parse(buf->base, size); } } void xmrig::Client::reconnect() { if (!m_listener) { m_storage.remove(m_key); return; } m_keepAlive = 0; if (m_failures == -1) { return m_listener->onClose(this, -1); } setState(ReconnectingState); m_failures++; m_listener->onClose(this, static_cast<int>(m_failures)); } void xmrig::Client::setState(SocketState state) { LOG_DEBUG("[%s] state: \"%s\" -> \"%s\"", url(), states[m_state], states[state]); if (m_state == state) { return; } switch (state) { case HostLookupState: m_expire = 0; break; case ConnectingState: m_expire = Chrono::steadyMSecs() + kConnectTimeout; break; case ReconnectingState: m_expire = Chrono::steadyMSecs() + m_retryPause; break; default: break; } m_state = state; } void xmrig::Client::startTimeout() { m_expire = 0; if (has<EXT_KEEPALIVE>()) { const uint64_t ms = static_cast<uint64_t>(m_pool.keepAlive() > 0 ? m_pool.keepAlive() : Pool::kKeepAliveTimeout) * 1000; m_keepAlive = Chrono::steadyMSecs() + ms; } } bool xmrig::Client::isCriticalError(const char *message) { if (!message) { return false; } if (strncasecmp(message, "Unauthenticated", 15) == 0) { return true; } if (strncasecmp(message, "your IP is banned", 17) == 0) { return true; } if (strncasecmp(message, "IP Address currently banned", 27) == 0) { return true; } if (strncasecmp(message, "Invalid job id", 14) == 0) { return true; } return false; } void xmrig::Client::onClose(uv_handle_t *handle) { auto client = getClient(handle->data); if (!client) { return; } client->onClose(); } void xmrig::Client::onConnect(uv_connect_t *req, int status) { auto client = getClient(req->data); delete req; if (!client) { return; } if (status < 0) { if (!client->isQuiet()) { LOG_ERR("%s " RED("connect error: ") RED_BOLD("\"%s\""), client->tag(), uv_strerror(status)); } if (client->state() == ReconnectingState || client->state() == ClosingState) { return; } if (client->state() != ConnectingState) { return; } client->close(); return; } if (client->state() == ConnectedState) { return; } client->setState(ConnectedState); uv_read_start(client->stream(), NetBuffer::onAlloc, onRead); client->handshake(); } void xmrig::Client::onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { auto client = getClient(stream->data); if (client) { client->read(nread, buf); } NetBuffer::release(buf); }
关键代码:
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); } # endif resolve(m_pool.host()); }
我们看看m_tls的类定义,
/* XMRig * Copyright (c) 2018 Lee Clagett <https://github.com/vtnerd> * Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh> * Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com> * * 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 <http://www.gnu.org/licenses/>. */ #ifndef XMRIG_CLIENT_TLS_H #define XMRIG_CLIENT_TLS_H using BIO = struct bio_st; using SSL = struct ssl_st; using SSL_CTX = struct ssl_ctx_st; using X509 = struct x509_st; #include "base/net/stratum/Client.h" #include "base/tools/Object.h" namespace xmrig { class Client::Tls { public: XMRIG_DISABLE_COPY_MOVE_DEFAULT(Tls) Tls(Client *client); ~Tls(); bool handshake(); bool send(const char *data, size_t size); const char *fingerprint() const; const char *version() const; void read(const char *data, size_t size); private: bool send(); bool verify(X509 *cert); bool verifyFingerprint(X509 *cert); BIO *m_read = nullptr; BIO *m_write = nullptr; bool m_ready = false; char m_fingerprint[32 * 2 + 8]{}; Client *m_client; SSL *m_ssl = nullptr; SSL_CTX *m_ctx; }; } /* namespace xmrig */ #endif /* XMRIG_CLIENT_TLS_H */
看看关键的函数实现,
/* XMRig * Copyright (c) 2018 Lee Clagett <https://github.com/vtnerd> * Copyright (c) 2018-2021 SChernykh <https://github.com/SChernykh> * Copyright (c) 2016-2021 XMRig <https://github.com/xmrig>, <support@xmrig.com> * * 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 <http://www.gnu.org/licenses/>. */ #include "base/net/stratum/Tls.h" #include "base/io/log/Log.h" #include "base/net/stratum/Client.h" #include "base/tools/Cvt.h" #ifdef _MSC_VER # define strncasecmp(x,y,z) _strnicmp(x,y,z) #endif #include <cassert> #include <openssl/ssl.h> xmrig::Client::Tls::Tls(Client *client) : m_client(client) { m_ctx = SSL_CTX_new(SSLv23_method()); assert(m_ctx != nullptr); if (!m_ctx) { return; } m_write = BIO_new(BIO_s_mem()); m_read = BIO_new(BIO_s_mem()); SSL_CTX_set_options(m_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); } xmrig::Client::Tls::~Tls() { if (m_ctx) { SSL_CTX_free(m_ctx); } if (m_ssl) { SSL_free(m_ssl); } } bool xmrig::Client::Tls::handshake() { m_ssl = SSL_new(m_ctx); assert(m_ssl != nullptr); if (!m_ssl) { return false; } SSL_set_connect_state(m_ssl); SSL_set_bio(m_ssl, m_read, m_write); SSL_do_handshake(m_ssl); return send(); } bool xmrig::Client::Tls::send(const char *data, size_t size) { SSL_write(m_ssl, data, size); return send(); } const char *xmrig::Client::Tls::fingerprint() const { return m_ready ? m_fingerprint : nullptr; } const char *xmrig::Client::Tls::version() const { return m_ready ? SSL_get_version(m_ssl) : nullptr; } void xmrig::Client::Tls::read(const char *data, size_t size) { BIO_write(m_read, data, size); if (!SSL_is_init_finished(m_ssl)) { const int rc = SSL_connect(m_ssl); if (rc < 0 && SSL_get_error(m_ssl, rc) == SSL_ERROR_WANT_READ) { send(); } else if (rc == 1) { X509 *cert = SSL_get_peer_certificate(m_ssl); if (!verify(cert)) { X509_free(cert); m_client->close(); return; } X509_free(cert); m_ready = true; m_client->login(); } return; } static char buf[16384]{}; int bytes_read = 0; while ((bytes_read = SSL_read(m_ssl, buf, sizeof(buf))) > 0) { m_client->m_reader.parse(buf, static_cast<size_t>(bytes_read)); } } bool xmrig::Client::Tls::send() { return m_client->send(m_write); } bool xmrig::Client::Tls::verify(X509 *cert) { if (cert == nullptr) { LOG_ERR("[%s] Failed to get server certificate", m_client->url()); return false; } if (!verifyFingerprint(cert)) { LOG_ERR("[%s] Failed to verify server certificate fingerprint", m_client->url()); const char *fingerprint = m_client->m_pool.fingerprint(); if (strlen(m_fingerprint) == 64 && fingerprint != nullptr) { LOG_ERR("\"%s\" was given", m_fingerprint); LOG_ERR("\"%s\" was configured", fingerprint); } return false; } return true; } bool xmrig::Client::Tls::verifyFingerprint(X509 *cert) { const EVP_MD *digest = EVP_get_digestbyname("sha256"); if (digest == nullptr) { return false; } unsigned char md[EVP_MAX_MD_SIZE]; unsigned int dlen = 0; if (X509_digest(cert, digest, md, &dlen) != 1) { return false; } Cvt::toHex(m_fingerprint, sizeof(m_fingerprint), md, 32); const char *fingerprint = m_client->m_pool.fingerprint(); return fingerprint == nullptr || strncasecmp(m_fingerprint, fingerprint, 64) == 0; }
从这里可以看出,支持tls1.2,和tls1.3
xmrig::Client::Tls::Tls(Client *client) : m_client(client) { m_ctx = SSL_CTX_new(SSLv23_method()); assert(m_ctx != nullptr); if (!m_ctx) { return; } m_write = BIO_new(BIO_s_mem()); m_read = BIO_new(BIO_s_mem()); SSL_CTX_set_options(m_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); }
openssl的使用可以参考: https://www.cnblogs.com/sxmcACM/p/6082907.html
/* ---------------------------------------------------------- *
51 * 发送SSL2 SSL3 TLS 1.0 TLS 2.0 TLS 3.0 与服务器建链 *
52 * ---------------------------------------------------------- */
53 method = SSLv23_client_method();
54
55 /* ---------------------------------------------------------- *
56 * 创建一个新的SSL上下文 *
57 * ---------------------------------------------------------- */
58 if ((ctx = SSL_CTX_new(method)) == NULL)
59 BIO_printf(outbio, "Unable to create a new SSL context structure.\n");
60
总结起来就是说,xmrig使用openssl的tls客户端进行加密通信。
xmrig介绍:
XMRig一款高性能开源、跨平台,支持RandomX,CryptoNight和Argon2 算法 CPU / GPU的挖矿软件。
官方下载地址:https://github.com/xmrig/xmrig/releases
备用下载地址:xmrig
网络:
-o,--url =矿池的URL
-a,--algo = ALGO挖掘算法https://xmrig.com/docs/algorithms
--coin = COIN指定硬币而不是算法
-u,--user = USERNAME采矿服务器的用户名
-p,--pass =采矿服务器的密码
-O,--userpass = U:P用户名:采矿服务器的密码对
-k,--keepalive发送keepalived数据包以防止超时(需要池支持)
--nicehash启用nicehash.com支持
--rig-id =池端统计信息的ID绑定标识符(需要池支持)
--tls启用SSL / TLS支持(需要池支持)
--tls-fingerprint =用于严格证书固定的HEX池TLS证书指纹
--daemon使用守护程序RPC而不是池进行单独挖掘
--daemon-poll-interval = N守护程序轮询间隔,以毫秒为单位(默认值:1000)
-r,--retries = N切换到备份服务器之前重试的次数(默认值:5)
-R,--retry-pause = N重试之间暂停的时间(默认值:5)
--user-agent设置池的自定义用户代理字符串
--donate-level = N捐赠级别,默认5 %%(100分钟内5分钟)
--donate-over-proxy = N控制通过xmrig-proxy功能捐赠
CPU后端:
--no-cpu禁用CPU挖掘后端
-t,--threads = N个CPU线程数
-v,--av = N算法变化,0自动选择
--cpu-affinity设置与CPU内核的进程亲和力,对于内核0和1使用掩码0x3
--cpu-priority设置进程优先级(0空闲,2正常到5最高)
--cpu-max-threads-hint = N自动配置的最大CPU线程数(百分比)提示
--cpu-memory-pool = N永久内存池的2 MB页面数,-1(自动),0(禁用)
--no-huge-pages禁用大页面支持
--asm = ASM ASM优化,可能的值:auto,none,intel,ryzen,推土机
--randomx-init = N个线程计数以初始化RandomX数据集
--randomx-no-numa禁用对RandomX的NUMA支持
API:
--api-worker-id = ID API的ID自定义工人ID
--api-id = ID API的自定义实例ID
--http-host = HOST绑定HTTP API的主机(默认值:127.0.0.1)
--http-port = N绑定HTTP API的端口
--http-access-token = HTTP API的T访问令牌
--http-no-restricted启用对HTTP API的完全远程访问(仅在设置了访问令牌的情况下)
OpenCL后端:
--opencl启用OpenCL挖掘后端
--opencl-devices = N用逗号分隔的OpenCL设备列表
--opencl-platform = N OpenCL平台索引或名称
--opencl-loader = OpenCL-ICD-Loader的路径(OpenCL.dll或libOpenCL.so)
--opencl-no-cache禁用OpenCL缓存
--print-platforms打印可用的OpenCL平台并退出
CUDA后端:
--cuda启用CUDA挖掘后端
--cuda-loader = CUDA插件的路径(xmrig-cuda.dll或libxmrig-cuda.so)
--cuda-devices =以逗号分隔的要使用的CUDA设备列表
--cuda-bfactor-hint =自动配置的N bfactor提示(0-12)
--cuda-bsleep-hint = N自动配置的睡眠提示
--no-nvml禁用NVML(NVIDIA Management Library)支持
正在记录:
-S,-syslog将系统日志用于输出消息
-l,--log-file = FILE将所有输出记录到文件
--print-time = N每N秒打印一次哈希率报告
--health-print-time =每N秒N次打印健康报告
--no-color禁用彩色输出
其他:
-c,--config = FILE加载JSON格式的配置文件
-B,--background在后台运行矿工
-V,--version输出版本信息并退出
-h,--help显示此帮助并退出
-空运行测试配置并退出
--export-topology将hwloc拓扑导出到XML文件并退出