2018-10-11 21:07:30 +00:00
/*-
* SSLsplit - transparent SSL / TLS interception
* https : //www.roe.ch/SSLsplit
*
* Copyright ( c ) 2009 - 2018 , Daniel Roethlisberger < daniel @ roe . ch > .
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
* 1. Redistributions of source code must retain the above copyright notice ,
* this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright notice ,
* this list of conditions and the following disclaimer in the documentation
* and / or other materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ` ` AS IS ' '
* AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR
* CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS
* INTERRUPTION ) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY , WHETHER IN
* CONTRACT , STRICT LIABILITY , OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE )
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE .
*/
# include "protoautossl.h"
2018-10-15 22:51:07 +00:00
# include "prototcp.h"
2018-10-16 00:37:07 +00:00
# include "protossl.h"
2018-10-15 22:51:07 +00:00
2018-10-11 21:07:30 +00:00
# include "pxysslshut.h"
# include <string.h>
# include <sys/param.h>
# include <event2/bufferevent_ssl.h>
2018-10-17 23:42:47 +00:00
typedef struct protoautossl_ctx protoautossl_ctx_t ;
struct protoautossl_ctx {
unsigned int clienthello_search : 1 ; /* 1 if waiting for hello */
unsigned int clienthello_found : 1 ; /* 1 if conn upgrade to SSL */
} ;
2018-10-11 21:07:30 +00:00
/*
* Peek into pending data to see if it is an SSL / TLS ClientHello , and if so ,
* upgrade the connection from plain TCP to SSL / TLS .
*
* Return 1 if ClientHello was found and connection was upgraded to SSL / TLS ,
* 0 otherwise .
*
* WARNING : This is experimental code and will need to be improved .
*
* TODO - enable search and skip bytes before ClientHello in case it does not
* start at offset 0 ( i . e . chello > vec_out [ 0 ] . iov_base )
* TODO - peek into more than just the current segment
* TODO - add retry mechanism for short truncated ClientHello , possibly generic
*/
2018-10-17 23:00:49 +00:00
static int NONNULL ( 1 )
2018-10-15 16:22:27 +00:00
protoautossl_peek_and_upgrade ( pxy_conn_ctx_t * ctx )
2018-10-11 21:07:30 +00:00
{
2018-10-15 10:42:40 +00:00
protoautossl_ctx_t * autossl_ctx = ctx - > protoctx - > arg ;
2018-10-11 21:07:30 +00:00
struct evbuffer * inbuf ;
struct evbuffer_iovec vec_out [ 1 ] ;
const unsigned char * chello ;
if ( OPTS_DEBUG ( ctx - > opts ) ) {
log_dbg_printf ( " Checking for a client hello \n " ) ;
}
2018-10-19 12:03:36 +00:00
2018-10-11 21:07:30 +00:00
# ifdef DEBUG_PROXY
2018-10-15 16:22:27 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " protoautossl_peek_and_upgrade: ENTER, fd=%d \n " , ctx - > fd ) ;
2018-10-11 21:07:30 +00:00
# endif /* DEBUG_PROXY */
/* peek the buffer */
inbuf = bufferevent_get_input ( ctx - > src . bev ) ;
if ( evbuffer_peek ( inbuf , 1024 , 0 , vec_out , 1 ) ) {
2018-10-15 10:42:40 +00:00
if ( ssl_tls_clienthello_parse ( vec_out [ 0 ] . iov_base , vec_out [ 0 ] . iov_len , 0 , & chello , & ctx - > sslctx - > sni ) = = 0 ) {
2018-10-11 21:07:30 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
log_dbg_printf ( " Peek found ClientHello \n " ) ;
}
2018-10-19 12:03:36 +00:00
if ( protossl_setup_srv_dst_ssl ( ctx ) = = - 1 ) {
return - 1 ;
2018-10-11 21:07:30 +00:00
}
2018-10-19 12:03:36 +00:00
if ( protossl_setup_srv_dst_new_sslbev ( ctx ) = = - 1 ) {
return - 1 ;
2018-10-11 21:07:30 +00:00
}
# ifdef DEBUG_PROXY
2018-10-20 21:25:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " protoautossl_peek_and_upgrade: Enabling srv_dst, fd=%d \n " , ctx - > fd ) ;
2018-10-11 21:07:30 +00:00
# endif /* DEBUG_PROXY */
2018-10-19 12:03:36 +00:00
bufferevent_setcb ( ctx - > srv_dst . bev , pxy_bev_readcb , pxy_bev_writecb , pxy_bev_eventcb , ctx ) ;
2018-10-11 21:07:30 +00:00
bufferevent_enable ( ctx - > srv_dst . bev , EV_READ | EV_WRITE ) ;
if ( OPTS_DEBUG ( ctx - > opts ) ) {
log_err_level_printf ( LOG_INFO , " Replaced srv_dst bufferevent, new one is %p \n " , ( void * ) ctx - > srv_dst . bev ) ;
}
autossl_ctx - > clienthello_search = 0 ;
autossl_ctx - > clienthello_found = 1 ;
return 1 ;
} else {
if ( OPTS_DEBUG ( ctx - > opts ) ) {
log_dbg_printf ( " Peek found no ClientHello \n " ) ;
}
return 0 ;
}
}
return 0 ;
}
2018-10-19 12:03:36 +00:00
static void NONNULL ( 1 , 2 )
protoautossl_bufferevent_free_and_close_fd ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
{
evutil_socket_t fd = bufferevent_getfd ( bev ) ;
# ifdef DEBUG_PROXY
2018-10-20 21:25:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " protoautossl_bufferevent_free_and_close_fd: in=%zu, out=%zu, fd=%d \n " ,
2018-10-19 12:03:36 +00:00
evbuffer_get_length ( bufferevent_get_input ( bev ) ) , evbuffer_get_length ( bufferevent_get_output ( bev ) ) , fd ) ;
# endif /* DEBUG_PROXY */
SSL * ssl = NULL ;
protoautossl_ctx_t * autossl_ctx = ctx - > protoctx - > arg ;
if ( autossl_ctx - > clienthello_found ) {
ssl = bufferevent_openssl_get_ssl ( bev ) ; /* does not inc refc */
}
// @todo Check if we need to NULL all cbs?
// @see https://stackoverflow.com/questions/31688709/knowing-all-callbacks-have-run-with-libevent-and-bufferevent-free
//bufferevent_setcb(bev, NULL, NULL, NULL, NULL);
bufferevent_free ( bev ) ; /* does not free SSL unless the option BEV_OPT_CLOSE_ON_FREE was set */
if ( ssl ) {
pxy_ssl_shutdown ( ctx - > opts , ctx - > evbase , ssl , fd ) ;
} else {
2018-10-19 23:03:21 +00:00
evutil_closesocket ( fd ) ;
2018-10-19 12:03:36 +00:00
}
}
static void NONNULL ( 1 )
protoautossl_conn_connect ( pxy_conn_ctx_t * ctx )
{
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " protoautossl_conn_connect: ENTER, fd=%d \n " , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
if ( prototcp_setup_dst ( ctx ) = = - 1 ) {
return ;
}
bufferevent_setcb ( ctx - > dst . bev , pxy_bev_readcb , pxy_bev_writecb , pxy_bev_eventcb , ctx ) ;
bufferevent_enable ( ctx - > dst . bev , EV_READ | EV_WRITE ) ;
/* create server-side socket and eventbuffer */
if ( prototcp_setup_srv_dst ( ctx ) = = - 1 ) {
return ;
}
// Enable srv_dst r cb for autossl mode
bufferevent_setcb ( ctx - > srv_dst . bev , pxy_bev_readcb , pxy_bev_writecb , pxy_bev_eventcb , ctx ) ;
bufferevent_enable ( ctx - > srv_dst . bev , EV_READ | EV_WRITE ) ;
/* initiate connection */
if ( bufferevent_socket_connect ( ctx - > srv_dst . bev , ( struct sockaddr * ) & ctx - > addr , ctx - > addrlen ) = = - 1 ) {
log_err_level_printf ( LOG_CRIT , " protoautossl_conn_connect: bufferevent_socket_connect for srv_dst failed \n " ) ;
# ifdef DEBUG_PROXY
2018-10-20 21:25:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " protoautossl_conn_connect: bufferevent_socket_connect for srv_dst failed, fd=%d \n " , ctx - > fd ) ;
2018-10-19 12:03:36 +00:00
# endif /* DEBUG_PROXY */
}
}
static void NONNULL ( 1 )
protoautossl_connect_child ( pxy_conn_child_ctx_t * ctx )
{
protoautossl_ctx_t * autossl_ctx = ctx - > conn - > protoctx - > arg ;
2018-10-19 23:03:21 +00:00
2018-10-19 12:03:36 +00:00
# ifdef DEBUG_PROXY
2018-10-20 21:25:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " protoautossl_connect_child: ENTER, child fd=%d, fd=%d \n " , ctx - > fd , ctx - > conn - > fd ) ;
2018-10-19 12:03:36 +00:00
# endif /* DEBUG_PROXY */
/* create server-side socket and eventbuffer */
// Children rely on the findings of parent
2018-10-20 21:25:01 +00:00
if ( ! autossl_ctx - > clienthello_found ) {
2018-10-19 12:03:36 +00:00
prototcp_setup_dst_child ( ctx ) ;
2018-10-20 21:25:01 +00:00
} else {
protossl_setup_dst_child ( ctx ) ;
2018-10-19 12:03:36 +00:00
}
}
static void NONNULL ( 1 )
protoautossl_bev_readcb_src ( struct bufferevent * bev , void * arg )
{
pxy_conn_ctx_t * ctx = arg ;
protoautossl_ctx_t * autossl_ctx = ctx - > protoctx - > arg ;
# ifdef DEBUG_PROXY
2018-10-20 21:25:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " protoautossl_bev_readcb_src: ENTER, size=%zu, fd=%d \n " ,
evbuffer_get_length ( bufferevent_get_input ( bev ) ) , ctx - > fd ) ;
2018-10-19 12:03:36 +00:00
# endif /* DEBUG_PROXY */
if ( autossl_ctx - > clienthello_search ) {
if ( protoautossl_peek_and_upgrade ( ctx ) ) {
return ;
}
}
if ( ctx - > dst . closed ) {
pxy_discard_inbuf ( bev ) ;
return ;
}
struct evbuffer * inbuf = bufferevent_get_input ( bev ) ;
struct evbuffer * outbuf = bufferevent_get_output ( ctx - > dst . bev ) ;
size_t packet_size = evbuffer_get_length ( inbuf ) ;
// +2 is for \r\n
2018-10-20 21:25:01 +00:00
unsigned char * packet = pxy_malloc_packet ( packet_size + ctx - > sslproxy_header_len + 2 , ctx ) ;
2018-10-19 12:03:36 +00:00
if ( ! packet ) {
return ;
}
evbuffer_remove ( inbuf , packet , packet_size ) ;
# ifdef DEBUG_PROXY
2018-10-20 21:25:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " protoautossl_bev_readcb_src: ORIG packet, size=%zu, fd=%d: \n %.*s \n " ,
2018-10-19 12:03:36 +00:00
packet_size , ctx - > fd , ( int ) packet_size , packet ) ;
# endif /* DEBUG_PROXY */
if ( autossl_ctx - > clienthello_search ) {
# ifdef DEBUG_PROXY
2018-10-20 21:25:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " protoautossl_bev_readcb_src: clienthello_search Duping packet to srv_dst, size=%zu, fd=%d: \n %.*s \n " ,
2018-10-19 12:03:36 +00:00
packet_size , ctx - > fd , ( int ) packet_size , packet ) ;
# endif /* DEBUG_PROXY */
// Dup packet to server while searching for clienthello in autossl mode, without adding SSLproxy specific header
evbuffer_add ( bufferevent_get_output ( ctx - > srv_dst . bev ) , packet , packet_size ) ;
2018-10-21 19:01:46 +00:00
pxy_try_set_watermark ( bev , ctx , ctx - > srv_dst . bev ) ;
2018-10-19 12:03:36 +00:00
}
2018-10-20 21:25:01 +00:00
if ( ! ctx - > sent_sslproxy_header ) {
2018-10-20 12:29:51 +00:00
pxy_insert_sslproxy_header ( ctx , packet , & packet_size ) ;
}
2018-10-19 12:03:36 +00:00
evbuffer_add ( outbuf , packet , packet_size ) ;
# ifdef DEBUG_PROXY
2018-10-20 21:25:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " protoautossl_bev_readcb_src: NEW packet, size=%zu, fd=%d: \n %.*s \n " ,
2018-10-19 12:03:36 +00:00
packet_size , ctx - > fd , ( int ) packet_size , packet ) ;
# endif /* DEBUG_PROXY */
free ( packet ) ;
2018-10-20 12:29:51 +00:00
pxy_try_set_watermark ( bev , ctx , ctx - > dst . bev ) ;
2018-10-19 12:03:36 +00:00
}
static void NONNULL ( 1 )
protoautossl_bev_readcb_dst ( struct bufferevent * bev , void * arg )
{
pxy_conn_ctx_t * ctx = arg ;
protoautossl_ctx_t * autossl_ctx = ctx - > protoctx - > arg ;
# ifdef DEBUG_PROXY
2018-10-20 21:25:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " protoautossl_bev_readcb_dst: ENTER, size=%zu, fd=%d \n " ,
evbuffer_get_length ( bufferevent_get_input ( bev ) ) , ctx - > fd ) ;
2018-10-19 12:03:36 +00:00
# endif /* DEBUG_PROXY */
if ( autossl_ctx - > clienthello_search ) {
if ( protoautossl_peek_and_upgrade ( ctx ) ) {
return ;
}
}
if ( ctx - > src . closed ) {
pxy_discard_inbuf ( bev ) ;
return ;
}
struct evbuffer * inbuf = bufferevent_get_input ( bev ) ;
struct evbuffer * outbuf = bufferevent_get_output ( ctx - > src . bev ) ;
evbuffer_add_buffer ( outbuf , inbuf ) ;
2018-10-20 12:29:51 +00:00
pxy_try_set_watermark ( bev , ctx , ctx - > src . bev ) ;
2018-10-19 12:03:36 +00:00
}
static void NONNULL ( 1 )
protoautossl_bev_readcb_srv_dst ( struct bufferevent * bev , void * arg )
{
pxy_conn_ctx_t * ctx = arg ;
protoautossl_ctx_t * autossl_ctx = ctx - > protoctx - > arg ;
# ifdef DEBUG_PROXY
2018-10-20 21:25:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " protoautossl_bev_readcb_srv_dst: ENTER, size=%zu, fd=%d \n " ,
evbuffer_get_length ( bufferevent_get_input ( bev ) ) , ctx - > fd ) ;
2018-10-19 12:03:36 +00:00
# endif /* DEBUG_PROXY */
if ( autossl_ctx - > clienthello_search ) {
if ( protoautossl_peek_and_upgrade ( ctx ) ) {
return ;
}
}
struct evbuffer * inbuf = bufferevent_get_input ( bev ) ;
size_t inbuf_size = evbuffer_get_length ( inbuf ) ;
# ifdef DEBUG_PROXY
2018-10-20 21:25:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " protoautossl_bev_readcb_srv_dst: clienthello_search Discarding packet, size=%zu, fd=%d \n " ,
2018-10-19 12:03:36 +00:00
inbuf_size , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
// Discard packets to client while searching for clienthello in autossl mode, because child conn passes them along already
// Otherwise client would receive the same packet twice
2018-10-19 23:03:21 +00:00
evbuffer_drain ( inbuf , inbuf_size ) ;
2018-10-19 12:03:36 +00:00
}
2018-10-17 23:00:49 +00:00
static void NONNULL ( 1 , 2 )
2018-10-20 12:29:51 +00:00
protoautossl_bev_eventcb_connected_src ( UNUSED struct bufferevent * bev , UNUSED pxy_conn_ctx_t * ctx )
2018-10-11 21:07:30 +00:00
{
# ifdef DEBUG_PROXY
2018-10-15 16:22:27 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " protoautossl_bev_eventcb_connected_src: ENTER, fd=%d \n " , ctx - > fd ) ;
2018-10-11 21:07:30 +00:00
# endif /* DEBUG_PROXY */
}
2018-10-17 23:00:49 +00:00
static void NONNULL ( 1 )
2018-10-17 13:28:21 +00:00
protoautossl_close_srv_dst ( pxy_conn_ctx_t * ctx )
{
# ifdef DEBUG_PROXY
2018-10-20 21:25:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " protoautossl_close_srv_dst: Closing srv_dst, srv_dst fd=%d, fd=%d \n " , bufferevent_getfd ( ctx - > srv_dst . bev ) , ctx - > fd ) ;
2018-10-17 13:28:21 +00:00
# endif /* DEBUG_PROXY */
2018-10-19 12:03:36 +00:00
// @attention Free the srv_dst of the conn asap, we don't need it anymore, but we need its fd
2018-10-17 13:28:21 +00:00
// So save its ssl info for logging
// @todo Do we always have srv_dst.ssl or not? Can we use ssl or tcp versions of this function?
if ( ctx - > srv_dst . ssl ) {
ctx - > sslctx - > srv_dst_ssl_version = strdup ( SSL_get_version ( ctx - > srv_dst . ssl ) ) ;
ctx - > sslctx - > srv_dst_ssl_cipher = strdup ( SSL_get_cipher ( ctx - > srv_dst . ssl ) ) ;
}
// @attention When both eventcb and writecb for srv_dst are enabled, either eventcb or writecb may get a NULL srv_dst bev, causing a crash with signal 10.
// So, from this point on, we should check if srv_dst is NULL or not.
ctx - > protoctx - > bufferevent_free_and_close_fd ( ctx - > srv_dst . bev , ctx ) ;
ctx - > srv_dst . bev = NULL ;
ctx - > srv_dst . closed = 1 ;
}
2018-10-17 23:00:49 +00:00
static int NONNULL ( 1 )
2018-10-15 16:22:27 +00:00
protoautossl_enable_src ( pxy_conn_ctx_t * ctx )
2018-10-11 21:07:30 +00:00
{
2018-10-15 10:42:40 +00:00
protoautossl_ctx_t * autossl_ctx = ctx - > protoctx - > arg ;
2018-10-11 21:07:30 +00:00
# ifdef DEBUG_PROXY
2018-10-15 16:22:27 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " protoautossl_enable_src: ENTER, fd=%d \n " , ctx - > fd ) ;
2018-10-11 21:07:30 +00:00
# endif /* DEBUG_PROXY */
// Create and set up src.bev
2018-10-17 13:28:21 +00:00
if ( ! autossl_ctx - > clienthello_found ) {
// Create tcp src.bev first
if ( prototcp_setup_src ( ctx ) = = - 1 ) {
return - 1 ;
}
} else {
2018-10-11 21:07:30 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
log_dbg_printf ( " Completing autossl upgrade \n " ) ;
}
2018-10-17 13:28:21 +00:00
// tcp src.bev is already created above
2018-10-11 21:07:30 +00:00
int rv ;
2018-10-17 13:28:21 +00:00
if ( ( rv = protossl_setup_src_ssl ( ctx ) ) ! = 0 ) {
2018-10-11 21:07:30 +00:00
return rv ;
}
2018-10-17 13:28:21 +00:00
// Replace tcp src.bev with ssl version
2018-10-17 23:00:49 +00:00
if ( protossl_setup_src_new_sslbev ( ctx ) = = - 1 ) {
2018-10-11 21:07:30 +00:00
return - 1 ;
}
}
bufferevent_setcb ( ctx - > src . bev , pxy_bev_readcb , pxy_bev_writecb , pxy_bev_eventcb , ctx ) ;
// srv_dst is not needed after clienthello search is over
if ( ctx - > srv_dst . bev & & ! autossl_ctx - > clienthello_search ) {
2018-10-17 13:28:21 +00:00
protoautossl_close_srv_dst ( ctx ) ;
2018-10-11 21:07:30 +00:00
}
// Skip child listener setup if completing autossl upgrade, after finding clienthello
if ( autossl_ctx - > clienthello_search ) {
if ( pxy_setup_child_listener ( ctx ) = = - 1 ) {
return - 1 ;
}
}
# ifdef DEBUG_PROXY
2018-10-20 21:25:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " pxy_autossl_enable_src: Enabling src, %s, child_fd=%d, fd=%d \n " , ctx - > sslproxy_header , ctx - > child_fd , ctx - > fd ) ;
2018-10-11 21:07:30 +00:00
# endif /* DEBUG_PROXY */
2018-10-19 12:03:36 +00:00
2018-10-11 21:07:30 +00:00
// Now open the gates, perhaps for a second time in autossl mode
bufferevent_enable ( ctx - > src . bev , EV_READ | EV_WRITE ) ;
return 0 ;
}
2018-10-17 23:00:49 +00:00
static void NONNULL ( 1 , 2 )
2018-10-21 19:01:46 +00:00
protoautossl_bev_eventcb_connected_dst ( UNUSED struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-10-11 21:07:30 +00:00
{
2018-10-15 10:42:40 +00:00
protoautossl_ctx_t * autossl_ctx = ctx - > protoctx - > arg ;
2018-10-18 22:31:10 +00:00
2018-10-11 21:07:30 +00:00
# ifdef DEBUG_PROXY
2018-10-21 19:01:46 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " protoautossl_bev_eventcb_connected_dst: ENTER, fd=%d \n " , ctx - > fd ) ;
2018-10-11 21:07:30 +00:00
# endif /* DEBUG_PROXY */
ctx - > dst_connected = 1 ;
if ( ctx - > srv_dst_connected & & ctx - > dst_connected & & ( ! ctx - > connected | | ( autossl_ctx - > clienthello_found & & ctx - > srv_dst . bev ) ) ) {
2018-10-19 23:03:21 +00:00
ctx - > connected = 1 ;
2018-10-15 16:22:27 +00:00
if ( protoautossl_enable_src ( ctx ) = = - 1 ) {
2018-10-15 10:42:40 +00:00
return ;
}
}
2018-10-11 21:07:30 +00:00
}
2018-10-17 23:00:49 +00:00
static void NONNULL ( 1 , 2 )
2018-10-15 16:22:27 +00:00
protoautossl_bev_eventcb_connected_srv_dst ( UNUSED struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-10-11 21:07:30 +00:00
{
2018-10-15 10:42:40 +00:00
protoautossl_ctx_t * autossl_ctx = ctx - > protoctx - > arg ;
2018-10-18 22:31:10 +00:00
2018-10-11 21:07:30 +00:00
# ifdef DEBUG_PROXY
2018-10-15 16:22:27 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " protoautossl_bev_eventcb_connected_srv_dst: ENTER, fd=%d \n " , ctx - > fd ) ;
2018-10-11 21:07:30 +00:00
# endif /* DEBUG_PROXY */
// srv_dst may be already connected while upgrading to ssl
if ( ! ctx - > srv_dst_connected ) {
ctx - > srv_dst_connected = 1 ;
2018-10-18 22:31:10 +00:00
2018-10-11 21:07:30 +00:00
// @attention Create and enable dst.bev before, but connect here, because we check if dst.bev is NULL elsewhere
if ( bufferevent_socket_connect ( ctx - > dst . bev , ( struct sockaddr * ) & ctx - > spec - > conn_dst_addr ,
ctx - > spec - > conn_dst_addrlen ) = = - 1 ) {
# ifdef DEBUG_PROXY
2018-10-15 16:22:27 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " protoautossl_bev_eventcb_connected_srv_dst: FAILED bufferevent_socket_connect for dst, fd=%d \n " , ctx - > fd ) ;
2018-10-11 21:07:30 +00:00
# endif /* DEBUG_PROXY */
2018-10-18 22:31:10 +00:00
2018-10-11 21:07:30 +00:00
pxy_conn_free ( ctx , 1 ) ;
return ;
}
}
2018-10-19 23:03:21 +00:00
if ( ctx - > srv_dst_connected & & ctx - > dst_connected & & ( ! ctx - > connected | | autossl_ctx - > clienthello_found ) ) {
ctx - > connected = 1 ;
2018-10-15 16:22:27 +00:00
if ( protoautossl_enable_src ( ctx ) = = - 1 ) {
2018-10-11 21:07:30 +00:00
return ;
}
}
}
2018-10-17 23:00:49 +00:00
static void NONNULL ( 1 )
2018-10-15 16:22:27 +00:00
protoautossl_bev_readcb_complete_child ( pxy_conn_child_ctx_t * ctx )
2018-10-11 21:07:30 +00:00
{
if ( OPTS_DEBUG ( ctx - > conn - > opts ) ) {
log_dbg_printf ( " Completing autossl upgrade on child conn \n " ) ;
}
2018-10-17 13:28:21 +00:00
if ( protossl_setup_dst_ssl_child ( ctx ) = = - 1 ) {
2018-10-11 21:07:30 +00:00
return ;
}
2018-10-17 23:00:49 +00:00
if ( protossl_setup_dst_new_sslbev_child ( ctx ) = = - 1 ) {
2018-10-11 21:07:30 +00:00
return ;
}
bufferevent_setcb ( ctx - > dst . bev , pxy_bev_readcb_child , pxy_bev_writecb_child , pxy_bev_eventcb_child , ctx ) ;
2018-10-17 13:28:21 +00:00
2018-10-11 21:07:30 +00:00
# ifdef DEBUG_PROXY
2018-10-20 21:25:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " protoautossl_bev_readcb_complete_child: Enabling dst, child fd=%d, fd=%d \n " , ctx - > fd , ctx - > conn - > fd ) ;
2018-10-11 21:07:30 +00:00
# endif /* DEBUG_PROXY */
2018-10-19 12:03:36 +00:00
2018-10-11 21:07:30 +00:00
bufferevent_enable ( ctx - > dst . bev , EV_READ | EV_WRITE ) ;
}
2018-10-17 23:00:49 +00:00
static void NONNULL ( 1 )
2018-10-15 16:22:27 +00:00
protoautossl_bev_readcb_src_child ( struct bufferevent * bev , void * arg )
2018-10-11 21:07:30 +00:00
{
pxy_conn_child_ctx_t * ctx = arg ;
2018-10-15 10:42:40 +00:00
protoautossl_ctx_t * autossl_ctx = ctx - > conn - > protoctx - > arg ;
2018-10-11 21:07:30 +00:00
# ifdef DEBUG_PROXY
2018-10-20 21:25:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " protoautossl_bev_readcb_src_child: ENTER, size=%zu, child fd=%d, fd=%d \n " ,
evbuffer_get_length ( bufferevent_get_input ( bev ) ) , ctx - > fd , ctx - > conn - > fd ) ;
2018-10-11 21:07:30 +00:00
# endif /* DEBUG_PROXY */
// Autossl upgrade on child connections follows the findings of parent
if ( autossl_ctx - > clienthello_found & & ! ctx - > dst . ssl ) {
2018-10-15 16:22:27 +00:00
protoautossl_bev_readcb_complete_child ( ctx ) ;
2018-10-11 21:07:30 +00:00
return ;
}
if ( ctx - > dst . closed ) {
pxy_discard_inbuf ( bev ) ;
return ;
}
struct evbuffer * inbuf = bufferevent_get_input ( bev ) ;
struct evbuffer * outbuf = bufferevent_get_output ( ctx - > dst . bev ) ;
2018-10-20 21:25:01 +00:00
if ( ! ctx - > removed_sslproxy_header ) {
2018-10-20 12:29:51 +00:00
size_t packet_size = evbuffer_get_length ( inbuf ) ;
unsigned char * packet = pxy_malloc_packet ( packet_size , ctx - > conn ) ;
if ( ! packet ) {
return ;
}
2018-10-11 21:07:30 +00:00
2018-10-20 12:29:51 +00:00
evbuffer_remove ( inbuf , packet , packet_size ) ;
pxy_try_remove_sslproxy_header ( ctx , packet , & packet_size ) ;
evbuffer_add ( outbuf , packet , packet_size ) ;
2018-10-11 21:07:30 +00:00
# ifdef DEBUG_PROXY
2018-10-20 21:25:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " protoautossl_bev_readcb_src_child: NEW packet, size=%zu, child fd=%d, fd=%d: \n %.*s \n " ,
2018-10-20 12:29:51 +00:00
packet_size , ctx - > fd , ctx - > conn - > fd , ( int ) packet_size , packet ) ;
2018-10-11 21:07:30 +00:00
# endif /* DEBUG_PROXY */
2018-10-20 12:29:51 +00:00
free ( packet ) ;
} else {
evbuffer_add_buffer ( outbuf , inbuf ) ;
}
pxy_try_set_watermark ( bev , ctx - > conn , ctx - > dst . bev ) ;
2018-10-11 21:07:30 +00:00
}
2018-10-17 23:00:49 +00:00
static void NONNULL ( 1 )
2018-10-15 16:22:27 +00:00
protoautossl_bev_readcb_dst_child ( struct bufferevent * bev , void * arg )
2018-10-11 21:07:30 +00:00
{
pxy_conn_child_ctx_t * ctx = arg ;
2018-10-15 10:42:40 +00:00
protoautossl_ctx_t * autossl_ctx = ctx - > conn - > protoctx - > arg ;
2018-10-11 21:07:30 +00:00
# ifdef DEBUG_PROXY
2018-10-20 21:25:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " protoautossl_bev_readcb_dst_child: ENTER, size=%zu, child fd=%d, fd=%d \n " ,
evbuffer_get_length ( bufferevent_get_input ( bev ) ) , ctx - > fd , ctx - > conn - > fd ) ;
2018-10-11 21:07:30 +00:00
# endif /* DEBUG_PROXY */
// Autossl upgrade on child connections follows the findings of parent
if ( autossl_ctx - > clienthello_found & & ! ctx - > dst . ssl ) {
2018-10-15 16:22:27 +00:00
protoautossl_bev_readcb_complete_child ( ctx ) ;
2018-10-11 21:07:30 +00:00
return ;
}
if ( ctx - > src . closed ) {
pxy_discard_inbuf ( bev ) ;
return ;
}
struct evbuffer * inbuf = bufferevent_get_input ( bev ) ;
struct evbuffer * outbuf = bufferevent_get_output ( ctx - > src . bev ) ;
evbuffer_add_buffer ( outbuf , inbuf ) ;
2018-10-20 12:29:51 +00:00
pxy_try_set_watermark ( bev , ctx - > conn , ctx - > src . bev ) ;
2018-10-11 21:07:30 +00:00
}
2018-10-17 23:00:49 +00:00
static void NONNULL ( 1 , 2 )
2018-10-15 16:22:27 +00:00
protoautossl_bev_eventcb_connected_dst_child ( UNUSED struct bufferevent * bev , pxy_conn_child_ctx_t * ctx )
2018-10-11 21:07:30 +00:00
{
2018-10-15 10:42:40 +00:00
protoautossl_ctx_t * autossl_ctx = ctx - > conn - > protoctx - > arg ;
2018-10-11 21:07:30 +00:00
# ifdef DEBUG_PROXY
2018-10-20 21:25:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " protoautossl_bev_eventcb_connected_dst_child: ENTER, child fd=%d, fd=%d \n " , ctx - > fd , ctx - > conn - > fd ) ;
2018-10-11 21:07:30 +00:00
# endif /* DEBUG_PROXY */
ctx - > connected = 1 ;
// @attention Create and enable src.bev before, but connect here, because we check if dst.bev is NULL elsewhere
bufferevent_enable ( ctx - > src . bev , EV_READ | EV_WRITE ) ;
2018-10-18 22:31:10 +00:00
// Check if we have arrived here right after autossl upgrade, which may be triggered by readcb on src
2018-10-11 21:07:30 +00:00
// Autossl upgrade code leaves readcb without processing any data in input buffer of src
// So, if we don't call readcb here, the connection would stall
if ( autossl_ctx - > clienthello_found & & evbuffer_get_length ( bufferevent_get_input ( ctx - > src . bev ) ) ) {
# ifdef DEBUG_PROXY
2018-10-20 21:25:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " protoautossl_bev_eventcb_connected_dst_child: clienthello_found src inbuf len > 0, calling pxy_bev_readcb_child for src, child fd=%d, fd=%d \n " , ctx - > fd , ctx - > conn - > fd ) ;
2018-10-11 21:07:30 +00:00
# endif /* DEBUG_PROXY */
2018-10-18 22:31:10 +00:00
2018-10-11 21:07:30 +00:00
pxy_bev_readcb_child ( ctx - > src . bev , ctx ) ;
}
}
2018-10-17 23:00:49 +00:00
static void NONNULL ( 1 )
2018-10-15 16:22:27 +00:00
protoautossl_bev_eventcb_src ( struct bufferevent * bev , short events , void * arg )
2018-10-11 21:07:30 +00:00
{
pxy_conn_ctx_t * ctx = arg ;
if ( events & BEV_EVENT_CONNECTED ) {
2018-10-15 16:22:27 +00:00
protoautossl_bev_eventcb_connected_src ( bev , ctx ) ;
2018-10-11 21:07:30 +00:00
} else if ( events & BEV_EVENT_EOF ) {
2018-10-15 22:51:07 +00:00
prototcp_bev_eventcb_eof_src ( bev , ctx ) ;
2018-10-11 21:07:30 +00:00
} else if ( events & BEV_EVENT_ERROR ) {
2018-10-15 22:51:07 +00:00
prototcp_bev_eventcb_error_src ( bev , ctx ) ;
2018-10-11 21:07:30 +00:00
}
}
2018-10-17 23:00:49 +00:00
static void NONNULL ( 1 )
2018-10-15 16:22:27 +00:00
protoautossl_bev_eventcb_dst ( struct bufferevent * bev , short events , void * arg )
2018-10-11 21:07:30 +00:00
{
pxy_conn_ctx_t * ctx = arg ;
if ( events & BEV_EVENT_CONNECTED ) {
2018-10-21 19:01:46 +00:00
protoautossl_bev_eventcb_connected_dst ( bev , ctx ) ;
2018-10-11 21:07:30 +00:00
} else if ( events & BEV_EVENT_EOF ) {
2018-10-15 22:51:07 +00:00
prototcp_bev_eventcb_eof_dst ( bev , ctx ) ;
2018-10-11 21:07:30 +00:00
} else if ( events & BEV_EVENT_ERROR ) {
2018-10-15 22:51:07 +00:00
prototcp_bev_eventcb_error_dst ( bev , ctx ) ;
2018-10-11 21:07:30 +00:00
}
}
2018-10-17 23:00:49 +00:00
static void NONNULL ( 1 )
2018-10-15 16:22:27 +00:00
protoautossl_bev_eventcb_srv_dst ( struct bufferevent * bev , short events , void * arg )
2018-10-11 21:07:30 +00:00
{
pxy_conn_ctx_t * ctx = arg ;
if ( events & BEV_EVENT_CONNECTED ) {
2018-10-15 16:22:27 +00:00
protoautossl_bev_eventcb_connected_srv_dst ( bev , ctx ) ;
2018-10-11 21:07:30 +00:00
} else if ( events & BEV_EVENT_EOF ) {
2018-10-15 22:51:07 +00:00
prototcp_bev_eventcb_eof_srv_dst ( bev , ctx ) ;
2018-10-11 21:07:30 +00:00
} else if ( events & BEV_EVENT_ERROR ) {
2018-10-15 22:51:07 +00:00
prototcp_bev_eventcb_error_srv_dst ( bev , ctx ) ;
2018-10-11 21:07:30 +00:00
}
}
2018-10-17 23:00:49 +00:00
static void NONNULL ( 1 )
2018-10-15 16:22:27 +00:00
protoautossl_bev_eventcb_dst_child ( struct bufferevent * bev , short events , void * arg )
2018-10-11 21:07:30 +00:00
{
pxy_conn_child_ctx_t * ctx = arg ;
if ( events & BEV_EVENT_CONNECTED ) {
2018-10-15 16:22:27 +00:00
protoautossl_bev_eventcb_connected_dst_child ( bev , ctx ) ;
2018-10-11 21:07:30 +00:00
} else if ( events & BEV_EVENT_EOF ) {
2018-10-15 22:51:07 +00:00
prototcp_bev_eventcb_eof_dst_child ( bev , ctx ) ;
2018-10-11 21:07:30 +00:00
} else if ( events & BEV_EVENT_ERROR ) {
2018-10-15 22:51:07 +00:00
prototcp_bev_eventcb_error_dst_child ( bev , ctx ) ;
2018-10-11 21:07:30 +00:00
}
}
2018-10-17 23:00:49 +00:00
static void NONNULL ( 1 )
2018-10-19 12:03:36 +00:00
protoautossl_bev_readcb ( struct bufferevent * bev , void * arg )
2018-10-11 21:07:30 +00:00
{
2018-10-19 12:03:36 +00:00
pxy_conn_ctx_t * ctx = arg ;
2018-10-11 21:07:30 +00:00
if ( bev = = ctx - > src . bev ) {
2018-10-19 12:03:36 +00:00
protoautossl_bev_readcb_src ( bev , arg ) ;
2018-10-11 21:07:30 +00:00
} else if ( bev = = ctx - > dst . bev ) {
2018-10-19 12:03:36 +00:00
protoautossl_bev_readcb_dst ( bev , arg ) ;
} else if ( bev = = ctx - > srv_dst . bev ) {
protoautossl_bev_readcb_srv_dst ( bev , arg ) ;
2018-10-11 21:07:30 +00:00
} else {
2018-10-19 12:03:36 +00:00
log_err_printf ( " protoautossl_bev_readcb: UNKWN conn end \n " ) ;
2018-10-11 21:07:30 +00:00
}
}
2018-10-19 12:03:36 +00:00
static void NONNULL ( 1 )
protoautossl_bev_readcb_child ( struct bufferevent * bev , void * arg )
2018-10-11 21:07:30 +00:00
{
2018-10-19 12:03:36 +00:00
pxy_conn_child_ctx_t * ctx = arg ;
2018-10-11 21:07:30 +00:00
2018-10-19 12:03:36 +00:00
if ( bev = = ctx - > src . bev ) {
protoautossl_bev_readcb_src_child ( bev , arg ) ;
} else if ( bev = = ctx - > dst . bev ) {
protoautossl_bev_readcb_dst_child ( bev , arg ) ;
} else {
log_err_printf ( " protoautossl_bev_readcb_child: UNKWN conn end \n " ) ;
}
}
2018-10-11 21:07:30 +00:00
2018-10-19 12:03:36 +00:00
static void NONNULL ( 1 )
protoautossl_bev_eventcb ( struct bufferevent * bev , short events , void * arg )
{
pxy_conn_ctx_t * ctx = arg ;
2018-10-21 19:01:46 +00:00
protoautossl_ctx_t * autossl_ctx = ctx - > protoctx - > arg ;
if ( ( events & BEV_EVENT_ERROR ) & & autossl_ctx - > clienthello_found ) {
protossl_log_ssl_error ( bev , ctx ) ;
}
2018-10-11 21:07:30 +00:00
2018-10-19 12:03:36 +00:00
if ( bev = = ctx - > src . bev ) {
protoautossl_bev_eventcb_src ( bev , events , arg ) ;
} else if ( bev = = ctx - > dst . bev ) {
protoautossl_bev_eventcb_dst ( bev , events , arg ) ;
} else if ( bev = = ctx - > srv_dst . bev ) {
protoautossl_bev_eventcb_srv_dst ( bev , events , arg ) ;
} else {
log_err_printf ( " protoautossl_bev_eventcb: UNKWN conn end \n " ) ;
2018-10-11 21:07:30 +00:00
}
2018-10-19 12:03:36 +00:00
}
2018-10-11 21:07:30 +00:00
2018-10-19 12:03:36 +00:00
static void NONNULL ( 1 )
protoautossl_bev_eventcb_child ( struct bufferevent * bev , short events , void * arg )
{
pxy_conn_child_ctx_t * ctx = arg ;
if ( bev = = ctx - > src . bev ) {
prototcp_bev_eventcb_src_child ( bev , events , arg ) ;
} else if ( bev = = ctx - > dst . bev ) {
protoautossl_bev_eventcb_dst_child ( bev , events , arg ) ;
2018-10-11 21:07:30 +00:00
} else {
2018-10-19 12:03:36 +00:00
log_err_printf ( " protoautossl_bev_eventcb_child: UNKWN conn end \n " ) ;
2018-10-11 21:07:30 +00:00
}
}
2018-10-17 23:00:49 +00:00
static void NONNULL ( 1 )
2018-10-11 21:07:30 +00:00
protoautossl_free ( pxy_conn_ctx_t * ctx )
{
2018-10-15 10:42:40 +00:00
protoautossl_ctx_t * autossl_ctx = ctx - > protoctx - > arg ;
2018-10-11 21:07:30 +00:00
free ( autossl_ctx ) ;
2018-10-15 10:42:40 +00:00
protossl_free ( ctx ) ;
2018-10-11 21:07:30 +00:00
}
2018-10-17 23:00:49 +00:00
protocol_t
2018-10-11 21:07:30 +00:00
protoautossl_setup ( pxy_conn_ctx_t * ctx )
{
2018-10-15 10:42:40 +00:00
ctx - > protoctx - > proto = PROTO_AUTOSSL ;
2018-10-15 16:22:27 +00:00
ctx - > protoctx - > connectcb = protoautossl_conn_connect ;
2018-10-15 22:51:07 +00:00
ctx - > protoctx - > fd_readcb = prototcp_fd_readcb ;
2018-10-11 21:07:30 +00:00
2018-10-15 10:42:40 +00:00
ctx - > protoctx - > bev_readcb = protoautossl_bev_readcb ;
2018-10-15 22:51:07 +00:00
ctx - > protoctx - > bev_writecb = prototcp_bev_writecb ;
2018-10-15 16:22:27 +00:00
ctx - > protoctx - > bev_eventcb = protoautossl_bev_eventcb ;
2018-10-11 21:07:30 +00:00
2018-10-15 16:22:27 +00:00
ctx - > protoctx - > bufferevent_free_and_close_fd = protoautossl_bufferevent_free_and_close_fd ;
2018-10-15 10:42:40 +00:00
ctx - > protoctx - > proto_free = protoautossl_free ;
2018-10-11 21:07:30 +00:00
2018-10-15 10:42:40 +00:00
ctx - > protoctx - > arg = malloc ( sizeof ( protoautossl_ctx_t ) ) ;
if ( ! ctx - > protoctx - > arg ) {
free ( ctx - > protoctx ) ;
2018-10-11 21:07:30 +00:00
return PROTO_ERROR ;
}
2018-10-15 10:42:40 +00:00
memset ( ctx - > protoctx - > arg , 0 , sizeof ( protoautossl_ctx_t ) ) ;
protoautossl_ctx_t * autossl_ctx = ctx - > protoctx - > arg ;
2018-10-11 21:07:30 +00:00
autossl_ctx - > clienthello_search = 1 ;
2018-10-15 10:42:40 +00:00
ctx - > sslctx = malloc ( sizeof ( ssl_ctx_t ) ) ;
if ( ! ctx - > sslctx ) {
free ( ctx - > protoctx - > arg ) ;
free ( ctx - > protoctx ) ;
return PROTO_ERROR ;
}
memset ( ctx - > sslctx , 0 , sizeof ( ssl_ctx_t ) ) ;
2018-10-11 21:07:30 +00:00
return PROTO_AUTOSSL ;
}
2018-10-17 23:00:49 +00:00
protocol_t
2018-10-11 21:07:30 +00:00
protoautossl_setup_child ( pxy_conn_child_ctx_t * ctx )
{
2018-10-15 10:42:40 +00:00
ctx - > protoctx - > proto = PROTO_AUTOSSL ;
2018-10-15 16:22:27 +00:00
ctx - > protoctx - > connectcb = protoautossl_connect_child ;
2018-10-11 21:07:30 +00:00
2018-10-15 16:22:27 +00:00
ctx - > protoctx - > bev_readcb = protoautossl_bev_readcb_child ;
2018-10-15 22:51:07 +00:00
ctx - > protoctx - > bev_writecb = prototcp_bev_writecb_child ;
2018-10-15 16:22:27 +00:00
ctx - > protoctx - > bev_eventcb = protoautossl_bev_eventcb_child ;
2018-10-11 21:07:30 +00:00
2018-10-15 16:22:27 +00:00
ctx - > protoctx - > bufferevent_free_and_close_fd = protoautossl_bufferevent_free_and_close_fd ;
2018-10-11 21:07:30 +00:00
return PROTO_AUTOSSL ;
}
/* vim: set noet ft=c: */