2 #include <openssl/ssl.h>
3 #include <openssl/err.h>
4 #include <netinet/in.h>
17 #include <unordered_map>
19 #include <openssl/rand.h>
20 #include <openssl/x509v3.h>
21 #include <openssl/pkcs12.h>
22 #include <openssl/err.h>
25 #include "tcpOpensslProxyServer.h"
38 static void *connection_handler(
void *socket_desc);
39 static void *clientRead_handler(
void *socket_desc);
41 tcpOpensslProxyServer::tcpOpensslProxyServer()
43 m_isServerprocessingEnabled =
true;
44 m_serverSSlCtx = NULL;
45 m_serverSocketListenfd = 0;
46 m_instanceServer =
this;
47 onMessageReceivedCallBack = NULL;
50 tcpOpensslProxyServer::~tcpOpensslProxyServer()
52 m_isServerprocessingEnabled =
false;
53 m_serverSSlCtx = NULL;
54 m_serverSocketListenfd = 0;
55 m_instanceServer = NULL;
56 onMessageReceivedCallBack = NULL;
59 void tcpOpensslProxyServer::freeSSLContext(SSL_CTX *ctx)
64 void tcpOpensslProxyServer::closeClient(
int clientId) {
66 printf (
"tcpOpensslProxyServer::%s %d entering client %d\n", __FUNCTION__, __LINE__, clientId);
67 if (m_clientSSLCtxList.find(clientId) != m_clientSSLCtxList.end()){
70 m_clientSSLCtxList.erase (clientId);
72 if (m_clientSSLIsReadEnabledList.find(clientId) != m_clientSSLIsReadEnabledList.end()){
73 printf (
"tcpOpensslProxyServer::%s %d Closing client %d\n", __FUNCTION__, __LINE__, clientId);
74 bool* isReadEnable = m_clientSSLIsReadEnabledList[clientId];
75 *isReadEnable =
false;
76 m_clientSSLIsReadEnabledList.erase (clientId);
81 void tcpOpensslProxyServer::closeAllClients() {
83 for (
auto& it: m_clientSSLCtxList) {
84 closeClient (it.first);
88 void tcpOpensslProxyServer::stopServer() {
89 m_isServerprocessingEnabled =
false;
91 if (m_serverSocketListenfd){
92 ::close (m_serverSocketListenfd);
93 m_serverSocketListenfd = 0;
95 if (NULL != m_serverSSlCtx){
96 freeSSLContext (m_serverSSlCtx);
97 m_serverSSlCtx = NULL;
102 printf (
"\ntcpOpensslProxyServer::%s %d exited\n", __FUNCTION__, __LINE__);
105 int tcpOpensslProxyServer::setUpServer(
const char* ipAddress,
unsigned short port_num,
const char *ca_pem,
106 const char *cert_pk12,
const char *pass)
112 if (port_num < 1 || port_num > 65535) {
113 fprintf(stderr,
"tcpOpensslProxyServer::%s %d Invalid port number: %d\n", __FUNCTION__, __LINE__, port_num);
114 onSocketError (QString (
"Invalid port number"));
119 SSL_load_error_strings();
120 OpenSSL_add_ssl_algorithms();
123 if (!(ctx = get_server_context_pk12(ca_pem, cert_pk12, pass))) {
128 if ((listen_fd = get_socket(ipAddress, port_num)) < 0) {
133 m_serverSSlCtx = ctx;
134 m_serverSocketListenfd = listen_fd;
136 std::thread t1(connection_handler, m_instanceServer);
143 SSL_CTX * tcpOpensslProxyServer::get_server_context_pk12(
const char *ca_pem,
144 const char *cert_pk12,
155 if (!(ctx = SSL_CTX_new(TLSv1_2_server_method()))) {
156 fprintf(stderr,
"tcpOpensslProxyServer::%s %d SSL_CTX_new failed\n", __FUNCTION__, __LINE__);
157 onSslErrors (QString(
"SSL_CTX_new failed"));
162 if(!SSL_CTX_set_ecdh_auto(ctx, 1)) {
163 fprintf(stderr,
"tcpOpensslProxyServer::%s %d SSL_CTX_set_ecdh_auto(ctx, 1)\n", __FUNCTION__, __LINE__);
164 onSslErrors (QString(
"failed to set ecdh param"));
165 freeSSLContext (ctx);
170 if (SSL_CTX_load_verify_locations(ctx, ca_pem, NULL) != 1) {
171 fprintf(stderr,
"tcpOpensslProxyServer::%s %d Could not set the CA file location\n", __FUNCTION__, __LINE__);
172 onSslErrors (QString(
"Could not set the CA file location"));
173 freeSSLContext (ctx);
178 SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(ca_pem));
180 f = fopen(cert_pk12,
"rb");
182 fprintf(stderr,
"tcpOpensslProxyServer::could not open PKCS12 file '%s'", cert_pk12);
185 p12 = d2i_PKCS12_fp(f, NULL);
190 if (!PKCS12_parse(p12, pass, &pri, &x509, NULL)) {
192 "tcpOpensslProxyServer::could not parse PKCS12 file, check password, OpenSSL error %s",
193 ERR_error_string(ERR_get_error(), NULL));
199 if(SSL_CTX_use_certificate(ctx, x509) != 1) {
201 fprintf(stderr,
"tcpOpensslProxyServer::pk12 certificate error");
207 if(SSL_CTX_use_PrivateKey(ctx, pri) != 1) {
208 fprintf(stderr,
"tcpOpensslProxyServer::unable to use private key from PKCS12 file '%s'",
219 if (SSL_CTX_check_private_key(ctx) != 1) {
220 fprintf(stderr,
"tcpOpensslProxyServer::%s %d Server's certificate and the key don't match\n", __FUNCTION__, __LINE__);
221 onSslErrors (QString(
"Server's certificate and the key don't match"));
222 freeSSLContext (ctx);
230 SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
233 SSL_CTX_set_verify(ctx,
234 SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
238 SSL_CTX_set_verify_depth(ctx, 2);
247 bool tcpOpensslProxyServer::SetSocketBlockingEnabled(
int fd,
bool blocking)
249 if (fd < 0)
return false;
251 unsigned long mode = blocking ? 0 : 1;
252 return (ioctlsocket(fd, FIONBIO, &mode) == 0) ?
TRUE : FALSE;
254 int flags = fcntl(fd, F_GETFL, 0);
255 if (flags < 0)
return false;
256 flags = blocking ? (flags&~O_NONBLOCK) : (flags|O_NONBLOCK);
257 return (fcntl(fd, F_SETFL, flags) == 0) ? true :
false;
261 int tcpOpensslProxyServer::get_socket(
const char* ipAddress,
unsigned short port_num) {
263 struct sockaddr_in sin;
267 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
268 fprintf(stderr,
"tcpOpensslProxyServer::%s %d Cannot create a socket\n", __FUNCTION__, __LINE__);
269 onSocketError (QString (
"Cannot create a socket"));
273 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &val,
sizeof(val)) < 0) {
274 fprintf(stderr,
"tcpOpensslProxyServer::%s %d Could not set SO_REUSEADDR on the socket\n", __FUNCTION__, __LINE__);
275 onSocketError (QString (
"Could not set SO_REUSEADDR on the socket"));
276 ::close(sock);
return -1;
280 memset(&sin, 0,
sizeof(sin));
281 sin.sin_family = AF_INET;
282 sin.sin_addr.s_addr = inet_addr(ipAddress);
283 sin.sin_port = htons(port_num);
287 if (bind(sock, (
struct sockaddr *) &sin,
sizeof(sin)) < 0) {
288 fprintf(stderr,
"tcpOpensslProxyServer::%s %d Could not bind the socket\n", __FUNCTION__, __LINE__);
289 onSocketError (QString (
"Could not bind the socket"));
290 ::close(sock);
return -1;
294 if (listen(sock, SOMAXCONN) < 0) {
295 fprintf(stderr,
"tcpOpensslProxyServer::%s %d Failed to listen on this socket\n", __FUNCTION__, __LINE__);
296 onSocketError (QString (
"Failed to listen on this socket"));
297 ::close(sock);
return -1;
306 void *connection_handler(
void *instance){
307 struct sockaddr_in sin;
314 SSL_CTX *ctx = instanceServer->m_serverSSlCtx;
315 int listen_fd = instanceServer->m_serverSocketListenfd;
320 setsockopt(listen_fd, SOL_SOCKET, SO_RCVTIMEO, (
const char*)&tv,
sizeof tv);
321 fprintf(stderr,
"tcpOpensslProxyServer::%s %d Server waiting to accept connection\n", __FUNCTION__, __LINE__);
323 while (instanceServer->m_isServerprocessingEnabled) {
325 sin_len =
sizeof(sin);
326 net_fd = ::accept(listen_fd, (
struct sockaddr *) &sin, &sin_len);
331 instanceServer->onAcceptError (QString(
"Failed to accept connection"));
332 fprintf(stderr,
"tcpOpensslProxyServer::%s %d Failed to accept connection net_fd:%d err:%d %s\n", __FUNCTION__, __LINE__, net_fd, err, strerror(errno));
338 if (!(ssl = SSL_new(ctx))) {
339 fprintf(stderr,
"tcpOpensslProxyServer::%s %d Could not get an SSL handle from the context\n", __FUNCTION__, __LINE__);
340 instanceServer->onSslErrors (QString(
"Could not get an SSL handle from the context"));
345 SSL_set_fd(ssl, net_fd);
348 instanceServer->onNewConnection (net_fd, instanceServer);
353 std::thread t1(clientRead_handler, &cc);
357 printf (
"tcpOpensslProxyServer::%s %d server thread exited\n", __FUNCTION__, __LINE__);
361 void *clientRead_handler(
void *socket_desc)
364 static char buffer[BUFSIZE];
366 bool isReadEnabled =
true;
368 printf(
"\ntcpOpensslProxyServer::%s:%d\n", __FUNCTION__, __LINE__);
371 int net_fd = SSL_get_fd(ssl);
377 if ((rc = SSL_accept(ssl)) != 1) {
378 fprintf(stderr,
"tcpOpensslProxyServer::%s %d Could not perform SSL handshake\n", __FUNCTION__, __LINE__);
379 instance->onPeerVerifyError (
"Could not perform SSL handshake");
388 instance->m_clientSSLCtxList [net_fd] = ssl;
389 instance->onConnected (net_fd, QString(
"connected"));
392 printf(
"tcpOpensslProxyServer::%s %d SSL handshake successful\n", __FUNCTION__, __LINE__);
395 instance->m_clientSSLIsReadEnabledList [net_fd] = &isReadEnabled;
399 setsockopt(net_fd, SOL_SOCKET, SO_RCVTIMEO, (
const char*)&tv,
sizeof tv);
402 memset (buffer,
'\0', BUFSIZE);
403 while (isReadEnabled) {
404 len = SSL_read(ssl, buffer, BUFSIZE);
410 }
else if (0 == len) {
411 printf(
"\ntcpOpensslProxyServer::%s:%d debug socket read data len:%d. Closing the socket\n", __FUNCTION__, __LINE__, len);
413 instance->closeClient(net_fd);
420 if (0 == strncmp(buffer,
"##PING##", 8)){
422 instance->onPong (net_fd, buffer+8, len-8);
427 printf(
"tcpOpensslProxyServer::%s:%d received: actual data is masked len:%d", __FUNCTION__, __LINE__, len);
428 instance->onMessageReceived (net_fd, buffer, len);
432 memset (buffer,
'\0', BUFSIZE);
434 printf(
"\ntcpOpensslProxyServer::%s %d client:%d read exited\n", __FUNCTION__, __LINE__, net_fd);
436 instance->onDisconnected (net_fd);
437 instance->m_clientSSLCtxList.erase (net_fd);
444 instance->closeClient (net_fd);
446 printf (
"\ntcpOpensslProxyServer::%s %d thread exited len:%d\n", __FUNCTION__, __LINE__, len);
451 void tcpOpensslProxyServer::sendTextMessage (
int clientId,
const char* buffer,
int len){
454 if (m_clientSSLCtxList.find(clientId) != m_clientSSLCtxList.end()){
455 SSL *ssl = m_clientSSLCtxList[clientId];
456 if ((rc = SSL_write(ssl, buffer, len)) != len){
457 fprintf(stderr,
"tcpOpensslProxyServer::%s %d SSL write failed\n", __FUNCTION__, __LINE__);
462 printf (
"\ntcpOpensslProxyServer::%s %d Not able to signal the write thread operation for the client: %d\n", __FUNCTION__, __LINE__, clientId);
467 void tcpOpensslProxyServer::setPingMsg (
int clientId,
const char* uniqueId,
int len){
468 std::string s =
"##PING##";
469 s.append (uniqueId, len);
470 m_clientPingMsgList [clientId] = s;
472 void tcpOpensslProxyServer::ping (
int clientId){
473 std::string s =
"##PING##DUMMY";
474 if (m_clientPingMsgList.find(clientId) != m_clientPingMsgList.end()){
475 s = m_clientPingMsgList [clientId];
477 sendTextMessage (clientId, s.c_str(), strlen(s.c_str()));
478 std::chrono::high_resolution_clock::time_point pingTime = std::chrono::high_resolution_clock::now();
479 m_clientPingTimeList [clientId] = pingTime;
482 void tcpOpensslProxyServer::onPong (
int clientId,
char* msg,
int len){
483 setPingMsg (clientId, msg, len);
484 QByteArray databuf = QByteArray((
char*)msg, len);
485 std::chrono::high_resolution_clock::time_point pingTime;
486 if (m_clientPingTimeList.find(clientId) != m_clientPingTimeList.end()){
487 pingTime = m_clientPingTimeList [clientId];
489 pingTime = std::chrono::high_resolution_clock::now();
491 std::chrono::high_resolution_clock::time_point pongTime = std::chrono::high_resolution_clock::now();
492 std::uint64_t ticks = (std::chrono::duration_cast<std::chrono::milliseconds>(pongTime - pingTime)).count();
493 if (NULL != onPongCallBack){
494 onPongCallBack (clientId, (quint64)ticks, databuf);
496 fprintf(stderr,
"tcpOpensslProxyServer::%s:%d onPongCallBack NULL\n",__FUNCTION__, __LINE__);
501 emit newConnection (clientId, ss);
504 void tcpOpensslProxyServer::onConnected (
int clientId, QString msg){
505 emit connected (clientId, msg);
508 void tcpOpensslProxyServer::onMessageReceived (
int clientId,
char* message,
size_t len){
509 if (NULL != onMessageReceivedCallBack){
510 onMessageReceivedCallBack (clientId, message, len);
514 void tcpOpensslProxyServer::onDisconnected (
int clientId){
515 emit disconnected (clientId);
518 void tcpOpensslProxyServer::onSocketError (QString err){
519 emit socketError (err);
522 void tcpOpensslProxyServer::onSslErrors (QString err) {
523 emit sslErrors (err);
526 void tcpOpensslProxyServer::onAcceptError (QString err){
527 emit acceptError (err);
530 void tcpOpensslProxyServer::onPeerVerifyError (QString err){
531 emit peerVerifyError (err);