summaryrefslogtreecommitdiffstats
path: root/xmrstak/net/socket.cpp
diff options
context:
space:
mode:
authorpsychocrypt <psychocrypt@users.noreply.github.com>2017-09-29 20:32:31 +0200
committerpsychocrypt <psychocrypt@users.noreply.github.com>2017-09-30 23:46:08 +0200
commitcc429b68fadc502b981fd0acd64a5ff6e2ae1d15 (patch)
tree3fb23fc4db15dbdd08af4c7ea20134b9d82e58fd /xmrstak/net/socket.cpp
parente5b0319d5a9f58762fa934ad700113908940cb31 (diff)
downloadxmr-stak-cc429b68fadc502b981fd0acd64a5ff6e2ae1d15.zip
xmr-stak-cc429b68fadc502b981fd0acd64a5ff6e2ae1d15.tar.gz
group files
- move source code to `src` - categorize files and move to group folder - change upper case class files to lower case - change C++ header to `*.hpp`
Diffstat (limited to 'xmrstak/net/socket.cpp')
-rw-r--r--xmrstak/net/socket.cpp366
1 files changed, 366 insertions, 0 deletions
diff --git a/xmrstak/net/socket.cpp b/xmrstak/net/socket.cpp
new file mode 100644
index 0000000..52f46b5
--- /dev/null
+++ b/xmrstak/net/socket.cpp
@@ -0,0 +1,366 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * 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"
+
+#ifndef CONF_NO_TLS
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/opensslconf.h>
+
+#ifndef OPENSSL_THREADS
+#error OpenSSL was compiled without thread support
+#endif
+#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)
+ {
+ sTmp += 2;
+ 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 <hostname>:<port>.");
+
+ 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;
+ std::vector<addrinfo*> ipv4;
+ std::vector<addrinfo*> ipv6;
+
+ while (ptr != nullptr)
+ {
+ if (ptr->ai_family == AF_INET)
+ ipv4.push_back(ptr);
+ if (ptr->ai_family == AF_INET6)
+ ipv6.push_back(ptr);
+ ptr = ptr->ai_next;
+ }
+
+ if (ipv4.empty() && ipv6.empty())
+ {
+ 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.empty() && ipv6.empty())
+ pSockAddr = ipv4[rand() % ipv4.size()];
+ else if (ipv4.empty() && !ipv6.empty())
+ pSockAddr = ipv6[rand() % ipv6.size()];
+ else if (!ipv4.empty() && !ipv6.empty())
+ {
+ if(jconf::inst()->PreferIpv4())
+ pSockAddr = ipv4[rand() % ipv4.size()];
+ else
+ pSockAddr = ipv6[rand() % ipv6.size()];
+ }
+
+ 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;
+ }
+}
+
+#ifndef CONF_NO_TLS
+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;
+ }
+}
+#endif
+
OpenPOWER on IntegriCloud