Created
December 6, 2022 12:32
-
-
Save nickfox-taterli/3bf15d16ca2bbeaa578cd3eca0a88aa2 to your computer and use it in GitHub Desktop.
tls_proxy_smtp.c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SSL/TLS 中继 SMTP 流量,由于Gmail证书精准识别,因此只能出此下策. | |
#include "mbedtls/build_info.h" | |
#include "mbedtls/platform.h" | |
#include <stdlib.h> | |
#include <string.h> | |
#include "mbedtls/entropy.h" | |
#include "mbedtls/ctr_drbg.h" | |
#include "mbedtls/x509.h" | |
#include "mbedtls/ssl.h" | |
#include "mbedtls/net_sockets.h" | |
#include "mbedtls/error.h" | |
#include "mbedtls/debug.h" | |
#include "test/certs.h" | |
#if defined(MBEDTLS_SSL_CACHE_C) | |
#include "mbedtls/ssl_cache.h" | |
#endif | |
#define DEBUG_LEVEL 0 | |
// 没办法,为了和其他交互. | |
static mbedtls_ssl_context ssl_client; | |
static void debug( void *ctx, int level, | |
const char *file, int line, | |
const char *str ) | |
{ | |
((void) level); | |
mbedtls_fprintf( (FILE *) ctx, "%s:%04d: %s", file, line, str ); | |
fflush( (FILE *) ctx ); | |
} | |
int ssl_relayclient( int init_or_exit ) | |
{ | |
int ret = 1, len; | |
int exit_code = MBEDTLS_EXIT_FAILURE; | |
static mbedtls_net_context server_fd; | |
uint32_t flags; | |
unsigned char buf[1024]; | |
const char *pers = "ssl_client"; | |
static mbedtls_entropy_context entropy; | |
static mbedtls_ctr_drbg_context ctr_drbg; | |
static mbedtls_ssl_config conf; | |
static mbedtls_x509_crt cacert; | |
if(init_or_exit){ | |
#if defined(MBEDTLS_DEBUG_C) | |
mbedtls_debug_set_threshold( DEBUG_LEVEL ); | |
#endif | |
/* | |
* 0. Initialize the RNG and the session data | |
*/ | |
mbedtls_net_init( &server_fd ); | |
mbedtls_ssl_init( &ssl_client ); | |
mbedtls_ssl_config_init( &conf ); | |
mbedtls_x509_crt_init( &cacert ); | |
mbedtls_ctr_drbg_init( &ctr_drbg ); | |
mbedtls_printf( "\n . Seeding the random number generator..." ); | |
fflush( stdout ); | |
mbedtls_entropy_init( &entropy ); | |
if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, | |
(const unsigned char *) pers, | |
strlen( pers ) ) ) != 0 ) | |
{ | |
mbedtls_printf( " failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret ); | |
for(;;); | |
} | |
mbedtls_printf( " ok\n" ); | |
/* | |
* 1. Initialize certificates (反正也不验证,随便Load一个测试证书.) | |
*/ | |
mbedtls_printf( " . Loading the CA root certificate ..." ); | |
fflush( stdout ); | |
ret = mbedtls_x509_crt_parse( &cacert, (const unsigned char *) mbedtls_test_cas_pem, | |
mbedtls_test_cas_pem_len ); | |
if( ret < 0 ) | |
{ | |
mbedtls_printf( " failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", (unsigned int) -ret ); | |
for(;;); | |
} | |
mbedtls_printf( " ok (%d skipped)\n", ret ); | |
/* | |
* 2. Start the connection | |
*/ | |
mbedtls_printf( " . Connecting to tcp/%s:%d...", "smtp.gmail.com", 465 ); | |
fflush( stdout ); | |
if( ( ret = mbedtls_net_connect( &server_fd, "smtp.gmail.com", | |
"465", MBEDTLS_NET_PROTO_TCP ) ) != 0 ) | |
{ | |
mbedtls_printf( " failed\n ! mbedtls_net_connect returned %d\n\n", ret ); | |
for(;;); | |
} | |
mbedtls_printf( " ok\n" ); | |
/* | |
* 3. Setup stuff | |
*/ | |
mbedtls_printf( " . Setting up the SSL/TLS structure..." ); | |
fflush( stdout ); | |
if( ( ret = mbedtls_ssl_config_defaults( &conf, | |
MBEDTLS_SSL_IS_CLIENT, | |
MBEDTLS_SSL_TRANSPORT_STREAM, | |
MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 ) | |
{ | |
mbedtls_printf( " failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret ); | |
for(;;); | |
} | |
mbedtls_printf( " ok\n" ); | |
/* OPTIONAL is not optimal for security, | |
* but makes interop easier in this simplified example */ | |
mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_OPTIONAL ); | |
mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL ); | |
mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg ); | |
mbedtls_ssl_conf_dbg( &conf, debug, stdout ); | |
mbedtls_ssl_conf_read_timeout( &conf, 1000 ); | |
if( ( ret = mbedtls_ssl_setup( &ssl_client, &conf ) ) != 0 ) | |
{ | |
mbedtls_printf( " failed\n ! mbedtls_ssl_setup returned %d\n\n", ret ); | |
for(;;); | |
} | |
if( ( ret = mbedtls_ssl_set_hostname( &ssl_client, "smtp.gmail.com" ) ) != 0 ) | |
{ | |
mbedtls_printf( " failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret ); | |
for(;;); | |
} | |
mbedtls_ssl_set_bio( &ssl_client, &server_fd, mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout ); | |
/* | |
* 4. Handshake | |
*/ | |
mbedtls_printf( " . Performing the SSL/TLS handshake..." ); | |
fflush( stdout ); | |
while( ( ret = mbedtls_ssl_handshake( &ssl_client ) ) != 0 ) | |
{ | |
if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) | |
{ | |
mbedtls_printf( " failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", (unsigned int) -ret ); | |
for(;;); | |
} | |
} | |
mbedtls_printf( " ok\n" ); | |
}else{ | |
mbedtls_net_free( &server_fd ); | |
mbedtls_x509_crt_free( &cacert ); | |
mbedtls_ssl_free( &ssl_client ); | |
mbedtls_ssl_config_free( &conf ); | |
mbedtls_ctr_drbg_free( &ctr_drbg ); | |
mbedtls_entropy_free( &entropy ); | |
} | |
} | |
int main( void ) | |
{ | |
int ret, len; | |
mbedtls_net_context listen_fd, client_fd; | |
unsigned char buf[1024]; | |
const char *pers = "ssl_server"; | |
mbedtls_entropy_context entropy; | |
mbedtls_ctr_drbg_context ctr_drbg; | |
mbedtls_ssl_context ssl; | |
mbedtls_ssl_config conf; | |
mbedtls_x509_crt srvcert; | |
mbedtls_pk_context pkey; | |
#if defined(MBEDTLS_SSL_CACHE_C) | |
mbedtls_ssl_cache_context cache; | |
#endif | |
mbedtls_net_init( &listen_fd ); | |
mbedtls_net_init( &client_fd ); | |
mbedtls_ssl_init( &ssl ); | |
mbedtls_ssl_config_init( &conf ); | |
#if defined(MBEDTLS_SSL_CACHE_C) | |
mbedtls_ssl_cache_init( &cache ); | |
#endif | |
mbedtls_x509_crt_init( &srvcert ); | |
mbedtls_pk_init( &pkey ); | |
mbedtls_entropy_init( &entropy ); | |
mbedtls_ctr_drbg_init( &ctr_drbg ); | |
#if defined(MBEDTLS_DEBUG_C) | |
mbedtls_debug_set_threshold( DEBUG_LEVEL ); | |
#endif | |
/* | |
* 1. Seed the RNG | |
*/ | |
mbedtls_printf( " . Seeding the random number generator..." ); | |
fflush( stdout ); | |
if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy, | |
(const unsigned char *) pers, | |
strlen( pers ) ) ) != 0 ) | |
{ | |
mbedtls_printf( " failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret ); | |
for(;;); | |
} | |
mbedtls_printf( " ok\n" ); | |
/* | |
* 2. Load the certificates and private RSA key | |
*/ | |
mbedtls_printf( "\n . Loading the server cert. and key..." ); | |
fflush( stdout ); | |
/* | |
* This demonstration program uses embedded test certificates. | |
* Instead, you may want to use mbedtls_x509_crt_parse_file() to read the | |
* server and CA certificates, as well as mbedtls_pk_parse_keyfile(). | |
*/ | |
ret = mbedtls_x509_crt_parse_file( &srvcert, "/etc/letsencrypt/live/lax-01.taterli.cyou/fullchain.pem" ); | |
if( ret != 0 ) | |
{ | |
mbedtls_printf( " failed\n ! mbedtls_x509_crt_parse returned %d\n\n", ret ); | |
for(;;); | |
} | |
ret = mbedtls_x509_crt_parse_file( &srvcert, "/etc/letsencrypt/live/lax-01.taterli.cyou/fullchain.pem" ); | |
if( ret != 0 ) | |
{ | |
mbedtls_printf( " failed\n ! mbedtls_x509_crt_parse returned %d\n\n", ret ); | |
for(;;); | |
} | |
ret = mbedtls_pk_parse_keyfile( &pkey, "/etc/letsencrypt/live/lax-01.taterli.cyou/privkey.pem", NULL,mbedtls_ctr_drbg_random, &ctr_drbg); | |
if( ret != 0 ) | |
{ | |
mbedtls_printf( " failed\n ! mbedtls_pk_parse_key returned %d\n\n", ret ); | |
for(;;); | |
} | |
mbedtls_printf( " ok\n" ); | |
/* | |
* 3. Setup the listening TCP socket | |
*/ | |
mbedtls_printf( " . Bind on https://0.0.0.0:465/ ..." ); | |
fflush( stdout ); | |
if( ( ret = mbedtls_net_bind( &listen_fd, NULL, "465", MBEDTLS_NET_PROTO_TCP ) ) != 0 ) | |
{ | |
mbedtls_printf( " failed\n ! mbedtls_net_bind returned %d\n\n", ret ); | |
for(;;); | |
} | |
mbedtls_printf( " ok\n" ); | |
/* | |
* 4. Setup stuff | |
*/ | |
mbedtls_printf( " . Setting up the SSL data...." ); | |
fflush( stdout ); | |
if( ( ret = mbedtls_ssl_config_defaults( &conf, | |
MBEDTLS_SSL_IS_SERVER, | |
MBEDTLS_SSL_TRANSPORT_STREAM, | |
MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 ) | |
{ | |
mbedtls_printf( " failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret ); | |
for(;;); | |
} | |
mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg ); | |
mbedtls_ssl_conf_dbg( &conf, debug, stdout ); | |
#if defined(MBEDTLS_SSL_CACHE_C) | |
mbedtls_ssl_conf_session_cache( &conf, &cache, | |
mbedtls_ssl_cache_get, | |
mbedtls_ssl_cache_set ); | |
#endif | |
mbedtls_ssl_conf_ca_chain( &conf, srvcert.next, NULL ); | |
if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &srvcert, &pkey ) ) != 0 ) | |
{ | |
mbedtls_printf( " failed\n ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret ); | |
for(;;); | |
} | |
if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 ) | |
{ | |
mbedtls_printf( " failed\n ! mbedtls_ssl_setup returned %d\n\n", ret ); | |
for(;;); | |
} | |
mbedtls_printf( " ok\n" ); | |
reset: | |
#ifdef MBEDTLS_ERROR_C | |
if( ret != 0 ) | |
{ | |
char error_buf[100]; | |
mbedtls_strerror( ret, error_buf, 100 ); | |
mbedtls_printf("Last error was: %d - %s\n\n", ret, error_buf ); | |
} | |
#endif | |
mbedtls_net_free( &client_fd ); | |
mbedtls_ssl_session_reset( &ssl ); | |
/* | |
* 3. Wait until a client connects | |
*/ | |
mbedtls_printf( " . Waiting for a remote connection ..." ); | |
fflush( stdout ); | |
if( ( ret = mbedtls_net_accept( &listen_fd, &client_fd, | |
NULL, 0, NULL ) ) != 0 ) | |
{ | |
mbedtls_printf( " failed\n ! mbedtls_net_accept returned %d\n\n", ret ); | |
for(;;); | |
} | |
mbedtls_ssl_set_bio( &ssl, &client_fd, mbedtls_net_send, mbedtls_net_recv, NULL ); | |
mbedtls_printf( " ok\n" ); | |
/* | |
* 5. Handshake | |
*/ | |
mbedtls_printf( " . Performing the SSL/TLS handshake..." ); | |
fflush( stdout ); | |
while( ( ret = mbedtls_ssl_handshake( &ssl ) ) != 0 ) | |
{ | |
if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) | |
{ | |
mbedtls_printf( " failed\n ! mbedtls_ssl_handshake returned %d\n\n", ret ); | |
goto reset; | |
} | |
} | |
mbedtls_printf( " ok\n" ); | |
// 这里开始建立到另一边的TCP SSL链接,并修改部分数据 | |
ssl_relayclient(1); // 初始化客户端 | |
do | |
{ | |
// 第一圈,从远端的送到客户端 | |
len = sizeof( buf ) - 1; | |
memset( buf, 0, sizeof( buf ) ); | |
ret = mbedtls_ssl_read( &ssl_client, buf, len ); /* 会从对面服务器获取数据 */ | |
if( ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY ) | |
break; | |
if(ret > 0){ | |
// 假定成功(事实上要判断ret) | |
len = ret; | |
mbedtls_printf( " %d bytes read\n\n%s", len, (char *) buf ); | |
mbedtls_printf( " > Write to client:" ); | |
fflush( stdout ); | |
// 这里针对地处理(比如替换GMIAL特征) | |
while( ( ret = mbedtls_ssl_write( &ssl, buf, len ) ) <= 0 ) | |
{ | |
if( ret == MBEDTLS_ERR_NET_CONN_RESET ) | |
{ | |
mbedtls_printf( " failed\n ! peer closed the connection\n\n" ); | |
goto reset; | |
} | |
if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) | |
{ | |
mbedtls_printf( " failed\n ! mbedtls_ssl_write returned %d\n\n", ret ); | |
for(;;); | |
} | |
} | |
len = ret; | |
mbedtls_printf( " %d bytes written\n\n%s\n", len, (char *) buf ); | |
} | |
// 第二圈,从客户端的送到远端. | |
len = sizeof( buf ) - 1; | |
memset( buf, 0, sizeof( buf ) ); | |
ret = mbedtls_ssl_read( &ssl, buf, len ); /* 会从对面服务器获取数据 */ | |
// 假定成功(事实上要判断ret) | |
if( ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY ) | |
break; | |
len = ret; | |
mbedtls_printf( " %d bytes read\n\n%s", ret, (char *) buf ); | |
mbedtls_printf( " > Read from client:" ); | |
fflush( stdout ); | |
while( ( ret = mbedtls_ssl_write( &ssl_client, buf, len ) ) <= 0 ) | |
{ | |
if( ret == MBEDTLS_ERR_NET_CONN_RESET ) | |
{ | |
mbedtls_printf( " failed\n ! peer closed the connection\n\n" ); | |
goto reset; | |
} | |
if( ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE ) | |
{ | |
mbedtls_printf( " failed\n ! mbedtls_ssl_write returned %d\n\n", ret ); | |
for(;;); | |
} | |
} | |
len = ret; | |
mbedtls_printf( " %d bytes read\n\n%s\n", len, (char *) buf ); | |
} | |
while( 1 ); | |
mbedtls_printf( " . Closing the connection..." ); | |
mbedtls_ssl_close_notify( &ssl_client ); | |
ssl_relayclient(0); // 取消客户端的初始化 | |
while( ( ret = mbedtls_ssl_close_notify( &ssl ) ) < 0 ) | |
{ | |
if( ret != MBEDTLS_ERR_SSL_WANT_READ && | |
ret != MBEDTLS_ERR_SSL_WANT_WRITE ) | |
{ | |
mbedtls_printf( " failed\n ! mbedtls_ssl_close_notify returned %d\n\n", ret ); | |
goto reset; | |
} | |
} | |
mbedtls_printf( " ok\n" ); | |
ret = 0; | |
goto reset; | |
#ifdef MBEDTLS_ERROR_C | |
if( ret != 0 ) | |
{ | |
char error_buf[100]; | |
mbedtls_strerror( ret, error_buf, 100 ); | |
mbedtls_printf("Last error was: %d - %s\n\n", ret, error_buf ); | |
} | |
#endif | |
mbedtls_net_free( &client_fd ); | |
mbedtls_net_free( &listen_fd ); | |
mbedtls_x509_crt_free( &srvcert ); | |
mbedtls_pk_free( &pkey ); | |
mbedtls_ssl_free( &ssl ); | |
mbedtls_ssl_config_free( &conf ); | |
#if defined(MBEDTLS_SSL_CACHE_C) | |
mbedtls_ssl_cache_free( &cache ); | |
#endif | |
mbedtls_ctr_drbg_free( &ctr_drbg ); | |
mbedtls_entropy_free( &entropy ); | |
mbedtls_exit( ret ); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment