From 6dc145b16b57b2e07b3ed4521e5a89bfa06749e1 Mon Sep 17 00:00:00 2001 From: Vladimir Dubrovin <3proxy@3proxy.ru> Date: Sun, 18 Feb 2024 19:07:09 +0300 Subject: [PATCH] initial commit to TLS refactoring --- src/plugins/SSLPlugin/my_ssl.c | 115 ++---------- src/plugins/SSLPlugin/my_ssl.h | 18 +- src/plugins/SSLPlugin/ssl_plugin.c | 285 ++++++++++++++++++----------- 3 files changed, 210 insertions(+), 208 deletions(-) diff --git a/src/plugins/SSLPlugin/my_ssl.c b/src/plugins/SSLPlugin/my_ssl.c index 9ad421a..8b4a326 100644 --- a/src/plugins/SSLPlugin/my_ssl.c +++ b/src/plugins/SSLPlugin/my_ssl.c @@ -32,11 +32,6 @@ typedef struct _ssl_conn { SSL *ssl; } ssl_conn; -static X509 *CA_cert = NULL; -static EVP_PKEY *CA_key = NULL; -static EVP_PKEY *server_key = NULL; -static X509_NAME *name = NULL; - pthread_mutex_t ssl_file_mutex; @@ -91,8 +86,6 @@ static int add_ext(X509 *cert, int nid, char *value) return 1; } -extern char *cert_path; - void del_ext(X509 *dst_cert, int nid, int where){ int ex; @@ -104,7 +97,7 @@ void del_ext(X509 *dst_cert, int nid, int where){ } -SSL_CERT ssl_copy_cert(SSL_CERT cert) +SSL_CERT ssl_copy_cert(SSL_CERT cert, SSL_CONFIG *config) { int err = -1; BIO *fcache; @@ -114,12 +107,8 @@ SSL_CERT ssl_copy_cert(SSL_CERT cert) EVP_PKEY *pk = NULL; RSA *rsa = NULL; - unsigned char p1[] = "RU"; - unsigned char p2[] = "3proxy"; - unsigned char p3[] = "3proxy CA"; - int hash_size = 20; - char hash_sha1[20]; + unsigned char hash_sha1[20]; char hash_name_sha1[(20*2) + 1]; char cache_name[256]; @@ -130,7 +119,7 @@ SSL_CERT ssl_copy_cert(SSL_CERT cert) } bin2hex(hash_sha1, 20, hash_name_sha1, sizeof(hash_name_sha1)); - sprintf(cache_name, "%s%s.pem", cert_path, hash_name_sha1); + sprintf(cache_name, "%s%s.pem", config->certcache, hash_name_sha1); /* check if certificate is already cached */ fcache = BIO_new_file(cache_name, "rb"); if ( fcache != NULL ) { @@ -157,19 +146,19 @@ SSL_CERT ssl_copy_cert(SSL_CERT cert) del_ext(dst_cert, NID_authority_key_identifier, -1); del_ext(dst_cert, NID_certificate_policies, 0); - err = X509_set_pubkey(dst_cert, server_key); + err = X509_set_pubkey(dst_cert, config->server_key); if ( err == 0 ) { X509_free(dst_cert); return NULL; } - err = X509_set_issuer_name(dst_cert, name); + err = X509_set_issuer_name(dst_cert, config->name); if(!err){ X509_free(dst_cert); return NULL; } - err = X509_sign(dst_cert, CA_key, EVP_sha256()); + err = X509_sign(dst_cert, config->CA_key, EVP_sha256()); if(!err){ X509_free(dst_cert); return NULL; @@ -247,7 +236,7 @@ SSL_CONN ssl_handshake_to_server(SOCKET s, char * hostname, SSL_CERT *server_cer return conn; } -SSL_CONN ssl_handshake_to_client(SOCKET s, SSL_CERT server_cert, char** errSSL) +SSL_CONN ssl_handshake_to_client(SOCKET s, SSL_CERT server_cert, EVP_PKEY *server_key, char** errSSL) { int err = 0; X509 *cert; @@ -414,89 +403,17 @@ int thread_cleanup(void) int ssl_file_init = 0; +int ssl_init_done = 0; -void ssl_init(void) +void ssl_init() { - BIO *f; - static char fname[200]; - - if(!ssl_file_init++)pthread_mutex_init(&ssl_file_mutex, NULL); - - pthread_mutex_lock(&ssl_file_mutex); - thread_setup(); - SSLeay_add_ssl_algorithms(); - SSL_load_error_strings(); - - sprintf(fname, "%.128s3proxy.pem", cert_path); - f = BIO_new_file(fname, "r"); - if ( f != NULL ) { - if(!(CA_cert=PEM_read_bio_X509(f, NULL, NULL, NULL))){ - unsigned long err; - err=ERR_get_error(); - fprintf(stderr, "failed to read: %s: [%lu] %s\n", fname, err, ERR_error_string(err, NULL)); - return; - } - BIO_free(f); + if(!ssl_init_done){ + ssl_init_done = 1; + thread_setup(); + SSLeay_add_ssl_algorithms(); + SSL_load_error_strings(); + pthread_mutex_init(&ssl_file_mutex, NULL); + bio_err=BIO_new_fp(stderr,BIO_NOCLOSE); } - else { - fprintf(stderr, "failed to open: %s\n", fname); - return; - } - name = X509_get_subject_name(CA_cert); - sprintf(fname, "%.128s3proxy.key", cert_path); - f = BIO_new_file(fname, "rb"); - if ( f != NULL ) { - CA_key = PEM_read_bio_PrivateKey(f, NULL, NULL, NULL); - if(!CA_key){ - unsigned long err; - err=ERR_get_error(); - fprintf(stderr, "failed to read: %s: [%lu] %s\n", fname, err, ERR_error_string(err, NULL)); - return; - } - BIO_free(f); - } - else { - fprintf(stderr, "failed to open: %s\n", fname); - return; - } - - sprintf(fname, "%.128sserver.key", cert_path); - f = BIO_new_file(fname, "rb"); - if ( f != NULL ) { - server_key = PEM_read_bio_PrivateKey(f, &server_key, NULL, NULL); - if(!server_key){ - unsigned long err; - err=ERR_get_error(); - fprintf(stderr, "failed to read: %s: [%lu] %s\n", fname, err, ERR_error_string(err, NULL)); - return; - } - BIO_free(f); - } - else { - fprintf(stderr, "failed to open: %s\n", fname); - } - - bio_err=BIO_new_fp(stderr,BIO_NOCLOSE); - pthread_mutex_unlock(&ssl_file_mutex); } -void ssl_release(void) -{ - pthread_mutex_lock(&ssl_file_mutex); - if ( CA_cert != NULL ) { - X509_free(CA_cert); - CA_cert = NULL; - } - - if ( CA_key != NULL ) { - EVP_PKEY_free(CA_key); - CA_key = NULL; - } - - if ( server_key != NULL ) { - EVP_PKEY_free(server_key); - server_key = NULL; - } - thread_cleanup(); - pthread_mutex_unlock(&ssl_file_mutex); -} diff --git a/src/plugins/SSLPlugin/my_ssl.h b/src/plugins/SSLPlugin/my_ssl.h index 8a89e9e..f76c774 100644 --- a/src/plugins/SSLPlugin/my_ssl.h +++ b/src/plugins/SSLPlugin/my_ssl.h @@ -10,16 +10,28 @@ typedef void *SSL_CONN; // typedef void *SSL_CERT; +struct ssl_config { + int transparent; + char *certcache; + X509 *CA_cert; + EVP_PKEY *CA_key; + EVP_PKEY *server_key; + X509_NAME *name; +}; + +typedef struct ssl_config SSL_CONFIG; + + // // Create copy of certificate signed by "other" CA // -SSL_CERT ssl_copy_cert(SSL_CERT cert); +SSL_CERT ssl_copy_cert(SSL_CERT cert, SSL_CONFIG *config); // // SSL/TLS handshakes // SSL_CONN ssl_handshake_to_server(SOCKET s, char * hostname, SSL_CERT *server_cert, char **errSSL); -SSL_CONN ssl_handshake_to_client(SOCKET s, SSL_CERT server_cert, char **errSSL); +SSL_CONN ssl_handshake_to_client(SOCKET s, SSL_CERT server_cert, EVP_PKEY *server_key, char **errSSL); // // SSL/TLS Read/Write @@ -38,6 +50,6 @@ void _ssl_cert_free(SSL_CERT cert); // Global (de)initialization // void ssl_init(void); -void ssl_release(void); + #endif // __my_ssl_h__ \ No newline at end of file diff --git a/src/plugins/SSLPlugin/ssl_plugin.c b/src/plugins/SSLPlugin/ssl_plugin.c index 8e18f81..5280c24 100644 --- a/src/plugins/SSLPlugin/ssl_plugin.c +++ b/src/plugins/SSLPlugin/ssl_plugin.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "../../proxy.h" #include "my_ssl.h" @@ -30,79 +31,68 @@ PROXYFUNC tcppmfunc, proxyfunc, smtppfunc, ftpprfunc; static struct pluginlink * pl; -pthread_mutex_t ssl_mutex; - static int ssl_loaded = 0; static int ssl_connect_timeout = 0; -char *cert_path = ""; +char *certcache = NULL; +int mitm = 0; +int ssl_inited = 0; typedef struct _ssl_conn { struct SSL_CTX *ctx; struct SSL *ssl; } ssl_conn; -struct SSLqueue { - struct SSLqueue *next; + +struct SSLsock { SOCKET s; - SSL_CERT cert; SSL_CONN conn; +}; + +struct SSLstate { + struct SSLsock cli, srv; struct clientparam* param; -} *SSLq = NULL; + SSL_CONFIG *config; +}; /* TO DO: use hashtable */ -static struct SSLqueue *searchSSL(SOCKET s){ - struct SSLqueue *sslq = NULL; - pthread_mutex_lock(&ssl_mutex); - for(sslq = SSLq; sslq; sslq = sslq->next) - if(sslq->s == s) break; - pthread_mutex_unlock(&ssl_mutex); - return sslq; +#define STATE ((struct SSLstate *)(state)) + +static struct SSLsock *searchSSL(void* state, SOCKET s){ + if(!state || s == INVALID_SOCKET) return NULL; + if(STATE->cli.s == s) return &STATE->cli; + if(STATE->srv.s == s) return &STATE->srv; + return NULL; } -static void addSSL(SOCKET s, SSL_CERT cert, SSL_CONN conn, struct clientparam* param){ - struct SSLqueue *sslq; +#define SOSTATE ((struct SSLstate *)(param->sostate)) - sslq = (struct SSLqueue *) malloc(sizeof(struct SSLqueue)); - sslq->s = s; - sslq->cert = cert; - sslq->conn = conn; - sslq->param = param; - pthread_mutex_lock(&ssl_mutex); - sslq->next = SSLq; - SSLq = sslq; - pthread_mutex_unlock(&ssl_mutex); +static void addSSL( + SOCKET cli_s, SSL_CONN cli_conn, + SOCKET srv_s, SSL_CONN srv_conn, + struct clientparam* param){ + if(!param->sostate) return; + SOSTATE->cli.s = cli_s; + SOSTATE->cli.conn = cli_conn; + SOSTATE->srv.s = srv_s; + SOSTATE->srv.conn = srv_conn; } -int delSSL(SOCKET s){ - struct SSLqueue *sqi, *sqt = NULL; - - if(!SSLq) return 0; - pthread_mutex_lock(&ssl_mutex); - if(SSLq){ - if(SSLq->s == s){ - sqt = SSLq; - SSLq = SSLq->next; - } - else for(sqi = SSLq; sqi->next; sqi = sqi->next){ - if (sqi->next->s == s){ - sqt = sqi->next; - sqi->next = sqt->next; - break; - } - } - } - pthread_mutex_unlock(&ssl_mutex); - if(sqt) { - _ssl_cert_free(sqt->cert); - ssl_conn_free(sqt->conn); - free(sqt); - return 1; - } - return 0; +void delSSL(void *state, SOCKET s){ + if(!state || s == INVALID_SOCKET) return; + if(STATE->cli.s == s) { + ssl_conn_free(STATE->cli.conn); + STATE->cli.conn = NULL; + STATE->cli.s = INVALID_SOCKET; + } + else if(STATE->srv.s == s) { + ssl_conn_free(STATE->cli.conn); + STATE->cli.conn = NULL; + STATE->cli.s = INVALID_SOCKET; + } } struct sockfuncs sso; @@ -112,9 +102,9 @@ static int WINAPI ssl_send(void *state, SOCKET s, const void *msg, int len, int #else static ssize_t ssl_send(void *state, SOCKET s, const void *msg, size_t len, int flags){ #endif - struct SSLqueue *sslq; + struct SSLsock *sslq; - if ((sslq = searchSSL(s))){ + if ((sslq = searchSSL(state, s))){ int res, err; if((res = ssl_write(sslq->conn, (void *)msg, len)) <= 0){ err = SSL_get_error((SSL *)((ssl_conn*)sslq->conn)->ssl, res); @@ -136,9 +126,9 @@ static int WINAPI ssl_sendto(void *state, SOCKET s, const void *msg, int len, in #else static ssize_t ssl_sendto(void *state, SOCKET s, const void *msg, size_t len, int flags, const struct sockaddr *to, SASIZETYPE tolen){ #endif - struct SSLqueue *sslq; + struct SSLsock *sslq; - if ((sslq = searchSSL(s))){ + if ((sslq = searchSSL(state, s))){ int res, err; if((res = ssl_write(sslq->conn, (void *)msg, len)) <= 0) { err = SSL_get_error((SSL *)((ssl_conn*)sslq->conn)->ssl, res); @@ -159,9 +149,9 @@ static int WINAPI ssl_recvfrom(void *state, SOCKET s, void *msg, int len, int fl #else static ssize_t ssl_recvfrom(void *state, SOCKET s, void *msg, size_t len, int flags, struct sockaddr *from, SASIZETYPE *fromlen){ #endif - struct SSLqueue *sslq; + struct SSLsock *sslq; - if ((sslq = searchSSL(s))){ + if ((sslq = searchSSL(state, s))){ int res, err; if((res = ssl_read(sslq->conn, (void *)msg, len)) <= 0) { err = SSL_get_error((SSL *)((ssl_conn*)sslq->conn)->ssl, res); @@ -181,9 +171,9 @@ static int WINAPI ssl_recv(void *state, SOCKET s, void *msg, int len, int flags) #else static ssize_t ssl_recv(void *state, SOCKET s, void *msg, size_t len, int flags){ #endif - struct SSLqueue *sslq; + struct SSLsock *sslq; - if ((sslq = searchSSL(s))){ + if ((sslq = searchSSL(state,s))){ int res, err; if((res = ssl_read(sslq->conn, (void *)msg, len)) <= 0) { err = SSL_get_error((SSL *)((ssl_conn*)sslq->conn)->ssl, res); @@ -200,16 +190,16 @@ static ssize_t ssl_recv(void *state, SOCKET s, void *msg, size_t len, int flags) } static int WINAPI ssl_closesocket(void *state, SOCKET s){ - delSSL(s); + delSSL(state, s); return sso._closesocket(sso.state, s); } static int WINAPI ssl_poll(void *state, struct pollfd *fds, unsigned int nfds, int timeout){ - struct SSLqueue *sslq = NULL; + struct SSLsock *sslq = NULL; unsigned int i; int ret = 0; for(i = 0; i < nfds; i++){ - if((fds[i].events & POLLIN) && (sslq = searchSSL(fds[i].fd)) && ssl_pending(sslq->conn)){ + if((fds[i].events & POLLIN) && (sslq = searchSSL(state, fds[i].fd)) && ssl_pending(sslq->conn)){ fds[i].revents = POLLIN; ret++; } @@ -221,6 +211,7 @@ static int WINAPI ssl_poll(void *state, struct pollfd *fds, unsigned int nfds, i return ret; } +#define PCONF (((struct SSLstate *)param->sostate)->config) int dossl(struct clientparam* param, SSL_CONN* ServerConnp, SSL_CONN* ClientConnp){ SSL_CERT ServerCert=NULL, FakeCert=NULL; @@ -253,23 +244,22 @@ int dossl(struct clientparam* param, SSL_CONN* ServerConnp, SSL_CONN* ClientConn if(errSSL)param->srv->logfunc(param, (unsigned char *)errSSL); return 1; } - FakeCert = ssl_copy_cert(ServerCert); + FakeCert = ssl_copy_cert(ServerCert, PCONF); + _ssl_cert_free(ServerCert); if ( FakeCert == NULL ) { param->res = 8012; - _ssl_cert_free(ServerCert); param->srv->logfunc(param, (unsigned char *)"Failed to create certificate copy"); ssl_conn_free(ServerConn); return 2; } - ClientConn = ssl_handshake_to_client(param->clisock, FakeCert, &errSSL); + ClientConn = ssl_handshake_to_client(param->clisock, FakeCert, PCONF->server_key, &errSSL); + _ssl_cert_free(FakeCert); if ( ClientConn == NULL ) { param->res = 8012; param->srv->logfunc(param, (unsigned char *)"Handshake to client failed"); if(errSSL)param->srv->logfunc(param, (unsigned char *)errSSL); - _ssl_cert_free(ServerCert); - _ssl_cert_free(FakeCert); ssl_conn_free(ServerConn); return 3; } @@ -289,8 +279,7 @@ int dossl(struct clientparam* param, SSL_CONN* ServerConnp, SSL_CONN* ClientConn SSL_set_mode((SSL *)((ssl_conn *)ClientConn)->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE|SSL_MODE_AUTO_RETRY); SSL_set_read_ahead((SSL *)((ssl_conn *)ServerConn)->ssl, 0); SSL_set_read_ahead((SSL *)((ssl_conn *)ClientConn)->ssl, 0); - addSSL(param->remsock, ServerCert, ServerConn, param); - addSSL(param->clisock, FakeCert, ClientConn, param); + addSSL(param->clisock, ClientConn, param->remsock, ServerConn, param); if(ServerConnp)*ServerConnp = ServerConn; if(ClientConnp)*ClientConnp = ClientConn; @@ -299,13 +288,95 @@ int dossl(struct clientparam* param, SSL_CONN* ServerConnp, SSL_CONN* ClientConn } -static void* ssl_filter_open(void * idata, struct srvparam * param){ - return idata; + +static void* ssl_filter_open(void * idata, struct srvparam * srv){ + struct ssl_config *sc; + sc = malloc(sizeof(struct ssl_config)); + if(!sc) return NULL; + memset(sc, 0, sizeof(struct ssl_config)); + if(certcache) sc->certcache = strdup(certcache); + if(mitm){ + BIO *f; + char fname[256]; + + + if(!certcache) { + free(sc); + return NULL; + } + sprintf(fname, "%.240s3proxy.pem", certcache); + f = BIO_new_file(fname, "r"); + if ( f != NULL ) { + sc->CA_cert=PEM_read_bio_X509(f, NULL, NULL, NULL); + BIO_free(f); + if(!sc->CA_cert){ + unsigned long err; + err=ERR_get_error(); + fprintf(stderr, "failed to read: %s: [%lu] %s\n", fname, err, ERR_error_string(err, NULL)); + free(sc); + return NULL; + } + } + else { + fprintf(stderr, "failed to open: %s\n", fname); + free(sc); + return NULL; + } + sc->name = X509_get_subject_name(sc->CA_cert); + sprintf(fname, "%.240s3proxy.key", sc->certcache); + f = BIO_new_file(fname, "rb"); + if ( f != NULL ) { + sc->CA_key = PEM_read_bio_PrivateKey(f, NULL, NULL, NULL); + BIO_free(f); + if(!sc->CA_key){ + unsigned long err; + err=ERR_get_error(); + fprintf(stderr, "failed to read: %s: [%lu] %s\n", fname, err, ERR_error_string(err, NULL)); + return NULL; + } + } + else { + fprintf(stderr, "failed to open: %s\n", fname); + return NULL; + } + + sprintf(fname, "%.128sserver.key", sc->certcache); + f = BIO_new_file(fname, "rb"); + if ( f != NULL ) { + sc->server_key = PEM_read_bio_PrivateKey(f, &sc->server_key, NULL, NULL); + BIO_free(f); + if(!sc->server_key){ + unsigned long err; + err=ERR_get_error(); + fprintf(stderr, "failed to read: %s: [%lu] %s\n", fname, err, ERR_error_string(err, NULL)); + return NULL; + } + } + else { + fprintf(stderr, "failed to open: %s\n", fname); + } + sc->transparent = 1; + srv->so._send = ssl_send; + srv->so._recv = ssl_recv; + srv->so._sendto = ssl_sendto; + srv->so._recvfrom = ssl_recvfrom; + srv->so._closesocket = ssl_closesocket; + srv->so._poll = ssl_poll; + } + return sc; } static FILTER_ACTION ssl_filter_client(void *fo, struct clientparam * param, void** fc){ + struct SSLstate *ssls; + + ssls = (struct SSLstate *) malloc(sizeof(struct SSLstate)); + memset(ssls, 0, sizeof(struct SSLstate)); + ssls->config = fo; + ssls->param = param; + param->sostate = ssls; + *fc = ssls; return CONTINUE; } @@ -319,16 +390,35 @@ static FILTER_ACTION ssl_filter_predata(void *fo, struct clientparam * param){ } -static void ssl_filter_clear(void *fo){ +static void ssl_filter_clear(void *fc){ + free(fc); } +#define CONFIG ((SSL_CONFIG *)fo) + static void ssl_filter_close(void *fo){ + free(CONFIG->certcache); + if ( CONFIG->CA_cert != NULL ) { + X509_free(CONFIG->CA_cert); + CONFIG->CA_cert = NULL; + } + + if ( CONFIG->CA_key != NULL ) { + EVP_PKEY_free(CONFIG->CA_key); + CONFIG->CA_key = NULL; + } + + if ( CONFIG->server_key != NULL ) { + EVP_PKEY_free(CONFIG->server_key); + CONFIG->server_key = NULL; + } + free(fo); } -static struct filter ssl_filter = { +static struct filter ssl_filter_mitm = { NULL, "ssl filter", - "ssl filter", + "mitm", ssl_filter_open, ssl_filter_client, NULL, NULL, NULL, ssl_filter_predata, NULL, NULL, @@ -336,50 +426,44 @@ static struct filter ssl_filter = { ssl_filter_close }; -int mitm = 0; -int ssl_inited = 0; static int h_mitm(int argc, unsigned char **argv){ - if(!ssl_inited) { - ssl_init(); - ssl_inited = 1; - } if((mitm&1)) return 1; if(mitm) usleep(100*SLEEPTIME); - ssl_filter.next = pl->conf->filters; - pl->conf->filters = &ssl_filter; - mitm++; + ssl_filter_mitm.next = pl->conf->filters; + pl->conf->filters = &ssl_filter_mitm; + sso = *pl->so; + mitm = 1; return 0; } static int h_nomitm(int argc, unsigned char **argv){ struct filter * sf; - if(!(mitm&1)) return 1; - if(mitm) usleep(100*SLEEPTIME); - if(pl->conf->filters == &ssl_filter) pl->conf->filters = ssl_filter.next; + if(!mitm) return 1; + if(pl->conf->filters == &ssl_filter_mitm) pl->conf->filters = ssl_filter_mitm.next; else for(sf = pl->conf->filters; sf && sf->next; sf=sf->next){ - if(sf->next == &ssl_filter) { - sf->next = ssl_filter.next; + if(sf->next == &ssl_filter_mitm) { + sf->next = ssl_filter_mitm.next; break; } } - mitm++; + mitm = 0; return 0; } -static int h_certpath(int argc, unsigned char **argv){ +static int h_certcache(int argc, unsigned char **argv){ size_t len; - len = strlen(argv[1]); + len = strlen((char *)argv[1]); if(!len || (argv[1][len - 1] != '/' && argv[1][len - 1] != '\\')) return 1; - if(cert_path && *cert_path) free(cert_path); - cert_path = strdup(argv[1]); + if(certcache) free(certcache); + certcache = strdup((char *)argv[1]); return 0; } static struct commands ssl_commandhandlers[] = { {ssl_commandhandlers+1, "ssl_mitm", h_mitm, 1, 1}, {ssl_commandhandlers+2, "ssl_nomitm", h_nomitm, 1, 1}, - {NULL, "ssl_certcache", h_certpath, 2, 2}, + {NULL, "ssl_certcache", h_certcache, 2, 2}, }; @@ -395,21 +479,10 @@ PLUGINAPI int PLUGINCALL ssl_plugin (struct pluginlink * pluginlink, pl = pluginlink; if(!ssl_loaded){ ssl_loaded = 1; - pthread_mutex_init(&ssl_mutex, NULL); - memcpy(&sso, pl->so, sizeof(struct sockfuncs)); - pl->so->_send = ssl_send; - pl->so->_recv = ssl_recv; - pl->so->_sendto = ssl_sendto; - pl->so->_recvfrom = ssl_recvfrom; - pl->so->_closesocket = ssl_closesocket; - pl->so->_poll = ssl_poll; + ssl_init(); ssl_commandhandlers[2].next = pl->commandhandlers->next; pl->commandhandlers->next = ssl_commandhandlers; } - else { - ssl_release(); - ssl_inited = 0; - } tcppmfunc = (PROXYFUNC)pl->findbyname("tcppm"); if(!tcppmfunc){return 13;}