diff --git a/CMakeLists.txt b/CMakeLists.txt index ce08ccb5..36e02a55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,7 +10,7 @@ option(WITH_AEON "CryptoNight-Lite support" ON) option(WITH_HTTPD "HTTP REST API" OFF) option(WITH_CC_CLIENT "CC Client" ON) option(WITH_CC_SERVER "CC Server" ON) -option(WITH_SSL_TLS "SSL/TLS support" ON) +option(WITH_TLS "TLS support" ON) include (CheckIncludeFile) include (cmake/cpu.cmake) @@ -18,6 +18,8 @@ include (cmake/cpu.cmake) set(SOURCES src/api/NetworkState.cpp src/App.cpp + src/3rdparty/clib-net/deps/buffer/buffer.c + src/3rdparty/clib-net/src/net.c src/net/Client.cpp src/net/Job.cpp src/net/Network.cpp @@ -110,24 +112,19 @@ find_package(UV REQUIRED) include(cmake/flags.cmake) -if (WITH_SSL_TLS) +if (WITH_TLS) find_package(OpenSSL REQUIRED) add_definitions(/DCPPHTTPLIB_OPENSSL_SUPPORT) if (OPENSSL_FOUND) include_directories(${OPENSSL_INCLUDE_DIR}) - - include_directories(src/3rdparty/evt-tls) - include_directories(src/3rdparty/evt-tls/api) - set(SOURCES_SSL_TLS - src/3rdparty/evt-tls/src/uv_tls.c - src/3rdparty/evt-tls/src/evt_tls.c) + set(SOURCES_SSL_TLS src/3rdparty/clib-net/src/tls.c) else() - message(FATAL_ERROR "OpenSSL NOT found: use `-DWITH_SSL_TLS=OFF` to build without SSL/TLS support") + message(FATAL_ERROR "OpenSSL NOT found: use `-DWITH_TLS=OFF` to build without TLS support") endif() else() - add_definitions(/DXMRIG_NO_SSL_TLS) + add_definitions(/DXMRIG_NO_TLS) endif() if (WITH_LIBCPUID) @@ -176,7 +173,7 @@ if (WITH_CC_SERVER) if (MHD_FOUND) include_directories(${MHD_INCLUDE_DIRS}) else() - message(FATAL_ERROR "microhttpd NOT found: use `-DWITH_CC=OFF` to build without CC Server support") + message(FATAL_ERROR "microhttpd NOT found: use `-DWITH_CC_SERVER=OFF` to build without CC Server support") endif() set(SOURCES_CC_SERVER @@ -204,18 +201,24 @@ endif() include_directories(src) include_directories(src/3rdparty) include_directories(${UV_INCLUDE_DIR}) +include_directories(src/3rdparty/clib-net/include) +include_directories(src/3rdparty/clib-net/deps) add_library(xmrig_common STATIC ${SOURCES_COMMON}) add_library(xmrig_os_dependencies STATIC ${SOURCES_OS} ${SOURCES_SYSLOG}) add_library(xmrig_cpuid STATIC ${SOURCES_CPUID}) +if (WITH_TLS) + add_library(xmrig_tls STATIC ${SOURCES_SSL_TLS}) +endif (WITH_TLS) + if (WITH_CC_SERVER OR WITH_CC_CLIENT) add_library(xmrig_cc_common STATIC ${SOURCES_CC_COMMON}) endif (WITH_CC_SERVER OR WITH_CC_CLIENT) -add_executable(xmrigMiner ${SOURCES} ${SOURCES_CRYPTO} ${HTTPD_SOURCES} ${SOURCES_CC_CLIENT} ${SOURCES_SSL_TLS} res/app.rc) +add_executable(xmrigMiner ${SOURCES} ${SOURCES_CRYPTO} ${HTTPD_SOURCES} ${SOURCES_CC_CLIENT} res/app.rc) -target_link_libraries(xmrigMiner xmrig_common xmrig_os_dependencies xmrig_cpuid +target_link_libraries(xmrigMiner xmrig_tls xmrig_common xmrig_os_dependencies xmrig_cpuid ${UV_LIBRARIES} ${MHD_LIBRARY} ${EXTRA_LIBS} ${CPUID_LIB} ${OPENSSL_LIBRARIES}) if (WITH_CC_CLIENT) @@ -228,7 +231,7 @@ if (WITH_CC_SERVER AND MHD_FOUND) add_library(xmrig_common_cc STATIC ${SOURCES_COMMON}) add_executable(xmrigCCServer ${SOURCES_CC_SERVER} res/app.rc) target_link_libraries(xmrigCCServer - xmrig_common_cc xmrig_os_dependencies xmrig_cpuid xmrig_cc_common + xmrig_common_cc xmrig_os_dependencies xmrig_cpuid xmrig_cc_common xmrig_tls ${UV_LIBRARIES} ${MHD_LIBRARY} ${EXTRA_LIBS} ${CPUID_LIB}) set_target_properties(xmrig_common_cc PROPERTIES COMPILE_FLAGS "-DXMRIG_CC_SERVER ${SHARED_FLAGS}") set_target_properties(xmrigCCServer PROPERTIES COMPILE_FLAGS "-DXMRIG_CC_SERVER ${SHARED_FLAGS}") diff --git a/src/3rdparty/clib-net/CHANGELOGS b/src/3rdparty/clib-net/CHANGELOGS new file mode 100644 index 00000000..602a3244 --- /dev/null +++ b/src/3rdparty/clib-net/CHANGELOGS @@ -0,0 +1,16 @@ + +# Change Logs + +2014-4-13(v0.1.1): + +* add a fake function: tls_get_peer_cert + +* tls_handle_bio_error and tls_handle_ssl_error added for a common usage + +* fix a high cpu bug in uv lines + +* make SSL_MODE_RELEASE_BUFFERS be gracefully imported + +* correct onConnect and onRead for ssl + +* fix a memory leak in ssl part \ No newline at end of file diff --git a/src/3rdparty/clib-net/Makefile b/src/3rdparty/clib-net/Makefile new file mode 100644 index 00000000..5c19c896 --- /dev/null +++ b/src/3rdparty/clib-net/Makefile @@ -0,0 +1,17 @@ + +CC ?= gcc +SRC = $(wildcard src/*.c) tests/simple.c +DEPS = $(wildcard deps/*/*.c) +CFLAGS = -std=c++11\ + -Iinclude\ + -Isrc\ + -Ideps\ + -Ideps/libuv/include\ + -Ldeps/libuv/build/Release\ + -Wall -Wno-unused-function +LDFLAGS = -lcrypto -lssl -luv + +test: $(SRC) + $(CC) $(CFLAGS) -o $@ $(SRC) $(DEPS) $(LDFLAGS) + +.PHONY: test diff --git a/src/3rdparty/clib-net/deps/buffer/History.md b/src/3rdparty/clib-net/deps/buffer/History.md new file mode 100644 index 00000000..86de93b4 --- /dev/null +++ b/src/3rdparty/clib-net/deps/buffer/History.md @@ -0,0 +1,40 @@ + +0.4.0 / 2015-01-05 +================== + + * refactor + * buffer: Remove printf() statement + * Add `buffer_appendf()` (#10, marcomorain) + +0.3.0 / 2014-12-24 +================== + + * travis: Fail the build if any memory is leaked + * test: Fix memory leaks + * travis: setup + * Add `buffer_append_n(buffer_t *, const char *, size_t)` + +0.2.1 / 2014-12-23 +================== + + * fix header guard + * fix compilation on linux + * Add missing null terminator after realloc (buffer resize) + * Make it safe to always use `data` as a character string + +0.2.0 / 2013-01-05 +================== + + * add print_buffer() + * add buffer_compact() + +0.1.0 / 2012-12-26 +================== + + * add trim functions + * add buffer_clear(buffer_t *self) + * add buffer_fill(buffer_t *self, int c) + * add buffer_new_with_string_length(char *str, size_t len) + * add buffer_new_with_copy(char *str) + * add buffer_indexof() + diff --git a/src/3rdparty/clib-net/deps/buffer/Makefile b/src/3rdparty/clib-net/deps/buffer/Makefile new file mode 100644 index 00000000..e2f516c8 --- /dev/null +++ b/src/3rdparty/clib-net/deps/buffer/Makefile @@ -0,0 +1,6 @@ + +test: buffer.c test.c + @$(CC) $^ -std=c99 -o $@ + @./test + +.PHONY: test diff --git a/src/3rdparty/clib-net/deps/buffer/Readme.md b/src/3rdparty/clib-net/deps/buffer/Readme.md new file mode 100644 index 00000000..c620ea0d --- /dev/null +++ b/src/3rdparty/clib-net/deps/buffer/Readme.md @@ -0,0 +1,82 @@ + +# buffer + + Tiny C string manipulation library. + +## Installation + + Install with [clib](https://github.com/clibs/clib): + +``` +$ clib install clibs/buffer +``` + +## API + +```c +buffer_t * +buffer_new(); + +buffer_t * +buffer_new_with_size(size_t n); + +buffer_t * +buffer_new_with_string(char *str); + +buffer_t * +buffer_new_with_string_length(char *str, size_t len); + +buffer_t * +buffer_new_with_copy(char *str); + +size_t +buffer_size(buffer_t *self); + +size_t +buffer_length(buffer_t *self); + +void +buffer_free(buffer_t *self); + +int +buffer_prepend(buffer_t *self, char *str); + +int +buffer_append(buffer_t *self, char *str); + +int +buffer_equals(buffer_t *self, buffer_t *other); + +ssize_t +buffer_indexof(buffer_t *self, char *str); + +buffer_t * +buffer_slice(buffer_t *self, size_t from, ssize_t to); + +ssize_t +buffer_compact(buffer_t *self); + +void +buffer_fill(buffer_t *self, int c); + +void +buffer_clear(buffer_t *self); + +void +buffer_trim_left(buffer_t *self); + +void +buffer_trim_right(buffer_t *self); + +void +buffer_trim(buffer_t *self); + +void +buffer_print(buffer_t *self); + +#define buffer_string(self) (self->data) +``` + +## License + + MIT diff --git a/src/3rdparty/clib-net/deps/buffer/buffer.c b/src/3rdparty/clib-net/deps/buffer/buffer.c new file mode 100644 index 00000000..c11b67fd --- /dev/null +++ b/src/3rdparty/clib-net/deps/buffer/buffer.c @@ -0,0 +1,353 @@ +// +// buffer.c +// +// Copyright (c) 2012 TJ Holowaychuk +// + +#include +#include +#include +#include +#include +#include +#include "buffer.h" + +// TODO: shared with reference counting +// TODO: linked list for append/prepend etc + +/* + * Compute the nearest multiple of `a` from `b`. + */ + +#define nearest_multiple_of(a, b) \ + (((b) + ((a) - 1)) & ~((a) - 1)) + +/* + * Allocate a new buffer with BUFFER_DEFAULT_SIZE. + */ + +buffer_t * +buffer_new() { + return buffer_new_with_size(BUFFER_DEFAULT_SIZE); +} + +/* + * Allocate a new buffer with `n` bytes. + */ + +buffer_t * +buffer_new_with_size(size_t n) { + buffer_t *self = malloc(sizeof(buffer_t)); + if (!self) return NULL; + self->len = n; + self->data = self->alloc = calloc(n + 1, 1); + return self; +} + +/* + * Allocate a new buffer with `str`. + */ + +buffer_t * +buffer_new_with_string(char *str) { + return buffer_new_with_string_length(str, strlen(str)); +} + +/* + * Allocate a new buffer with `str` and `len`. + */ + +buffer_t * +buffer_new_with_string_length(char *str, size_t len) { + buffer_t *self = malloc(sizeof(buffer_t)); + if (!self) return NULL; + self->len = len; + self->data = self->alloc = str; + return self; +} + +/* + * Allocate a new buffer with a copy of `str`. + */ + +buffer_t * +buffer_new_with_copy(char *str) { + size_t len = strlen(str); + buffer_t *self = buffer_new_with_size(len); + if (!self) return NULL; + memcpy(self->alloc, str, len); + self->data = self->alloc; + return self; +} + +/* + * Deallocate excess memory, the number + * of bytes removed or -1. + */ + +ssize_t +buffer_compact(buffer_t *self) { + size_t len = buffer_length(self); + size_t rem = self->len - len; + char *buf = calloc(len + 1, 1); + if (!buf) return -1; + memcpy(buf, self->data, len); + free(self->alloc); + self->len = len; + self->data = self->alloc = buf; + return rem; +} + +/* + * Free the buffer. + */ + +void +buffer_free(buffer_t *self) { + free(self->alloc); + free(self); +} + +/* + * Return buffer size. + */ + +size_t +buffer_size(buffer_t *self) { + return self->len; +} + +/* + * Return string length. + */ + +size_t +buffer_length(buffer_t *self) { + return strlen(self->data); +} + +/* + * Resize to hold `n` bytes. + */ + +int +buffer_resize(buffer_t *self, size_t n) { + n = nearest_multiple_of(1024, n); + self->len = n; + self->alloc = self->data = realloc(self->alloc, n + 1); + if (!self->alloc) return -1; + self->alloc[n] = '\0'; + return 0; +} + +/* + * Append a printf-style formatted string to the buffer. + */ + +int buffer_appendf(buffer_t *self, const char *format, ...) { + va_list ap; + va_list tmpa; + char *dst = NULL; + int length = 0; + int required = 0; + int bytes = 0; + + va_start(ap, format); + + length = buffer_length(self); + + // First, we compute how many bytes are needed + // for the formatted string and allocate that + // much more space in the buffer. + va_copy(tmpa, ap); + required = vsnprintf(NULL, 0, format, tmpa); + va_end(tmpa); + if (-1 == buffer_resize(self, length + required)) { + va_end(ap); + return -1; + } + + // Next format the string into the space that we + // have made room for. + dst = self->data + length; + bytes = vsnprintf(dst, 1 + required, format, ap); + va_end(ap); + + return bytes < 0 + ? -1 + : 0; +} + +/* + * Append `str` to `self` and return 0 on success, -1 on failure. + */ + +int +buffer_append(buffer_t *self, const char *str) { + return buffer_append_n(self, str, strlen(str)); +} + +/* + * Append the first `len` bytes from `str` to `self` and + * return 0 on success, -1 on failure. + */ +int +buffer_append_n(buffer_t *self, const char *str, size_t len) { + size_t prev = strlen(self->data); + size_t needed = len + prev; + + // enough space + if (self->len > needed) { + strncat(self->data, str, len); + return 0; + } + + // resize + int ret = buffer_resize(self, needed); + if (-1 == ret) return -1; + strncat(self->data, str, len); + + return 0; +} + +/* + * Prepend `str` to `self` and return 0 on success, -1 on failure. + */ + +int +buffer_prepend(buffer_t *self, char *str) { + size_t len = strlen(str); + size_t prev = strlen(self->data); + size_t needed = len + prev; + + // enough space + if (self->len > needed) goto move; + + // resize + int ret = buffer_resize(self, needed); + if (-1 == ret) return -1; + + // move + move: + memmove(self->data + len, self->data, len + 1); + memcpy(self->data, str, len); + + return 0; +} + +/* + * Return a new buffer based on the `from..to` slice of `buf`, + * or NULL on error. + */ + +buffer_t * +buffer_slice(buffer_t *buf, size_t from, ssize_t to) { + size_t len = strlen(buf->data); + + // bad range + if (to < from) return NULL; + + // relative to end + if (to < 0) to = len - ~to; + + // cap end + if (to > len) to = len; + + size_t n = to - from; + buffer_t *self = buffer_new_with_size(n); + memcpy(self->data, buf->data + from, n); + return self; +} + +/* + * Return 1 if the buffers contain equivalent data. + */ + +int +buffer_equals(buffer_t *self, buffer_t *other) { + return 0 == strcmp(self->data, other->data); +} + +/* + * Return the index of the substring `str`, or -1 on failure. + */ + +ssize_t +buffer_indexof(buffer_t *self, char *str) { + char *sub = strstr(self->data, str); + if (!sub) return -1; + return sub - self->data; +} + +/* + * Trim leading whitespace. + */ + +void +buffer_trim_left(buffer_t *self) { + int c; + while ((c = *self->data) && isspace(c)) { + ++self->data; + } +} + +/* + * Trim trailing whitespace. + */ + +void +buffer_trim_right(buffer_t *self) { + int c; + size_t i = buffer_length(self) - 1; + while ((c = self->data[i]) && isspace(c)) { + self->data[i--] = 0; + } +} + +/* + * Trim trailing and leading whitespace. + */ + +void +buffer_trim(buffer_t *self) { + buffer_trim_left(self); + buffer_trim_right(self); +} + +/* + * Fill the buffer with `c`. + */ + +void +buffer_fill(buffer_t *self, int c) { + memset(self->data, c, self->len); +} + +/* + * Fill the buffer with 0. + */ + +void +buffer_clear(buffer_t *self) { + buffer_fill(self, 0); +} + +/* + * Print a hex dump of the buffer. + */ + +void +buffer_print(buffer_t *self) { + int i; + size_t len = self->len; + + printf("\n "); + + // hex + for (i = 0; i < len; ++i) { + printf(" %02x", self->alloc[i]); + if ((i + 1) % 8 == 0) printf("\n "); + } + + printf("\n"); +} diff --git a/src/3rdparty/clib-net/deps/buffer/buffer.h b/src/3rdparty/clib-net/deps/buffer/buffer.h new file mode 100644 index 00000000..5cecbb0d --- /dev/null +++ b/src/3rdparty/clib-net/deps/buffer/buffer.h @@ -0,0 +1,101 @@ + +// +// buffer.h +// +// Copyright (c) 2012 TJ Holowaychuk +// + +#ifndef BUFFER_H +#define BUFFER_H 1 + +#include + +/* + * Default buffer size. + */ + +#ifndef BUFFER_DEFAULT_SIZE +#define BUFFER_DEFAULT_SIZE 64 +#endif + +/* + * Buffer struct. + */ + +typedef struct { + size_t len; + char *alloc; + char *data; +} buffer_t; + +// prototypes + +buffer_t * +buffer_new(); + +buffer_t * +buffer_new_with_size(size_t n); + +buffer_t * +buffer_new_with_string(char *str); + +buffer_t * +buffer_new_with_string_length(char *str, size_t len); + +buffer_t * +buffer_new_with_copy(char *str); + +size_t +buffer_size(buffer_t *self); + +size_t +buffer_length(buffer_t *self); + +void +buffer_free(buffer_t *self); + +int +buffer_prepend(buffer_t *self, char *str); + +int +buffer_append(buffer_t *self, const char *str); + +int +buffer_appendf(buffer_t *self, const char *format, ...); + +int +buffer_append_n(buffer_t *self, const char *str, size_t len); + +int +buffer_equals(buffer_t *self, buffer_t *other); + +ssize_t +buffer_indexof(buffer_t *self, char *str); + +buffer_t * +buffer_slice(buffer_t *self, size_t from, ssize_t to); + +ssize_t +buffer_compact(buffer_t *self); + +void +buffer_fill(buffer_t *self, int c); + +void +buffer_clear(buffer_t *self); + +void +buffer_trim_left(buffer_t *self); + +void +buffer_trim_right(buffer_t *self); + +void +buffer_trim(buffer_t *self); + +void +buffer_print(buffer_t *self); + +#define buffer_string(self) (self->data) + +#endif diff --git a/src/3rdparty/clib-net/include/net.h b/src/3rdparty/clib-net/include/net.h new file mode 100644 index 00000000..d9f1ce6d --- /dev/null +++ b/src/3rdparty/clib-net/include/net.h @@ -0,0 +1,177 @@ + +/* + * Copyright 2014 + */ + +#ifndef __NET_H__ +#define __NET_H__ + +#include +#include + +#ifndef XMRIG_NO_TLS +#include "tls.h" +#endif + +#define NOT_SSL 0x00 +#define USE_SSL 0x01 + +#define NET_OK 0 +#define NET_VERSION_MAJOR 0 +#define NET_VERSION_MINOR 1 +#define NET_VERSION_PATCH 2 +#define NET_VERSION_IS_RELEASE 0 + +typedef struct net_s net_t; +typedef struct addrinfo net_ai; +typedef struct sockaddr_in socketPair_t; + +#define NET_FIELDS \ + NET_CONNECTION_FIELDS \ + NET_UV_FIELDS \ + NET_TLS_FIELDS \ + +#define NET_CONNECTION_FIELDS \ + char *hostname; \ + int port; \ + int connected; \ + + +#define NET_UV_FIELDS \ + uv_getaddrinfo_t *resolver; \ + uv_loop_t *loop; \ + uv_tcp_t *handle; \ + uv_connect_t *conn; \ + +#ifndef XMRIG_NO_TLS + #define NET_TLS_FIELDS \ + int use_ssl; \ + int tls_established; \ + tls_t *tls; +#else + #define NET_TLS_FIELDS \ + int use_ssl; \ + int tls_established; +#endif + + +struct net_s { + NET_FIELDS; + void *data; + void (*conn_cb)(net_t*); + void (*read_cb)(net_t*, size_t, char*); + void (*error_cb)(net_t*, int, char*); + void (*close_cb)(uv_handle_t*); +}; + +/* + * Create an new network. + */ +net_t * +net_new(char * hostname, int port); + + +#ifndef XMRIG_NO_TLS +/* + * Set SSL's Context + */ +int +net_set_tls(net_t * net, tls_ctx * ctx); +#endif +/* + * Do connect to new + */ +int +net_connect(net_t * net); + +/* + * Just close the holding connection + */ +int +net_close(net_t * net, void (*cb)(uv_handle_t*)); + +/* + * free connection + */ +int +net_free(net_t * net); + +/* + * real free function + */ +void +net_free_cb(uv_handle_t * handle); + +/* + * DNS resolve + */ +int +net_resolve(net_t * net); + +/* + * DNS -> IP done, and call `net_resolve_cb` + */ +void +net_resolve_cb(uv_getaddrinfo_t *rv, int stat, net_ai * ai); + +/* + * connect created, and call `net_connect_cb` + */ +void +net_connect_cb(uv_connect_t *conn, int stat); + +/* + * realloc buffer before you read + */ +void +net_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf); + +/* + * read buffer + */ +void +net_read(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf); + +/* + * write buffer + */ +int +net_write(net_t * net, char * buf); + +/* + * write buffer with length specified + */ +int +net_write2(net_t * net, char * buf, unsigned int len); + +/* + * return use_ssl + */ +int +net_use_ssl(net_t * net); + +/* + * continue to read after on data + */ +int +net_resume(net_t * net); + +/* + * pause read + */ +int +net_pause(net_t * net); + +/* + * set error_cb + */ +int +net_set_error_cb(net_t * net, void * cb); + +/* + * write buffer, and call `net_write_cb`. + */ +void +net_write_cb(uv_write_t *writer, int stat); + +#endif /* __NET_H__ */ \ No newline at end of file diff --git a/src/3rdparty/clib-net/include/tls.h b/src/3rdparty/clib-net/include/tls.h new file mode 100644 index 00000000..76ca8fd0 --- /dev/null +++ b/src/3rdparty/clib-net/include/tls.h @@ -0,0 +1,133 @@ + +/* + * Copyright 2014 + */ + +#ifndef __TLS_H__ +#define __TLS_H__ + +#include +#include +#include +#include +#include + +#define SSL_CHUNK_SIZE 512 + +typedef SSL_CTX tls_ctx; +typedef struct tls_s { + SSL_CTX * ctx; + SSL * ssl; + BIO * bio_in; + BIO * bio_out; + buffer_t * buffer; + int connected; + char * data; + char buf[SSL_CHUNK_SIZE]; /* internal usage */ +} tls_t; + +static const int X509_NAME_FLAGS = ASN1_STRFLGS_ESC_CTRL + | ASN1_STRFLGS_ESC_MSB + | XN_FLAG_SEP_MULTILINE + | XN_FLAG_FN_SN; + +/* + * initialize the ssl + */ +void +ssl_init(); + +/* + * destroy the ssl settings and internal tables + */ +void +ssl_destroy(); + +/* + * create a context for ssl + */ +tls_ctx * +tls_ctx_new(); + +/* + * create a tls instance + */ +tls_t * +tls_create(tls_ctx * ctx); + +/* + * shutdown tls + */ +int +tls_shutdown(tls_t * tls); + +/* + * destroy a tls instance + */ +int +tls_free(tls_t * tls); + +/* + * get peer certification info + */ +int +tls_get_peer_cert(tls_t * tls); + +/* + * do connect to tls + */ +int +tls_connect(tls_t * tls); + +/* + * handle error in bio + */ +int +tls_handle_bio_error(tls_t * tls, int err); + +/* + * handle error in ssl + */ +int +tls_handle_ssl_error(tls_t *tls, int err); + +/* + * a port in tls for `bio_read` + */ +int +tls_bio_read(tls_t * tls, int len); + +/* + * a port in tls for `bio_write` + */ +int +tls_bio_write(tls_t * tls, char * written, int len); + +/* + * read + */ +int +tls_read(tls_t * tls); + +/* + * write + */ +int +tls_write(tls_t * tls, char * written, int len); + +/* + * write a tls packet + */ +#define REQUEST_TLS_WRITE(name, cmd, read, req) do { \ + tls_write(req->tls, cmd); \ + do { \ + read = tls_bio_read(req->tls, 0); \ + if (read > 0) { \ + REQUEST_WRITE(req, req->tls->buf, read, name); \ + } \ + } while (read > 0); \ +} \ +while (0) + + +#endif /* __TLS_H__ */ \ No newline at end of file diff --git a/src/3rdparty/clib-net/readme.md b/src/3rdparty/clib-net/readme.md new file mode 100644 index 00000000..b034d353 --- /dev/null +++ b/src/3rdparty/clib-net/readme.md @@ -0,0 +1,53 @@ + +# net-client + +Simple network client + +### Requirement + +* libuv 0.10.x + +* buffer 0.2.0 + +### Installation + +```sh +$ clib install clibs/net +$ git clone https://github.com/joyent/libuv.git deps/libuv +$ checkout v0.10.25 +``` + +### Run tests + +```sh +make test +./test +``` + +### Example + +```c +static void +imap_parser(net_t * net, size_t read, char * buf) { + printf("%s\n", buf); + printf("%zu\n", read); +} + +int +main(int argc, char *argv[]) { + ssl_init(); + tls_ctx * ctx = tls_ctx_new(); + net_t * net = net_new("imap.gmail.com", 993); + net->onRead = imap_parser; + + // convert this socket to ssl + net_set_tls(net, ctx); + net_connect(net); + + uv_run(net->loop, UV_RUN_DEFAULT); +} +``` + +### License + +MIT diff --git a/src/3rdparty/clib-net/src/net.c b/src/3rdparty/clib-net/src/net.c new file mode 100644 index 00000000..e992c229 --- /dev/null +++ b/src/3rdparty/clib-net/src/net.c @@ -0,0 +1,390 @@ + +#include +#include +#include "net.h" + +net_t * +net_new(char * hostname, int port) { + net_t * net = (net_t*) malloc(sizeof(net_t)); + net->loop = uv_default_loop(); + net->hostname = hostname; + net->port = port; + net->connected = 0; + net->tls_established = 0; + net->use_ssl = 0; + net->conn_cb = NULL; + net->read_cb = NULL; + net->error_cb = NULL; + net->close_cb = NULL; + net->handle = (uv_tcp_t *) malloc(sizeof(uv_tcp_t)); + net->conn = (uv_connect_t *) malloc(sizeof(uv_connect_t)); + net->handle->data + = net->conn->data + = (void *) net; + + return net; +} + +#ifndef XMRIG_NO_TLS +int +net_set_tls(net_t * net, tls_ctx * ctx) { + net->use_ssl = USE_SSL; + net->tls = tls_create(ctx); + return NET_OK; +} +#endif + +int +net_connect(net_t * net) { + net_resolve(net); + return NET_OK; +} + +int +net_close(net_t * net, void (*cb)(uv_handle_t*)) { + int r = net->connected; + if (r == 1) { + net->connected = 0; + net->tls_established = 0; + +#ifndef XMRIG_NO_TLS + if (net->use_ssl) { + tls_shutdown(net->tls); + } +#endif + + uv_close((uv_handle_t*)net->handle, cb); + +#ifndef XMRIG_NO_TLS + if (net->use_ssl) { + tls_free(net->tls); + } +#endif + } + + return r; +} + +int +net_free(net_t * net) { + net_close(net, NULL); + free(net->resolver); + free(net); + return NET_OK; +} + +void +net_free_cb(uv_handle_t * handle) { + net_t * net = (net_t *) handle->data; + if (net->handle != NULL) { + free(net->handle); + net->handle = NULL; + } + if (net->conn != NULL) { + free(net->conn); + net->conn = NULL; + } + if (net->resolver != NULL) { + free(net->resolver); + net->resolver = NULL; + } + if (net != NULL) { + free(net); + net = NULL; + } +} + +int +net_resolve(net_t * net) { + net_ai hints; + int ret; + char buf[6]; + + snprintf(buf, sizeof(buf), "%d", net->port); + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + net->resolver = malloc(sizeof(uv_getaddrinfo_t)); + if (!net->resolver) { + /* + * TODO(Yorkie): depent parital handles + */ + return -1; + } + + net->resolver->data = (void *) net; + ret = uv_getaddrinfo(net->loop, net->resolver, + net_resolve_cb, net->hostname, NULL, &hints); + + return ret; +} + +void +net_resolve_cb(uv_getaddrinfo_t *rv, int err, net_ai * ai) { + net_t * net = (net_t*) rv->data; + char addr[INET6_ADDRSTRLEN]; + int ret; + struct sockaddr_in dest; + + if (err != 0) { + if (net->error_cb) { + net->error_cb(net, err, (char *) uv_strerror(err)); + } else { + printf("error(%s:%d) %s", net->hostname, net->port, (char *) uv_strerror(err)); + net_free(net); + } + return; + } + + uv_ip4_name((socketPair_t *) ai->ai_addr, addr, INET6_ADDRSTRLEN); + ret = uv_ip4_addr(addr, net->port, &dest); + + if (ret != 0) { + if (net->error_cb) { + net->error_cb(net, ret, (char *) uv_strerror(err)); + } else { + printf("error(%s:%d) %s", net->hostname, net->port, (char *) uv_strerror(err)); + net_free(net); + } + return; + } + + /* + * create tcp instance. + */ + uv_tcp_init(net->loop, net->handle); + ret = uv_tcp_connect(net->conn, net->handle, (const struct sockaddr*) &dest, net_connect_cb); + if (ret != NET_OK) { + if (net->error_cb) { + net->error_cb(net, ret, (char *) uv_strerror(err)); + } else { + printf("error(%s:%d) %s", net->hostname, net->port, (char *) uv_strerror(err)); + net_free(net); + } + return; + } + + /* + * free + */ + uv_freeaddrinfo(ai); +} + +void +net_connect_cb(uv_connect_t *conn, int err) { + net_t * net = (net_t *) conn->data; + int read; + + if (err < 0) { + if (net->error_cb) { + net->error_cb(net, err, (char *) uv_strerror(err)); + } else { + printf("error(%s:%d) %s", net->hostname, net->port, (char *) uv_strerror(err)); + net_free(net); + } + return; + } + + /* + * change the `connected` state + */ + net->connected = 1; + + /* + * read buffers via uv + */ + uv_read_start((uv_stream_t *) net->handle, net_alloc, net_read); + + /* + * call `onConnect`, the tcp connection has been + * established in user-land. + */ + if (net->use_ssl == NOT_SSL && net->conn_cb != NULL) { + net->conn_cb(net); + } + +#ifndef XMRIG_NO_TLS + /* + * Handle TLS Partial + */ + if (net->use_ssl == USE_SSL && tls_connect(net->tls) == NET_OK) { + read = 0; + do { + read = tls_bio_read(net->tls, 0); + if (read > 0) { + char buf[read]; + uv_write_t * req = malloc(sizeof(uv_write_t)); + req->data = net; + memset(buf, 0, read); + memcpy(buf, net->tls->buf, read); + uv_buf_t uvbuf = uv_buf_init(buf, read); + uv_write(req, (uv_stream_t*)net->handle, &uvbuf, 1, net_write_cb); + } + } while (read > 0); + } +#endif +} + +void +net_alloc(uv_handle_t* handle, size_t size, uv_buf_t* buf) { + buf->base = (char *) calloc(size, 1); + buf->len = size; +} + +void +net_read(uv_stream_t* handle, ssize_t nread, const uv_buf_t* buf) { + net_t * net = (net_t *) handle->data; + + if (nread < 0) { + if (net->error_cb) { + net->error_cb(net, nread, (char *) uv_strerror(nread)); + } else { + printf("error(%s:%d) %s", net->hostname, net->port, (char *) uv_strerror(nread)); + net_free(net); + } + return; + } + +#ifndef XMRIG_NO_TLS + /* + * BIO Return rule: + * All these functions return either the amount of data successfully + * read or written (if the return value is positive) or that no data + * was successfully read or written if the result is 0 or -1. If the + * return value is -2 then the operation is not implemented in the specific BIO type. + */ + if (net->use_ssl) { + tls_bio_write(net->tls, buf->base, nread); + free(buf->base); + + int read = 0; + int stat = tls_read(net->tls); + if (stat == 1) { + /* + * continue: Say hello + */ + do { + read = tls_bio_read(net->tls, 0); + if (read > 0) { + char buf2[read]; + uv_write_t * req = malloc(sizeof(uv_write_t)); + req->data = net; + memset(buf2, 0, read); + memcpy(buf2, net->tls->buf, read); + uv_buf_t uvbuf = uv_buf_init(buf2, read); + uv_write(req, (uv_stream_t*)net->handle, &uvbuf, 1, net_write_cb); + } + } while (read > 0); + + } else { + /* + * SSL Connection is created + * Here need to call user-land callback + */ + if (!net->tls_established) { + net->tls_established = 1; + if (net->conn_cb != NULL) { + net->conn_cb(net); + } + } + + /* + * read buffer + */ + if (stat == 0) { + if (buffer_string(net->tls->buffer) > 0) + // uv_read_stop((uv_stream_t*)net->handle); + + if (net->read_cb != NULL && net->connected && net->tls_established) { + net->read_cb(net, buffer_length(net->tls->buffer), + buffer_string(net->tls->buffer)); + } + } + } + return; + } +#endif + + /* + * TCP Part, no SSL, just proxy of uv. + */ + uv_read_stop(handle); + buf->base[nread] = 0; + if (net->read_cb != NULL) { + net->read_cb(net, nread, buf->base); + free(buf->base); + } +} + +int +net_write(net_t * net, char * buf) { + return net_write2(net, buf, strlen(buf)); +} + +int +net_write2(net_t * net, char * buf, unsigned int len) { + uv_write_t * req; + uv_buf_t uvbuf; + int read = 0; + + switch (net->use_ssl) { + case USE_SSL: +#ifndef XMRIG_NO_TLS + tls_write(net->tls, buf, (int)len); + do { + read = tls_bio_read(net->tls, 0); + if (read > 0) { + req = (uv_write_t *) malloc(sizeof(uv_write_t)); + req->data = net; + uvbuf = uv_buf_init(net->tls->buf, read); + uv_write(req, (uv_stream_t*)net->handle, + &uvbuf, + 1, + net_write_cb); + } + } while (read > 0); + break; +#endif + case NOT_SSL: + req = (uv_write_t *) malloc(sizeof(uv_write_t)); + req->data = net; + uvbuf = uv_buf_init(buf, len); + uv_write(req, (uv_stream_t*)net->handle, + &uvbuf, + 1, + net_write_cb); + break; + } + + return NET_OK; +} + +int +net_use_ssl(net_t * net) { + return net->use_ssl == USE_SSL; +} + +int +net_resume(net_t * net) { + uv_read_start((uv_stream_t *)net->handle, net_alloc, net_read); + return NET_OK; +} + +int +net_pause(net_t * net) { + uv_read_stop((uv_stream_t *)net->handle); + return NET_OK; +} + +int +net_set_error_cb(net_t * net, void * cb) { + net->error_cb = cb; + return NET_OK; +} + +void +net_write_cb(uv_write_t *req, int stat) { + net_resume((net_t*)req->data); + free(req); +} diff --git a/src/3rdparty/clib-net/src/tls.c b/src/3rdparty/clib-net/src/tls.c new file mode 100644 index 00000000..26d2e1b4 --- /dev/null +++ b/src/3rdparty/clib-net/src/tls.c @@ -0,0 +1,221 @@ + +/* + * Copyright 2014 + */ + +#include +#include "tls.h" + +void +ssl_init() { + SSL_library_init(); + OpenSSL_add_all_algorithms(); + SSL_load_error_strings(); + ERR_load_crypto_strings(); +} + +void +ssl_destroy() { + EVP_cleanup(); + ERR_free_strings(); +} + +tls_ctx * +tls_ctx_new() { + tls_ctx *ctx = SSL_CTX_new(SSLv23_method()); +#ifdef SSL_OP_NO_COMPRESSION + SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION); +#endif + + return ctx; +} + +tls_t * +tls_create(tls_ctx *ctx) { + tls_t * tls = (tls_t *) malloc(sizeof(tls_t)+1); + if (tls == NULL) + fprintf(stderr, "tls> %s", "Out of Memory"); + + tls->ctx = ctx; + tls->ssl = SSL_new(tls->ctx); + tls->bio_in = BIO_new(BIO_s_mem()); + tls->bio_out = BIO_new(BIO_s_mem()); + tls->connected = -1; + tls->buffer = buffer_new(); + +#ifdef SSL_MODE_RELEASE_BUFFERS + long mode = SSL_get_mode(tls->ssl); + SSL_set_mode(tls->ssl, mode | SSL_MODE_RELEASE_BUFFERS); +#endif + + if (tls->ssl == NULL) + printf("tls> %s", "Out of Memory"); + + SSL_set_connect_state(tls->ssl); + SSL_set_bio(tls->ssl, tls->bio_in, tls->bio_out); + return tls; +} + +int +tls_shutdown(tls_t * tls) { + assert(tls != NULL); + if (SSL_shutdown(tls->ssl) == 0) { + SSL_shutdown(tls->ssl); + } + return 0; +} + +int +tls_free(tls_t * tls) { + if (tls->ssl) { + SSL_free(tls->ssl); + SSL_CTX_free(tls->ctx); + tls->ssl = NULL; + } + + buffer_free(tls->buffer); + free(tls); + return 0; +} + +int +tls_get_peer_cert(tls_t *tls) { + X509* peer_cert = SSL_get_peer_certificate(tls->ssl); + if (peer_cert != NULL) { + /* + * TODO(Yorkie): This function is used just for debug + */ + X509_free(peer_cert); + } + return 0; +} + +int +tls_connect(tls_t *tls) { + int rv; + int er; + + rv = SSL_do_handshake(tls->ssl); + if (rv == 1) { + /* + * `SSL_do_handshake()` could not return 1, + * that caused no message could be returned in `SSL_get_error()`. + * TODO(Yorkie): handle error, exit? + */ + return -1; + } + + if (!SSL_is_init_finished(tls->ssl)) + er = SSL_connect(tls->ssl); + else + return -1; + + if (er < 0 && SSL_get_error(tls->ssl, er) == SSL_ERROR_WANT_READ) + return 0; + else + return -1; +} + +int +tls_handle_bio_error(tls_t *tls, int err) { + int rv; + int retry = BIO_should_retry(tls->bio_out); + if (BIO_should_write(tls->bio_out)) + rv = -retry; + else if (BIO_should_read(tls->bio_out)) + rv = -retry; + else { + char ssl_error_buf[512]; + ERR_error_string_n(err, ssl_error_buf, sizeof(ssl_error_buf)); + fprintf(stderr, "[%p] BIO: read failed: (%d) %s\n", tls->ssl, err, ssl_error_buf); + return err; + } + return err; +} + +int +tls_handle_ssl_error(tls_t *tls, int err) { + int ret; + int rv = SSL_get_error(tls->ssl, err); + switch (rv) { + case SSL_ERROR_WANT_READ: + ret = 1; + break; + default: + ret = -2; + break; + } + return ret; +} + +int +tls_bio_read(tls_t *tls, int buf_len) { + if (buf_len == 0) { + buf_len = sizeof(tls->buf); + } + memset(tls->buf, 0, buf_len); + + int ret = BIO_read(tls->bio_out, tls->buf, buf_len); + if (ret >= 0) { + tls->buf[ret] = 0; + return ret; + } else { + return tls_handle_bio_error(tls, ret); + } +} + +int +tls_bio_write(tls_t *tls, char *buf, int len) { + int ret = BIO_write(tls->bio_in, buf, len); + if (ret >= 0) + return ret; + else + return tls_handle_bio_error(tls, ret); +} + +int +tls_read(tls_t *tls) { + int err; + int ret; + int read; + + int done = SSL_is_init_finished(tls->ssl); + if (!done) { + err = SSL_connect(tls->ssl); + if (err <= 0) { + return tls_handle_ssl_error(tls, err); + } + + /* + * TODO(Yorkie): returns not 1 nor < 0 + */ + assert(err == 1); + } + + /* finished */ + buffer_clear(tls->buffer); + + ret = -1; + do { + read = SSL_read(tls->ssl, tls->buf, SSL_CHUNK_SIZE); + if (read > 0) { + ret = 0; + tls->buf[read] = 0; + buffer_append(tls->buffer, tls->buf); + } else { + tls_handle_ssl_error(tls, read); + } + } while (read > 0); + + if (tls->connected == -1) { + tls->connected = 1; + } else { + ret = 0; + } + return ret; +} + +int +tls_write(tls_t *tls, char *buf_w, int len) { + return SSL_write(tls->ssl, buf_w, len); +} \ No newline at end of file diff --git a/src/Options.cpp b/src/Options.cpp index 104ee499..69e1daea 100644 --- a/src/Options.cpp +++ b/src/Options.cpp @@ -74,7 +74,7 @@ Options:\n" -k, --keepalive send keepalived for prevent timeout (need pool support)\n\ -r, --retries=N number of times to retry before switch to backup server (default: 5)\n\ -R, --retry-pause=N time to pause between retries (default: 5)\n\ - --multihash-thread-mask for av=2/4 only, limits multihash to given threads (mask), (default: all threads)\n\ + --multihash-thread-mask for av=2/4 only, limits multihash to given threads (mask), (default: all threads)\n\ --cpu-affinity set process affinity to CPU core(s), mask 0x3 for cores 0 and 1\n\ --cpu-priority set process priority (0 idle, 2 normal to 5 highest)\n\ --no-huge-pages disable huge pages support\n\ @@ -90,6 +90,7 @@ Options:\n" # ifndef XMRIG_NO_CC "\ --cc-url=URL url of the CC Server\n\ + --cc-use-tls turn on tls encryption for CC communication\ --cc-access-token=T access token for CC Server\n\ --cc-worker-id=ID custom worker-id for CC Server\n\ --cc-update-interval-s status update interval in seconds (default: 10 min: 1)\n" @@ -101,7 +102,10 @@ Options:\n" --cc-user=USERNAME CC Server admin user\n\ --cc-pass=PASSWORD CC Server admin pass\n\ --cc-access-token=T CC Server access token for CC Client\n\ - --cc-port=N CC Server\n\ + --cc-port=N CC Server port\n\ + --cc-use-tls turn on tls encryption for CC communication \ + --cc-cert-file=FILE when tls is turned on, use this to point to the right cert file (default: server.pem) \ + --cc-key-file when tls is turned on, use this to point to the right key file (default: server.key) \ --cc-client-config-folder=FOLDER Folder contains the client config files\n\ --cc-custom-dashboard=FILE loads a custom dashboard and serve it to '/'\n" # endif @@ -164,6 +168,9 @@ static struct option const options[] = { { "cc-pass", 1, nullptr, 4008 }, { "cc-client-config-folder", 1, nullptr, 4009 }, { "cc-custom-dashboard", 1, nullptr, 4010 }, + { "cc-cert-file", 1, nullptr, 4014 }, + { "cc-key-file", 1, nullptr, 4015 }, + { "cc-use-tls", 1, nullptr, 4016 }, { "daemonized", 0, nullptr, 4011 }, { "doublehash-thread-mask", 1, nullptr, 4013 }, { "multihash-thread-mask", 1, nullptr, 4013 }, @@ -231,6 +238,9 @@ static struct option const cc_server_options[] = { { "pass", 1, nullptr, 4008 }, { "client-config-folder", 1, nullptr, 4009 }, { "custom-dashboard", 1, nullptr, 4010 }, + { "cert-file", 1, nullptr, 4014 }, + { "key-file", 1, nullptr, 4015 }, + { "use-tls", 1, nullptr, 4016 }, { nullptr, 0, nullptr, 0 } }; @@ -269,8 +279,7 @@ Options::Options(int argc, char **argv) : m_safe(false), m_syslog(false), m_daemonized(false), - m_useTls(true), - m_ccUseTls(true), + m_ccUseTls(false), m_configFile(Platform::defaultConfigName()), m_apiToken(nullptr), m_apiWorkerId(nullptr), @@ -484,6 +493,16 @@ bool Options::parseArg(int key, const char *arg) m_ccCustomDashboard = strdup(arg); break; + case 4014: /* --cc-cert-file */ + free(m_ccCertFile); + m_ccCertFile = strdup(arg); + break; + + case 4015: /* --cc-key-file */ + free(m_ccKeyFile); + m_ccKeyFile = strdup(arg); + break; + case 4011: /* --daemonized */ m_daemonized = true; break; @@ -515,6 +534,9 @@ bool Options::parseArg(int key, const char *arg) case 1009: /* --no-huge-pages */ return parseBoolean(key, false); + case 4016: /* --use-tls */ + return parseBoolean(key, true); + case 't': /* --threads */ if (strncmp(arg, "all", 3) == 0) { m_threads = Cpu::threads(); @@ -719,10 +741,15 @@ bool Options::parseBoolean(int key, bool enable) m_hugePages = enable; break; - case 2000: /* colors */ + case 2000: /* --colors */ m_colors = enable; break; + case 4016: /* --use-tls */ + m_pools.back()->setUseTls(enable); + m_ccUseTls = enable; + break; + default: break; } diff --git a/src/Options.h b/src/Options.h index 40a8eea7..9e24c34e 100644 --- a/src/Options.h +++ b/src/Options.h @@ -69,7 +69,6 @@ public: inline bool hugePages() const { return m_hugePages; } inline bool syslog() const { return m_syslog; } inline bool daemonized() const { return m_daemonized; } - inline bool useTls() const { return m_useTls; } inline bool ccUseTls() const { return m_ccUseTls; } inline const char *configFile() const { return m_configFile; } inline const char *apiToken() const { return m_apiToken; } @@ -138,7 +137,6 @@ private: bool m_safe; bool m_syslog; bool m_daemonized; - bool m_useTls; bool m_ccUseTls; const char* m_configFile; char *m_apiToken; diff --git a/src/api/NetworkState.cpp b/src/api/NetworkState.cpp index bae290d0..374d1e1a 100644 --- a/src/api/NetworkState.cpp +++ b/src/api/NetworkState.cpp @@ -94,7 +94,7 @@ void NetworkState::add(const SubmitResult &result, const char *error) } -void NetworkState::setPool(const char *host, int port, const char *ip) +void NetworkState::setPool(const char *host, int port) { snprintf(pool, sizeof(pool) - 1, "%s:%d", host, port); diff --git a/src/api/NetworkState.h b/src/api/NetworkState.h index d0998074..0aa8c09e 100644 --- a/src/api/NetworkState.h +++ b/src/api/NetworkState.h @@ -41,7 +41,7 @@ public: uint32_t avgTime() const; uint32_t latency() const; void add(const SubmitResult &result, const char *error); - void setPool(const char *host, int port, const char *ip); + void setPool(const char *host, int port); void stop(); char pool[256]; diff --git a/src/cc/CCClient.cpp b/src/cc/CCClient.cpp index e0639525..2a8d776c 100644 --- a/src/cc/CCClient.cpp +++ b/src/cc/CCClient.cpp @@ -262,13 +262,13 @@ std::shared_ptr CCClient::performRequest(const std::string& r { std::shared_ptr cli; -# ifndef XMRIG_NO_SSL_TLS +# ifndef XMRIG_NO_TLS if (m_self->m_options->ccUseTls()) { cli = std::make_shared(m_self->m_options->ccHost(), m_self->m_options->ccPort()); } else { # endif cli = std::make_shared(m_self->m_options->ccHost(), m_self->m_options->ccPort()); -# ifndef XMRIG_NO_SSL_TLS +# ifndef XMRIG_NO_TLS } # endif diff --git a/src/cc/Httpd.cpp b/src/cc/Httpd.cpp index ce996fad..d388fc43 100644 --- a/src/cc/Httpd.cpp +++ b/src/cc/Httpd.cpp @@ -45,7 +45,7 @@ bool Httpd::start() return false; } -# ifndef XMRIG_NO_SSL_TLS +# ifndef XMRIG_NO_TLS if (m_options->ccUseTls()) { m_keyPem = readFile(m_options->ccKeyFile()); @@ -67,7 +67,7 @@ bool Httpd::start() m_daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, static_cast(m_options->ccPort()), nullptr, nullptr, &Httpd::handler, this, MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 10, MHD_OPTION_END); -# ifndef XMRIG_NO_SSL_TLS +# ifndef XMRIG_NO_TLS } # endif diff --git a/src/config.json b/src/config.json index 30c58b47..b2d57950 100644 --- a/src/config.json +++ b/src/config.json @@ -26,6 +26,7 @@ "url": "", // URL of mining server "user": "", // username for mining server "pass": "x", // password for mining server + "useTls" : false, // use tls for pool communication (need pool support) "keepalive": true, // send keepalived for prevent timeout (need pool support) "nicehash": false // enable nicehash/xmrig-proxy support } @@ -37,6 +38,7 @@ }, "cc-client": { "url": "localhost:3344", // url of the CC Server (ip:port) + "useTls" : false, // use tls for CC communication (needs to be enabled on CC Server too) "access-token": "mySecret", // access token for CC Server (has to be the same in config_cc.json) "worker-id": null, // custom worker-id for CC Server (otherwise hostname is used) "update-interval-s": 10 // status update interval in seconds (default: 10 min: 1) diff --git a/src/config_cc.json b/src/config_cc.json index 3315d83c..a459e5e0 100644 --- a/src/config_cc.json +++ b/src/config_cc.json @@ -5,6 +5,9 @@ "syslog": false, // use system log for output messages "cc-server": { "port": 3344, // port the CC Server will listens on + "useTls" : false, // use tls for CC communication (needs to be enabled on miners too) + "cert-file" : "server.pem", // when tls is turned on, use this to point to the right cert file + "key-file" : "server.key", // when tls is turned on, use this to point to the right key file "access-token": "mySecret", // access token for CC Clients (should be set!!!) "user": "admin", // admin user for access CC Dashboard "pass": "pass", // admin pass for access CC Dashboard diff --git a/src/default_config.json b/src/default_config.json index 30c58b47..b2d57950 100644 --- a/src/default_config.json +++ b/src/default_config.json @@ -26,6 +26,7 @@ "url": "", // URL of mining server "user": "", // username for mining server "pass": "x", // password for mining server + "useTls" : false, // use tls for pool communication (need pool support) "keepalive": true, // send keepalived for prevent timeout (need pool support) "nicehash": false // enable nicehash/xmrig-proxy support } @@ -37,6 +38,7 @@ }, "cc-client": { "url": "localhost:3344", // url of the CC Server (ip:port) + "useTls" : false, // use tls for CC communication (needs to be enabled on CC Server too) "access-token": "mySecret", // access token for CC Server (has to be the same in config_cc.json) "worker-id": null, // custom worker-id for CC Server (otherwise hostname is used) "update-interval-s": 10 // status update interval in seconds (default: 10 min: 1) diff --git a/src/net/Client.cpp b/src/net/Client.cpp index 8e8ebcfd..45daf2f1 100644 --- a/src/net/Client.cpp +++ b/src/net/Client.cpp @@ -5,6 +5,7 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2016-2017 XMRig + * Copyright 2018- BenDr0id * * * This program is free software: you can redistribute it and/or modify @@ -23,15 +24,13 @@ #include #include -#include #include #include - +#include #include "interfaces/IClientListener.h" #include "log/Log.h" #include "net/Client.h" -#include "net/Url.h" #include "rapidjson/document.h" #include "rapidjson/error/en.h" #include "rapidjson/stringbuffer.h" @@ -61,20 +60,8 @@ Client::Client(int id, const char *agent, IClientListener *listener) : m_retryPause(5000), m_failures(0), m_recvBufPos(0), - m_state(UnconnectedState), - m_expire(0), - m_stream(nullptr), - m_socket(nullptr) + m_expire(0) { - memset(m_ip, 0, sizeof(m_ip)); - memset(&m_hints, 0, sizeof(m_hints)); - - m_resolver.data = this; - - m_hints.ai_family = PF_INET; - m_hints.ai_socktype = SOCK_STREAM; - m_hints.ai_protocol = IPPROTO_TCP; - m_recvBuf.base = m_buf; m_recvBuf.len = sizeof(m_buf); @@ -87,13 +74,9 @@ Client::Client(int id, const char *agent, IClientListener *listener) : Client::~Client() { - delete m_socket; -} - - -void Client::connect() -{ - resolve(m_url.host()); + if (m_net) { + net_free(m_net); + } } @@ -105,7 +88,7 @@ void Client::connect() void Client::connect(const Url *url) { setUrl(url); - resolve(m_url.host()); + connect(); } @@ -138,13 +121,11 @@ void Client::tick(uint64_t now) return; } - if (m_state == ConnectedState) { + if (m_net) { LOG_DEBUG_ERR("[%s:%u] timeout", m_url.host(), m_url.port()); - close(); + reconnect(); } - - - if (m_state == ConnectingState) { + else { connect(); } } @@ -247,41 +228,15 @@ bool Client::parseLogin(const rapidjson::Value &result, int *code) return parseJob(result["job"], code); } - -int Client::resolve(const char *host) -{ - setState(HostLookupState); - - m_expire = 0; - m_recvBufPos = 0; - - if (m_failures == -1) { - m_failures = 0; - } - - const int r = uv_getaddrinfo(uv_default_loop(), &m_resolver, Client::onResolved, host, NULL, &m_hints); - if (r) { - if (!m_quiet) { - LOG_ERR("[%s:%u] getaddrinfo error: \"%s\"", host, m_url.port(), uv_strerror(r)); - } - return 1; - } - - return 0; -} - - int64_t Client::send(size_t size) { - LOG_DEBUG("[%s:%u] send (%d bytes): \"%s\"", m_url.host(), m_url.port(), size, m_sendBuf); - if (state() != ConnectedState || !uv_is_writable(m_stream)) { - LOG_DEBUG_ERR("[%s:%u] send failed, invalid state: %d", m_url.host(), m_url.port(), m_state); + LOG_DEBUG("[%s:%u] send (%d bytes): \"%s\"", m_url.host(), m_url.port(), size, buf); + if (!m_net) { + LOG_DEBUG_ERR("[%s:%u] send failed", m_url.host(), m_url.port()); return -1; } - uv_buf_t buf = uv_buf_init(m_sendBuf, (unsigned int) size); - - if (uv_try_write(m_stream, &buf, 1) < 0) { + if (net_write2(m_net, m_sendBuf, static_cast(size)) < 0) { close(); return -1; } @@ -293,42 +248,93 @@ int64_t Client::send(size_t size) void Client::close() { - if (m_state == UnconnectedState || m_state == ClosingState || !m_socket) { + if (m_net) { + auto client = getClient(m_net->data); + + net_free(m_net); + + m_net = nullptr; + + client->reconnect(); + } +} + + +void Client::connect() +{ + m_net = net_new(const_cast(m_url.host()), m_url.port()); + m_net->data = this; + m_net->conn_cb = Client::onConnect; + m_net->read_cb = Client::onRead; + m_net->error_cb = Client::onError; + +#ifndef XMRIG_NO_TLS + if (m_url.useTls()) { + tls_ctx* tls_ctx = tls_ctx_new(); + net_set_tls(m_net, tls_ctx); + } +#endif + + net_connect(m_net); +} + +void Client::onRead(net_t *net, size_t size, char *buf) +{ + auto client = getClient(net->data); + + if (size < 0) { + if (size != UV_EOF && !client->m_quiet) { + LOG_ERR("[%s:%u] read error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror((int) size)); + } + + return client->close(); + } + + client->m_recvBufPos += size; + + char* end; + char* start = buf; + size_t remaining = client->m_recvBufPos; + + 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_recvBufPos = 0; return; } - setState(ClosingState); + if (start == buf) { + return; + } - if (uv_is_closing(reinterpret_cast(m_socket)) == 0) { - uv_close(reinterpret_cast(m_socket), Client::onClose); + memcpy(buf, start, remaining); + client->m_recvBufPos = remaining; +} + +void Client::onConnect(net_t *net) { + auto client = getClient(net->data); + client->login(); +} + +void Client::onError(net_t *net, int err, char *errStr) +{ + if (net) { + auto client = getClient(net->data); + if (!client->m_quiet) { + LOG_ERR("[%s:%u] error: \"%s\"", client->m_url.host(), client->m_url.port(), errStr); + } + + client->close(); } } - -void Client::connect(struct sockaddr *addr) -{ - setState(ConnectingState); - - reinterpret_cast(addr)->sin_port = htons(m_url.port()); - delete m_socket; - - uv_connect_t *req = new uv_connect_t; - req->data = this; - - m_socket = new uv_tcp_t; - m_socket->data = this; - - 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, reinterpret_cast(addr), Client::onConnect); -} - - void Client::login() { m_results.clear(); @@ -480,9 +486,7 @@ void Client::ping() } -void Client::reconnect() -{ - setState(ConnectingState); +void Client::reconnect() { # ifndef XMRIG_PROXY_PROJECT if (m_url.isKeepAlive()) { @@ -500,19 +504,6 @@ void Client::reconnect() m_expire = uv_now(uv_default_loop()) + m_retryPause; } - -void Client::setState(SocketState state) -{ - LOG_DEBUG("[%s:%u] state: %d", m_url.host(), m_url.port(), state); - - if (m_state == state) { - return; - } - - m_state = state; -} - - void Client::startTimeout() { m_expire = 0; @@ -525,127 +516,3 @@ void Client::startTimeout() uv_timer_start(&m_keepAliveTimer, [](uv_timer_t *handle) { getClient(handle->data)->ping(); }, kKeepAliveTimeout, 0); # endif } - - -void Client::onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) -{ - auto client = getClient(handle->data); - - buf->base = &client->m_recvBuf.base[client->m_recvBufPos]; - buf->len = client->m_recvBuf.len - client->m_recvBufPos; -} - - -void Client::onClose(uv_handle_t *handle) -{ - auto client = getClient(handle->data); - - delete client->m_socket; - - client->m_stream = nullptr; - client->m_socket = nullptr; - client->setState(UnconnectedState); - - client->reconnect(); -} - - -void Client::onConnect(uv_connect_t *req, int status) -{ - auto client = getClient(req->data); - if (status < 0) { - if (!client->m_quiet) { - LOG_ERR("[%s:%u] connect error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror(status)); - } - - delete req; - client->close(); - return; - } - - client->m_stream = static_cast(req->handle); - client->m_stream->data = req->data; - client->setState(ConnectedState); - - uv_read_start(client->m_stream, Client::onAllocBuffer, Client::onRead); - delete req; - - client->login(); -} - - -void Client::onRead(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) -{ - auto client = getClient(stream->data); - if (nread < 0) { - if (nread != UV_EOF && !client->m_quiet) { - LOG_ERR("[%s:%u] read error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror((int) nread)); - } - - return client->close(); - } - - if ((size_t) nread > (sizeof(m_buf) - 8 - client->m_recvBufPos)) { - return client->close(); - } - - client->m_recvBufPos += nread; - - char* end; - char* start = buf->base; - size_t remaining = client->m_recvBufPos; - - 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_recvBufPos = 0; - return; - } - - if (start == buf->base) { - return; - } - - memcpy(buf->base, start, remaining); - client->m_recvBufPos = remaining; -} - - -void Client::onResolved(uv_getaddrinfo_t *req, int status, struct addrinfo *res) -{ - auto client = getClient(req->data); - if (status < 0) { - LOG_ERR("[%s:%u] DNS error: \"%s\"", client->m_url.host(), client->m_url.port(), uv_strerror(status)); - return client->reconnect(); - } - - addrinfo *ptr = res; - std::vector ipv4; - - while (ptr != nullptr) { - if (ptr->ai_family == AF_INET) { - ipv4.push_back(ptr); - } - - ptr = ptr->ai_next; - } - - if (ipv4.empty()) { - LOG_ERR("[%s:%u] DNS error: \"No IPv4 records found\"", client->m_url.host(), client->m_url.port()); - return client->reconnect(); - } - - ptr = ipv4[rand() % ipv4.size()]; - - uv_ip4_name(reinterpret_cast(ptr->ai_addr), client->m_ip, 16); - - client->connect(ptr->ai_addr); - uv_freeaddrinfo(res); -} diff --git a/src/net/Client.h b/src/net/Client.h index f66f079c..363f0d1b 100644 --- a/src/net/Client.h +++ b/src/net/Client.h @@ -5,6 +5,7 @@ * Copyright 2014-2016 Wolf9466 * Copyright 2016 Jay D Dee * Copyright 2016-2017 XMRig + * Copyright 2018- BenDr0id * * * This program is free software: you can redistribute it and/or modify @@ -35,6 +36,14 @@ #include "net/Url.h" #include "rapidjson/fwd.h" +extern "C" +{ +#include "net.h" + +#ifndef XMRIG_NO_TLS +#include "tls.h" +#endif +} class IClientListener; class JobResult; @@ -43,14 +52,6 @@ class JobResult; class Client { public: - enum SocketState { - UnconnectedState, - HostLookupState, - ConnectingState, - ConnectedState, - ClosingState - }; - constexpr static int kResponseTimeout = 20 * 1000; constexpr static int kKeepAliveTimeout = 60 * 1000; @@ -64,12 +65,9 @@ public: void setUrl(const Url *url); void tick(uint64_t now); - inline bool isReady() const { return m_state == ConnectedState && m_failures == 0; } inline const char *host() const { return m_url.host(); } - inline const char *ip() const { return m_ip; } inline const Job &job() const { return m_job; } inline int id() const { return m_id; } - inline SocketState state() const { return m_state; } inline uint16_t port() const { return m_url.port(); } inline void setQuiet(bool quiet) { m_quiet = quiet; } inline void setRetryPause(int ms) { m_retryPause = ms; } @@ -78,31 +76,24 @@ private: bool isCriticalError(const char *message); bool parseJob(const rapidjson::Value ¶ms, int *code); bool parseLogin(const rapidjson::Value &result, int *code); - int resolve(const char *host); int64_t send(size_t size); void close(); - void connect(struct sockaddr *addr); void login(); void parse(char *line, size_t len); 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 reconnect(); - void setState(SocketState state); void startTimeout(); - static void onAllocBuffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf); - 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 void onResolved(uv_getaddrinfo_t *req, int status, struct addrinfo *res); + static void onRead(net_t *net, size_t read, char *buf); + static void onConnect(net_t *net); + static void onError(net_t *net, int err, char *errStr); static inline Client *getClient(void *data) { return static_cast(data); } - addrinfo m_hints; bool m_quiet; char m_buf[2048]; - char m_ip[17]; char m_rpcId[64]; char m_sendBuf[768]; const char *m_agent; @@ -112,15 +103,13 @@ private: int64_t m_failures; Job m_job; size_t m_recvBufPos; - SocketState m_state; static int64_t m_sequence; std::map m_results; uint64_t m_expire; Url m_url; uv_buf_t m_recvBuf; - uv_getaddrinfo_t m_resolver; - uv_stream_t *m_stream; - uv_tcp_t *m_socket; + + net_t* m_net; # ifndef XMRIG_PROXY_PROJECT uv_timer_t m_keepAliveTimer; diff --git a/src/net/Network.cpp b/src/net/Network.cpp index 60fc91a2..490da91f 100644 --- a/src/net/Network.cpp +++ b/src/net/Network.cpp @@ -56,6 +56,10 @@ Network::Network(const Options *options) : const std::vector &pools = options->pools(); +#ifndef XMRIG_NO_TLS + ssl_init(); +#endif + if (pools.size() > 1) { m_strategy = new FailoverStrategy(pools, Platform::userAgent(), this); } @@ -76,6 +80,9 @@ Network::Network(const Options *options) : Network::~Network() { +#ifndef XMRIG_NO_TLS + ssl_destroy(); +#endif } @@ -102,9 +109,8 @@ void Network::onActive(Client *client) return; } - m_state.setPool(client->host(), client->port(), client->ip()); - - LOG_INFO(m_options->colors() ? "\x1B[01;37muse pool \x1B[01;36m%s:%d \x1B[01;30m%s" : "use pool %s:%d %s", client->host(), client->port(), client->ip()); + m_state.setPool(client->host(), client->port()); + LOG_INFO(m_options->colors() ? "\x1B[01;37muse pool \x1B[01;36m%s:%d" : "use pool %s:%d", client->host(), client->port()); } diff --git a/src/net/Url.cpp b/src/net/Url.cpp index 3bfc92a3..c020d4f7 100644 --- a/src/net/Url.cpp +++ b/src/net/Url.cpp @@ -58,7 +58,7 @@ Url::Url() : * @param url */ Url::Url(const char *url) : - m_tls(false), + m_useTls(false), m_keepAlive(false), m_nicehash(false), m_host(nullptr), @@ -70,8 +70,8 @@ Url::Url(const char *url) : } -Url::Url(const char *host, uint16_t port, const char *user, const char *password, bool tls, bool keepAlive, bool nicehash) : - m_tls(tls), +Url::Url(const char *host, uint16_t port, const char *user, const char *password, bool useTls, bool keepAlive, bool nicehash) : + m_useTls(useTls), m_keepAlive(keepAlive), m_nicehash(nicehash), m_password(password ? strdup(password) : nullptr), @@ -182,7 +182,7 @@ void Url::setUser(const char *user) Url &Url::operator=(const Url *other) { - m_tls = other->m_tls; + m_useTls = other->m_useTls; m_keepAlive = other->m_keepAlive; m_nicehash = other->m_nicehash; m_port = other->m_port; diff --git a/src/net/Url.h b/src/net/Url.h index ee588c25..6d4788c6 100644 --- a/src/net/Url.h +++ b/src/net/Url.h @@ -37,10 +37,10 @@ public: Url(); Url(const char *url); - Url(const char *host, uint16_t port, const char *user = nullptr, const char *password = nullptr, bool tls = false, bool keepAlive = false, bool nicehash = false ); + Url(const char *host, uint16_t port, const char *user = nullptr, const char *password = nullptr, bool useTls = false, bool keepAlive = false, bool nicehash = false ); ~Url(); - inline bool isTls() const { return m_tls; } + inline bool useTls() const { return m_useTls; } inline bool isKeepAlive() const { return m_keepAlive; } inline bool isNicehash() const { return m_nicehash; } inline bool isValid() const { return m_host && m_port > 0; } @@ -48,7 +48,7 @@ public: inline const char *password() const { return m_password ? m_password : kDefaultPassword; } inline const char *user() const { return m_user ? m_user : kDefaultUser; } inline uint16_t port() const { return m_port; } - inline void setTls(bool tls) { m_tls = tls; } + inline void setUseTls(bool tls) { m_useTls = tls; } inline void setKeepAlive(bool keepAlive) { m_keepAlive = keepAlive; } inline void setNicehash(bool nicehash) { m_nicehash = nicehash; } @@ -61,7 +61,7 @@ public: Url &operator=(const Url *other); private: - bool m_tls; + bool m_useTls; bool m_keepAlive; bool m_nicehash; char *m_host; diff --git a/src/net/strategies/DonateStrategy.cpp b/src/net/strategies/DonateStrategy.cpp index 3f795190..4c5555ce 100644 --- a/src/net/strategies/DonateStrategy.cpp +++ b/src/net/strategies/DonateStrategy.cpp @@ -49,7 +49,11 @@ DonateStrategy::DonateStrategy(const char *agent, IStrategyListener *listener) : keccak(reinterpret_cast(user), static_cast(strlen(user)), hash, sizeof(hash)); Job::toHex(hash, 32, userId); - Url *url = new Url("donate.graef.in", Options::i()->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 80 : 443, userId, nullptr, false, true); +#ifndef XMRIG_NO_TLS + Url *url = new Url("donate.graef.in", Options::i()->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 8080 : 8081, userId, nullptr, true, false, true); +#else + Url *url = new Url("donate.graef.in", Options::i()->algo() == Options::ALGO_CRYPTONIGHT_LITE ? 80 : 443, userId, nullptr, false, false, true); +#endif m_client = new Client(-1, agent, this); m_client->setUrl(url);