diff options
author | psychocrypt <psychocrypt@users.noreply.github.com> | 2017-09-29 20:32:31 +0200 |
---|---|---|
committer | psychocrypt <psychocrypt@users.noreply.github.com> | 2017-09-30 23:46:08 +0200 |
commit | cc429b68fadc502b981fd0acd64a5ff6e2ae1d15 (patch) | |
tree | 3fb23fc4db15dbdd08af4c7ea20134b9d82e58fd /xmrstak/net/socket.cpp | |
parent | e5b0319d5a9f58762fa934ad700113908940cb31 (diff) | |
download | xmr-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.cpp | 366 |
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 + |