diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0010171..72c9fc8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -13,6 +13,8 @@ if("${MHTD}" STREQUAL "MHTD-NOTFOUND")
message(FATAL_ERROR "libmicrohttpd is required")
endif()
+find_package(OpenSSL REQUIRED)
+
#set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_CONFIGURATION_TYPES "RELEASE;STATIC")
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
@@ -30,6 +32,6 @@ set(EXECUTABLE_OUTPUT_PATH "bin")
file(GLOB SOURCES "crypto/*.c" "crypto/*.cpp" "amd_gpu/*.c" "*.cpp")
add_executable(xmr-stak-amd ${SOURCES})
-target_link_libraries(xmr-stak-amd pthread microhttpd OpenCL)
+target_link_libraries(xmr-stak-amd pthread microhttpd OpenCL crypto ssl)
diff --git a/cli-miner.cpp b/cli-miner.cpp
index 250d6ed..184d5aa 100644
--- a/cli-miner.cpp
+++ b/cli-miner.cpp
@@ -11,6 +11,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
+ *
+ * Additional permission under GNU GPL version 3 section 7
+ *
+ * If you modify this Program, or any covered work, by linking or combining
+ * it with OpenSSL (or a modified version of that library), containing parts
+ * covered by the terms of OpenSSL License and SSLeay License, the licensors
+ * of this Program grant you additional permission to convey the resulting work.
+ *
*/
#include "executor.h"
@@ -24,6 +32,8 @@
#include
#include
+#include
+
//Do a press any key for the windows folk. *insert any key joke here*
#ifdef _WIN32
void win_exit()
@@ -39,9 +49,17 @@ void win_exit()
void win_exit() { return; }
#endif // _WIN32
+void do_benchmark();
+
int main(int argc, char *argv[])
{
+ SSL_library_init();
+ SSL_load_error_strings();
+ ERR_load_BIO_strings();
+ OpenSSL_add_all_digests();
+
const char* sFilename = "config.txt";
+ bool benchmark_mode = false;
if(argc >= 2)
{
@@ -53,7 +71,14 @@ int main(int argc, char *argv[])
}
if(argc >= 3 && strcasecmp(argv[1], "-c") == 0)
+ {
sFilename = argv[2];
+ }
+ else if(argc >= 3 && strcasecmp(argv[1], "benchmark_mode") == 0)
+ {
+ sFilename = argv[2];
+ benchmark_mode = true;
+ }
else
sFilename = argv[1];
}
@@ -70,6 +95,13 @@ int main(int argc, char *argv[])
return 0;
}
+ if(benchmark_mode)
+ {
+ do_benchmark();
+ win_exit();
+ return 0;
+ }
+
if(jconf::inst()->GetHttpdPort() != 0)
{
if (!httpd::inst()->start_daemon())
@@ -92,6 +124,9 @@ int main(int argc, char *argv[])
printer::inst()->print_str("'c' - connection\n");
printer::inst()->print_str("-------------------------------------------------------------------\n");
+ if(strlen(jconf::inst()->GetOutputFile()) != 0)
+ printer::inst()->open_logfile(jconf::inst()->GetOutputFile());
+
executor::inst()->ex_start();
int key;
@@ -117,3 +152,34 @@ int main(int argc, char *argv[])
return 0;
}
+
+void do_benchmark()
+{
+ using namespace std::chrono;
+ std::vector* pvThreads;
+
+ printer::inst()->print_msg(L0, "Running a 60 second benchmark...");
+
+ uint8_t work[76] = {0};
+ minethd::miner_work oWork = minethd::miner_work("", work, sizeof(work), 0, 0, 0);
+ pvThreads = minethd::thread_starter(oWork);
+
+ uint64_t iStartStamp = time_point_cast(high_resolution_clock::now()).time_since_epoch().count();
+
+ std::this_thread::sleep_for(std::chrono::seconds(60));
+
+ oWork = minethd::miner_work();
+ minethd::switch_work(oWork);
+
+ double fTotalHps = 0.0;
+ for (uint32_t i = 0; i < pvThreads->size(); i++)
+ {
+ double fHps = pvThreads->at(i)->iHashCount;
+ fHps /= (pvThreads->at(i)->iTimestamp - iStartStamp) / 1000.0;
+
+ printer::inst()->print_msg(L0, "Thread %u: %.1f H/S", i, fHps);
+ fTotalHps += fHps;
+ }
+
+ printer::inst()->print_msg(L0, "Total: %.1f H/S", fTotalHps);
+}
diff --git a/config.txt b/config.txt
index 44dbf2f..0d6e254 100644
--- a/config.txt
+++ b/config.txt
@@ -24,6 +24,19 @@
*/
"platform_index" : 0,
+/*
+ * TLS Settings
+ * If you need real security, make sure tls_secure_algo is enabled (otherwise MITM attack can downgrade encryption
+ * to trivially breakable stuff like DES and MD5), and verify the server's fingerprint through a trusted channel.
+ *
+ * use_tls - This option will make us connect using Transport Layer Security.
+ * tls_secure_algo - Use only secure algorithms. This will make us quit with an error if we can't negotiate a secure algo.
+ * tls_fingerprint - Server's SHA256 fingerprint. If this string is non-empty then we will check the server's cert against it.
+ */
+"use_tls" : false,
+"tls_secure_algo" : true,
+"tls_fingerprint" : "",
+
/*
* pool_address - Pool address should be in the form "pool.supportxmr.com:3333". Only stratum pools are supported.
* wallet_address - Your wallet, or pool login.
@@ -44,9 +57,12 @@
* call_timeout - How long should we wait for a response from the server before we assume it is dead and drop the connection.
* retry_time - How long should we wait before another connection attempt.
* Both values are in seconds.
+ * giveup_limit - Limit how many times we try to reconnect to the pool. Zero means no limit. Note that stak miners
+ * don't mine while the connection is lost, so your computer's power usage goes down to idle.
*/
"call_timeout" : 10,
"retry_time" : 10,
+"giveup_limit" : 0,
/*
* Output control.
@@ -71,6 +87,14 @@
*/
"h_print_time" : 60,
+/*
+ * Output file
+ *
+ * output_file - This option will log all output to a file.
+ *
+ */
+"output_file" : "",
+
/*
* Built-in web server
* I like checking my hashrate on my phone. Don't you?
diff --git a/console.cpp b/console.cpp
index 5550359..62b6957 100644
--- a/console.cpp
+++ b/console.cpp
@@ -11,6 +11,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
+ *
+ * Additional permission under GNU GPL version 3 section 7
+ *
+ * If you modify this Program, or any covered work, by linking or combining
+ * it with OpenSSL (or a modified version of that library), containing parts
+ * covered by the terms of OpenSSL License and SSLeay License, the licensors
+ * of this Program grant you additional permission to convey the resulting work.
+ *
*/
#include "console.h"
@@ -147,6 +155,13 @@ printer* printer::oInst = nullptr;
printer::printer()
{
verbose_level = LINF;
+ logfile = nullptr;
+}
+
+bool printer::open_logfile(const char* file)
+{
+ logfile = fopen(file, "ab+");
+ return logfile != nullptr;
}
void printer::print_msg(verbosity verbose, const char* fmt, ...)
@@ -177,12 +192,24 @@ void printer::print_msg(verbosity verbose, const char* fmt, ...)
std::unique_lock lck(print_mutex);
fputs(buf, stdout);
+
+ if(logfile != nullptr)
+ {
+ fputs(buf, logfile);
+ fflush(logfile);
+ }
}
void printer::print_str(const char* str)
{
std::unique_lock lck(print_mutex);
fputs(str, stdout);
+
+ if(logfile != nullptr)
+ {
+ fputs(str, logfile);
+ fflush(logfile);
+ }
}
extern "C" void printer_print_msg(const char* fmt, ...)
diff --git a/console.h b/console.h
index 5c86830..47c3c94 100644
--- a/console.h
+++ b/console.h
@@ -31,6 +31,7 @@ public:
inline void set_verbose_level(size_t level) { verbose_level = (verbosity)level; }
void print_msg(verbosity verbose, const char* fmt, ...);
void print_str(const char* str);
+ bool open_logfile(const char* file);
private:
printer();
@@ -38,4 +39,5 @@ private:
std::mutex print_mutex;
verbosity verbose_level;
+ FILE* logfile;
};
diff --git a/crypto/cryptonight_common.cpp b/crypto/cryptonight_common.cpp
index 533dd6a..2c90d78 100644
--- a/crypto/cryptonight_common.cpp
+++ b/crypto/cryptonight_common.cpp
@@ -11,6 +11,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
+ *
+ * Additional permission under GNU GPL version 3 section 7
+ *
+ * If you modify this Program, or any covered work, by linking or combining
+ * it with OpenSSL (or a modified version of that library), containing parts
+ * covered by the terms of OpenSSL License and SSLeay License, the licensors
+ * of this Program grant you additional permission to convey the resulting work.
+ *
*/
extern "C"
diff --git a/crypto/soft_aes.c b/crypto/soft_aes.c
index 76c9c1c..b8309cf 100644
--- a/crypto/soft_aes.c
+++ b/crypto/soft_aes.c
@@ -11,6 +11,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
+ *
+ * Additional permission under GNU GPL version 3 section 7
+ *
+ * If you modify this Program, or any covered work, by linking or combining
+ * it with OpenSSL (or a modified version of that library), containing parts
+ * covered by the terms of OpenSSL License and SSLeay License, the licensors
+ * of this Program grant you additional permission to convey the resulting work.
+ *
*/
/*
diff --git a/donate-level.h b/donate-level.h
index 7b30212..ccae28f 100644
--- a/donate-level.h
+++ b/donate-level.h
@@ -6,6 +6,10 @@
* Example of how it works for the default setting of 1.0:
* You miner will mine into your usual pool for 99 minutes, then switch to the developer's pool for 1.0 minute.
* Switching is instant, and only happens after a successful connection, so you never loose any hashes.
+ *
+ * If you plan on changing this setting to 0.0 please consider making a one off donation to my wallet:
+ * 4581HhZkQHgZrZjKeCfCJxZff9E3xCgHGF25zABZz7oR71TnbbgiS7sK9jveE6Dx6uMs2LwszDuvQJgRZQotdpHt1fTdDhk
+ *
*/
constexpr double fDevDonationLevel = 1.0 / 100.0;
diff --git a/executor.cpp b/executor.cpp
index bbab126..fc7ead5 100644
--- a/executor.cpp
+++ b/executor.cpp
@@ -11,6 +11,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
+ *
+ * Additional permission under GNU GPL version 3 section 7
+ *
+ * If you modify this Program, or any covered work, by linking or combining
+ * it with OpenSSL (or a modified version of that library), containing parts
+ * covered by the terms of OpenSSL License and SSLeay License, the licensors
+ * of this Program grant you additional permission to convey the resulting work.
+ *
*/
#include
@@ -103,8 +111,17 @@ void executor::ex_clock_thd()
void executor::sched_reconnect()
{
+ iReconnectAttempts++;
+ size_t iLimit = jconf::inst()->GetGiveUpLimit();
+ if(iLimit != 0 && iReconnectAttempts > iLimit)
+ {
+ printer::inst()->print_msg(L0, "Give up limit reached. Exitting.");
+ exit(0);
+ }
+
long long unsigned int rt = jconf::inst()->GetNetRetry();
- printer::inst()->print_msg(L1, "Pool connection lost. Waiting %lld s before retry.", rt);
+ printer::inst()->print_msg(L1, "Pool connection lost. Waiting %lld s before retry (attempt %llu).",
+ rt, int_port(iReconnectAttempts));
auto work = minethd::miner_work();
minethd::switch_work(work);
@@ -185,7 +202,10 @@ void executor::on_sock_ready(size_t pool_id)
}
}
else
+ {
+ iReconnectAttempts = 0;
reset_stats();
+ }
}
void executor::on_sock_error(size_t pool_id, std::string&& sError)
@@ -333,7 +353,8 @@ void executor::on_switch_pool(size_t pool_id)
// If it fails, it fails, we carry on on the usr pool
// as we never receive further events
printer::inst()->print_msg(L1, "Connecting to dev pool...");
- if(!pool->connect("donate.xmr-stak.net:3333", error))
+ const char* dev_pool_addr = jconf::inst()->GetTlsSetting() ? "donate.xmr-stak.net:6666" : "donate.xmr-stak.net:3333";
+ if(!pool->connect(dev_pool_addr, error))
printer::inst()->print_msg(L1, "Error connecting to dev pool. Staying with user pool.");
}
else
@@ -368,8 +389,8 @@ void executor::ex_main()
telem = new telemetry(pvThreads->size());
current_pool_id = usr_pool_id;
- usr_pool = new jpsock(usr_pool_id);
- dev_pool = new jpsock(dev_pool_id);
+ usr_pool = new jpsock(usr_pool_id, jconf::inst()->GetTlsSetting());
+ dev_pool = new jpsock(dev_pool_id, jconf::inst()->GetTlsSetting());
ex_event ev;
std::thread clock_thd(&executor::ex_clock_thd, this);
diff --git a/executor.h b/executor.h
index 81aad08..dc5274b 100644
--- a/executor.h
+++ b/executor.h
@@ -29,6 +29,10 @@ public:
inline void push_event(ex_event&& ev) { oEventQ.push(std::move(ev)); }
void push_timed_event(ex_event&& ev, size_t sec);
+ constexpr static size_t invalid_pool_id = 0;
+ constexpr static size_t dev_pool_id = 1;
+ constexpr static size_t usr_pool_id = 2;
+
private:
struct timed_event
{
@@ -47,10 +51,6 @@ private:
// We will divide up this period according to the config setting
constexpr static size_t iDevDonatePeriod = 100 * 60;
- constexpr static size_t invalid_pool_id = 0;
- constexpr static size_t dev_pool_id = 1;
- constexpr static size_t usr_pool_id = 2;
-
std::list lTimedEvents;
std::mutex timed_event_mutex;
thdq oEventQ;
@@ -85,6 +85,8 @@ private:
std::promise httpReady;
std::mutex httpMutex;
+ size_t iReconnectAttempts = 0;
+
struct sck_error_log
{
std::chrono::system_clock::time_point time;
diff --git a/httpd.cpp b/httpd.cpp
index 339d15f..a21e4cd 100644
--- a/httpd.cpp
+++ b/httpd.cpp
@@ -1,3 +1,26 @@
+/*
+ * 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
+ * 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 .
+ *
+ * Additional permission under GNU GPL version 3 section 7
+ *
+ * If you modify this Program, or any covered work, by linking or combining
+ * it with OpenSSL (or a modified version of that library), containing parts
+ * covered by the terms of OpenSSL License and SSLeay License, the licensors
+ * of this Program grant you additional permission to convey the resulting work.
+ *
+ */
+
#include
#include
#include
diff --git a/jconf.cpp b/jconf.cpp
index d9a2589..5d22f80 100644
--- a/jconf.cpp
+++ b/jconf.cpp
@@ -11,6 +11,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
+ *
+ * Additional permission under GNU GPL version 3 section 7
+ *
+ * If you modify this Program, or any covered work, by linking or combining
+ * it with OpenSSL (or a modified version of that library), containing parts
+ * covered by the terms of OpenSSL License and SSLeay License, the licensors
+ * of this Program grant you additional permission to convey the resulting work.
+ *
*/
#include "jconf.h"
@@ -37,8 +45,10 @@ using namespace rapidjson;
/*
* This enum needs to match index in oConfigValues, otherwise we will get a runtime error
*/
-enum configEnum { iGpuThreadNum, aGpuThreadsConf, iPlatformIdx, sPoolAddr, sWalletAddr,
- sPoolPwd, iCallTimeout, iNetRetry, iVerboseLevel, iAutohashTime, iHttpdPort, bPreferIpv4 };
+enum configEnum { iGpuThreadNum, aGpuThreadsConf, iPlatformIdx,
+ bTlsMode, bTlsSecureAlgo, sTlsFingerprint, sPoolAddr, sWalletAddr, sPoolPwd,
+ iCallTimeout, iNetRetry, iGiveUpLimit, iVerboseLevel, iAutohashTime,
+ sOutputFile, iHttpdPort, bPreferIpv4 };
struct configVal {
configEnum iName;
@@ -51,13 +61,18 @@ configVal oConfigValues[] = {
{ iGpuThreadNum, "gpu_thread_num", kNumberType },
{ aGpuThreadsConf, "gpu_threads_conf", kArrayType },
{ iPlatformIdx, "platform_index", kNumberType },
+ { bTlsMode, "use_tls", kTrueType },
+ { bTlsSecureAlgo, "tls_secure_algo", kTrueType },
+ { sTlsFingerprint, "tls_fingerprint", kStringType },
{ sPoolAddr, "pool_address", kStringType },
{ sWalletAddr, "wallet_address", kStringType },
{ sPoolPwd, "pool_password", kStringType },
{ iCallTimeout, "call_timeout", kNumberType },
{ iNetRetry, "retry_time", kNumberType },
+ { iGiveUpLimit, "giveup_limit", kNumberType },
{ iVerboseLevel, "verbose_level", kNumberType },
{ iAutohashTime, "h_print_time", kNumberType },
+ { sOutputFile, "output_file", kStringType },
{ iHttpdPort, "httpd_port", kNumberType },
{ bPreferIpv4, "prefer_ipv4", kTrueType }
};
@@ -135,6 +150,21 @@ size_t jconf::GetPlatformIdx()
return prv->configValues[iPlatformIdx]->GetUint64();
}
+bool jconf::GetTlsSetting()
+{
+ return prv->configValues[bTlsMode]->GetBool();
+}
+
+bool jconf::TlsSecureAlgos()
+{
+ return prv->configValues[bTlsSecureAlgo]->GetBool();
+}
+
+const char* jconf::GetTlsFingerprint()
+{
+ return prv->configValues[sTlsFingerprint]->GetString();
+}
+
const char* jconf::GetPoolAddress()
{
return prv->configValues[sPoolAddr]->GetString();
@@ -170,6 +200,11 @@ uint64_t jconf::GetNetRetry()
return prv->configValues[iNetRetry]->GetUint64();
}
+uint64_t jconf::GetGiveUpLimit()
+{
+ return prv->configValues[iGiveUpLimit]->GetUint64();
+}
+
uint64_t jconf::GetVerboseLevel()
{
return prv->configValues[iVerboseLevel]->GetUint64();
@@ -185,6 +220,11 @@ uint16_t jconf::GetHttpdPort()
return prv->configValues[iHttpdPort]->GetUint();
}
+const char* jconf::GetOutputFile()
+{
+ return prv->configValues[sOutputFile]->GetString();
+}
+
bool jconf::check_cpu_features()
{
constexpr int AESNI_BIT = 1 << 25;
@@ -319,10 +359,12 @@ bool jconf::parse_config(const char* sFilename)
}
}
- if(!prv->configValues[iCallTimeout]->IsUint64() || !prv->configValues[iNetRetry]->IsUint64())
+ if(!prv->configValues[iCallTimeout]->IsUint64() ||
+ !prv->configValues[iNetRetry]->IsUint64() ||
+ !prv->configValues[iGiveUpLimit]->IsUint64())
{
printer::inst()->print_msg(L0,
- "Invalid config file. call_timeout and retry_time need to be positive integers.");
+ "Invalid config file. call_timeout, retry_time and giveup_limit need to be positive integers.");
return false;
}
diff --git a/jconf.h b/jconf.h
index d069167..51af4d2 100644
--- a/jconf.h
+++ b/jconf.h
@@ -25,6 +25,10 @@ public:
size_t GetPlatformIdx();
+ bool GetTlsSetting();
+ bool TlsSecureAlgos();
+ const char* GetTlsFingerprint();
+
const char* GetPoolAddress();
const char* GetPoolPwd();
const char* GetWalletAddress();
@@ -32,8 +36,11 @@ public:
uint64_t GetVerboseLevel();
uint64_t GetAutohashTime();
+ const char* GetOutputFile();
+
uint64_t GetCallTimeout();
uint64_t GetNetRetry();
+ uint64_t GetGiveUpLimit();
uint16_t GetHttpdPort();
diff --git a/jpsock.cpp b/jpsock.cpp
index de01009..b072c21 100644
--- a/jpsock.cpp
+++ b/jpsock.cpp
@@ -11,6 +11,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
+ *
+ * Additional permission under GNU GPL version 3 section 7
+ *
+ * If you modify this Program, or any covered work, by linking or combining
+ * it with OpenSSL (or a modified version of that library), containing parts
+ * covered by the terms of OpenSSL License and SSLeay License, the licensors
+ * of this Program grant you additional permission to convey the resulting work.
+ *
*/
#include
@@ -23,6 +31,7 @@
#include "rapidjson/document.h"
#include "jext.h"
#include "socks.h"
+#include "socket.h"
#define AGENTID_STR "xmr-stak-amd/1.0"
@@ -60,10 +69,6 @@ typedef GenericDocument, MemoryPoolAllocator<>, MemoryPoolAllocator<>> Me
struct jpsock::opaque_private
{
- addrinfo *pSockAddr;
- addrinfo *pAddrRoot;
- SOCKET hSocket;
-
Value oCallValue;
MemoryPoolAllocator<> callAllocator;
@@ -79,8 +84,6 @@ struct jpsock::opaque_private
jsonDoc(&recvAllocator, jpsock::iJsonMemSize, &parseAllocator),
oCallRsp(nullptr)
{
- hSocket = INVALID_SOCKET;
- pSockAddr = nullptr;
}
};
@@ -90,7 +93,7 @@ struct jpsock::opq_json_val
opq_json_val(const Value* val) : val(val) {}
};
-jpsock::jpsock(size_t id) : pool_id(id)
+jpsock::jpsock(size_t id, bool tls) : pool_id(id)
{
sock_init();
@@ -100,6 +103,11 @@ jpsock::jpsock(size_t id) : pool_id(id)
prv = new opaque_private(bJsonCallMem, bJsonRecvMem, bJsonParseMem);
+ if(tls)
+ sck = new tls_socket(this);
+ else
+ sck = new plain_socket(this);
+
oRecvThd = nullptr;
bRunning = false;
bLoggedIn = false;
@@ -123,7 +131,7 @@ std::string&& jpsock::get_call_error()
return std::move(prv->oCallRsp.sCallErr);
}
-inline bool jpsock::set_socket_error(const char* a)
+bool jpsock::set_socket_error(const char* a)
{
if(!bHaveSocketError)
{
@@ -134,7 +142,7 @@ inline bool jpsock::set_socket_error(const char* a)
return false;
}
-inline bool jpsock::set_socket_error(const char* a, const char* b)
+bool jpsock::set_socket_error(const char* a, const char* b)
{
if(!bHaveSocketError)
{
@@ -150,6 +158,17 @@ inline bool jpsock::set_socket_error(const char* a, const char* b)
return false;
}
+bool jpsock::set_socket_error(const char* a, size_t len)
+{
+ if(!bHaveSocketError)
+ {
+ bHaveSocketError = true;
+ sSocketError.assign(a, len);
+ }
+
+ return false;
+}
+
bool jpsock::set_socket_error_strerr(const char* a)
{
char sSockErrText[512];
@@ -191,12 +210,8 @@ void jpsock::jpsock_thread()
bool jpsock::jpsock_thd_main()
{
- int ret = ::connect(prv->hSocket, prv->pSockAddr->ai_addr, (int)prv->pSockAddr->ai_addrlen);
- freeaddrinfo(prv->pAddrRoot);
- prv->pAddrRoot = nullptr;
-
- if (ret != 0)
- return set_socket_error_strerr("CONNECT error: ");
+ if(!sck->connect())
+ return false;
executor::inst()->push_event(ex_event(EV_SOCK_READY, pool_id));
@@ -204,18 +219,16 @@ bool jpsock::jpsock_thd_main()
size_t datalen = 0;
while (true)
{
- ret = recv(prv->hSocket, buf + datalen, sizeof(buf) - datalen, 0);
+ int ret = sck->recv(buf + datalen, sizeof(buf) - datalen);
- if(ret == 0)
- return set_socket_error("RECEIVE error: socket closed");
- if(ret == SOCKET_ERROR || ret < 0)
- return set_socket_error("RECEIVE error: ");
+ if(ret <= 0)
+ return false;
datalen += ret;
if (datalen >= sizeof(buf))
{
- sock_close(prv->hSocket);
+ sck->close(false);
return set_socket_error("RECEIVE error: data overflow");
}
@@ -228,7 +241,7 @@ bool jpsock::jpsock_thd_main()
if (!process_line(lnstart, lnlen))
{
- sock_close(prv->hSocket);
+ sck->close(false);
return false;
}
@@ -370,10 +383,12 @@ bool jpsock::process_pool_job(const opq_json_val* params)
size_t target_slen = target->GetStringLength();
if(target_slen <= 8)
{
- uint32_t iTempInt;
+ uint32_t iTempInt = 0;
char sTempStr[] = "00000000"; // Little-endian CPU FTW
memcpy(sTempStr, target->GetString(), target_slen);
- hex2bin(sTempStr, 8, (unsigned char*)&iTempInt);
+ if(!hex2bin(sTempStr, 8, (unsigned char*)&iTempInt) || iTempInt == 0)
+ return set_socket_error("PARSE error: Invalid target");
+
oPoolJob.iTarget = iTempInt;
}
else
@@ -390,100 +405,24 @@ bool jpsock::process_pool_job(const opq_json_val* params)
bool jpsock::connect(const char* sAddr, std::string& sConnectError)
{
- if(prv_connect(sAddr))
+ bHaveSocketError = false;
+ sSocketError.clear();
+ iJobDiff = 0;
+
+ if(sck->set_hostname(sAddr))
+ {
+ bRunning = true;
+ oRecvThd = new std::thread(&jpsock::jpsock_thread, this);
return true;
+ }
sConnectError = std::move(sSocketError);
return false;
}
-bool jpsock::prv_connect(const char* sAddr)
-{
- char sAddrMb[256];
- char *sTmp, *sPort;
-
- bHaveSocketError = false;
- sSocketError.clear();
- iJobDiff = 0;
-
- size_t ln = strlen(sAddr);
- if (ln >= sizeof(sAddrMb))
- return set_socket_error("CONNECT error: Pool address overflow.");
-
- memcpy(sAddrMb, sAddr, ln);
- sAddrMb[ln] = '\0';
-
- if ((sTmp = strstr(sAddrMb, "//")) != nullptr)
- memmove(sAddrMb, sTmp, strlen(sTmp) + 1);
-
- if ((sPort = strchr(sAddrMb, ':')) == nullptr)
- return set_socket_error("CONNECT error: Pool port number not specified, please use format :.");
-
- sPort[0] = '\0';
- sPort++;
-
- addrinfo hints = { 0 };
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_protocol = IPPROTO_TCP;
-
- prv->pAddrRoot = nullptr;
- int err;
- if ((err = getaddrinfo(sAddrMb, sPort, &hints, &prv->pAddrRoot)) != 0)
- return set_socket_error_strerr("CONNECT error: GetAddrInfo: ", err);
-
- addrinfo *ptr = prv->pAddrRoot;
- addrinfo *ipv4 = nullptr, *ipv6 = nullptr;
-
- while (ptr != nullptr)
- {
- if (ptr->ai_family == AF_INET)
- ipv4 = ptr;
- if (ptr->ai_family == AF_INET6)
- ipv6 = ptr;
- ptr = ptr->ai_next;
- }
-
- if (ipv4 == nullptr && ipv6 == nullptr)
- {
- freeaddrinfo(prv->pAddrRoot);
- prv->pAddrRoot = nullptr;
- return set_socket_error("CONNECT error: I found some DNS records but no IPv4 or IPv6 addresses.");
- }
- else if (ipv4 != nullptr && ipv6 == nullptr)
- prv->pSockAddr = ipv4;
- else if (ipv4 == nullptr && ipv6 != nullptr)
- prv->pSockAddr = ipv6;
- else if (ipv4 != nullptr && ipv6 != nullptr)
- {
- if(jconf::inst()->PreferIpv4())
- prv->pSockAddr = ipv4;
- else
- prv->pSockAddr = ipv6;
- }
-
- prv->hSocket = socket(prv->pSockAddr->ai_family, prv->pSockAddr->ai_socktype, prv->pSockAddr->ai_protocol);
-
- if (prv->hSocket == INVALID_SOCKET)
- {
- freeaddrinfo(prv->pAddrRoot);
- prv->pAddrRoot = nullptr;
- return set_socket_error_strerr("CONNECT error: Socket creation failed ");
- }
-
- bRunning = true;
- oRecvThd = new std::thread(&jpsock::jpsock_thread, this);
-
- return true;
-}
-
void jpsock::disconnect()
{
- if(prv->hSocket != INVALID_SOCKET)
- {
- sock_close(prv->hSocket);
- prv->hSocket = INVALID_SOCKET;
- }
+ sck->close(false);
if(oRecvThd != nullptr)
{
@@ -491,6 +430,8 @@ void jpsock::disconnect()
delete oRecvThd;
oRecvThd = nullptr;
}
+
+ sck->close(true);
}
bool jpsock::cmd_ret_wait(const char* sPacket, opq_json_val& poResult)
@@ -505,18 +446,10 @@ bool jpsock::cmd_ret_wait(const char* sPacket, opq_json_val& poResult)
prv->oCallRsp = call_rsp(&prv->oCallValue);
mlock.unlock();
- int pos = 0, slen = strlen(sPacket);
- while (pos != slen)
+ if(!sck->send(sPacket))
{
- int ret = send(prv->hSocket, sPacket + pos, slen - pos, 0);
- if (ret == SOCKET_ERROR)
- {
- set_socket_error_strerr("SEND error: ");
- disconnect(); //This will join the other thread;
- return false;
- }
- else
- pos += ret;
+ disconnect(); //This will join the other thread;
+ return false;
}
//Success is true if the server approves, result is true if there was no socket error
diff --git a/jpsock.h b/jpsock.h
index ad1545e..0b66866 100644
--- a/jpsock.h
+++ b/jpsock.h
@@ -19,11 +19,12 @@
We parse it in-situ in the network buffer, after that we copy it to a
std::string. Executor will move the buffer via an r-value ref.
*/
+class base_socket;
class jpsock
{
public:
- jpsock(size_t id);
+ jpsock(size_t id, bool tls);
~jpsock();
bool connect(const char* sAddr, std::string& sConnectError);
@@ -51,6 +52,13 @@ public:
bool get_current_job(pool_job& job);
size_t pool_id;
+
+ bool set_socket_error(const char* a);
+ bool set_socket_error(const char* a, const char* b);
+ bool set_socket_error(const char* a, size_t len);
+ bool set_socket_error_strerr(const char* a);
+ bool set_socket_error_strerr(const char* a, int res);
+
private:
std::atomic bRunning;
std::atomic bLoggedIn;
@@ -78,13 +86,6 @@ private:
std::string sSocketError;
std::atomic bHaveSocketError;
- bool set_socket_error(const char* a);
- bool set_socket_error(const char* a, const char* b);
- bool set_socket_error_strerr(const char* a);
- bool set_socket_error_strerr(const char* a, int res);
-
- bool prv_connect(const char* sAddr);
-
std::mutex call_mutex;
std::condition_variable call_cond;
std::thread* oRecvThd;
@@ -93,5 +94,6 @@ private:
pool_job oCurrentJob;
opaque_private* prv;
+ base_socket* sck;
};
diff --git a/minethd.cpp b/minethd.cpp
index 7665b33..181421a 100644
--- a/minethd.cpp
+++ b/minethd.cpp
@@ -11,6 +11,14 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
+ *
+ * Additional permission under GNU GPL version 3 section 7
+ *
+ * If you modify this Program, or any covered work, by linking or combining
+ * it with OpenSSL (or a modified version of that library), containing parts
+ * covered by the terms of OpenSSL License and SSLeay License, the licensors
+ * of this Program grant you additional permission to convey the resulting work.
+ *
*/
#include
diff --git a/socket.cpp b/socket.cpp
new file mode 100644
index 0000000..b472feb
--- /dev/null
+++ b/socket.cpp
@@ -0,0 +1,358 @@
+/*
+ * 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
+ * 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 .
+ *
+ * Additional permission under GNU GPL version 3 section 7
+ *
+ * If you modify this Program, or any covered work, by linking or combining
+ * it with OpenSSL (or a modified version of that library), containing parts
+ * covered by the terms of OpenSSL License and SSLeay License, the licensors
+ * of this Program grant you additional permission to convey the resulting work.
+ *
+ */
+
+#include "socket.h"
+#include "jpsock.h"
+#include "jconf.h"
+#include "console.h"
+#include "executor.h"
+
+#include
+#include
+#include
+
+#ifndef OPENSSL_THREADS
+#error OpenSSL was compiled without thread support
+#endif
+
+plain_socket::plain_socket(jpsock* err_callback) : pCallback(err_callback)
+{
+ hSocket = INVALID_SOCKET;
+ pSockAddr = nullptr;
+}
+
+bool plain_socket::set_hostname(const char* sAddr)
+{
+ char sAddrMb[256];
+ char *sTmp, *sPort;
+
+ size_t ln = strlen(sAddr);
+ if (ln >= sizeof(sAddrMb))
+ return pCallback->set_socket_error("CONNECT error: Pool address overflow.");
+
+ memcpy(sAddrMb, sAddr, ln);
+ sAddrMb[ln] = '\0';
+
+ if ((sTmp = strstr(sAddrMb, "//")) != nullptr)
+ memmove(sAddrMb, sTmp, strlen(sTmp) + 1);
+
+ if ((sPort = strchr(sAddrMb, ':')) == nullptr)
+ return pCallback->set_socket_error("CONNECT error: Pool port number not specified, please use format :.");
+
+ sPort[0] = '\0';
+ sPort++;
+
+ addrinfo hints = { 0 };
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ pAddrRoot = nullptr;
+ int err;
+ if ((err = getaddrinfo(sAddrMb, sPort, &hints, &pAddrRoot)) != 0)
+ return pCallback->set_socket_error_strerr("CONNECT error: GetAddrInfo: ", err);
+
+ addrinfo *ptr = pAddrRoot;
+ addrinfo *ipv4 = nullptr, *ipv6 = nullptr;
+
+ while (ptr != nullptr)
+ {
+ if (ptr->ai_family == AF_INET)
+ ipv4 = ptr;
+ if (ptr->ai_family == AF_INET6)
+ ipv6 = ptr;
+ ptr = ptr->ai_next;
+ }
+
+ if (ipv4 == nullptr && ipv6 == nullptr)
+ {
+ freeaddrinfo(pAddrRoot);
+ pAddrRoot = nullptr;
+ return pCallback->set_socket_error("CONNECT error: I found some DNS records but no IPv4 or IPv6 addresses.");
+ }
+ else if (ipv4 != nullptr && ipv6 == nullptr)
+ pSockAddr = ipv4;
+ else if (ipv4 == nullptr && ipv6 != nullptr)
+ pSockAddr = ipv6;
+ else if (ipv4 != nullptr && ipv6 != nullptr)
+ {
+ if(jconf::inst()->PreferIpv4())
+ pSockAddr = ipv4;
+ else
+ pSockAddr = ipv6;
+ }
+
+ hSocket = socket(pSockAddr->ai_family, pSockAddr->ai_socktype, pSockAddr->ai_protocol);
+
+ if (hSocket == INVALID_SOCKET)
+ {
+ freeaddrinfo(pAddrRoot);
+ pAddrRoot = nullptr;
+ return pCallback->set_socket_error_strerr("CONNECT error: Socket creation failed ");
+ }
+
+ return true;
+}
+
+bool plain_socket::connect()
+{
+ int ret = ::connect(hSocket, pSockAddr->ai_addr, (int)pSockAddr->ai_addrlen);
+
+ freeaddrinfo(pAddrRoot);
+ pAddrRoot = nullptr;
+
+ if (ret != 0)
+ return pCallback->set_socket_error_strerr("CONNECT error: ");
+ else
+ return true;
+}
+
+int plain_socket::recv(char* buf, unsigned int len)
+{
+ int ret = ::recv(hSocket, buf, len, 0);
+
+ if(ret == 0)
+ pCallback->set_socket_error("RECEIVE error: socket closed");
+ if(ret == SOCKET_ERROR || ret < 0)
+ pCallback->set_socket_error_strerr("RECEIVE error: ");
+
+ return ret;
+}
+
+bool plain_socket::send(const char* buf)
+{
+ int pos = 0, slen = strlen(buf);
+ while (pos != slen)
+ {
+ int ret = ::send(hSocket, buf + pos, slen - pos, 0);
+ if (ret == SOCKET_ERROR)
+ {
+ pCallback->set_socket_error_strerr("SEND error: ");
+ return false;
+ }
+ else
+ pos += ret;
+ }
+
+ return true;
+}
+
+void plain_socket::close(bool free)
+{
+ if(hSocket != INVALID_SOCKET)
+ {
+ sock_close(hSocket);
+ hSocket = INVALID_SOCKET;
+ }
+}
+
+tls_socket::tls_socket(jpsock* err_callback) : pCallback(err_callback)
+{
+}
+
+void tls_socket::print_error()
+{
+ BIO* err_bio = BIO_new(BIO_s_mem());
+ ERR_print_errors(err_bio);
+
+ char *buf = nullptr;
+ size_t len = BIO_get_mem_data(err_bio, &buf);
+
+ pCallback->set_socket_error(buf, len);
+
+ BIO_free(err_bio);
+}
+
+void tls_socket::init_ctx()
+{
+ const SSL_METHOD* method = SSLv23_method();
+
+ if(method == nullptr)
+ return;
+
+ ctx = SSL_CTX_new(method);
+ if(ctx == nullptr)
+ return;
+
+ if(jconf::inst()->TlsSecureAlgos())
+ {
+ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_COMPRESSION);
+ }
+}
+
+bool tls_socket::set_hostname(const char* sAddr)
+{
+ if(ctx == nullptr)
+ {
+ init_ctx();
+ if(ctx == nullptr)
+ {
+ print_error();
+ return false;
+ }
+ }
+
+ if((bio = BIO_new_ssl_connect(ctx)) == nullptr)
+ {
+ print_error();
+ return false;
+ }
+
+ if(BIO_set_conn_hostname(bio, sAddr) != 1)
+ {
+ print_error();
+ return false;
+ }
+
+ BIO_get_ssl(bio, &ssl);
+ if(ssl == nullptr)
+ {
+ print_error();
+ return false;
+ }
+
+ if(jconf::inst()->TlsSecureAlgos())
+ {
+ if(SSL_set_cipher_list(ssl, "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4:!SHA1") != 1)
+ {
+ print_error();
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool tls_socket::connect()
+{
+ if(BIO_do_connect(bio) != 1)
+ {
+ print_error();
+ return false;
+ }
+
+ if(BIO_do_handshake(bio) != 1)
+ {
+ print_error();
+ return false;
+ }
+
+ /* Step 1: verify a server certificate was presented during the negotiation */
+ X509* cert = SSL_get_peer_certificate(ssl);
+ if(cert == nullptr)
+ {
+ print_error();
+ return false;
+ }
+
+ const EVP_MD* digest;
+ unsigned char md[EVP_MAX_MD_SIZE];
+ unsigned int dlen;
+
+ digest = EVP_get_digestbyname("sha256");
+ if(digest == nullptr)
+ {
+ print_error();
+ return false;
+ }
+
+ if(X509_digest(cert, digest, md, &dlen) != 1)
+ {
+ X509_free(cert);
+ print_error();
+ return false;
+ }
+
+ if(pCallback->pool_id != executor::dev_pool_id)
+ {
+ //Base64 encode digest
+ BIO *bmem, *b64;
+ b64 = BIO_new(BIO_f_base64());
+ bmem = BIO_new(BIO_s_mem());
+
+ BIO_puts(bmem, "SHA256:");
+ b64 = BIO_push(b64, bmem);
+ BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
+ BIO_write(b64, md, dlen);
+ BIO_flush(b64);
+
+ const char* conf_md = jconf::inst()->GetTlsFingerprint();
+ char *b64_md = nullptr;
+ size_t b64_len = BIO_get_mem_data(bmem, &b64_md);
+
+ if(strlen(conf_md) == 0)
+ {
+ printer::inst()->print_msg(L1, "Server fingerprint: %.*s", (int)b64_len, b64_md);
+ }
+ else if(strncmp(b64_md, conf_md, b64_len) != 0)
+ {
+ printer::inst()->print_msg(L0, "FINGERPRINT FAILED CHECK: %.*s was given, %s was configured",
+ (int)b64_len, b64_md, conf_md);
+
+ pCallback->set_socket_error("FINGERPRINT FAILED CHECK");
+ BIO_free_all(b64);
+ X509_free(cert);
+ return false;
+ }
+
+ BIO_free_all(b64);
+ }
+
+ X509_free(cert);
+ return true;
+}
+
+int tls_socket::recv(char* buf, unsigned int len)
+{
+ int ret = BIO_read(bio, buf, len);
+
+ if(ret == 0)
+ pCallback->set_socket_error("RECEIVE error: socket closed");
+ if(ret < 0)
+ print_error();
+
+ return ret;
+}
+
+bool tls_socket::send(const char* buf)
+{
+ return BIO_puts(bio, buf) > 0;
+}
+
+void tls_socket::close(bool free)
+{
+ if(bio == nullptr || ssl == nullptr)
+ return;
+
+ if(!free)
+ {
+ sock_close(BIO_get_fd(bio, nullptr));
+ }
+ else
+ {
+ BIO_free_all(bio);
+ ssl = nullptr;
+ bio = nullptr;
+ }
+}
+
diff --git a/socket.h b/socket.h
new file mode 100644
index 0000000..94bbf03
--- /dev/null
+++ b/socket.h
@@ -0,0 +1,57 @@
+#pragma once
+#include "socks.h"
+class jpsock;
+
+class base_socket
+{
+public:
+ virtual bool set_hostname(const char* sAddr) = 0;
+ virtual bool connect() = 0;
+ virtual int recv(char* buf, unsigned int len) = 0;
+ virtual bool send(const char* buf) = 0;
+ virtual void close(bool free) = 0;
+};
+
+class plain_socket : public base_socket
+{
+public:
+ plain_socket(jpsock* err_callback);
+
+ bool set_hostname(const char* sAddr);
+ bool connect();
+ int recv(char* buf, unsigned int len);
+ bool send(const char* buf);
+ void close(bool free);
+
+private:
+ jpsock* pCallback;
+ addrinfo *pSockAddr;
+ addrinfo *pAddrRoot;
+ SOCKET hSocket;
+};
+
+typedef struct ssl_ctx_st SSL_CTX;
+typedef struct bio_st BIO;
+typedef struct ssl_st SSL;
+
+class tls_socket : public base_socket
+{
+public:
+ tls_socket(jpsock* err_callback);
+
+ bool set_hostname(const char* sAddr);
+ bool connect();
+ int recv(char* buf, unsigned int len);
+ bool send(const char* buf);
+ void close(bool free);
+
+private:
+ void init_ctx();
+ void print_error();
+
+ jpsock* pCallback;
+
+ SSL_CTX* ctx = nullptr;
+ BIO* bio = nullptr;
+ SSL* ssl = nullptr;
+};
diff --git a/xmr-stak-amd.cbp b/xmr-stak-amd.cbp
index adc183a..7e971a3 100644
--- a/xmr-stak-amd.cbp
+++ b/xmr-stak-amd.cbp
@@ -68,6 +68,8 @@
+
+
@@ -154,6 +156,8 @@
+
+