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 &params, 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 &params, 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 &params = 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 &params, 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文件并退出

posted @ 2022-07-12 10:34  bonelee  阅读(3805)  评论(0编辑  收藏  举报