diff options
author | fireice-uk <fireice2@o2.pl> | 2017-01-27 22:34:28 +0000 |
---|---|---|
committer | fireice-uk <fireice2@o2.pl> | 2017-02-08 21:20:19 +0000 |
commit | 1a8323ef6f366058803ce6590b8167ec59928872 (patch) | |
tree | e583eb0c7de30a8d21ab8c6417104c8e8e41944d /socket.cpp | |
parent | 426b1991a20520a3afe94da44a8f96ab539553bb (diff) | |
download | xmr-stak-1a8323ef6f366058803ce6590b8167ec59928872.zip xmr-stak-1a8323ef6f366058803ce6590b8167ec59928872.tar.gz |
Inital OpenSSL integration
Diffstat (limited to 'socket.cpp')
-rw-r--r-- | socket.cpp | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/socket.cpp b/socket.cpp new file mode 100644 index 0000000..86069dd --- /dev/null +++ b/socket.cpp @@ -0,0 +1,288 @@ +#include "socket.h" +#include "jpsock.h" +#include "jconf.h" + +#include <openssl/ssl.h> +#include <openssl/err.h> +#include <openssl/opensslconf.h> +#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 <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; + 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; + + /* Cannot fail ??? */ + //SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_callback); + + /* Cannot fail ??? */ + //SSL_CTX_set_verify_depth(ctx, 4); + + /* Cannot fail ??? */ + SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | 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(SSL_set_cipher_list(ssl, "HIGH:!aNULL:!kRSA:!PSK:!SRP:!MD5:!RC4") != 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) { X509_free(cert); } /* Free immediately */ + + if(cert == nullptr) + { + print_error(); + return false; + } + + /* Step 2: verify the result of chain verification */ + /* Verification performed according to RFC 4158 */ + //res = SSL_get_verify_result(ssl); + //if(!(X509_V_OK == res)) handleFailure(); + + /* Step 3: hostname verification */ + /* An exercise left to the reader */ + + 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) + { + SSL_shutdown(ssl); + } + else + { + BIO_free_all(bio); + ssl = nullptr; + bio = nullptr; + } +} + |