diff --git a/CMakeLists.txt b/CMakeLists.txt index 62ec419ed..8d38b1a04 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,6 +6,7 @@ option(WITH_AEON "CryptoNight-Lite support" ON) option(WITH_SUMO "CryptoNight-Heavy support" ON) option(WITH_HTTPD "HTTP REST API" ON) option(WITH_DEBUG_LOG "Enable debug log output" OFF) +option(WITH_TLS "Enable OpenSSL support" OFF) option(BUILD_STATIC "Build static binary" OFF) include (CheckIncludeFile) @@ -194,6 +195,8 @@ else() endif() endif() +include(cmake/OpenSSL.cmake) + CHECK_INCLUDE_FILE (syslog.h HAVE_SYSLOG_H) if (HAVE_SYSLOG_H) add_definitions(/DHAVE_SYSLOG_H) @@ -233,6 +236,7 @@ if (WITH_HTTPD) message(FATAL_ERROR "microhttpd NOT found: use `-DWITH_HTTPD=OFF` to build without http deamon support") endif() else() + set(HTTPD_SOURCES "") set(MHD_LIBRARY "") add_definitions(/DXMRIG_NO_HTTPD) add_definitions(/DXMRIG_NO_API) @@ -250,5 +254,5 @@ if (WITH_DEBUG_LOG) add_definitions(/DAPP_DEBUG) endif() -add_executable(${PROJECT_NAME} ${HEADERS} ${SOURCES} ${SOURCES_OS} ${SOURCES_CPUID} ${HEADERS_CRYPTO} ${SOURCES_CRYPTO} ${SOURCES_SYSLOG} ${HTTPD_SOURCES}) -target_link_libraries(${PROJECT_NAME} ${UV_LIBRARIES} ${MHD_LIBRARY} ${EXTRA_LIBS} ${CPUID_LIB}) +add_executable(${PROJECT_NAME} ${HEADERS} ${SOURCES} ${SOURCES_OS} ${SOURCES_CPUID} ${HEADERS_CRYPTO} ${SOURCES_CRYPTO} ${SOURCES_SYSLOG} ${HTTPD_SOURCES} ${TLS_SOURCES}) +target_link_libraries(${PROJECT_NAME} ${OPENSSL_LIBRARIES} ${UV_LIBRARIES} ${MHD_LIBRARY} ${EXTRA_LIBS} ${CPUID_LIB}) diff --git a/cmake/OpenSSL.cmake b/cmake/OpenSSL.cmake new file mode 100644 index 000000000..154a82789 --- /dev/null +++ b/cmake/OpenSSL.cmake @@ -0,0 +1,18 @@ +if (WITH_TLS) + set(OPENSSL_ROOT_DIR ${XMRIG_DEPS}) + set(OPENSSL_USE_STATIC_LIBS TRUE) + set(OPENSSL_MSVC_STATIC_RT TRUE) + + find_package(OpenSSL) + + if (OPENSSL_FOUND) + set(TLS_SOURCES src/common/net/Tls.h src/common/net/Tls.cpp) + include_directories(${OPENSSL_INCLUDE_DIR}) + else() + message(FATAL_ERROR "OpenSSL NOT found: use `-DWITH_TLS=OFF` to build without TLS support") + endif() +else() + set(TLS_SOURCES "") + set(OPENSSL_LIBRARIES "") + add_definitions(/DXMRIG_NO_TLS) +endif() diff --git a/src/common/Platform.cpp b/src/common/Platform.cpp index 52b55987f..a95f78e7e 100644 --- a/src/common/Platform.cpp +++ b/src/common/Platform.cpp @@ -26,6 +26,12 @@ #include +#ifndef XMRIG_NO_TLS +# include +# include +#endif + + #include "Platform.h" @@ -61,3 +67,23 @@ const char *Platform::defaultConfigName() *m_defaultConfigName = '\0'; return nullptr; } + + +void Platform::init(const char *userAgent) +{ +# ifndef XMRIG_NO_TLS + SSL_library_init(); + SSL_load_error_strings(); + ERR_load_BIO_strings(); + ERR_load_crypto_strings(); + SSL_load_error_strings(); + OpenSSL_add_all_digests(); +# endif + + if (userAgent) { + m_userAgent = userAgent; + } + else { + m_userAgent = createUserAgent(); + } +} diff --git a/src/common/Platform.h b/src/common/Platform.h index 8704604a8..5dfb9ff7f 100644 --- a/src/common/Platform.h +++ b/src/common/Platform.h @@ -21,8 +21,8 @@ * along with this program. If not, see . */ -#ifndef __PLATFORM_H__ -#define __PLATFORM_H__ +#ifndef XMRIG_PLATFORM_H +#define XMRIG_PLATFORM_H #include @@ -43,9 +43,11 @@ public: static inline const char *userAgent() { return m_userAgent.data(); } private: + static char *createUserAgent(); + static char m_defaultConfigName[520]; static xmrig::c_str m_userAgent; }; -#endif /* __PLATFORM_H__ */ +#endif /* XMRIG_PLATFORM_H */ diff --git a/src/common/Platform_mac.cpp b/src/common/Platform_mac.cpp index b8181cc49..d0c533b08 100644 --- a/src/common/Platform_mac.cpp +++ b/src/common/Platform_mac.cpp @@ -38,7 +38,7 @@ #endif -static inline char *createUserAgent() +char *Platform::createUserAgent() { const size_t max = 160; @@ -65,17 +65,6 @@ bool Platform::setThreadAffinity(uint64_t cpu_id) } -void Platform::init(const char *userAgent) -{ - if (userAgent) { - m_userAgent = userAgent; - } - else { - m_userAgent = createUserAgent(); - } -} - - void Platform::setProcessPriority(int priority) { diff --git a/src/common/Platform_unix.cpp b/src/common/Platform_unix.cpp index 97b32ee8d..058920ec5 100644 --- a/src/common/Platform_unix.cpp +++ b/src/common/Platform_unix.cpp @@ -52,7 +52,7 @@ typedef cpuset_t cpu_set_t; #endif -static inline char *createUserAgent() +char *Platform::createUserAgent() { const size_t max = 160; @@ -92,23 +92,11 @@ bool Platform::setThreadAffinity(uint64_t cpu_id) } -void Platform::init(const char *userAgent) -{ - if (userAgent) { - m_userAgent = userAgent; - } - else { - m_userAgent = createUserAgent(); - } -} - - void Platform::setProcessPriority(int priority) { } - void Platform::setThreadPriority(int priority) { if (priority == -1) { diff --git a/src/common/Platform_win.cpp b/src/common/Platform_win.cpp index 47f418671..32b850d14 100644 --- a/src/common/Platform_win.cpp +++ b/src/common/Platform_win.cpp @@ -55,7 +55,7 @@ static inline OSVERSIONINFOEX winOsVersion() } -static inline char *createUserAgent() +char *Platform::createUserAgent() { const auto osver = winOsVersion(); const size_t max = 160; @@ -94,17 +94,6 @@ bool Platform::setThreadAffinity(uint64_t cpu_id) } -void Platform::init(const char *userAgent) -{ - if (userAgent) { - m_userAgent = userAgent; - } - else { - m_userAgent = createUserAgent(); - } -} - - void Platform::setProcessPriority(int priority) { if (priority == -1) { diff --git a/src/common/config/CommonConfig.cpp b/src/common/config/CommonConfig.cpp index ca9017579..f22a632c1 100644 --- a/src/common/config/CommonConfig.cpp +++ b/src/common/config/CommonConfig.cpp @@ -157,6 +157,10 @@ bool xmrig::CommonConfig::parseBoolean(int key, bool enable) m_pools.back().setKeepAlive(enable ? Pool::kKeepAliveTimeout : 0); break; + case TlsKey: /* --tls */ + m_pools.back().setTLS(enable); + break; + # ifndef XMRIG_PROXY_PROJECT case NicehashKey: /* --nicehash */ m_pools.back().setNicehash(enable); @@ -235,6 +239,10 @@ bool xmrig::CommonConfig::parseString(int key, const char *arg) m_pools.back().setRigId(arg); break; + case FingerprintKey: /* --tls-fingerprint */ + m_pools.back().setFingerprint(arg); + break; + case VariantKey: /* --variant */ m_pools.back().algorithm().parseVariant(arg); break; @@ -269,6 +277,7 @@ bool xmrig::CommonConfig::parseString(int key, const char *arg) case SyslogKey: /* --syslog */ case KeepAliveKey: /* --keepalive */ case NicehashKey: /* --nicehash */ + case TlsKey: /* --tls */ case ApiIPv6Key: /* --api-ipv6 */ case DryRunKey: /* --dry-run */ return parseBoolean(key, true); diff --git a/src/common/interfaces/IConfig.h b/src/common/interfaces/IConfig.h index 95a4babf7..ece8e3b47 100644 --- a/src/common/interfaces/IConfig.h +++ b/src/common/interfaces/IConfig.h @@ -63,6 +63,8 @@ public: VerboseKey = 1100, VersionKey = 'V', WatchKey = 1105, + TlsKey = 1013, + FingerprintKey = 1014, // xmrig common CPUPriorityKey = 1021, @@ -80,17 +82,13 @@ public: HardwareAESKey = 1011, // xmrig amd - OclPlatformKey = 1400, - OclAffinityKey = 1401, - OclDevicesKey = 1402, - OclLaunchKey = 1403, - OclCacheKey = 1404, - OclPrintKey = 1405, - OclLoaderKey = 1406, - OclSridedIndexKey = 1407, - OclMemChunkKey = 1408, - OclUnrollKey = 1409, - OclCompModeKey = 1410, + OclPlatform = 1400, + OclAffinity = 1401, + OclDevices = 1402, + OclLaunch = 1403, + OclCache = 1404, + OclPrint = 1405, + OclLoader = 1406, // xmrig-proxy AccessLogFileKey = 'A', diff --git a/src/common/net/Client.cpp b/src/common/net/Client.cpp index 2a9db4445..1057c4742 100644 --- a/src/common/net/Client.cpp +++ b/src/common/net/Client.cpp @@ -29,6 +29,13 @@ #include +#ifndef XMRIG_NO_TLS +# include +# include +# include "common/net/Tls.h" +#endif + + #include "common/interfaces/IClientListener.h" #include "common/log/Log.h" #include "common/net/Client.h" @@ -48,6 +55,17 @@ int64_t Client::m_sequence = 1; xmrig::Storage Client::m_storage; +#ifdef APP_DEBUG +static const char *states[] = { + "unconnected", + "host-lookup", + "connecting", + "connected", + "closing" +}; +#endif + + Client::Client(int id, const char *agent, IClientListener *listener) : m_ipv6(false), m_nicehash(false), @@ -61,6 +79,7 @@ Client::Client(int id, const char *agent, IClientListener *listener) : m_failures(0), m_recvBufPos(0), m_state(UnconnectedState), + m_tls(nullptr), m_expire(0), m_jobs(0), m_keepAlive(0), @@ -92,6 +111,12 @@ Client::~Client() void Client::connect() { +# ifndef XMRIG_NO_TLS + if (m_pool.isTLS()) { + m_tls = new Tls(this); + } +# endif + resolve(m_pool.host()); } @@ -122,6 +147,7 @@ void Client::deleteLater() } + void Client::setPool(const Pool &pool) { if (!pool.isValid()) { @@ -160,6 +186,12 @@ bool Client::disconnect() } +bool Client::isTLS() const +{ + return m_pool.isTLS() && m_tls; +} + + int64_t Client::submit(const JobResult &result) { using namespace rapidjson; @@ -330,6 +362,39 @@ bool Client::parseLogin(const rapidjson::Value &result, int *code) } +bool Client::send(BIO *bio) +{ +# ifndef XMRIG_NO_TLS + uv_buf_t buf; + buf.len = BIO_get_mem_data(bio, &buf.base); + + if (buf.len == 0) { + return true; + } + + LOG_DEBUG("[%s] TLS send (%d bytes)", m_pool.url(), static_cast(buf.len)); + + bool result = false; + if (state() == ConnectedState && uv_is_writable(m_stream)) { + result = uv_try_write(m_stream, &buf, 1) > 0; + + if (!result) { + close(); + } + } + else { + LOG_DEBUG_ERR("[%s] send failed, invalid state: %d", m_pool.url(), m_state); + } + + BIO_reset(bio); + + return result; +# else + return false; +# endif +} + + bool Client::verifyAlgorithm(const xmrig::Algorithm &algorithm) const { # ifdef XMRIG_PROXY_PROJECT @@ -404,16 +469,27 @@ int64_t Client::send(const rapidjson::Document &doc) int64_t Client::send(size_t size) { LOG_DEBUG("[%s] send (%d bytes): \"%s\"", m_pool.url(), size, m_sendBuf); - if (state() != ConnectedState || !uv_is_writable(m_stream)) { - LOG_DEBUG_ERR("[%s] send failed, invalid state: %d", m_pool.url(), m_state); - return -1; + +# ifndef XMRIG_NO_TLS + if (isTLS()) { + if (!m_tls->send(m_sendBuf, size)) { + return -1; + } } + else +# endif + { + if (state() != ConnectedState || !uv_is_writable(m_stream)) { + LOG_DEBUG_ERR("[%s] send failed, invalid state: %d", m_pool.url(), m_state); + return -1; + } - uv_buf_t buf = uv_buf_init(m_sendBuf, (unsigned int) size); + uv_buf_t buf = uv_buf_init(m_sendBuf, (unsigned int) size); - if (uv_try_write(m_stream, &buf, 1) < 0) { - close(); - return -1; + if (uv_try_write(m_stream, &buf, 1) < 0) { + close(); + return -1; + } } m_expire = uv_now(uv_default_loop()) + kResponseTimeout; @@ -463,6 +539,22 @@ void Client::connect(sockaddr *addr) } +void Client::handshake() +{ +# ifndef XMRIG_NO_TLS + if (isTLS()) { + m_expire = uv_now(uv_default_loop()) + kResponseTimeout; + + m_tls->handshake(); + } + else +# endif + { + login(); + } +} + + void Client::login() { using namespace rapidjson; @@ -511,6 +603,13 @@ void Client::onClose() m_socket = nullptr; setState(UnconnectedState); +# ifndef XMRIG_NO_TLS + if (m_tls) { + delete m_tls; + m_tls = nullptr; + } +# endif + reconnect(); } @@ -665,6 +764,35 @@ void Client::ping() } +void Client::read() +{ + char* end; + char* start = m_recvBuf.base; + size_t remaining = m_recvBufPos; + + while ((end = static_cast(memchr(start, '\n', remaining))) != nullptr) { + end++; + size_t len = end - start; + parse(start, len); + + remaining -= len; + start = end; + } + + if (remaining == 0) { + m_recvBufPos = 0; + return; + } + + if (start == m_recvBuf.base) { + return; + } + + memcpy(m_recvBuf.base, start, remaining); + m_recvBufPos = remaining; +} + + void Client::reconnect() { if (!m_listener) { @@ -689,7 +817,7 @@ void Client::reconnect() void Client::setState(SocketState state) { - LOG_DEBUG("[%s] state: %d", m_pool.url(), state); + LOG_DEBUG("[%s] state: \"%s\"", m_pool.url(), states[state]); if (m_state == state) { return; @@ -757,7 +885,7 @@ void Client::onConnect(uv_connect_t *req, int status) uv_read_start(client->m_stream, Client::onAllocBuffer, Client::onRead); delete req; - client->login(); + client->handshake(); } @@ -789,30 +917,18 @@ void Client::onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) client->m_recvBufPos += nread; - char* end; - char* start = client->m_recvBuf.base; - size_t remaining = client->m_recvBufPos; +# ifndef XMRIG_NO_TLS + if (client->isTLS()) { + LOG_DEBUG("[%s] TLS received (%d bytes)", client->m_pool.url(), static_cast(nread)); - while ((end = static_cast(memchr(start, '\n', remaining))) != nullptr) { - end++; - size_t len = end - start; - client->parse(start, len); - - remaining -= len; - start = end; - } - - if (remaining == 0) { + client->m_tls->read(client->m_recvBuf.base, client->m_recvBufPos); client->m_recvBufPos = 0; - return; } - - if (start == client->m_recvBuf.base) { - return; + else +# endif + { + client->read(); } - - memcpy(client->m_recvBuf.base, start, remaining); - client->m_recvBufPos = remaining; } diff --git a/src/common/net/Client.h b/src/common/net/Client.h index 4be8badba..893fabfc8 100644 --- a/src/common/net/Client.h +++ b/src/common/net/Client.h @@ -21,8 +21,8 @@ * along with this program. If not, see . */ -#ifndef __CLIENT_H__ -#define __CLIENT_H__ +#ifndef XMRIG_CLIENT_H +#define XMRIG_CLIENT_H #include @@ -43,6 +43,9 @@ class IClientListener; class JobResult; +typedef struct bio_st BIO; + + class Client { public: @@ -54,12 +57,19 @@ public: ClosingState }; - constexpr static int kResponseTimeout = 20 * 1000; + constexpr static int kResponseTimeout = 20 * 1000; + +# ifndef XMRIG_NO_TLS + constexpr static int kInputBufferSize = 1024 * 16; +# else + constexpr static int kInputBufferSize = 1024 * 2; +# endif Client(int id, const char *agent, IClientListener *listener); ~Client(); bool disconnect(); + bool isTLS() const; int64_t submit(const JobResult &result); void connect(); void connect(const Pool &pool); @@ -80,6 +90,9 @@ public: inline void setRetryPause(int ms) { m_retryPause = ms; } private: + class Tls; + + enum Extensions { NicehashExt = 1, AlgoExt = 2 @@ -89,12 +102,14 @@ private: bool isCriticalError(const char *message); bool parseJob(const rapidjson::Value ¶ms, int *code); bool parseLogin(const rapidjson::Value &result, int *code); + bool send(BIO *bio); bool verifyAlgorithm(const xmrig::Algorithm &algorithm) const; int resolve(const char *host); int64_t send(const rapidjson::Document &doc); int64_t send(size_t size); void connect(const std::vector &ipv4, const std::vector &ipv6); void connect(sockaddr *addr); + void handshake(); void login(); void onClose(); void parse(char *line, size_t len); @@ -102,6 +117,7 @@ private: void parseNotification(const char *method, const rapidjson::Value ¶ms, const rapidjson::Value &error); void parseResponse(int64_t id, const rapidjson::Value &result, const rapidjson::Value &error); void ping(); + void read(); void reconnect(); void setState(SocketState state); void startTimeout(); @@ -120,9 +136,9 @@ private: bool m_ipv6; bool m_nicehash; bool m_quiet; - char m_buf[2048]; + char m_buf[kInputBufferSize]; char m_ip[46]; - char m_sendBuf[768]; + char m_sendBuf[1024]; const char *m_agent; IClientListener *m_listener; int m_extensions; @@ -135,6 +151,7 @@ private: size_t m_recvBufPos; SocketState m_state; std::map m_results; + Tls *m_tls; uint64_t m_expire; uint64_t m_jobs; uint64_t m_keepAlive; @@ -150,4 +167,4 @@ private: }; -#endif /* __CLIENT_H__ */ +#endif /* XMRIG_CLIENT_H */ diff --git a/src/common/net/Pool.cpp b/src/common/net/Pool.cpp index 49f4e54c7..02bf5fa54 100644 --- a/src/common/net/Pool.cpp +++ b/src/common/net/Pool.cpp @@ -46,6 +46,7 @@ Pool::Pool() : m_nicehash(false), + m_tls(false), m_keepAlive(0), m_port(kDefaultPort) { @@ -65,6 +66,7 @@ Pool::Pool() : */ Pool::Pool(const char *url) : m_nicehash(false), + m_tls(false), m_keepAlive(0), m_port(kDefaultPort) { @@ -72,8 +74,9 @@ Pool::Pool(const char *url) : } -Pool::Pool(const char *host, uint16_t port, const char *user, const char *password, int keepAlive, bool nicehash) : +Pool::Pool(const char *host, uint16_t port, const char *user, const char *password, int keepAlive, bool nicehash, bool tls) : m_nicehash(nicehash), + m_tls(tls), m_keepAlive(keepAlive), m_port(port), m_host(host), @@ -134,7 +137,13 @@ bool Pool::parse(const char *url) const char *base = url; if (p) { - if (strncasecmp(url, "stratum+tcp://", 14)) { + if (strncasecmp(url, "stratum+tcp://", 14) == 0) { + m_tls = false; + } + else if (strncasecmp(url, "stratum+ssl://", 14) == 0) { + m_tls = true; + } + else { return false; } @@ -221,6 +230,9 @@ rapidjson::Value Pool::toJSON(rapidjson::Document &doc) const break; } + obj.AddMember("tls", isTLS(), allocator); + obj.AddMember("tls-fingerprint", fingerprint() ? Value(StringRef(fingerprint())).Move() : Value(kNullType).Move(), allocator); + return obj; } diff --git a/src/common/net/Pool.h b/src/common/net/Pool.h index 0641b851d..123cc131f 100644 --- a/src/common/net/Pool.h +++ b/src/common/net/Pool.h @@ -45,30 +45,35 @@ public: Pool(); Pool(const char *url); Pool(const char *host, - uint16_t port, - const char *user = nullptr, - const char *password = nullptr, - int keepAlive = 0, - bool nicehash = false + uint16_t port, + const char *user = nullptr, + const char *password = nullptr, + int keepAlive = 0, + bool nicehash = false, + bool tls = false ); - inline bool isNicehash() const { return m_nicehash; } - inline bool isValid() const { return !m_host.isNull() && m_port > 0; } - inline const char *host() const { return m_host.data(); } - inline const char *password() const { return !m_password.isNull() ? m_password.data() : kDefaultPassword; } - inline const char *rigId() const { return m_rigId.data(); } - inline const char *url() const { return m_url.data(); } - inline const char *user() const { return !m_user.isNull() ? m_user.data() : kDefaultUser; } - inline const xmrig::Algorithm &algorithm() const { return m_algorithm; } - inline const xmrig::Algorithms &algorithms() const { return m_algorithms; } - inline int keepAlive() const { return m_keepAlive; } - inline uint16_t port() const { return m_port; } - inline void setKeepAlive(int keepAlive) { m_keepAlive = keepAlive >= 0 ? keepAlive : 0; } - inline void setNicehash(bool nicehash) { m_nicehash = nicehash; } - inline void setPassword(const char *password) { m_password = password; } - inline void setRigId(const char *rigId) { m_rigId = rigId; } - inline void setUser(const char *user) { m_user = user; } - inline xmrig::Algorithm &algorithm() { return m_algorithm; } + inline bool isNicehash() const { return m_nicehash; } + inline bool isTLS() const { return m_tls; } + inline bool isValid() const { return !m_host.isNull() && m_port > 0; } + inline const char *fingerprint() const { return m_fingerprint.data(); } + inline const char *host() const { return m_host.data(); } + inline const char *password() const { return !m_password.isNull() ? m_password.data() : kDefaultPassword; } + inline const char *rigId() const { return m_rigId.data(); } + inline const char *url() const { return m_url.data(); } + inline const char *user() const { return !m_user.isNull() ? m_user.data() : kDefaultUser; } + inline const xmrig::Algorithm &algorithm() const { return m_algorithm; } + inline const xmrig::Algorithms &algorithms() const { return m_algorithms; } + inline int keepAlive() const { return m_keepAlive; } + inline uint16_t port() const { return m_port; } + inline void setFingerprint(const char *fingerprint) { m_fingerprint = fingerprint; } + inline void setKeepAlive(int keepAlive) { m_keepAlive = keepAlive >= 0 ? keepAlive : 0; } + inline void setNicehash(bool nicehash) { m_nicehash = nicehash; } + inline void setPassword(const char *password) { m_password = password; } + inline void setRigId(const char *rigId) { m_rigId = rigId; } + inline void setTLS(bool tls) { m_tls = tls; } + inline void setUser(const char *user) { m_user = user; } + inline xmrig::Algorithm &algorithm() { return m_algorithm; } inline bool operator!=(const Pool &other) const { return !isEqual(other); } inline bool operator==(const Pool &other) const { return isEqual(other); } @@ -92,10 +97,12 @@ private: void rebuild(); bool m_nicehash; + bool m_tls; int m_keepAlive; uint16_t m_port; xmrig::Algorithm m_algorithm; xmrig::Algorithms m_algorithms; + xmrig::c_str m_fingerprint; xmrig::c_str m_host; xmrig::c_str m_password; xmrig::c_str m_rigId; diff --git a/src/common/net/Tls.cpp b/src/common/net/Tls.cpp new file mode 100644 index 000000000..679e5d240 --- /dev/null +++ b/src/common/net/Tls.cpp @@ -0,0 +1,136 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2018 Lee Clagett + * Copyright 2018 SChernykh + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + + +#include + + +#include "common/net/Client.h" +#include "common/net/Tls.h" +#include "common/log/Log.h" + + +Client::Tls::Tls(Client *client) : + m_buf(), + m_client(client), + m_ssl(nullptr) +{ + m_ctx = SSL_CTX_new(SSLv23_method()); + assert(m_ctx != nullptr); + + if (!m_ctx) { + return; + } + + m_writeBio = BIO_new(BIO_s_mem()); + m_readBio = BIO_new(BIO_s_mem()); + SSL_CTX_set_options(m_ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); +} + + +Client::Tls::~Tls() +{ + if (m_ctx) { + SSL_CTX_free(m_ctx); + } + + if (m_ssl) { + SSL_free(m_ssl); + } +} + + +bool 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_readBio, m_writeBio); + SSL_do_handshake(m_ssl); + + return send(); +} + + +bool Client::Tls::send(const char *data, size_t size) +{ + SSL_write(m_ssl, data, size); + + return send(); +} + + +void Client::Tls::read(const char *data, size_t size) +{ + BIO_write(m_readBio, 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(); + } + + if (rc == 1) { + if (!verify()) { + LOG_ERR("[%s] TLS certificate verification failed", m_client->m_pool.url()); + m_client->close(); + + return; + } + + m_client->login(); + } + + return; + } + + int bytes_read = 0; + while ((bytes_read = SSL_read(m_ssl, m_buf, sizeof(m_buf))) > 0) { + m_client->parse(m_buf, bytes_read); + } +} + + +bool Client::Tls::send() +{ + return m_client->send(m_writeBio); +} + + +bool Client::Tls::verify() +{ + X509* cert = SSL_get_peer_certificate(m_ssl); + if (cert == nullptr) { + return false; + } + + return true; +} diff --git a/src/common/net/Tls.h b/src/common/net/Tls.h new file mode 100644 index 000000000..134742378 --- /dev/null +++ b/src/common/net/Tls.h @@ -0,0 +1,58 @@ +/* XMRig + * Copyright 2010 Jeff Garzik + * Copyright 2012-2014 pooler + * Copyright 2014 Lucas Jones + * Copyright 2014-2016 Wolf9466 + * Copyright 2016 Jay D Dee + * Copyright 2017-2018 XMR-Stak , + * Copyright 2016-2018 XMRig , + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef XMRIG_TLS_H +#define XMRIG_TLS_H + + +#include + + +#include "common/net/Client.h" + + +class Client::Tls +{ +public: + Tls(Client *client); + ~Tls(); + + bool handshake(); + bool send(const char *data, size_t size); + + void read(const char *data, size_t size); + +private: + bool send(); + bool verify(); + + BIO *m_readBio; + BIO *m_writeBio; + char m_buf[1024 * 2]; + Client *m_client; + SSL *m_ssl; + SSL_CTX *m_ctx; +}; + + +#endif /* XMRIG_TLS_H */ diff --git a/src/core/ConfigLoader_platform.h b/src/core/ConfigLoader_platform.h index 987242716..c034f3e75 100644 --- a/src/core/ConfigLoader_platform.h +++ b/src/core/ConfigLoader_platform.h @@ -132,6 +132,8 @@ static struct option const options[] = { { "user-agent", 1, nullptr, xmrig::IConfig::UserAgentKey }, { "userpass", 1, nullptr, xmrig::IConfig::UserpassKey }, { "rig-id", 1, nullptr, xmrig::IConfig::RigIdKey }, + { "tls", 0, nullptr, xmrig::IConfig::TlsKey }, + { "tls-fingerprint", 1, nullptr, xmrig::IConfig::FingerprintKey }, { "version", 0, nullptr, xmrig::IConfig::VersionKey }, { nullptr, 0, nullptr, 0 } }; @@ -162,15 +164,17 @@ static struct option const config_options[] = { static struct option const pool_options[] = { - { "url", 1, nullptr, xmrig::IConfig::UrlKey }, - { "pass", 1, nullptr, xmrig::IConfig::PasswordKey }, - { "user", 1, nullptr, xmrig::IConfig::UserKey }, - { "userpass", 1, nullptr, xmrig::IConfig::UserpassKey }, - { "nicehash", 0, nullptr, xmrig::IConfig::NicehashKey }, - { "keepalive", 2, nullptr, xmrig::IConfig::KeepAliveKey }, - { "variant", 1, nullptr, xmrig::IConfig::VariantKey }, - { "rig-id", 1, nullptr, xmrig::IConfig::RigIdKey }, - { nullptr, 0, nullptr, 0 } + { "url", 1, nullptr, xmrig::IConfig::UrlKey }, + { "pass", 1, nullptr, xmrig::IConfig::PasswordKey }, + { "user", 1, nullptr, xmrig::IConfig::UserKey }, + { "userpass", 1, nullptr, xmrig::IConfig::UserpassKey }, + { "nicehash", 0, nullptr, xmrig::IConfig::NicehashKey }, + { "keepalive", 2, nullptr, xmrig::IConfig::KeepAliveKey }, + { "variant", 1, nullptr, xmrig::IConfig::VariantKey }, + { "rig-id", 1, nullptr, xmrig::IConfig::RigIdKey }, + { "tls", 0, nullptr, xmrig::IConfig::TlsKey }, + { "tls-fingerprint", 1, nullptr, xmrig::IConfig::FingerprintKey }, + { nullptr, 0, nullptr, 0 } };