2018-02-27 19:20:58 +00:00
/*-
2015-02-24 18:19:20 +00:00
* SSLsplit - transparent SSL / TLS interception
2018-02-27 19:20:58 +00:00
* https : //www.roe.ch/SSLsplit
*
* Copyright ( c ) 2009 - 2018 , Daniel Roethlisberger < daniel @ roe . ch > .
2012-04-13 12:47:30 +00:00
* All rights reserved .
*
* Redistribution and use in source and binary forms , with or without
2018-02-27 19:20:58 +00:00
* 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 .
2012-04-13 12:47:30 +00:00
*
2018-02-27 19:20:58 +00:00
* 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 .
2012-04-13 12:47:30 +00:00
*/
# include "pxyconn.h"
2017-07-15 18:51:20 +00:00
# include "privsep.h"
2012-04-13 12:47:30 +00:00
# include "pxysslshut.h"
# include "cachemgr.h"
# include "ssl.h"
# include "opts.h"
# include "sys.h"
2012-04-22 11:28:03 +00:00
# include "util.h"
2012-04-22 17:12:38 +00:00
# include "base64.h"
# include "url.h"
2012-04-13 12:47:30 +00:00
# include "log.h"
# include "attrib.h"
2014-11-13 23:41:27 +00:00
# include "proc.h"
2012-04-13 12:47:30 +00:00
# include <netinet/in.h>
2017-05-29 09:22:23 +00:00
# include <arpa/inet.h>
2012-04-13 12:47:30 +00:00
# include <stdlib.h>
# include <stdio.h>
# include <string.h>
# include <errno.h>
# include <event2/event.h>
# include <event2/listener.h>
# include <event2/bufferevent.h>
# include <event2/bufferevent_ssl.h>
# include <event2/buffer.h>
# include <event2/thread.h>
# include <event2/dns.h>
# include <openssl/ssl.h>
# include <openssl/err.h>
# include <openssl/rand.h>
# include <openssl/x509.h>
# include <openssl/x509v3.h>
2017-05-29 09:22:23 +00:00
# include <assert.h>
2017-07-29 21:34:46 +00:00
# include <sys/param.h>
2012-04-13 12:47:30 +00:00
2018-02-20 17:46:08 +00:00
# ifdef HAVE_NETFILTER
# include <glob.h>
# endif /* HAVE_NETFILTER */
2012-04-13 12:47:30 +00:00
/*
* Maximum size of data to buffer per connection direction before
* temporarily stopping to read data from the other end .
*/
# define OUTBUF_LIMIT (128*1024)
/*
* Context used for all server sessions .
*/
# ifdef USE_SSL_SESSION_ID_CONTEXT
static unsigned long ssl_session_context = 0x31415926 ;
# endif /* USE_SSL_SESSION_ID_CONTEXT */
/*
* Proxy connection context state , describes a proxy connection
* with source and destination socket bufferevents , SSL context and
* other session state . One of these exists per handled proxy
* connection .
*/
2017-07-07 14:18:01 +00:00
# ifdef HAVE_LOCAL_PROCINFO
/* local process data - filled in iff pid != -1 */
typedef struct pxy_conn_lproc_desc {
struct sockaddr_storage srcaddr ;
socklen_t srcaddrlen ;
pid_t pid ;
uid_t uid ;
gid_t gid ;
/* derived log strings */
char * exec_path ;
char * user ;
char * group ;
} pxy_conn_lproc_desc_t ;
# endif /* HAVE_LOCAL_PROCINFO */
2017-07-15 01:07:42 +00:00
# define WANT_CONNECT_LOG(ctx) ((ctx)->opts->connectlog||!(ctx)->opts->detach)
# define WANT_CONTENT_LOG(ctx) ((ctx)->opts->contentlog&&!(ctx)->passthrough)
2012-04-13 12:47:30 +00:00
2017-08-11 12:01:51 +00:00
# define SSLPROXY_KEY "SSLproxy:"
# define SSLPROXY_KEY_LEN strlen(SSLPROXY_KEY)
2017-07-22 10:52:40 +00:00
2018-05-09 17:05:29 +00:00
int descriptor_table_size = 0 ;
2018-10-05 01:55:24 +00:00
typedef void ( * callback_func_t ) ( struct bufferevent * , pxy_conn_ctx_t * ) ;
// Forward declarations of callback function tables
callback_func_t readcb_funcs [ ] [ 3 ] ;
callback_func_t writecb_funcs [ ] [ 3 ] ;
callback_func_t eventcb_funcs [ ] [ 3 ] [ 3 ] ;
2017-07-15 10:04:13 +00:00
static pxy_conn_ctx_t * MALLOC NONNULL ( 2 , 3 , 4 )
2017-07-14 19:34:15 +00:00
pxy_conn_ctx_new ( evutil_socket_t fd ,
pxy_thrmgr_ctx_t * thrmgr ,
proxyspec_t * spec , opts_t * opts ,
evutil_socket_t clisock )
2012-04-13 12:47:30 +00:00
{
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_conn_ctx_new: ENTER fd=%d \n " , fd ) ;
# endif /* DEBUG_PROXY */
2017-07-14 19:34:15 +00:00
2012-04-13 12:47:30 +00:00
pxy_conn_ctx_t * ctx = malloc ( sizeof ( pxy_conn_ctx_t ) ) ;
2017-07-12 13:46:51 +00:00
if ( ! ctx ) {
2017-10-14 22:39:30 +00:00
log_err_level_printf ( LOG_CRIT , " Error allocating memory \n " ) ;
2017-07-14 19:34:15 +00:00
evutil_closesocket ( fd ) ;
2012-04-13 12:47:30 +00:00
return NULL ;
2017-07-12 13:46:51 +00:00
}
2012-04-13 12:47:30 +00:00
memset ( ctx , 0 , sizeof ( pxy_conn_ctx_t ) ) ;
2017-07-15 01:07:42 +00:00
2017-10-26 17:10:36 +00:00
ctx - > id = thrmgr - > conn_count + + ;
2017-07-15 01:07:42 +00:00
2017-10-26 17:10:36 +00:00
# if defined (DEBUG_PROXY)
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_conn_ctx_new: id=%llu, fd=%d \n " , ctx - > id , fd ) ;
# endif /* DEBUG_PROXY */
2017-07-15 01:07:42 +00:00
ctx - > fd = fd ;
2018-09-22 23:02:15 +00:00
ctx - > conn = ctx ;
2017-07-15 01:07:42 +00:00
ctx - > thrmgr = thrmgr ;
ctx - > spec = spec ;
2018-10-05 01:55:24 +00:00
if ( ctx - > spec - > upgrade ) {
ctx - > proto = AUTOSSL ;
} else if ( ctx - > spec - > http ) {
ctx - > proto = HTTP ;
} else {
ctx - > proto = DEFAULT ;
}
2017-07-15 01:07:42 +00:00
ctx - > opts = opts ;
ctx - > clisock = clisock ;
ctx - > clienthello_search = ctx - > spec - > upgrade ;
2017-07-15 10:04:13 +00:00
ctx - > ctime = time ( NULL ) ;
ctx - > atime = ctx - > ctime ;
2017-07-15 01:07:42 +00:00
ctx - > next = NULL ;
pxy_thrmgr_attach ( ctx ) ;
2017-07-12 13:46:51 +00:00
2014-11-14 14:36:16 +00:00
# ifdef HAVE_LOCAL_PROCINFO
2014-11-14 14:31:30 +00:00
ctx - > lproc . pid = - 1 ;
2014-11-14 14:36:16 +00:00
# endif /* HAVE_LOCAL_PROCINFO */
2012-04-13 12:47:30 +00:00
# ifdef DEBUG_PROXY
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2017-07-12 13:46:51 +00:00
log_dbg_printf ( " %p pxy_conn_ctx_new \n " , ( void * ) ctx ) ;
2012-04-13 12:47:30 +00:00
}
# endif /* DEBUG_PROXY */
2017-05-29 09:22:23 +00:00
return ctx ;
}
2017-07-15 10:04:13 +00:00
static pxy_conn_child_ctx_t * MALLOC NONNULL ( 2 )
2018-09-22 23:02:15 +00:00
pxy_conn_ctx_new_child ( evutil_socket_t fd , pxy_conn_ctx_t * conn )
2017-06-25 11:21:32 +00:00
{
2018-09-22 23:02:15 +00:00
assert ( conn ! = NULL ) ;
2017-06-27 14:09:01 +00:00
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_conn_ctx_new_child: ENTER fd=%d \n " , fd ) ;
# endif /* DEBUG_PROXY */
2017-07-11 22:45:15 +00:00
pxy_conn_child_ctx_t * ctx = malloc ( sizeof ( pxy_conn_child_ctx_t ) ) ;
2017-07-12 13:46:51 +00:00
if ( ! ctx ) {
2017-06-25 11:21:32 +00:00
return NULL ;
2017-07-12 13:46:51 +00:00
}
2017-07-11 22:45:15 +00:00
memset ( ctx , 0 , sizeof ( pxy_conn_child_ctx_t ) ) ;
2017-06-25 11:21:32 +00:00
ctx - > fd = fd ;
2018-09-22 23:02:15 +00:00
ctx - > is_child = 1 ;
ctx - > conn = conn ;
2018-10-05 01:55:24 +00:00
if ( ctx - > conn - > spec - > upgrade ) {
ctx - > proto = AUTOSSL ;
} else if ( ctx - > conn - > spec - > http ) {
ctx - > proto = HTTP ;
} else {
ctx - > proto = DEFAULT ;
}
2018-09-22 23:02:15 +00:00
// @attention Child connections use the parent's event bases, otherwise we would get multithreading issues
pxy_thrmgr_attach_child ( conn ) ;
2017-06-25 11:21:32 +00:00
# ifdef DEBUG_PROXY
2018-09-22 23:02:15 +00:00
if ( OPTS_DEBUG ( conn - > opts ) ) {
2017-07-12 13:46:51 +00:00
log_dbg_printf ( " %p pxy_conn_ctx_new_child \n " , ( void * ) ctx ) ;
2017-06-25 11:21:32 +00:00
}
# endif /* DEBUG_PROXY */
return ctx ;
}
2017-07-14 19:34:15 +00:00
static void NONNULL ( 1 )
pxy_conn_ctx_free_child ( pxy_conn_child_ctx_t * ctx )
{
# ifdef DEBUG_PROXY
2018-09-24 00:09:05 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_conn_ctx_free_child: ENTER fd=%d, conn fd=%d \n " , ctx - > fd , ctx - > conn - > fd ) ;
2018-09-22 23:02:15 +00:00
if ( OPTS_DEBUG ( ctx - > conn - > opts ) ) {
2017-07-14 19:34:15 +00:00
log_dbg_printf ( " %p pxy_conn_ctx_free_child \n " ,
( void * ) ctx ) ;
}
# endif /* DEBUG_PROXY */
2018-09-22 23:02:15 +00:00
pxy_thrmgr_detach_child ( ctx - > conn ) ;
2017-07-14 19:34:15 +00:00
if ( ctx - > srchost_str ) {
free ( ctx - > srchost_str ) ;
}
if ( ctx - > srcport_str ) {
free ( ctx - > srcport_str ) ;
}
if ( ctx - > dsthost_str ) {
free ( ctx - > dsthost_str ) ;
}
if ( ctx - > dstport_str ) {
free ( ctx - > dstport_str ) ;
}
if ( ctx - > ssl_names ) {
free ( ctx - > ssl_names ) ;
}
if ( ctx - > origcrtfpr ) {
free ( ctx - > origcrtfpr ) ;
}
if ( ctx - > usedcrtfpr ) {
free ( ctx - > usedcrtfpr ) ;
}
free ( ctx ) ;
}
/*
* Free bufferenvent and close underlying socket properly .
* For OpenSSL bufferevents , this will shutdown the SSL connection .
*/
static void
2017-07-15 01:07:42 +00:00
bufferevent_free_and_close_fd ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2017-07-14 19:34:15 +00:00
{
evutil_socket_t fd = bufferevent_getfd ( bev ) ;
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " bufferevent_free_and_close_fd: ENTER i:%zu o:%zu, fd=%d \n " ,
evbuffer_get_length ( bufferevent_get_input ( bev ) ) , evbuffer_get_length ( bufferevent_get_output ( bev ) ) , fd ) ;
# endif /* DEBUG_PROXY */
2017-07-14 19:34:15 +00:00
SSL * ssl = NULL ;
2017-07-25 13:07:39 +00:00
if ( ( ctx - > spec - > ssl | | ctx - > clienthello_found ) & & ! ctx - > passthrough ) {
2017-07-14 19:34:15 +00:00
ssl = bufferevent_openssl_get_ssl ( bev ) ; /* does not inc refc */
}
# ifdef DEBUG_PROXY
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2017-08-01 11:57:49 +00:00
log_dbg_printf ( " %p bufferevent_free_and_close_fd fd=%d \n " ,
2017-07-14 19:34:15 +00:00
( void * ) bev , fd ) ;
}
# endif /* DEBUG_PROXY */
// @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 ) {
2017-07-15 01:07:42 +00:00
pxy_ssl_shutdown ( ctx - > opts , ctx - > evbase , ssl , fd ) ;
2017-07-14 19:34:15 +00:00
} else {
if ( evutil_closesocket ( fd ) = = - 1 ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " bufferevent_free_and_close_fd: evutil_closesocket FAILED, fd=%d \n " , fd ) ;
# endif /* DEBUG_PROXY */
2017-07-14 19:34:15 +00:00
}
}
}
/*
* Free bufferenvent and close underlying socket properly .
* This is for non - OpenSSL bufferevents .
*/
static void
2017-07-28 22:15:39 +00:00
bufferevent_free_and_close_fd_nonssl ( struct bufferevent * bev , UNUSED pxy_conn_ctx_t * ctx )
2017-07-14 19:34:15 +00:00
{
evutil_socket_t fd = bufferevent_getfd ( bev ) ;
# ifdef DEBUG_PROXY
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2017-08-01 11:57:49 +00:00
log_dbg_printf ( " %p bufferevent_free_and_close_fd_nonssl fd=%d \n " ,
2017-07-14 19:34:15 +00:00
( void * ) bev , fd ) ;
}
# endif /* DEBUG_PROXY */
2017-08-13 01:36:33 +00:00
bufferevent_free ( bev ) ;
2017-07-14 19:34:15 +00:00
if ( evutil_closesocket ( fd ) = = - 1 ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " bufferevent_free_and_close_fd_nonssl: evutil_closesocket FAILED, fd=%d \n " , fd ) ;
# endif /* DEBUG_PROXY */
2017-07-14 19:34:15 +00:00
}
}
2017-07-15 10:04:13 +00:00
static void NONNULL ( 1 , 2 )
2017-08-13 01:36:33 +00:00
pxy_conn_remove_child ( pxy_conn_child_ctx_t * child , pxy_conn_child_ctx_t * * head )
{
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_conn_remove_child: ENTER fd=%d \n " , child - > fd ) ;
# endif /* DEBUG_PROXY */
2017-07-14 19:34:15 +00:00
if ( child - > fd = = ( * head ) - > fd ) {
* head = ( * head ) - > next ;
return ;
}
pxy_conn_child_ctx_t * current = ( * head ) - > next ;
pxy_conn_child_ctx_t * previous = * head ;
while ( current ! = NULL & & previous ! = NULL ) {
if ( child - > fd = = current - > fd ) {
previous - > next = current - > next ;
return ;
}
previous = current ;
current = current - > next ;
}
return ;
}
2017-07-15 10:04:13 +00:00
static void NONNULL ( 1 )
2017-07-14 19:34:15 +00:00
pxy_conn_free_child ( pxy_conn_child_ctx_t * ctx )
{
2018-09-22 23:02:15 +00:00
assert ( ctx - > conn ! = NULL ) ;
2017-07-14 19:34:15 +00:00
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_conn_free_child: ENTER fd=%d \n " , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
2017-07-14 19:34:15 +00:00
pxy_conn_desc_t * dst = & ctx - > dst ;
if ( dst - > bev ) {
2018-09-22 23:02:15 +00:00
bufferevent_free_and_close_fd ( dst - > bev , ctx - > conn ) ;
2017-07-14 19:34:15 +00:00
dst - > bev = NULL ;
}
pxy_conn_desc_t * src = & ctx - > src ;
if ( src - > bev ) {
2018-09-22 23:02:15 +00:00
bufferevent_free_and_close_fd_nonssl ( src - > bev , ctx - > conn ) ;
2017-07-14 19:34:15 +00:00
src - > bev = NULL ;
}
2018-09-22 23:02:15 +00:00
pxy_conn_remove_child ( ctx , & ctx - > conn - > children ) ;
2017-07-14 19:34:15 +00:00
pxy_conn_ctx_free_child ( ctx ) ;
}
2014-12-13 01:36:45 +00:00
static void NONNULL ( 1 )
2017-07-25 13:07:39 +00:00
pxy_conn_ctx_free ( pxy_conn_ctx_t * ctx , int by_requestor )
2012-04-13 12:47:30 +00:00
{
# ifdef DEBUG_PROXY
2017-08-13 01:36:33 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_conn_ctx_free: ENTER fd=%d \n " , ctx - > fd ) ;
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2012-04-13 12:47:30 +00:00
log_dbg_printf ( " %p pxy_conn_ctx_free \n " ,
( void * ) ctx ) ;
}
# endif /* DEBUG_PROXY */
2017-07-25 13:07:39 +00:00
if ( WANT_CONTENT_LOG ( ctx ) & & ctx - > logctx ) {
if ( log_content_close ( & ctx - > logctx , by_requestor ) = = - 1 ) {
2017-10-14 22:39:30 +00:00
log_err_level_printf ( LOG_WARNING , " Content log close failed \n " ) ;
2017-07-25 13:07:39 +00:00
}
}
2017-07-15 23:22:35 +00:00
pxy_thrmgr_detach ( ctx ) ;
2015-03-15 16:10:25 +00:00
if ( ctx - > srchost_str ) {
free ( ctx - > srchost_str ) ;
2012-04-13 12:47:30 +00:00
}
2015-03-15 16:10:25 +00:00
if ( ctx - > srcport_str ) {
free ( ctx - > srcport_str ) ;
}
if ( ctx - > dsthost_str ) {
free ( ctx - > dsthost_str ) ;
}
if ( ctx - > dstport_str ) {
free ( ctx - > dstport_str ) ;
2012-04-13 12:47:30 +00:00
}
if ( ctx - > http_method ) {
free ( ctx - > http_method ) ;
}
if ( ctx - > http_uri ) {
free ( ctx - > http_uri ) ;
}
if ( ctx - > http_host ) {
free ( ctx - > http_host ) ;
}
2012-04-22 17:12:38 +00:00
if ( ctx - > http_content_type ) {
free ( ctx - > http_content_type ) ;
}
2013-06-29 20:35:51 +00:00
if ( ctx - > http_status_code ) {
free ( ctx - > http_status_code ) ;
}
if ( ctx - > http_status_text ) {
free ( ctx - > http_status_text ) ;
}
2013-06-29 20:50:39 +00:00
if ( ctx - > http_content_length ) {
free ( ctx - > http_content_length ) ;
}
2012-04-13 12:47:30 +00:00
if ( ctx - > ssl_names ) {
free ( ctx - > ssl_names ) ;
}
2014-12-13 01:36:45 +00:00
if ( ctx - > origcrtfpr ) {
free ( ctx - > origcrtfpr ) ;
}
if ( ctx - > usedcrtfpr ) {
free ( ctx - > usedcrtfpr ) ;
}
2014-11-14 14:36:16 +00:00
# ifdef HAVE_LOCAL_PROCINFO
2014-11-14 14:31:30 +00:00
if ( ctx - > lproc . exec_path ) {
free ( ctx - > lproc . exec_path ) ;
2014-10-18 20:16:50 +00:00
}
2014-11-14 14:31:30 +00:00
if ( ctx - > lproc . user ) {
free ( ctx - > lproc . user ) ;
2014-10-18 20:16:50 +00:00
}
2014-11-14 14:31:30 +00:00
if ( ctx - > lproc . group ) {
free ( ctx - > lproc . group ) ;
2014-10-18 20:16:50 +00:00
}
2014-11-14 14:36:16 +00:00
# endif /* HAVE_LOCAL_PROCINFO */
2012-04-13 12:47:30 +00:00
if ( ctx - > origcrt ) {
X509_free ( ctx - > origcrt ) ;
}
if ( ctx - > ev ) {
event_free ( ctx - > ev ) ;
}
2017-07-15 01:07:42 +00:00
if ( ctx - > sni ) {
free ( ctx - > sni ) ;
2017-06-25 11:21:32 +00:00
}
2017-08-11 12:01:51 +00:00
if ( ctx - > header_str ) {
free ( ctx - > header_str ) ;
2017-08-03 11:55:57 +00:00
}
2017-07-22 22:15:59 +00:00
if ( ctx - > srv_dst_ssl_version ) {
free ( ctx - > srv_dst_ssl_version ) ;
}
if ( ctx - > srv_dst_ssl_cipher ) {
free ( ctx - > srv_dst_ssl_cipher ) ;
}
2017-07-15 01:07:42 +00:00
free ( ctx ) ;
2017-06-25 11:21:32 +00:00
}
2012-04-13 12:47:30 +00:00
2017-07-15 10:04:13 +00:00
void NONNULL ( 1 )
2017-07-25 13:07:39 +00:00
pxy_conn_free ( pxy_conn_ctx_t * ctx , int by_requestor )
2017-07-01 15:08:28 +00:00
{
2017-07-15 01:07:42 +00:00
evutil_socket_t fd = ctx - > fd ;
2017-07-14 19:34:15 +00:00
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
evutil_socket_t child_fd = ctx - > child_fd ;
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " pxy_conn_free: ENTER fd=%d, child_fd=%d \n " , fd , child_fd ) ;
# endif /* DEBUG_PROXY */
2017-07-14 19:34:15 +00:00
pxy_conn_desc_t * src = & ctx - > src ;
if ( ! src - > closed ) {
if ( src - > bev ) {
2017-07-15 01:07:42 +00:00
bufferevent_free_and_close_fd ( src - > bev , ctx ) ;
2017-07-14 19:34:15 +00:00
src - > bev = NULL ;
} else {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " pxy_conn_free: evutil_closesocket on NULL src->bev, fd=%d \n " , fd ) ;
# endif /* DEBUG_PROXY */
2017-07-14 19:34:15 +00:00
// @todo src fd may be open, although src.bev is NULL, where do we close the src fd?
evutil_closesocket ( fd ) ;
}
2017-07-01 15:08:28 +00:00
}
2017-07-14 19:34:15 +00:00
pxy_conn_desc_t * srv_dst = & ctx - > srv_dst ;
if ( srv_dst - > bev ) {
2017-07-15 01:07:42 +00:00
bufferevent_free_and_close_fd ( srv_dst - > bev , ctx ) ;
2017-07-14 19:34:15 +00:00
srv_dst - > bev = NULL ;
2017-07-01 15:08:28 +00:00
}
2017-07-14 19:34:15 +00:00
pxy_conn_desc_t * dst = & ctx - > dst ;
if ( dst - > bev ) {
2017-07-15 01:07:42 +00:00
bufferevent_free_and_close_fd_nonssl ( dst - > bev , ctx ) ;
2017-07-14 19:34:15 +00:00
dst - > bev = NULL ;
2017-07-05 19:32:10 +00:00
}
2017-07-14 19:34:15 +00:00
2017-07-15 01:07:42 +00:00
// @attention Free the child ctxs asap, we need their fds
2017-07-15 10:04:13 +00:00
while ( ctx - > children ) {
pxy_conn_free_child ( ctx - > children ) ;
2017-07-15 01:07:42 +00:00
}
2017-07-15 10:04:13 +00:00
// @attention Parent may be closing before there was any child at all nor was child_evcl ever created
if ( ctx - > child_evcl ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-09-24 00:09:05 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " pxy_conn_free: Freeing child_evcl, conn fd=%d, child_fd=%d, cfd=%d \n " ,
2017-07-15 10:04:13 +00:00
ctx - > fd , ctx - > child_fd , ctx - > children ? ctx - > children - > fd : - 1 ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-08-01 11:57:49 +00:00
// @attention child_evcl was created with LEV_OPT_CLOSE_ON_FREE, so do not close ctx->child_fd
2017-07-15 10:04:13 +00:00
evconnlistener_free ( ctx - > child_evcl ) ;
ctx - > child_evcl = NULL ;
2017-07-15 01:07:42 +00:00
}
2017-07-25 13:07:39 +00:00
pxy_conn_ctx_free ( ctx , by_requestor ) ;
2017-07-01 15:08:28 +00:00
}
2012-04-13 12:47:30 +00:00
/* forward declaration of libevent callbacks */
static void pxy_bev_readcb ( struct bufferevent * , void * ) ;
static void pxy_bev_writecb ( struct bufferevent * , void * ) ;
static void pxy_bev_eventcb ( struct bufferevent * , short , void * ) ;
static void pxy_fd_readcb ( evutil_socket_t , short , void * ) ;
2017-07-07 14:18:01 +00:00
static void pxy_bev_readcb_child ( struct bufferevent * , void * ) ;
static void pxy_bev_writecb_child ( struct bufferevent * , void * ) ;
static void pxy_bev_eventcb_child ( struct bufferevent * , short , void * ) ;
2012-04-13 12:47:30 +00:00
/* forward declaration of OpenSSL callbacks */
# ifndef OPENSSL_NO_TLSEXT
static int pxy_ossl_servername_cb ( SSL * ssl , int * al , void * arg ) ;
# endif /* !OPENSSL_NO_TLSEXT */
static int pxy_ossl_sessnew_cb ( SSL * , SSL_SESSION * ) ;
static void pxy_ossl_sessremove_cb ( SSL_CTX * , SSL_SESSION * ) ;
2018-01-18 00:18:53 +00:00
# if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
2012-04-13 12:47:30 +00:00
static SSL_SESSION * pxy_ossl_sessget_cb ( SSL * , unsigned char * , int , int * ) ;
2018-01-18 00:18:53 +00:00
# else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
static SSL_SESSION * pxy_ossl_sessget_cb ( SSL * , const unsigned char * , int , int * ) ;
# endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
2012-04-13 12:47:30 +00:00
/*
* Dump information on a certificate to the debug log .
*/
static void
pxy_debug_crt ( X509 * crt )
{
char * sj = ssl_x509_subject ( crt ) ;
if ( sj ) {
log_dbg_printf ( " Subject DN: %s \n " , sj ) ;
free ( sj ) ;
}
2012-04-17 21:35:43 +00:00
char * names = ssl_x509_names_to_str ( crt ) ;
2012-04-13 12:47:30 +00:00
if ( names ) {
log_dbg_printf ( " Common Names: %s \n " , names ) ;
free ( names ) ;
}
2014-12-13 01:36:45 +00:00
char * fpr ;
if ( ! ( fpr = ssl_x509_fingerprint ( crt , 1 ) ) ) {
2017-10-14 22:39:30 +00:00
log_err_level_printf ( LOG_WARNING , " Error generating X509 fingerprint \n " ) ;
2012-04-13 12:47:30 +00:00
} else {
2014-12-13 01:36:45 +00:00
log_dbg_printf ( " Fingerprint: %s \n " , fpr ) ;
2015-07-10 10:01:52 +00:00
free ( fpr ) ;
2012-04-13 12:47:30 +00:00
}
# ifdef DEBUG_CERTIFICATE
/* dump certificate */
log_dbg_print_free ( ssl_x509_to_str ( crt ) ) ;
log_dbg_print_free ( ssl_x509_to_pem ( crt ) ) ;
# endif /* DEBUG_CERTIFICATE */
}
static void
pxy_log_connect_nonhttp ( pxy_conn_ctx_t * ctx )
{
char * msg ;
2014-11-16 19:11:25 +00:00
# ifdef HAVE_LOCAL_PROCINFO
char * lpi = NULL ;
# endif /* HAVE_LOCAL_PROCINFO */
2012-04-13 12:47:30 +00:00
int rv ;
2014-11-16 19:11:25 +00:00
# ifdef HAVE_LOCAL_PROCINFO
2017-07-15 01:07:42 +00:00
if ( ctx - > opts - > lprocinfo ) {
2014-11-17 18:14:29 +00:00
rv = asprintf ( & lpi , " lproc:%i:%s:%s:%s " ,
2014-11-16 19:11:25 +00:00
ctx - > lproc . pid ,
STRORDASH ( ctx - > lproc . user ) ,
STRORDASH ( ctx - > lproc . group ) ,
STRORDASH ( ctx - > lproc . exec_path ) ) ;
2014-11-17 18:11:27 +00:00
if ( ( rv < 0 ) | | ! lpi ) {
2014-11-16 19:11:25 +00:00
ctx - > enomem = 1 ;
goto out ;
}
2014-11-19 21:39:51 +00:00
} else {
lpi = " " ;
2014-11-16 19:11:25 +00:00
}
# endif /* HAVE_LOCAL_PROCINFO */
2018-01-18 00:18:53 +00:00
/*
* The following ifdef ' s within asprintf arguments list generates
* warnings with - Wembedded - directive on some compilers .
* Not fixing the code in order to avoid more code duplication .
*/
2016-03-27 11:49:50 +00:00
if ( ! ctx - > src . ssl ) {
2017-08-19 22:46:57 +00:00
rv = asprintf ( & msg , " CONN: %s %s %s %s %s "
2014-11-16 19:11:25 +00:00
# ifdef HAVE_LOCAL_PROCINFO
" %s "
# endif /* HAVE_LOCAL_PROCINFO */
" \n " ,
2017-08-19 22:46:57 +00:00
ctx - > passthrough ? " passthrough " : ( ctx - > spec - > pop3 ? " pop3 " : ( ctx - > spec - > smtp ? " smtp " : " tcp " ) ) ,
2015-03-15 16:10:25 +00:00
STRORDASH ( ctx - > srchost_str ) ,
STRORDASH ( ctx - > srcport_str ) ,
STRORDASH ( ctx - > dsthost_str ) ,
STRORDASH ( ctx - > dstport_str )
2014-11-16 19:11:25 +00:00
# ifdef HAVE_LOCAL_PROCINFO
, lpi
# endif /* HAVE_LOCAL_PROCINFO */
) ;
2012-04-13 12:47:30 +00:00
} else {
2017-08-19 22:46:57 +00:00
rv = asprintf ( & msg , " CONN: %s %s %s %s %s "
2014-11-17 18:14:29 +00:00
" sni:%s names:%s "
2014-12-13 01:36:45 +00:00
" sproto:%s:%s dproto:%s:%s "
" origcrt:%s usedcrt:%s "
2014-11-16 19:11:25 +00:00
# ifdef HAVE_LOCAL_PROCINFO
" %s "
# endif /* HAVE_LOCAL_PROCINFO */
2014-12-13 01:36:45 +00:00
" \n " ,
2017-08-19 22:46:57 +00:00
ctx - > clienthello_found ? " upgrade " : ( ctx - > spec - > pop3 ? " pop3s " : ( ctx - > spec - > smtp ? " smtps " : " ssl " ) ) ,
2015-03-15 16:10:25 +00:00
STRORDASH ( ctx - > srchost_str ) ,
STRORDASH ( ctx - > srcport_str ) ,
STRORDASH ( ctx - > dsthost_str ) ,
STRORDASH ( ctx - > dstport_str ) ,
2017-07-15 01:07:42 +00:00
STRORDASH ( ctx - > sni ) ,
2012-04-13 12:47:30 +00:00
STRORDASH ( ctx - > ssl_names ) ,
2014-11-17 18:11:27 +00:00
SSL_get_version ( ctx - > src . ssl ) ,
SSL_get_cipher ( ctx - > src . ssl ) ,
2018-09-21 00:14:37 +00:00
! ctx - > srv_dst . closed & & ctx - > srv_dst . ssl ? SSL_get_version ( ctx - > srv_dst . ssl ) : ctx - > srv_dst_ssl_version ,
! ctx - > srv_dst . closed & & ctx - > srv_dst . ssl ? SSL_get_cipher ( ctx - > srv_dst . ssl ) : ctx - > srv_dst_ssl_cipher ,
2014-12-13 01:36:45 +00:00
STRORDASH ( ctx - > origcrtfpr ) ,
STRORDASH ( ctx - > usedcrtfpr )
2014-11-16 19:11:25 +00:00
# ifdef HAVE_LOCAL_PROCINFO
, lpi
# endif /* HAVE_LOCAL_PROCINFO */
2014-12-13 01:36:45 +00:00
) ;
2012-04-13 12:47:30 +00:00
}
2014-11-17 18:11:27 +00:00
if ( ( rv < 0 ) | | ! msg ) {
2012-05-02 13:00:22 +00:00
ctx - > enomem = 1 ;
2014-11-16 19:11:25 +00:00
goto out ;
2012-05-02 13:00:22 +00:00
}
2017-07-15 01:07:42 +00:00
if ( ! ctx - > opts - > detach ) {
2017-08-19 22:46:57 +00:00
log_err_printf ( " %s " , msg ) ;
} else if ( ctx - > opts - > statslog ) {
2017-10-29 22:22:34 +00:00
if ( log_conn ( msg ) = = - 1 ) {
log_err_level_printf ( LOG_WARNING , " Conn logging failed \n " ) ;
2017-08-19 22:46:57 +00:00
}
2012-04-13 12:47:30 +00:00
}
2017-07-15 01:07:42 +00:00
if ( ctx - > opts - > connectlog ) {
2014-11-21 16:42:10 +00:00
if ( log_connect_print_free ( msg ) = = - 1 ) {
free ( msg ) ;
2017-10-14 22:39:30 +00:00
log_err_level_printf ( LOG_WARNING , " Connection logging failed \n " ) ;
2014-11-21 16:42:10 +00:00
}
2012-04-13 12:47:30 +00:00
} else {
free ( msg ) ;
}
2014-11-16 19:11:25 +00:00
out :
# ifdef HAVE_LOCAL_PROCINFO
2017-07-15 01:07:42 +00:00
if ( lpi & & ctx - > opts - > lprocinfo ) {
2014-11-16 19:11:25 +00:00
free ( lpi ) ;
}
# endif /* HAVE_LOCAL_PROCINFO */
2014-11-16 20:57:33 +00:00
return ;
2012-04-13 12:47:30 +00:00
}
static void
pxy_log_connect_http ( pxy_conn_ctx_t * ctx )
{
char * msg ;
2014-11-16 19:11:25 +00:00
# ifdef HAVE_LOCAL_PROCINFO
char * lpi = NULL ;
# endif /* HAVE_LOCAL_PROCINFO */
2012-04-13 12:47:30 +00:00
int rv ;
# ifdef DEBUG_PROXY
2017-07-15 01:07:42 +00:00
if ( ctx - > passthrough ) {
2017-10-14 22:39:30 +00:00
log_err_level_printf ( LOG_WARNING , " pxy_log_connect_http called while in "
2012-04-13 12:47:30 +00:00
" passthrough mode \n " ) ;
return ;
}
# endif
2014-11-16 19:11:25 +00:00
# ifdef HAVE_LOCAL_PROCINFO
2017-07-15 01:07:42 +00:00
if ( ctx - > opts - > lprocinfo ) {
2014-11-17 18:14:29 +00:00
rv = asprintf ( & lpi , " lproc:%i:%s:%s:%s " ,
2014-11-16 19:11:25 +00:00
ctx - > lproc . pid ,
STRORDASH ( ctx - > lproc . user ) ,
STRORDASH ( ctx - > lproc . group ) ,
STRORDASH ( ctx - > lproc . exec_path ) ) ;
2014-11-17 18:11:27 +00:00
if ( ( rv < 0 ) | | ! lpi ) {
2014-11-16 19:11:25 +00:00
ctx - > enomem = 1 ;
goto out ;
}
}
# endif /* HAVE_LOCAL_PROCINFO */
2018-01-18 00:18:53 +00:00
/*
* The following ifdef ' s within asprintf arguments list generates
* warnings with - Wembedded - directive on some compilers .
* Not fixing the code in order to avoid more code duplication .
*/
2017-07-15 01:07:42 +00:00
if ( ! ctx - > spec - > ssl ) {
2017-08-19 22:46:57 +00:00
rv = asprintf ( & msg , " CONN: http %s %s %s %s %s %s %s %s %s "
2014-11-16 19:11:25 +00:00
# ifdef HAVE_LOCAL_PROCINFO
" %s "
# endif /* HAVE_LOCAL_PROCINFO */
2014-12-13 01:36:45 +00:00
" %s \n " ,
2015-03-15 16:10:25 +00:00
STRORDASH ( ctx - > srchost_str ) ,
STRORDASH ( ctx - > srcport_str ) ,
STRORDASH ( ctx - > dsthost_str ) ,
STRORDASH ( ctx - > dstport_str ) ,
2012-04-13 12:47:30 +00:00
STRORDASH ( ctx - > http_host ) ,
STRORDASH ( ctx - > http_method ) ,
2012-04-22 17:12:38 +00:00
STRORDASH ( ctx - > http_uri ) ,
2013-06-29 20:35:51 +00:00
STRORDASH ( ctx - > http_status_code ) ,
2013-06-29 20:50:39 +00:00
STRORDASH ( ctx - > http_content_length ) ,
2014-11-16 19:11:25 +00:00
# ifdef HAVE_LOCAL_PROCINFO
lpi ,
# endif /* HAVE_LOCAL_PROCINFO */
2014-12-13 01:36:45 +00:00
ctx - > ocsp_denied ? " ocsp:denied " : " " ) ;
2012-04-13 12:47:30 +00:00
} else {
2017-08-19 22:46:57 +00:00
rv = asprintf ( & msg , " CONN: https %s %s %s %s %s %s %s %s %s "
2014-11-17 18:14:29 +00:00
" sni:%s names:%s "
2014-12-13 01:36:45 +00:00
" sproto:%s:%s dproto:%s:%s "
" origcrt:%s usedcrt:%s "
2014-11-16 19:11:25 +00:00
# ifdef HAVE_LOCAL_PROCINFO
" %s "
# endif /* HAVE_LOCAL_PROCINFO */
2014-12-13 01:36:45 +00:00
" %s \n " ,
2015-03-15 16:10:25 +00:00
STRORDASH ( ctx - > srchost_str ) ,
STRORDASH ( ctx - > srcport_str ) ,
STRORDASH ( ctx - > dsthost_str ) ,
STRORDASH ( ctx - > dstport_str ) ,
2012-04-13 12:47:30 +00:00
STRORDASH ( ctx - > http_host ) ,
STRORDASH ( ctx - > http_method ) ,
STRORDASH ( ctx - > http_uri ) ,
2013-06-29 20:35:51 +00:00
STRORDASH ( ctx - > http_status_code ) ,
2013-06-29 20:50:39 +00:00
STRORDASH ( ctx - > http_content_length ) ,
2017-07-15 01:07:42 +00:00
STRORDASH ( ctx - > sni ) ,
2012-04-13 12:47:30 +00:00
STRORDASH ( ctx - > ssl_names ) ,
2014-11-17 18:11:27 +00:00
SSL_get_version ( ctx - > src . ssl ) ,
SSL_get_cipher ( ctx - > src . ssl ) ,
2017-07-22 22:15:59 +00:00
! ctx - > srv_dst . closed ? SSL_get_version ( ctx - > srv_dst . ssl ) : ctx - > srv_dst_ssl_version ,
! ctx - > srv_dst . closed ? SSL_get_cipher ( ctx - > srv_dst . ssl ) : ctx - > srv_dst_ssl_cipher ,
2014-12-13 01:36:45 +00:00
STRORDASH ( ctx - > origcrtfpr ) ,
STRORDASH ( ctx - > usedcrtfpr ) ,
2014-11-16 19:11:25 +00:00
# ifdef HAVE_LOCAL_PROCINFO
lpi ,
# endif /* HAVE_LOCAL_PROCINFO */
2014-12-13 01:36:45 +00:00
ctx - > ocsp_denied ? " ocsp:denied " : " " ) ;
2012-04-13 12:47:30 +00:00
}
2014-11-17 18:11:27 +00:00
if ( ( rv < 0 ) | | ! msg ) {
2012-05-02 13:00:22 +00:00
ctx - > enomem = 1 ;
2014-11-16 19:11:25 +00:00
goto out ;
2012-05-02 13:00:22 +00:00
}
2017-07-15 01:07:42 +00:00
if ( ! ctx - > opts - > detach ) {
2017-08-19 22:46:57 +00:00
log_err_printf ( " %s " , msg ) ;
} else if ( ctx - > opts - > statslog ) {
2017-10-29 22:22:34 +00:00
if ( log_conn ( msg ) = = - 1 ) {
log_err_level_printf ( LOG_WARNING , " Conn logging failed \n " ) ;
2017-08-19 22:46:57 +00:00
}
2012-04-13 12:47:30 +00:00
}
2017-07-15 01:07:42 +00:00
if ( ctx - > opts - > connectlog ) {
2014-11-21 16:42:10 +00:00
if ( log_connect_print_free ( msg ) = = - 1 ) {
free ( msg ) ;
2017-10-14 22:39:30 +00:00
log_err_level_printf ( LOG_WARNING , " Connection logging failed \n " ) ;
2014-11-21 16:42:10 +00:00
}
2012-04-13 12:47:30 +00:00
} else {
free ( msg ) ;
}
2014-11-16 19:11:25 +00:00
out :
# ifdef HAVE_LOCAL_PROCINFO
if ( lpi ) {
free ( lpi ) ;
}
# endif /* HAVE_LOCAL_PROCINFO */
return ;
2012-04-13 12:47:30 +00:00
}
/*
* Called by OpenSSL when a new src SSL session is created .
2014-01-13 22:50:30 +00:00
* OpenSSL increments the refcount before calling the callback and will
* decrement it again if we return 0. Returning 1 will make OpenSSL skip
* the refcount decrementing . In other words , return 0 if we did not
* keep a pointer to the object ( which we never do here ) .
2012-04-13 12:47:30 +00:00
*/
2015-07-28 21:23:53 +00:00
# ifdef HAVE_SSLV2
2012-05-13 13:29:39 +00:00
# define MAYBE_UNUSED
2015-07-28 21:23:53 +00:00
# else /* !HAVE_SSLV2 */
2012-05-13 13:29:39 +00:00
# define MAYBE_UNUSED UNUSED
2015-07-28 21:23:53 +00:00
# endif /* !HAVE_SSLV2 */
2012-04-13 12:47:30 +00:00
static int
2012-05-13 13:29:39 +00:00
pxy_ossl_sessnew_cb ( MAYBE_UNUSED SSL * ssl , SSL_SESSION * sess )
# undef MAYBE_UNUSED
2012-04-13 12:47:30 +00:00
{
# ifdef DEBUG_SESSION_CACHE
log_dbg_printf ( " ===> OpenSSL new session callback: \n " ) ;
if ( sess ) {
log_dbg_print_free ( ssl_session_to_str ( sess ) ) ;
2014-11-03 21:10:01 +00:00
} else {
2015-04-18 10:50:26 +00:00
log_dbg_printf ( " (null) \n " ) ;
2012-04-13 12:47:30 +00:00
}
# endif /* DEBUG_SESSION_CACHE */
2015-07-28 21:23:53 +00:00
# ifdef HAVE_SSLV2
2012-04-13 12:47:30 +00:00
/* Session resumption seems to fail for SSLv2 with protocol
* parsing errors , so we disable caching for SSLv2 . */
if ( SSL_version ( ssl ) = = SSL2_VERSION ) {
2017-10-14 22:39:30 +00:00
log_err_level_printf ( LOG_WARNING , " Session resumption denied to SSLv2 "
2012-04-13 12:47:30 +00:00
" client. \n " ) ;
return 0 ;
}
2015-07-28 21:23:53 +00:00
# endif /* HAVE_SSLV2 */
2014-11-03 21:10:01 +00:00
if ( sess ) {
cachemgr_ssess_set ( sess ) ;
}
2012-04-13 12:47:30 +00:00
return 0 ;
}
/*
* Called by OpenSSL when a src SSL session should be removed .
2014-01-13 22:50:30 +00:00
* OpenSSL calls SSL_SESSION_free ( ) after calling the callback ;
* we do not need to free the reference here .
2012-04-13 12:47:30 +00:00
*/
static void
pxy_ossl_sessremove_cb ( UNUSED SSL_CTX * sslctx , SSL_SESSION * sess )
{
# ifdef DEBUG_SESSION_CACHE
log_dbg_printf ( " ===> OpenSSL remove session callback: \n " ) ;
if ( sess ) {
log_dbg_print_free ( ssl_session_to_str ( sess ) ) ;
2014-11-03 21:10:01 +00:00
} else {
2015-04-18 10:50:26 +00:00
log_dbg_printf ( " (null) \n " ) ;
2012-04-13 12:47:30 +00:00
}
# endif /* DEBUG_SESSION_CACHE */
2014-11-03 21:10:01 +00:00
if ( sess ) {
cachemgr_ssess_del ( sess ) ;
}
2012-04-13 12:47:30 +00:00
}
/*
* Called by OpenSSL when a src SSL session is requested by the client .
*/
static SSL_SESSION *
2018-01-18 00:18:53 +00:00
# if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER)
2012-04-13 12:47:30 +00:00
pxy_ossl_sessget_cb ( UNUSED SSL * ssl , unsigned char * id , int idlen , int * copy )
2018-01-18 00:18:53 +00:00
# else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
pxy_ossl_sessget_cb ( UNUSED SSL * ssl , const unsigned char * id , int idlen , int * copy )
# endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
2012-04-13 12:47:30 +00:00
{
SSL_SESSION * sess ;
# ifdef DEBUG_SESSION_CACHE
log_dbg_printf ( " ===> OpenSSL get session callback: \n " ) ;
# endif /* DEBUG_SESSION_CACHE */
* copy = 0 ; /* SSL should not increment reference count of session */
sess = cachemgr_ssess_get ( id , idlen ) ;
# ifdef DEBUG_SESSION_CACHE
if ( sess ) {
log_dbg_print_free ( ssl_session_to_str ( sess ) ) ;
}
# endif /* DEBUG_SESSION_CACHE */
log_dbg_printf ( " SSL session cache: %s \n " , sess ? " HIT " : " MISS " ) ;
return sess ;
}
/*
2015-07-28 21:23:53 +00:00
* Set SSL_CTX options that are the same for incoming and outgoing SSL_CTX .
2012-04-13 12:47:30 +00:00
*/
2015-07-28 21:23:53 +00:00
static void
pxy_sslctx_setoptions ( SSL_CTX * sslctx , pxy_conn_ctx_t * ctx )
2012-04-13 12:47:30 +00:00
{
SSL_CTX_set_options ( sslctx , SSL_OP_ALL ) ;
# ifdef SSL_OP_TLS_ROLLBACK_BUG
SSL_CTX_set_options ( sslctx , SSL_OP_TLS_ROLLBACK_BUG ) ;
# endif /* SSL_OP_TLS_ROLLBACK_BUG */
# ifdef SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION
SSL_CTX_set_options ( sslctx , SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION ) ;
# endif /* SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION */
# ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
SSL_CTX_set_options ( sslctx , SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS ) ;
# endif /* SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS */
# ifdef SSL_OP_NO_TICKET
SSL_CTX_set_options ( sslctx , SSL_OP_NO_TICKET ) ;
# endif /* SSL_OP_NO_TICKET */
2014-11-05 19:06:11 +00:00
# ifdef SSL_OP_NO_SSLv2
2018-02-27 19:20:58 +00:00
# ifdef HAVE_SSLV2
2017-07-15 01:07:42 +00:00
if ( ctx - > opts - > no_ssl2 ) {
2018-02-27 19:20:58 +00:00
# endif /* HAVE_SSLV2 */
2014-11-05 19:06:11 +00:00
SSL_CTX_set_options ( sslctx , SSL_OP_NO_SSLv2 ) ;
2018-02-27 19:20:58 +00:00
# ifdef HAVE_SSLV2
2014-11-05 19:06:11 +00:00
}
2018-02-27 19:20:58 +00:00
# endif /* HAVE_SSLV2 */
2014-11-05 19:06:11 +00:00
# endif /* !SSL_OP_NO_SSLv2 */
2015-07-28 21:23:53 +00:00
# ifdef HAVE_SSLV3
2017-07-15 01:07:42 +00:00
if ( ctx - > opts - > no_ssl3 ) {
2014-11-05 19:06:11 +00:00
SSL_CTX_set_options ( sslctx , SSL_OP_NO_SSLv3 ) ;
}
2015-07-28 21:23:53 +00:00
# endif /* HAVE_SSLV3 */
# ifdef HAVE_TLSV10
2017-07-15 01:07:42 +00:00
if ( ctx - > opts - > no_tls10 ) {
2014-11-05 19:06:11 +00:00
SSL_CTX_set_options ( sslctx , SSL_OP_NO_TLSv1 ) ;
}
2015-07-28 21:23:53 +00:00
# endif /* HAVE_TLSV10 */
# ifdef HAVE_TLSV11
2017-07-15 01:07:42 +00:00
if ( ctx - > opts - > no_tls11 ) {
2014-11-05 19:06:11 +00:00
SSL_CTX_set_options ( sslctx , SSL_OP_NO_TLSv1_1 ) ;
}
2015-07-28 21:23:53 +00:00
# endif /* HAVE_TLSV11 */
# ifdef HAVE_TLSV12
2017-07-15 01:07:42 +00:00
if ( ctx - > opts - > no_tls12 ) {
2014-11-05 19:06:11 +00:00
SSL_CTX_set_options ( sslctx , SSL_OP_NO_TLSv1_2 ) ;
}
2015-07-28 21:23:53 +00:00
# endif /* HAVE_TLSV12 */
# ifdef SSL_OP_NO_COMPRESSION
2017-07-15 01:07:42 +00:00
if ( ! ctx - > opts - > sslcomp ) {
2015-07-28 21:23:53 +00:00
SSL_CTX_set_options ( sslctx , SSL_OP_NO_COMPRESSION ) ;
}
# endif /* SSL_OP_NO_COMPRESSION */
2014-11-05 19:06:11 +00:00
2017-07-15 01:07:42 +00:00
SSL_CTX_set_cipher_list ( sslctx , ctx - > opts - > ciphers ) ;
2015-07-28 21:23:53 +00:00
}
/*
* Create and set up a new SSL_CTX instance for terminating SSL .
* Set up all the necessary callbacks , the certificate , the cert chain and key .
*/
static SSL_CTX *
pxy_srcsslctx_create ( pxy_conn_ctx_t * ctx , X509 * crt , STACK_OF ( X509 ) * chain ,
EVP_PKEY * key )
{
2017-07-15 01:07:42 +00:00
SSL_CTX * sslctx = SSL_CTX_new ( ctx - > opts - > sslmethod ( ) ) ;
2015-07-28 21:23:53 +00:00
if ( ! sslctx )
return NULL ;
pxy_sslctx_setoptions ( sslctx , ctx ) ;
2018-08-22 19:48:55 +00:00
# if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
2018-03-16 09:12:48 +00:00
if ( ctx - > opts - > sslversion ) {
if ( SSL_CTX_set_min_proto_version ( sslctx , ctx - > opts - > sslversion ) = = 0 | |
SSL_CTX_set_max_proto_version ( sslctx , ctx - > opts - > sslversion ) = = 0 ) {
SSL_CTX_free ( sslctx ) ;
return NULL ;
}
}
# endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
2012-04-13 12:47:30 +00:00
SSL_CTX_sess_set_new_cb ( sslctx , pxy_ossl_sessnew_cb ) ;
SSL_CTX_sess_set_remove_cb ( sslctx , pxy_ossl_sessremove_cb ) ;
SSL_CTX_sess_set_get_cb ( sslctx , pxy_ossl_sessget_cb ) ;
SSL_CTX_set_session_cache_mode ( sslctx , SSL_SESS_CACHE_SERVER |
SSL_SESS_CACHE_NO_INTERNAL ) ;
# ifdef USE_SSL_SESSION_ID_CONTEXT
SSL_CTX_set_session_id_context ( sslctx , ( void * ) ( & ssl_session_context ) ,
sizeof ( ssl_session_context ) ) ;
# endif /* USE_SSL_SESSION_ID_CONTEXT */
# ifndef OPENSSL_NO_TLSEXT
SSL_CTX_set_tlsext_servername_callback ( sslctx , pxy_ossl_servername_cb ) ;
SSL_CTX_set_tlsext_servername_arg ( sslctx , ctx ) ;
# endif /* !OPENSSL_NO_TLSEXT */
# ifndef OPENSSL_NO_DH
2017-07-15 01:07:42 +00:00
if ( ctx - > opts - > dh ) {
SSL_CTX_set_tmp_dh ( sslctx , ctx - > opts - > dh ) ;
2016-03-25 15:28:30 +00:00
} else {
2012-04-13 12:47:30 +00:00
SSL_CTX_set_tmp_dh_callback ( sslctx , ssl_tmp_dh_callback ) ;
}
# endif /* !OPENSSL_NO_DH */
# ifndef OPENSSL_NO_ECDH
2017-07-15 01:07:42 +00:00
if ( ctx - > opts - > ecdhcurve ) {
EC_KEY * ecdh = ssl_ec_by_name ( ctx - > opts - > ecdhcurve ) ;
2012-04-13 12:47:30 +00:00
SSL_CTX_set_tmp_ecdh ( sslctx , ecdh ) ;
EC_KEY_free ( ecdh ) ;
2016-03-25 15:28:30 +00:00
} else {
2012-05-11 15:39:12 +00:00
EC_KEY * ecdh = ssl_ec_by_name ( NULL ) ;
2012-04-13 12:47:30 +00:00
SSL_CTX_set_tmp_ecdh ( sslctx , ecdh ) ;
EC_KEY_free ( ecdh ) ;
}
# endif /* !OPENSSL_NO_ECDH */
SSL_CTX_use_certificate ( sslctx , crt ) ;
SSL_CTX_use_PrivateKey ( sslctx , key ) ;
for ( int i = 0 ; i < sk_X509_num ( chain ) ; i + + ) {
X509 * c = sk_X509_value ( chain , i ) ;
ssl_x509_refcount_inc ( c ) ; /* next call consumes a reference */
SSL_CTX_add_extra_chain_cert ( sslctx , c ) ;
}
# ifdef DEBUG_SESSION_CACHE
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2012-04-13 12:47:30 +00:00
int mode = SSL_CTX_get_session_cache_mode ( sslctx ) ;
log_dbg_printf ( " SSL session cache mode: %08x \n " , mode ) ;
if ( mode = = SSL_SESS_CACHE_OFF )
log_dbg_printf ( " SSL_SESS_CACHE_OFF \n " ) ;
if ( mode & SSL_SESS_CACHE_CLIENT )
log_dbg_printf ( " SSL_SESS_CACHE_CLIENT \n " ) ;
if ( mode & SSL_SESS_CACHE_SERVER )
log_dbg_printf ( " SSL_SESS_CACHE_SERVER \n " ) ;
if ( mode & SSL_SESS_CACHE_NO_AUTO_CLEAR )
log_dbg_printf ( " SSL_SESS_CACHE_NO_AUTO_CLEAR \n " ) ;
if ( mode & SSL_SESS_CACHE_NO_INTERNAL_LOOKUP )
log_dbg_printf ( " SSL_SESS_CACHE_NO_INTERNAL_LOOKUP \n " ) ;
if ( mode & SSL_SESS_CACHE_NO_INTERNAL_STORE )
log_dbg_printf ( " SSL_SESS_CACHE_NO_INTERNAL_STORE \n " ) ;
}
# endif /* DEBUG_SESSION_CACHE */
return sslctx ;
}
2014-12-13 01:36:45 +00:00
static int
pxy_srccert_write_to_gendir ( pxy_conn_ctx_t * ctx , X509 * crt , int is_orig )
{
char * fn ;
int rv ;
if ( ! ctx - > origcrtfpr )
return - 1 ;
if ( is_orig ) {
2017-07-15 01:07:42 +00:00
rv = asprintf ( & fn , " %s/%s.crt " , ctx - > opts - > certgendir ,
2014-12-13 01:36:45 +00:00
ctx - > origcrtfpr ) ;
} else {
if ( ! ctx - > usedcrtfpr )
return - 1 ;
2017-07-15 01:07:42 +00:00
rv = asprintf ( & fn , " %s/%s-%s.crt " , ctx - > opts - > certgendir ,
2014-12-13 01:36:45 +00:00
ctx - > origcrtfpr , ctx - > usedcrtfpr ) ;
}
if ( rv = = - 1 ) {
ctx - > enomem = 1 ;
return - 1 ;
}
2014-12-13 22:52:17 +00:00
rv = log_cert_submit ( fn , crt ) ;
2014-12-13 01:36:45 +00:00
free ( fn ) ;
2014-12-13 22:52:17 +00:00
return rv ;
2014-12-13 01:36:45 +00:00
}
static void
pxy_srccert_write ( pxy_conn_ctx_t * ctx )
{
2017-07-15 01:07:42 +00:00
if ( ctx - > opts - > certgen_writeall | | ctx - > generated_cert ) {
2014-12-13 01:36:45 +00:00
if ( pxy_srccert_write_to_gendir ( ctx ,
SSL_get_certificate ( ctx - > src . ssl ) , 0 ) = = - 1 ) {
2017-10-14 22:39:30 +00:00
log_err_level_printf ( LOG_CRIT , " Failed to write used certificate \n " ) ;
2014-12-13 01:36:45 +00:00
}
}
2017-07-15 01:07:42 +00:00
if ( ctx - > opts - > certgen_writeall ) {
2014-12-13 01:36:45 +00:00
if ( pxy_srccert_write_to_gendir ( ctx , ctx - > origcrt , 1 ) = = - 1 ) {
2017-10-14 22:39:30 +00:00
log_err_level_printf ( LOG_CRIT , " Failed to write orig certificate \n " ) ;
2014-12-13 01:36:45 +00:00
}
}
}
2012-04-13 12:47:30 +00:00
static cert_t *
pxy_srccert_create ( pxy_conn_ctx_t * ctx )
{
cert_t * cert = NULL ;
2017-07-15 01:07:42 +00:00
if ( ctx - > opts - > tgcrtdir ) {
if ( ctx - > sni ) {
cert = cachemgr_tgcrt_get ( ctx - > sni ) ;
2012-04-13 12:47:30 +00:00
if ( ! cert ) {
2014-01-14 16:37:57 +00:00
char * wildcarded ;
2017-07-15 01:07:42 +00:00
wildcarded = ssl_wildcardify ( ctx - > sni ) ;
2012-05-02 13:37:47 +00:00
if ( ! wildcarded ) {
ctx - > enomem = 1 ;
return NULL ;
}
2012-04-13 12:47:30 +00:00
cert = cachemgr_tgcrt_get ( wildcarded ) ;
free ( wildcarded ) ;
}
2017-07-15 01:07:42 +00:00
if ( cert & & OPTS_DEBUG ( ctx - > opts ) ) {
2012-05-02 13:37:47 +00:00
log_dbg_printf ( " Target cert by SNI \n " ) ;
}
} else if ( ctx - > origcrt ) {
2012-04-13 12:47:30 +00:00
char * * names = ssl_x509_names ( ctx - > origcrt ) ;
for ( char * * p = names ; * p ; p + + ) {
if ( ! cert ) {
cert = cachemgr_tgcrt_get ( * p ) ;
}
if ( ! cert ) {
2014-01-14 16:37:57 +00:00
char * wildcarded ;
2012-04-13 12:47:30 +00:00
wildcarded = ssl_wildcardify ( * p ) ;
2012-05-02 13:37:47 +00:00
if ( ! wildcarded ) {
ctx - > enomem = 1 ;
} else {
cert = cachemgr_tgcrt_get (
wildcarded ) ;
free ( wildcarded ) ;
}
2012-04-13 12:47:30 +00:00
}
free ( * p ) ;
}
free ( names ) ;
2012-05-02 13:37:47 +00:00
if ( ctx - > enomem ) {
return NULL ;
}
2017-07-15 01:07:42 +00:00
if ( cert & & OPTS_DEBUG ( ctx - > opts ) ) {
2012-05-02 13:37:47 +00:00
log_dbg_printf ( " Target cert by origcrt \n " ) ;
}
2012-04-13 12:47:30 +00:00
}
if ( cert ) {
ctx - > immutable_cert = 1 ;
}
}
2017-07-15 01:07:42 +00:00
if ( ! cert & & ctx - > origcrt & & ctx - > opts - > key ) {
2012-04-13 12:47:30 +00:00
cert = cert_new ( ) ;
cert - > crt = cachemgr_fkcrt_get ( ctx - > origcrt ) ;
if ( cert - > crt ) {
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) )
2012-04-13 12:47:30 +00:00
log_dbg_printf ( " Certificate cache: HIT \n " ) ;
} else {
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) )
2012-04-13 12:47:30 +00:00
log_dbg_printf ( " Certificate cache: MISS \n " ) ;
2017-07-15 01:07:42 +00:00
cert - > crt = ssl_x509_forge ( ctx - > opts - > cacrt ,
ctx - > opts - > cakey ,
2018-01-18 00:18:53 +00:00
ctx - > origcrt ,
ctx - > opts - > key ,
NULL ,
ctx - > opts - > crlurl ) ;
2012-04-13 12:47:30 +00:00
cachemgr_fkcrt_set ( ctx - > origcrt , cert - > crt ) ;
}
2017-07-15 01:07:42 +00:00
cert_set_key ( cert , ctx - > opts - > key ) ;
cert_set_chain ( cert , ctx - > opts - > chain ) ;
2014-12-13 01:36:45 +00:00
ctx - > generated_cert = 1 ;
2012-04-13 12:47:30 +00:00
}
2017-07-15 01:07:42 +00:00
if ( ( WANT_CONNECT_LOG ( ctx ) | | ctx - > opts - > certgendir ) & & ctx - > origcrt ) {
2014-12-13 01:36:45 +00:00
ctx - > origcrtfpr = ssl_x509_fingerprint ( ctx - > origcrt , 0 ) ;
if ( ! ctx - > origcrtfpr )
ctx - > enomem = 1 ;
}
2017-07-15 01:07:42 +00:00
if ( ( WANT_CONNECT_LOG ( ctx ) | | ctx - > opts - > certgen_writeall ) & &
2014-12-13 01:36:45 +00:00
cert & & cert - > crt ) {
ctx - > usedcrtfpr = ssl_x509_fingerprint ( cert - > crt , 0 ) ;
if ( ! ctx - > usedcrtfpr )
ctx - > enomem = 1 ;
2014-12-09 20:02:25 +00:00
}
2012-04-13 12:47:30 +00:00
return cert ;
}
/*
* Create new SSL context for the incoming connection , based on the original
* destination SSL certificate .
* Returns NULL if no suitable certificate could be found .
*/
static SSL *
pxy_srcssl_create ( pxy_conn_ctx_t * ctx , SSL * origssl )
{
cert_t * cert ;
cachemgr_dsess_set ( ( struct sockaddr * ) & ctx - > addr ,
2017-07-15 01:07:42 +00:00
ctx - > addrlen , ctx - > sni ,
2012-04-13 12:47:30 +00:00
SSL_get0_session ( origssl ) ) ;
ctx - > origcrt = SSL_get_peer_certificate ( origssl ) ;
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2012-05-02 13:00:22 +00:00
if ( ctx - > origcrt ) {
log_dbg_printf ( " ===> Original server certificate: \n " ) ;
pxy_debug_crt ( ctx - > origcrt ) ;
} else {
log_dbg_printf ( " ===> Original server has no cert! \n " ) ;
}
2012-04-13 12:47:30 +00:00
}
cert = pxy_srccert_create ( ctx ) ;
if ( ! cert )
return NULL ;
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2012-04-13 12:47:30 +00:00
log_dbg_printf ( " ===> Forged server certificate: \n " ) ;
pxy_debug_crt ( cert - > crt ) ;
}
if ( WANT_CONNECT_LOG ( ctx ) ) {
2014-11-17 18:14:29 +00:00
ctx - > ssl_names = ssl_x509_names_to_str ( ctx - > origcrt ?
ctx - > origcrt :
cert - > crt ) ;
2012-05-02 13:00:22 +00:00
if ( ! ctx - > ssl_names )
ctx - > enomem = 1 ;
2012-04-13 12:47:30 +00:00
}
SSL_CTX * sslctx = pxy_srcsslctx_create ( ctx , cert - > crt , cert - > chain ,
cert - > key ) ;
cert_free ( cert ) ;
2012-05-02 13:37:47 +00:00
if ( ! sslctx ) {
ctx - > enomem = 1 ;
2012-05-02 13:00:22 +00:00
return NULL ;
2012-05-02 13:37:47 +00:00
}
2012-04-13 12:47:30 +00:00
SSL * ssl = SSL_new ( sslctx ) ;
2014-01-10 23:30:04 +00:00
SSL_CTX_free ( sslctx ) ; /* SSL_new() increments refcount */
2012-05-02 13:00:22 +00:00
if ( ! ssl ) {
2012-05-02 13:37:47 +00:00
ctx - > enomem = 1 ;
2012-05-02 13:00:22 +00:00
return NULL ;
}
2014-01-13 22:33:31 +00:00
# ifdef SSL_MODE_RELEASE_BUFFERS
2012-04-13 12:47:30 +00:00
/* lower memory footprint for idle connections */
SSL_set_mode ( ssl , SSL_get_mode ( ssl ) | SSL_MODE_RELEASE_BUFFERS ) ;
2014-01-13 22:33:31 +00:00
# endif /* SSL_MODE_RELEASE_BUFFERS */
2012-04-13 12:47:30 +00:00
return ssl ;
}
# ifndef OPENSSL_NO_TLSEXT
/*
* OpenSSL servername callback , called when OpenSSL receives a servername
* TLS extension in the clientHello . Must switch to a new SSL_CTX with
* a different certificate if we want to replace the server cert here .
* We generate a new certificate if the current one does not match the
* supplied servername . This should only happen if the original destination
* server supplies a certificate which does not match the server name we
* indicate to it .
*/
static int
pxy_ossl_servername_cb ( SSL * ssl , UNUSED int * al , void * arg )
{
pxy_conn_ctx_t * ctx = arg ;
const char * sn ;
2014-01-14 16:37:57 +00:00
X509 * sslcrt ;
2012-04-13 12:47:30 +00:00
if ( ! ( sn = SSL_get_servername ( ssl , TLSEXT_NAMETYPE_host_name ) ) )
return SSL_TLSEXT_ERR_NOACK ;
2017-07-15 01:07:42 +00:00
if ( ! ctx - > sni ) {
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2016-03-27 11:25:50 +00:00
log_dbg_printf ( " Warning: SNI parser yielded no "
" hostname, copying OpenSSL one: "
" [NULL] != [%s] \n " , sn ) ;
}
2017-07-15 01:07:42 +00:00
ctx - > sni = strdup ( sn ) ;
if ( ! ctx - > sni ) {
2016-03-27 11:25:50 +00:00
ctx - > enomem = 1 ;
return SSL_TLSEXT_ERR_NOACK ;
}
}
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
if ( ! ! strcmp ( sn , ctx - > sni ) ) {
2012-04-13 12:47:30 +00:00
/*
* This may happen if the client resumes a session , but
* uses a different SNI hostname when resuming than it
* used when the session was created . OpenSSL
* correctly ignores the SNI in the ClientHello in this
* case , but since we have already sent the SNI onwards
* to the original destination , there is no way back .
* We log an error and hope this never happens .
*/
2016-03-27 11:25:50 +00:00
log_dbg_printf ( " Warning: SNI parser yielded different "
2012-04-13 12:47:30 +00:00
" hostname than OpenSSL callback for "
" the same ClientHello message: "
2017-07-15 01:07:42 +00:00
" [%s] != [%s] \n " , ctx - > sni , sn ) ;
2012-04-13 12:47:30 +00:00
}
}
/* generate a new certificate with sn as additional altSubjectName
* and replace it both in the current SSL ctx and in the cert cache */
2018-01-18 00:18:53 +00:00
if ( ctx - > opts - > allow_wrong_host & & ! ctx - > immutable_cert & &
2012-04-13 12:47:30 +00:00
! ssl_x509_names_match ( ( sslcrt = SSL_get_certificate ( ssl ) ) , sn ) ) {
2014-01-14 16:37:57 +00:00
X509 * newcrt ;
SSL_CTX * newsslctx ;
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2012-04-13 12:47:30 +00:00
log_dbg_printf ( " Certificate cache: UPDATE "
" (SNI mismatch) \n " ) ;
2012-05-02 13:00:22 +00:00
}
2017-07-15 01:07:42 +00:00
newcrt = ssl_x509_forge ( ctx - > opts - > cacrt , ctx - > opts - > cakey ,
2018-01-18 00:18:53 +00:00
sslcrt , ctx - > opts - > key ,
sn , ctx - > opts - > crlurl ) ;
2012-05-02 13:00:22 +00:00
if ( ! newcrt ) {
ctx - > enomem = 1 ;
return SSL_TLSEXT_ERR_NOACK ;
}
2012-04-13 12:47:30 +00:00
cachemgr_fkcrt_set ( ctx - > origcrt , newcrt ) ;
2014-12-13 01:36:45 +00:00
ctx - > generated_cert = 1 ;
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2012-04-13 12:47:30 +00:00
log_dbg_printf ( " ===> Updated forged server "
" certificate: \n " ) ;
pxy_debug_crt ( newcrt ) ;
}
if ( WANT_CONNECT_LOG ( ctx ) ) {
if ( ctx - > ssl_names ) {
free ( ctx - > ssl_names ) ;
}
2012-04-17 21:35:43 +00:00
ctx - > ssl_names = ssl_x509_names_to_str ( newcrt ) ;
2012-05-02 13:00:22 +00:00
if ( ! ctx - > ssl_names ) {
ctx - > enomem = 1 ;
}
2012-04-13 12:47:30 +00:00
}
2017-07-15 01:07:42 +00:00
if ( WANT_CONNECT_LOG ( ctx ) | | ctx - > opts - > certgendir ) {
2014-12-13 01:36:45 +00:00
if ( ctx - > usedcrtfpr ) {
free ( ctx - > usedcrtfpr ) ;
}
ctx - > usedcrtfpr = ssl_x509_fingerprint ( newcrt , 0 ) ;
if ( ! ctx - > usedcrtfpr ) {
ctx - > enomem = 1 ;
}
}
2017-07-15 01:07:42 +00:00
newsslctx = pxy_srcsslctx_create ( ctx , newcrt , ctx - > opts - > chain ,
ctx - > opts - > key ) ;
2012-05-02 13:00:22 +00:00
if ( ! newsslctx ) {
X509_free ( newcrt ) ;
ctx - > enomem = 1 ;
return SSL_TLSEXT_ERR_NOACK ;
}
2014-01-13 22:50:30 +00:00
SSL_set_SSL_CTX ( ssl , newsslctx ) ; /* decr's old incr new refc */
SSL_CTX_free ( newsslctx ) ;
2012-04-13 12:47:30 +00:00
X509_free ( newcrt ) ;
2017-07-15 01:07:42 +00:00
} else if ( OPTS_DEBUG ( ctx - > opts ) ) {
2012-04-13 12:47:30 +00:00
log_dbg_printf ( " Certificate cache: KEEP (SNI match or "
" target mode) \n " ) ;
}
return SSL_TLSEXT_ERR_OK ;
}
# endif /* !OPENSSL_NO_TLSEXT */
/*
* Create new SSL context for outgoing connections to the original destination .
* If hostname sni is provided , use it for Server Name Indication .
*/
static SSL *
pxy_dstssl_create ( pxy_conn_ctx_t * ctx )
{
SSL_CTX * sslctx ;
SSL * ssl ;
SSL_SESSION * sess ;
2017-07-15 01:07:42 +00:00
sslctx = SSL_CTX_new ( ctx - > opts - > sslmethod ( ) ) ;
2012-05-02 13:37:47 +00:00
if ( ! sslctx ) {
ctx - > enomem = 1 ;
2012-05-02 13:00:22 +00:00
return NULL ;
2012-05-02 13:37:47 +00:00
}
2012-05-02 13:00:22 +00:00
2015-07-28 21:23:53 +00:00
pxy_sslctx_setoptions ( sslctx , ctx ) ;
2014-11-05 19:06:11 +00:00
2018-08-22 19:48:55 +00:00
# if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
2018-03-16 09:12:48 +00:00
if ( ctx - > opts - > sslversion ) {
if ( SSL_CTX_set_min_proto_version ( sslctx , ctx - > opts - > sslversion ) = = 0 | |
SSL_CTX_set_max_proto_version ( sslctx , ctx - > opts - > sslversion ) = = 0 ) {
SSL_CTX_free ( sslctx ) ;
ctx - > enomem = 1 ;
return NULL ;
}
}
# endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */
2018-01-18 00:18:53 +00:00
if ( ctx - > opts - > verify_peer ) {
SSL_CTX_set_verify ( sslctx , SSL_VERIFY_PEER , NULL ) ;
SSL_CTX_set_default_verify_paths ( sslctx ) ;
} else {
SSL_CTX_set_verify ( sslctx , SSL_VERIFY_NONE , NULL ) ;
}
2012-04-13 12:47:30 +00:00
2018-08-03 20:36:51 +00:00
if ( ctx - > opts - > clientcrt ) {
if ( ! SSL_CTX_use_certificate ( sslctx , ctx - > opts - > clientcrt ) )
log_dbg_printf ( " loading client certificate failed " ) ;
}
if ( ctx - > opts - > clientkey ) {
if ( ! SSL_CTX_use_PrivateKey ( sslctx , ctx - > opts - > clientkey ) )
log_dbg_printf ( " loading client key failed " ) ;
}
2012-04-13 12:47:30 +00:00
ssl = SSL_new ( sslctx ) ;
2014-01-10 23:30:04 +00:00
SSL_CTX_free ( sslctx ) ; /* SSL_new() increments refcount */
if ( ! ssl ) {
ctx - > enomem = 1 ;
return NULL ;
}
2012-04-13 12:47:30 +00:00
# ifndef OPENSSL_NO_TLSEXT
2017-07-15 01:07:42 +00:00
if ( ctx - > sni ) {
SSL_set_tlsext_host_name ( ssl , ctx - > sni ) ;
2012-04-13 12:47:30 +00:00
}
# endif /* !OPENSSL_NO_TLSEXT */
2014-01-13 22:33:31 +00:00
# ifdef SSL_MODE_RELEASE_BUFFERS
2012-04-13 12:47:30 +00:00
/* lower memory footprint for idle connections */
SSL_set_mode ( ssl , SSL_get_mode ( ssl ) | SSL_MODE_RELEASE_BUFFERS ) ;
2014-01-13 22:33:31 +00:00
# endif /* SSL_MODE_RELEASE_BUFFERS */
2012-04-13 12:47:30 +00:00
/* session resuming based on remote endpoint address and port */
sess = cachemgr_dsess_get ( ( struct sockaddr * ) & ctx - > addr ,
2017-07-15 01:07:42 +00:00
ctx - > addrlen , ctx - > sni ) ; /* new sess inst */
2012-04-13 12:47:30 +00:00
if ( sess ) {
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2012-04-13 12:47:30 +00:00
log_dbg_printf ( " Attempt reuse dst SSL session \n " ) ;
}
2014-01-11 18:03:15 +00:00
SSL_set_session ( ssl , sess ) ; /* increments sess refcount */
2012-04-13 12:47:30 +00:00
SSL_SESSION_free ( sess ) ;
}
return ssl ;
}
/*
* Set up a bufferevent structure for either a dst or src connection ,
* optionally with or without SSL . Sets all callbacks , enables read
* and write events , but does not call bufferevent_socket_connect ( ) .
*
* For dst connections , pass - 1 as fd . Pass a pointer to an initialized
* SSL struct as ssl if the connection should use SSL .
*
* Returns pointer to initialized bufferevent structure , as returned
* by bufferevent_socket_new ( ) or bufferevent_openssl_socket_new ( ) .
*/
2017-07-15 10:04:13 +00:00
static struct bufferevent * NONNULL ( 1 )
2012-04-13 12:47:30 +00:00
pxy_bufferevent_setup ( pxy_conn_ctx_t * ctx , evutil_socket_t fd , SSL * ssl )
{
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bufferevent_setup: ENTER fd=%d \n " , fd ) ;
# endif /* DEBUG_PROXY */
2012-04-13 12:47:30 +00:00
2017-08-13 01:36:33 +00:00
struct bufferevent * bev ;
2017-05-29 09:22:23 +00:00
2012-04-13 12:47:30 +00:00
if ( ssl ) {
2017-07-15 01:07:42 +00:00
bev = bufferevent_openssl_socket_new ( ctx - > evbase , fd , ssl ,
2017-07-27 14:50:45 +00:00
( ( fd = = - 1 ) ? BUFFEREVENT_SSL_CONNECTING : BUFFEREVENT_SSL_ACCEPTING ) , BEV_OPT_DEFER_CALLBACKS ) ;
2012-04-13 12:47:30 +00:00
} else {
2017-07-17 09:47:42 +00:00
// @todo Do we really need to defer callbacks? BEV_OPT_DEFER_CALLBACKS seems responsible for the issue with srv_dst: We get writecb sometimes, no eventcb for CONNECTED event
2017-07-15 01:07:42 +00:00
bev = bufferevent_socket_new ( ctx - > evbase , fd , BEV_OPT_DEFER_CALLBACKS ) ;
2012-04-13 12:47:30 +00:00
}
if ( ! bev ) {
2017-10-14 22:39:30 +00:00
log_err_level_printf ( LOG_CRIT , " Error creating bufferevent socket \n " ) ;
2012-04-13 12:47:30 +00:00
return NULL ;
}
# if LIBEVENT_VERSION_NUMBER >= 0x02010000
if ( ssl ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bufferevent_setup: bufferevent_openssl_set_allow_dirty_shutdown \n " ) ;
# endif /* DEBUG_PROXY */
2012-04-13 12:47:30 +00:00
/* Prevent unclean (dirty) shutdowns to cause error
* events on the SSL socket bufferevent . */
bufferevent_openssl_set_allow_dirty_shutdown ( bev , 1 ) ;
}
# endif /* LIBEVENT_VERSION_NUMBER >= 0x02010000 */
2017-07-03 23:12:17 +00:00
2017-07-20 14:55:00 +00:00
// @attention Do not set callbacks here, srv_dst does not set r cb
2017-07-16 14:10:18 +00:00
//bufferevent_setcb(bev, pxy_bev_readcb, pxy_bev_writecb, pxy_bev_eventcb, ctx);
2017-07-03 23:12:17 +00:00
// @todo Should we enable events here?
2017-07-01 15:08:28 +00:00
//bufferevent_enable(bev, EV_READ|EV_WRITE);
2017-07-03 23:12:17 +00:00
2012-04-13 12:47:30 +00:00
# ifdef DEBUG_PROXY
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2012-04-13 12:47:30 +00:00
log_dbg_printf ( " %p pxy_bufferevent_setup \n " ,
( void * ) bev ) ;
}
# endif /* DEBUG_PROXY */
2017-05-29 09:22:23 +00:00
return bev ;
}
2017-07-15 10:04:13 +00:00
static struct bufferevent * NONNULL ( 1 )
2017-07-11 22:45:15 +00:00
pxy_bufferevent_setup_child ( pxy_conn_child_ctx_t * ctx , evutil_socket_t fd , SSL * ssl )
2017-05-29 09:22:23 +00:00
{
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bufferevent_setup_child: ENTER fd=%d \n " , fd ) ;
# endif /* DEBUG_PROXY */
2017-05-29 09:22:23 +00:00
2017-08-13 01:36:33 +00:00
struct bufferevent * bev ;
2017-05-29 09:22:23 +00:00
2017-06-10 18:50:03 +00:00
if ( ssl ) {
2018-09-22 23:02:15 +00:00
bev = bufferevent_openssl_socket_new ( ctx - > conn - > evbase , fd , ssl ,
2017-06-10 18:50:03 +00:00
( ( fd = = - 1 ) ? BUFFEREVENT_SSL_CONNECTING : BUFFEREVENT_SSL_ACCEPTING ) , BEV_OPT_DEFER_CALLBACKS ) ;
} else {
2018-09-22 23:02:15 +00:00
bev = bufferevent_socket_new ( ctx - > conn - > evbase , fd , BEV_OPT_DEFER_CALLBACKS ) ;
2017-06-10 18:50:03 +00:00
}
2017-05-29 09:22:23 +00:00
if ( ! bev ) {
2017-10-14 22:39:30 +00:00
log_err_level_printf ( LOG_CRIT , " Error creating bufferevent socket \n " ) ;
2017-05-29 09:22:23 +00:00
return NULL ;
}
2017-07-03 23:12:17 +00:00
# if LIBEVENT_VERSION_NUMBER >= 0x02010000
if ( ssl ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bufferevent_setup_child: bufferevent_openssl_set_allow_dirty_shutdown \n " ) ;
# endif /* DEBUG_PROXY */
2017-07-03 23:12:17 +00:00
/* Prevent unclean (dirty) shutdowns to cause error
* events on the SSL socket bufferevent . */
bufferevent_openssl_set_allow_dirty_shutdown ( bev , 1 ) ;
}
# endif /* LIBEVENT_VERSION_NUMBER >= 0x02010000 */
2017-07-07 14:18:01 +00:00
bufferevent_setcb ( bev , pxy_bev_readcb_child , pxy_bev_writecb_child , pxy_bev_eventcb_child , ctx ) ;
2017-07-03 23:12:17 +00:00
2017-07-12 21:45:12 +00:00
// @attention We cannot enable events here, because src events will be deferred until after dst is connected
2017-07-03 23:12:17 +00:00
//bufferevent_enable(bev, EV_READ|EV_WRITE);
2017-05-29 09:22:23 +00:00
# ifdef DEBUG_PROXY
2018-09-22 23:02:15 +00:00
if ( OPTS_DEBUG ( ctx - > conn - > opts ) ) {
2017-07-07 14:18:01 +00:00
log_dbg_printf ( " %p pxy_bufferevent_setup_child \n " ,
2017-05-29 09:22:23 +00:00
( void * ) bev ) ;
}
# endif /* DEBUG_PROXY */
2012-04-13 12:47:30 +00:00
return bev ;
}
2013-06-29 20:35:51 +00:00
/*
* Filter a single line of HTTP request headers .
* Also fills in some context fields for logging .
*
* Returns NULL if the current line should be deleted from the request .
* Returns a newly allocated string if the current line should be replaced .
* Returns ` line ' if the line should be kept .
*/
2012-04-13 12:47:30 +00:00
static char *
2018-10-05 13:55:02 +00:00
pxy_http_filter_request_header_line ( const char * line , pxy_conn_ctx_t * ctx )
2012-04-13 12:47:30 +00:00
{
/* parse information for connect log */
if ( ! ctx - > http_method ) {
/* first line */
2014-01-14 16:37:57 +00:00
char * space1 , * space2 ;
2012-04-13 12:47:30 +00:00
space1 = strchr ( line , ' ' ) ;
space2 = space1 ? strchr ( space1 + 1 , ' ' ) : NULL ;
if ( ! space1 ) {
/* not HTTP */
ctx - > seen_req_header = 1 ;
} else {
ctx - > http_method = malloc ( space1 - line + 1 ) ;
if ( ctx - > http_method ) {
memcpy ( ctx - > http_method , line , space1 - line ) ;
ctx - > http_method [ space1 - line ] = ' \0 ' ;
} else {
2012-05-02 13:00:22 +00:00
ctx - > enomem = 1 ;
return NULL ;
2012-04-13 12:47:30 +00:00
}
space1 + + ;
if ( ! space2 ) {
/* HTTP/0.9 */
ctx - > seen_req_header = 1 ;
space2 = space1 + strlen ( space1 ) ;
}
ctx - > http_uri = malloc ( space2 - space1 + 1 ) ;
if ( ctx - > http_uri ) {
memcpy ( ctx - > http_uri , space1 , space2 - space1 ) ;
ctx - > http_uri [ space2 - space1 ] = ' \0 ' ;
} else {
2012-05-02 13:00:22 +00:00
ctx - > enomem = 1 ;
return NULL ;
2012-04-13 12:47:30 +00:00
}
}
} else {
/* not first line */
2014-01-14 16:37:57 +00:00
char * newhdr ;
2014-10-28 22:31:07 +00:00
if ( ! ctx - > http_host & & ! strncasecmp ( line , " Host: " , 5 ) ) {
ctx - > http_host = strdup ( util_skipws ( line + 5 ) ) ;
2012-05-02 13:00:22 +00:00
if ( ! ctx - > http_host ) {
ctx - > enomem = 1 ;
return NULL ;
}
2014-10-28 22:31:07 +00:00
} else if ( ! strncasecmp ( line , " Content-Type: " , 13 ) ) {
ctx - > http_content_type = strdup ( util_skipws ( line + 13 ) ) ;
2012-05-02 13:00:22 +00:00
if ( ! ctx - > http_content_type ) {
ctx - > enomem = 1 ;
return NULL ;
}
2018-02-27 19:20:58 +00:00
/* Override Connection: keepalive and Connection: upgrade */
2014-10-28 22:31:07 +00:00
} else if ( ! strncasecmp ( line , " Connection: " , 11 ) ) {
2012-04-13 12:47:30 +00:00
ctx - > sent_http_conn_close = 1 ;
2012-05-02 13:00:22 +00:00
if ( ! ( newhdr = strdup ( " Connection: close " ) ) ) {
ctx - > enomem = 1 ;
return NULL ;
}
return newhdr ;
2018-09-22 23:02:15 +00:00
// @attention Always use conn ctx for opts, child ctx does not have opts, see the comments in pxy_conn_child_ctx
} else if ( ctx - > conn - > opts - > remove_http_accept_encoding & & ! strncasecmp ( line , " Accept-Encoding: " , 16 ) ) {
2017-08-24 10:30:23 +00:00
return NULL ;
2018-09-22 23:02:15 +00:00
} else if ( ctx - > conn - > opts - > remove_http_referer & & ! strncasecmp ( line , " Referer: " , 8 ) ) {
2017-09-03 20:11:20 +00:00
return NULL ;
2018-02-27 19:20:58 +00:00
/* Suppress upgrading to SSL/TLS, WebSockets or HTTP/2,
* unsupported encodings , and keep - alive */
} else if ( ! strncasecmp ( line , " Upgrade: " , 8 ) | |
! strncasecmp ( line , " Accept-Encoding: " , 16 ) | |
! strncasecmp ( line , " Keep-Alive: " , 11 ) ) {
2017-07-28 09:52:53 +00:00
return NULL ;
2018-09-22 23:02:15 +00:00
} else if ( ctx - > is_child & & ( ! strncasecmp ( line , SSLPROXY_KEY , SSLPROXY_KEY_LEN ) | |
2017-07-27 14:50:45 +00:00
// @attention flickr keeps redirecting to https with 301 unless we remove the Via line of squid
// Apparently flickr assumes the existence of Via header field or squid keyword a sign of plain http, even if we are using https
! strncasecmp ( line , " Via: " , 4 ) | |
// Also do not send the loopback address to the Internet
2017-07-28 09:52:53 +00:00
! strncasecmp ( line , " X-Forwarded-For: " , 16 ) ) ) {
2017-07-25 13:07:39 +00:00
return NULL ;
2012-04-13 12:47:30 +00:00
} else if ( line [ 0 ] = = ' \0 ' ) {
ctx - > seen_req_header = 1 ;
if ( ! ctx - > sent_http_conn_close ) {
2012-05-02 13:00:22 +00:00
newhdr = strdup ( " Connection: close \r \n " ) ;
if ( ! newhdr ) {
ctx - > enomem = 1 ;
return NULL ;
}
return newhdr ;
2012-04-13 12:47:30 +00:00
}
}
}
return ( char * ) line ;
}
2013-06-29 20:35:51 +00:00
/*
* Filter a single line of HTTP response headers .
*
* Returns NULL if the current line should be deleted from the response .
* Returns a newly allocated string if the current line should be replaced .
* Returns ` line ' if the line should be kept .
*/
static char *
2018-10-05 13:55:02 +00:00
pxy_http_filter_response_header_line ( const char * line , pxy_conn_ctx_t * ctx )
2013-06-29 20:35:51 +00:00
{
/* parse information for connect log */
if ( ! ctx - > http_status_code ) {
/* first line */
2014-01-14 16:37:57 +00:00
char * space1 , * space2 ;
2013-06-29 20:35:51 +00:00
space1 = strchr ( line , ' ' ) ;
space2 = space1 ? strchr ( space1 + 1 , ' ' ) : NULL ;
if ( ! space1 | | ! ! strncmp ( line , " HTTP " , 4 ) ) {
/* not HTTP or HTTP/0.9 */
ctx - > seen_resp_header = 1 ;
} else {
2014-01-14 16:37:57 +00:00
size_t len_code , len_text ;
2013-06-29 20:35:51 +00:00
if ( space2 ) {
len_code = space2 - space1 - 1 ;
len_text = strlen ( space2 + 1 ) ;
} else {
len_code = strlen ( space1 + 1 ) ;
len_text = 0 ;
}
ctx - > http_status_code = malloc ( len_code + 1 ) ;
ctx - > http_status_text = malloc ( len_text + 1 ) ;
if ( ! ctx - > http_status_code | | ! ctx - > http_status_text ) {
ctx - > enomem = 1 ;
return NULL ;
}
memcpy ( ctx - > http_status_code , space1 + 1 , len_code ) ;
ctx - > http_status_code [ len_code ] = ' \0 ' ;
if ( space2 ) {
memcpy ( ctx - > http_status_text ,
space2 + 1 , len_text ) ;
}
ctx - > http_status_text [ len_text ] = ' \0 ' ;
}
} else {
/* not first line */
2013-06-29 20:50:39 +00:00
if ( ! ctx - > http_content_length & &
2014-10-28 22:31:07 +00:00
! strncasecmp ( line , " Content-Length: " , 15 ) ) {
2013-06-29 20:50:39 +00:00
ctx - > http_content_length =
2014-10-28 22:31:07 +00:00
strdup ( util_skipws ( line + 15 ) ) ;
2013-06-29 20:50:39 +00:00
if ( ! ctx - > http_content_length ) {
ctx - > enomem = 1 ;
return NULL ;
}
2014-11-02 19:25:17 +00:00
} else if (
/* HPKP: Public Key Pinning Extension for HTTP
* ( draft - ietf - websec - key - pinning )
* remove to prevent public key pinning */
! strncasecmp ( line , " Public-Key-Pins: " , 16 ) | |
2014-10-28 22:31:07 +00:00
! strncasecmp ( line , " Public-Key-Pins-Report-Only: " , 28 ) | |
2014-11-02 19:25:17 +00:00
/* HSTS: HTTP Strict Transport Security (RFC 6797)
* remove to allow users to accept bad certs */
! strncasecmp ( line , " Strict-Transport-Security: " , 26 ) | |
2018-09-14 23:51:26 +00:00
/* Expect-CT: Expect Certificate Transparency
* ( draft - ietf - httpbis - expect - ct - latest )
* remove to prevent failed CT log lookups */
! strncasecmp ( line , " Expect-CT: " , 10 ) | |
2014-11-02 19:25:17 +00:00
/* Alternate Protocol
* remove to prevent switching to QUIC , SPDY et al */
2018-02-27 19:20:58 +00:00
! strncasecmp ( line , " Alternate-Protocol: " , 19 ) | |
/* Upgrade header
* remove to prevent upgrading to HTTPS in unhandled ways ,
* and more importantly , WebSockets and HTTP / 2 */
! strncasecmp ( line , " Upgrade: " , 8 ) ) {
2013-06-29 20:35:51 +00:00
return NULL ;
} else if ( line [ 0 ] = = ' \0 ' ) {
ctx - > seen_resp_header = 1 ;
}
}
return ( char * ) line ;
}
2012-04-22 17:12:38 +00:00
/*
* Return 1 if uri is an OCSP GET URI , 0 if not .
*/
static int
2012-05-02 13:00:22 +00:00
pxy_ocsp_is_valid_uri ( const char * uri , pxy_conn_ctx_t * ctx )
2012-04-22 17:12:38 +00:00
{
char * buf_url ;
2012-04-22 19:45:18 +00:00
size_t sz_url ;
2012-04-22 17:12:38 +00:00
char * buf_b64 ;
size_t sz_b64 ;
unsigned char * buf_asn1 ;
size_t sz_asn1 ;
int ret ;
buf_url = strrchr ( uri , ' / ' ) ;
if ( ! buf_url )
return 0 ;
2012-04-22 19:45:18 +00:00
buf_url + + ;
/*
* Do some quick checks to avoid unnecessary buffer allocations and
* decoding URL , Base64 and ASN .1 :
* - OCSP requests begin with a SEQUENCE ( 0x30 ) , so the first Base64
* byte is ' M ' or , unlikely but legal , the URL encoding thereof .
* - There should be no query string in OCSP GET requests .
* - Encoded OCSP request ASN .1 blobs are longer than 32 bytes .
*/
if ( buf_url [ 0 ] ! = ' M ' & & buf_url [ 0 ] ! = ' % ' )
return 0 ;
if ( strchr ( uri , ' ? ' ) )
return 0 ;
sz_url = strlen ( buf_url ) ;
if ( sz_url < 32 )
return 0 ;
buf_b64 = url_dec ( buf_url , sz_url , & sz_b64 ) ;
2012-05-02 13:00:22 +00:00
if ( ! buf_b64 ) {
ctx - > enomem = 1 ;
2012-04-22 17:12:38 +00:00
return 0 ;
2012-05-02 13:00:22 +00:00
}
2012-04-22 17:12:38 +00:00
buf_asn1 = base64_dec ( buf_b64 , sz_b64 , & sz_asn1 ) ;
if ( ! buf_asn1 ) {
2012-05-02 13:00:22 +00:00
ctx - > enomem = 1 ;
2012-04-22 17:12:38 +00:00
free ( buf_b64 ) ;
return 0 ;
}
ret = ssl_is_ocspreq ( buf_asn1 , sz_asn1 ) ;
free ( buf_asn1 ) ;
free ( buf_b64 ) ;
return ret ;
}
2018-10-03 23:56:02 +00:00
static const char ocspresp [ ] =
" HTTP/1.0 200 OK \r \n "
" Content-Type: application/ocsp-response \r \n "
" Content-Length: 5 \r \n "
" Connection: close \r \n "
" \r \n "
" \x30 \x03 " /* OCSPResponse: SEQUENCE */
" \x0a \x01 " /* OCSPResponseStatus: ENUMERATED */
" \x03 " ; /* tryLater (3) */
2012-04-22 17:12:38 +00:00
/*
* Called after a request header was completely read .
* If the request is an OCSP request , deny the request by sending an
* OCSP response of type tryLater and close the connection to the server .
*
* Reference :
* RFC 2560 : X .509 Internet PKI Online Certificate Status Protocol ( OCSP )
*/
static void
2018-09-22 23:02:15 +00:00
pxy_ocsp_deny ( pxy_conn_ctx_t * ctx )
2012-04-22 17:12:38 +00:00
{
struct evbuffer * inbuf , * outbuf ;
if ( ! ctx - > http_method )
return ;
if ( ! strncasecmp ( ctx - > http_method , " GET " , 3 ) & &
2018-10-05 01:55:24 +00:00
pxy_ocsp_is_valid_uri ( ctx - > http_uri , ctx ) )
2017-07-18 19:07:29 +00:00
goto deny ;
if ( ! strncasecmp ( ctx - > http_method , " POST " , 4 ) & &
ctx - > http_content_type & &
! strncasecmp ( ctx - > http_content_type ,
" application/ocsp-request " , 24 ) )
goto deny ;
return ;
deny :
inbuf = bufferevent_get_input ( ctx - > src . bev ) ;
outbuf = bufferevent_get_output ( ctx - > src . bev ) ;
if ( evbuffer_get_length ( inbuf ) > 0 ) {
evbuffer_drain ( inbuf , evbuffer_get_length ( inbuf ) ) ;
}
2018-09-22 23:02:15 +00:00
bufferevent_free_and_close_fd ( ctx - > dst . bev , ctx - > conn ) ;
2017-07-18 19:07:29 +00:00
ctx - > dst . bev = NULL ;
ctx - > dst . closed = 1 ;
evbuffer_add_printf ( outbuf , ocspresp ) ;
ctx - > ocsp_denied = 1 ;
}
2016-03-27 11:26:39 +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
*/
2015-04-18 12:26:03 +00:00
int
2016-03-27 11:26:39 +00:00
pxy_conn_autossl_peek_and_upgrade ( pxy_conn_ctx_t * ctx )
2015-04-18 12:26:03 +00:00
{
struct evbuffer * inbuf ;
struct evbuffer_iovec vec_out [ 1 ] ;
2015-05-17 18:23:25 +00:00
const unsigned char * chello ;
2018-09-26 19:13:07 +00:00
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2015-04-18 12:26:03 +00:00
log_dbg_printf ( " Checking for a client hello \n " ) ;
}
2018-09-26 19:13:07 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_conn_autossl_peek_and_upgrade: ENTER, fd=%d \n " , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
2015-04-18 12:26:03 +00:00
/* peek the buffer */
inbuf = bufferevent_get_input ( ctx - > src . bev ) ;
2015-05-17 18:23:25 +00:00
if ( evbuffer_peek ( inbuf , 1024 , 0 , vec_out , 1 ) ) {
2018-09-25 09:24:23 +00:00
if ( ssl_tls_clienthello_parse ( vec_out [ 0 ] . iov_base , vec_out [ 0 ] . iov_len , 0 , & chello , & ctx - > sni ) = = 0 ) {
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2016-03-27 11:26:39 +00:00
log_dbg_printf ( " Peek found ClientHello \n " ) ;
2015-04-18 12:26:03 +00:00
}
2018-09-26 19:13:07 +00:00
2017-07-12 19:37:36 +00:00
ctx - > srv_dst . ssl = pxy_dstssl_create ( ctx ) ;
if ( ! ctx - > srv_dst . ssl ) {
2018-09-25 09:24:23 +00:00
log_err_level_printf ( LOG_CRIT , " Error creating SSL for upgrade \n " ) ;
2018-09-26 20:45:52 +00:00
// @todo Should we close the connection?
2015-04-18 12:26:03 +00:00
return 0 ;
}
2018-09-26 20:45:52 +00:00
2018-09-25 09:24:23 +00:00
ctx - > srv_dst . bev = bufferevent_openssl_filter_new ( ctx - > evbase , ctx - > srv_dst . bev , ctx - > srv_dst . ssl ,
BUFFEREVENT_SSL_CONNECTING , BEV_OPT_DEFER_CALLBACKS ) ;
2018-09-26 20:45:52 +00:00
if ( ! ctx - > srv_dst . bev ) {
log_err_level_printf ( LOG_CRIT , " Error creating bufferevent \n " ) ;
if ( ctx - > srv_dst . ssl ) {
SSL_free ( ctx - > srv_dst . ssl ) ;
ctx - > srv_dst . ssl = NULL ;
}
// @todo Should we close the connection?
return 0 ;
}
2018-09-26 19:13:07 +00:00
2018-09-25 09:24:23 +00:00
bufferevent_setcb ( ctx - > srv_dst . bev , pxy_bev_readcb , pxy_bev_writecb , pxy_bev_eventcb , ctx ) ;
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-09-25 09:24:23 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_conn_autossl_peek_and_upgrade: Enabling srv_dst, fd=%d \n " , ctx - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-12 19:37:36 +00:00
bufferevent_enable ( ctx - > srv_dst . bev , EV_READ | EV_WRITE ) ;
2018-09-26 20:45:52 +00:00
2017-07-25 13:07:39 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2018-09-25 09:24:23 +00:00
log_err_level_printf ( LOG_INFO , " Replaced srv_dst bufferevent, new one is %p \n " , ( void * ) ctx - > srv_dst . bev ) ;
2017-07-14 19:34:15 +00:00
}
2018-09-26 19:13:07 +00:00
2017-07-14 19:34:15 +00:00
ctx - > clienthello_search = 0 ;
ctx - > clienthello_found = 1 ;
return 1 ;
} else {
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2017-07-14 19:34:15 +00:00
log_dbg_printf ( " Peek found no ClientHello \n " ) ;
}
return 0 ;
2017-07-10 09:27:46 +00:00
}
2017-07-12 19:37:36 +00:00
}
2017-07-14 19:34:15 +00:00
return 0 ;
2017-06-29 21:38:37 +00:00
}
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2017-07-05 19:32:10 +00:00
char * bev_names [ ] = {
" src " ,
" dst " ,
2017-07-12 19:37:36 +00:00
" srv_dst " ,
2017-07-05 19:32:10 +00:00
" NULL " ,
" UNKWN "
} ;
2017-07-07 14:18:01 +00:00
static char *
2017-07-05 19:32:10 +00:00
pxy_get_event_name ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
{
if ( bev = = ctx - > src . bev ) {
return bev_names [ 0 ] ;
} else if ( bev = = ctx - > dst . bev ) {
return bev_names [ 1 ] ;
2017-07-12 19:37:36 +00:00
} else if ( bev = = ctx - > srv_dst . bev ) {
2017-07-05 19:32:10 +00:00
return bev_names [ 2 ] ;
} else if ( bev = = NULL ) {
2017-08-13 01:36:33 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " pxy_get_event_name: event_name=NULL \n " ) ;
2017-07-12 19:37:36 +00:00
return bev_names [ 3 ] ;
2017-07-05 19:32:10 +00:00
} else {
2017-08-13 01:36:33 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " pxy_get_event_name: event_name=UNKWN \n " ) ;
2017-07-12 19:37:36 +00:00
return bev_names [ 4 ] ;
2017-07-05 19:32:10 +00:00
}
}
2017-07-11 22:45:15 +00:00
static char *
pxy_get_event_name_child ( struct bufferevent * bev , pxy_conn_child_ctx_t * ctx )
{
2017-07-12 13:46:51 +00:00
if ( bev = = ctx - > src . bev ) {
return bev_names [ 0 ] ;
} else if ( bev = = ctx - > dst . bev ) {
2017-07-11 22:45:15 +00:00
return bev_names [ 1 ] ;
} else if ( bev = = NULL ) {
2017-08-13 01:36:33 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " pxy_get_event_name_child: event_name=NULL \n " ) ;
2017-07-12 19:37:36 +00:00
return bev_names [ 3 ] ;
2017-07-11 22:45:15 +00:00
} else {
2017-08-13 01:36:33 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " pxy_get_event_name_child: event_name=UNKWN \n " ) ;
2017-07-12 19:37:36 +00:00
return bev_names [ 4 ] ;
2017-07-11 22:45:15 +00:00
}
}
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-11 22:45:15 +00:00
2018-10-01 22:46:12 +00:00
# ifdef HAVE_NETFILTER
/*
* Copied from :
* https : //github.com/tmux/tmux/blob/master/compat/getdtablecount.c
*/
int
getdtablecount ( void )
{
char path [ PATH_MAX ] ;
glob_t g ;
int n = 0 ;
if ( snprintf ( path , sizeof path , " /proc/%ld/fd/* " , ( long ) getpid ( ) ) < 0 ) {
log_err_level_printf ( LOG_CRIT , " snprintf overflow \n " ) ;
return 0 ;
}
if ( glob ( path , 0 , NULL , & g ) = = 0 )
n = g . gl_pathc ;
globfree ( & g ) ;
return n ;
}
# endif /* HAVE_NETFILTER */
/*
* Callback for accept events on the socket listener bufferevent .
*/
static void
proxy_listener_acceptcb_child ( UNUSED struct evconnlistener * listener , evutil_socket_t fd ,
UNUSED struct sockaddr * peeraddr , UNUSED int peeraddrlen , void * arg )
{
pxy_conn_ctx_t * conn = arg ;
conn - > atime = time ( NULL ) ;
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " proxy_listener_acceptcb_child: ENTER fd=%d, conn fd=%d, child_fd=%d \n " , fd , conn - > fd , conn - > child_fd ) ;
char * host , * port ;
if ( sys_sockaddr_str ( peeraddr , peeraddrlen , & host , & port ) = = 0 ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " proxy_listener_acceptcb_child: Peer addr=[%s]:%s, child fd=%d, conn fd=%d \n " , host , port , fd , conn - > fd ) ;
free ( host ) ;
free ( port ) ;
}
# endif /* DEBUG_PROXY */
int dtable_count = getdtablecount ( ) ;
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " proxy_listener_acceptcb_child: descriptor_table_size=%d, current fd count=%d, reserve=%d, fd=%d \n " , descriptor_table_size , dtable_count , FD_RESERVE , fd ) ;
# endif /* DEBUG_PROXY */
// Close the conn if we are out of file descriptors, or libevent will crash us, @see pxy_conn_setup() for explanation
if ( dtable_count + FD_RESERVE > = descriptor_table_size ) {
errno = EMFILE ;
log_err_level_printf ( LOG_CRIT , " Out of file descriptors \n " ) ;
evutil_closesocket ( fd ) ;
pxy_conn_free ( conn , 1 ) ;
return ;
}
pxy_conn_child_ctx_t * ctx = pxy_conn_ctx_new_child ( fd , conn ) ;
if ( ! ctx ) {
log_err_level_printf ( LOG_CRIT , " Error allocating memory \n " ) ;
evutil_closesocket ( fd ) ;
pxy_conn_free ( conn , 1 ) ;
return ;
}
// Prepend child ctx to conn ctx child list
// @attention If the last child is deleted, the children list may become null again
ctx - > next = conn - > children ;
conn - > children = ctx ;
conn - > child_count + + ;
ctx - > idx = conn - > child_count ;
if ( ! ctx - > conn - > addrlen ) {
log_err_level_printf ( LOG_CRIT , " Child no target address; aborting connection \n " ) ;
evutil_closesocket ( ctx - > fd ) ;
pxy_conn_free ( ctx - > conn , 1 ) ;
return ;
}
ctx - > src . ssl = NULL ;
ctx - > src . bev = pxy_bufferevent_setup_child ( ctx , ctx - > fd , ctx - > src . ssl ) ;
if ( ! ctx - > src . bev ) {
log_err_level_printf ( LOG_CRIT , " Error creating child src \n " ) ;
evutil_closesocket ( ctx - > fd ) ;
pxy_conn_free ( ctx - > conn , 1 ) ;
return ;
}
ctx - > src_fd = bufferevent_getfd ( ctx - > src . bev ) ;
ctx - > conn - > child_src_fd = ctx - > src_fd ;
ctx - > conn - > thr - > max_fd = MAX ( ctx - > conn - > thr - > max_fd , ctx - > src_fd ) ;
// @attention Do not enable src events here yet, they will be enabled after dst connects
/* create server-side socket and eventbuffer */
// Children rely on the findings of parent
if ( ctx - > conn - > spec - > ssl | | ctx - > conn - > clienthello_found ) {
ctx - > dst . ssl = pxy_dstssl_create ( ctx - > conn ) ;
if ( ! ctx - > dst . ssl ) {
log_err_level_printf ( LOG_CRIT , " Error creating SSL \n " ) ;
// pxy_conn_free()>pxy_conn_free_child() will close the fd, since we have a non-NULL src.bev now
pxy_conn_free ( ctx - > conn , 1 ) ;
return ;
}
}
ctx - > dst . bev = pxy_bufferevent_setup_child ( ctx , - 1 , ctx - > dst . ssl ) ;
if ( ! ctx - > dst . bev ) {
log_err_level_printf ( LOG_CRIT , " Error creating bufferevent \n " ) ;
if ( ctx - > dst . ssl ) {
SSL_free ( ctx - > dst . ssl ) ;
ctx - > dst . ssl = NULL ;
}
pxy_conn_free ( ctx - > conn , 1 ) ;
return ;
}
bufferevent_enable ( ctx - > dst . bev , EV_READ | EV_WRITE ) ;
if ( OPTS_DEBUG ( ctx - > conn - > opts ) ) {
char * host , * port ;
if ( sys_sockaddr_str ( ( struct sockaddr * ) & ctx - > conn - > addr , ctx - > conn - > addrlen , & host , & port ) ! = 0 ) {
log_dbg_printf ( " proxy_listener_acceptcb_child: Connecting to [?]:? \n " ) ;
} else {
log_dbg_printf ( " proxy_listener_acceptcb_child: Connecting to [%s]:%s \n " , host , port ) ;
free ( host ) ;
free ( port ) ;
}
}
/* initiate connection */
// @attention No need to check retval here, the eventcb should handle the errors
bufferevent_socket_connect ( ctx - > dst . bev , ( struct sockaddr * ) & ctx - > conn - > addr , ctx - > conn - > addrlen ) ;
ctx - > dst_fd = bufferevent_getfd ( ctx - > dst . bev ) ;
ctx - > conn - > child_dst_fd = ctx - > dst_fd ;
ctx - > conn - > thr - > max_fd = MAX ( ctx - > conn - > thr - > max_fd , ctx - > dst_fd ) ;
}
2018-09-23 21:41:00 +00:00
static int
pxy_log_content_buf ( pxy_conn_ctx_t * ctx , unsigned char * buf , size_t sz , int req )
{
if ( WANT_CONTENT_LOG ( ctx - > conn ) ) {
if ( buf ) {
logbuf_t * lb = logbuf_new_alloc ( sz , NULL , NULL ) ;
if ( ! lb ) {
2018-10-01 22:46:12 +00:00
ctx - > enomem = 1 ;
2018-09-23 21:41:00 +00:00
return - 1 ;
}
memcpy ( lb - > buf , buf , lb - > sz ) ;
if ( log_content_submit ( ctx - > conn - > logctx , lb , req ) = = - 1 ) {
logbuf_free ( lb ) ;
log_err_level_printf ( LOG_WARNING , " Content log submission failed \n " ) ;
return - 1 ;
}
}
}
return 0 ;
}
static int
pxy_log_content_inbuf ( pxy_conn_ctx_t * ctx , struct evbuffer * inbuf , int req )
{
if ( WANT_CONTENT_LOG ( ctx - > conn ) ) {
size_t sz = evbuffer_get_length ( inbuf ) ;
unsigned char * buf = malloc ( sz ) ;
2018-10-01 22:46:12 +00:00
if ( ! buf ) {
ctx - > enomem = 1 ;
return - 1 ;
}
if ( evbuffer_copyout ( inbuf , buf , sz ) = = - 1 ) {
return - 1 ;
}
if ( pxy_log_content_buf ( ctx , buf , sz , req ) = = - 1 ) {
2018-09-23 21:41:00 +00:00
return - 1 ;
}
}
return 0 ;
}
2017-07-21 21:44:12 +00:00
static void
2018-10-05 13:55:02 +00:00
pxy_http_filter_request_header ( struct evbuffer * inbuf , struct evbuffer * outbuf , pxy_conn_ctx_t * ctx )
2017-07-21 21:44:12 +00:00
{
char * line ;
2018-09-22 20:14:49 +00:00
2018-10-04 18:33:33 +00:00
while ( ! ctx - > seen_req_header & & ( line = evbuffer_readln ( inbuf , NULL , EVBUFFER_EOL_CRLF ) ) ) {
2018-10-05 13:55:02 +00:00
char * replace = pxy_http_filter_request_header_line ( line , ctx ) ;
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_http_filter_request_header: src line, fd=%d: %s \n " , ctx - > fd , line ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-21 21:44:12 +00:00
if ( replace = = line ) {
evbuffer_add_printf ( outbuf , " %s \r \n " , line ) ;
} else if ( replace ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " pxy_http_filter_request_header: src REPLACED line, fd=%d: %s \n " , ctx - > fd , replace ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-21 21:44:12 +00:00
evbuffer_add_printf ( outbuf , " %s \r \n " , replace ) ;
free ( replace ) ;
} else {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " pxy_http_filter_request_header: src REMOVED line, fd=%d: %s \n " , ctx - > fd , line ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-21 21:44:12 +00:00
}
free ( line ) ;
2018-09-22 23:02:15 +00:00
if ( ! ctx - > is_child & & ! ctx - > sent_header ) {
2018-09-22 20:14:49 +00:00
ctx - > sent_header = 1 ;
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " pxy_http_filter_request_header: src INSERT header_str line, fd=%d: %s \n " , ctx - > fd , ctx - > header_str ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-08-11 12:01:51 +00:00
evbuffer_add_printf ( outbuf , " %s \r \n " , ctx - > header_str ) ;
2017-07-21 21:44:12 +00:00
}
}
2018-09-23 21:41:00 +00:00
2018-10-04 18:33:33 +00:00
if ( ctx - > seen_req_header ) {
/* request header complete */
if ( ctx - > conn - > opts - > deny_ocsp ) {
pxy_ocsp_deny ( ctx ) ;
}
2017-07-21 21:44:12 +00:00
2018-10-04 18:33:33 +00:00
// @todo Fix this
/* out of memory condition? */
if ( ctx - > enomem ) {
pxy_conn_free ( ctx - > conn , 1 ) ;
return ;
}
2017-07-21 21:44:12 +00:00
2018-10-04 18:33:33 +00:00
/* no data left after parsing headers? */
if ( evbuffer_get_length ( inbuf ) = = 0 ) {
return ;
}
evbuffer_add_buffer ( outbuf , inbuf ) ;
2017-07-21 21:44:12 +00:00
}
}
static void
2018-10-05 13:55:02 +00:00
pxy_http_filter_response_header ( struct evbuffer * inbuf , struct evbuffer * outbuf , pxy_conn_ctx_t * ctx )
2017-07-21 21:44:12 +00:00
{
char * line ;
2018-09-23 21:41:00 +00:00
2018-10-04 18:33:33 +00:00
while ( ! ctx - > seen_resp_header & & ( line = evbuffer_readln ( inbuf , NULL , EVBUFFER_EOL_CRLF ) ) ) {
2018-10-05 13:55:02 +00:00
char * replace = pxy_http_filter_response_header_line ( line , ctx ) ;
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_http_filter_response_header: dst line, fd=%d: %s \n " , ctx - > fd , line ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-21 21:44:12 +00:00
if ( replace = = line ) {
evbuffer_add_printf ( outbuf , " %s \r \n " , line ) ;
} else if ( replace ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " pxy_http_filter_response_header: dst REPLACED line, fd=%d: %s \n " , ctx - > fd , replace ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-21 21:44:12 +00:00
evbuffer_add_printf ( outbuf , " %s \r \n " , replace ) ;
free ( replace ) ;
} else {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " pxy_http_filter_response_header: dst REMOVED line, fd=%d: %s \n " , ctx - > fd , line ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-21 21:44:12 +00:00
}
free ( line ) ;
}
2018-09-23 21:41:00 +00:00
2018-10-04 18:33:33 +00:00
if ( ctx - > seen_resp_header ) {
// @todo Fix this
/* out of memory condition? */
if ( ctx - > enomem ) {
pxy_conn_free ( ctx - > conn , 0 ) ;
return ;
}
2017-07-21 21:44:12 +00:00
2018-10-04 18:33:33 +00:00
/* no data left after parsing headers? */
if ( evbuffer_get_length ( inbuf ) = = 0 ) {
return ;
}
evbuffer_add_buffer ( outbuf , inbuf ) ;
2017-07-21 21:44:12 +00:00
}
}
2012-04-13 12:47:30 +00:00
static void
2018-10-01 22:46:12 +00:00
pxy_set_watermark ( struct bufferevent * bev , pxy_conn_ctx_t * ctx , struct bufferevent * other )
2012-04-13 12:47:30 +00:00
{
2018-10-01 22:46:12 +00:00
if ( evbuffer_get_length ( bufferevent_get_output ( other ) ) > = OUTBUF_LIMIT ) {
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " pxy_set_watermark: fd=%d \n " , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
/* temporarily disable data source;
* set an appropriate watermark . */
bufferevent_setwatermark ( other , EV_WRITE , OUTBUF_LIMIT / 2 , OUTBUF_LIMIT ) ;
bufferevent_disable ( bev , EV_READ ) ;
ctx - > thr - > set_watermarks + + ;
}
}
2017-06-27 14:09:01 +00:00
2018-10-05 13:55:02 +00:00
static void
pxy_discard_inbuf ( struct bufferevent * bev )
2018-10-01 22:46:12 +00:00
{
struct evbuffer * inbuf = bufferevent_get_input ( bev ) ;
size_t inbuf_size = evbuffer_get_length ( inbuf ) ;
2018-10-05 13:55:02 +00:00
log_dbg_printf ( " Warning: Drained %zu bytes (conn closed) \n " , inbuf_size ) ;
evbuffer_drain ( inbuf , inbuf_size ) ;
2018-10-01 22:46:12 +00:00
}
2017-08-13 01:36:33 +00:00
2018-10-01 22:46:12 +00:00
static void
pxy_bev_readcb_passthrough_src ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
{
2017-07-25 13:07:39 +00:00
# ifdef DEBUG_PROXY
2018-10-01 22:46:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_passthrough_src: ENTER, fd=%d, size=%zu \n " ,
ctx - > fd , evbuffer_get_length ( bufferevent_get_input ( bev ) ) ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-21 21:44:12 +00:00
2018-10-01 22:46:12 +00:00
// Passthrough packets are transfered between src and srv_dst
2018-10-05 13:55:02 +00:00
if ( ctx - > srv_dst . closed ) {
pxy_discard_inbuf ( bev ) ;
2017-07-25 13:07:39 +00:00
return ;
2017-07-21 21:44:12 +00:00
}
2017-07-05 19:32:10 +00:00
2018-10-01 22:46:12 +00:00
evbuffer_add_buffer ( bufferevent_get_output ( ctx - > srv_dst . bev ) , bufferevent_get_input ( bev ) ) ;
pxy_set_watermark ( bev , ctx , ctx - > srv_dst . bev ) ;
}
static void
pxy_bev_readcb_passthrough_srv_dst ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
{
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_passthrough_srv_dst: ENTER, fd=%d, size=%zu \n " ,
ctx - > fd , evbuffer_get_length ( bufferevent_get_input ( bev ) ) ) ;
# endif /* DEBUG_PROXY */
// Passthrough packets are transfered between src and srv_dst
2018-10-05 13:55:02 +00:00
if ( ctx - > src . closed ) {
pxy_discard_inbuf ( bev ) ;
2018-10-01 22:46:12 +00:00
return ;
2018-09-26 19:13:07 +00:00
}
2018-10-01 22:46:12 +00:00
evbuffer_add_buffer ( bufferevent_get_output ( ctx - > src . bev ) , bufferevent_get_input ( bev ) ) ;
pxy_set_watermark ( bev , ctx , ctx - > src . bev ) ;
}
static void
2018-10-05 13:55:02 +00:00
pxy_insert_sslproxy_header ( pxy_conn_ctx_t * ctx , unsigned char * packet , size_t * packet_size )
2018-10-01 22:46:12 +00:00
{
size_t header_len = strlen ( ctx - > header_str ) ;
// @attention Cannot use string manipulation functions; we are dealing with binary arrays here, not NULL-terminated strings
if ( ! ctx - > sent_header ) {
memmove ( packet + header_len + 2 , packet , * packet_size ) ;
memcpy ( packet , ctx - > header_str , header_len ) ;
memcpy ( packet + header_len , " \r \n " , 2 ) ;
* packet_size + = header_len + 2 ;
ctx - > sent_header = 1 ;
}
}
static void
pxy_bev_readcb_autossl_src ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
{
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_autossl_src: ENTER %s, fd=%d, size=%zu \n " ,
pxy_get_event_name ( bev , ctx ) , ctx - > fd , evbuffer_get_length ( bufferevent_get_input ( bev ) ) ) ;
# endif /* DEBUG_PROXY */
2018-10-05 01:55:24 +00:00
if ( ctx - > clienthello_search ) {
if ( pxy_conn_autossl_peek_and_upgrade ( ctx ) ) {
return ;
}
}
2018-10-05 13:55:02 +00:00
if ( ctx - > dst . closed ) {
pxy_discard_inbuf ( bev ) ;
2018-10-01 22:46:12 +00:00
return ;
2018-09-19 21:52:24 +00:00
}
2017-07-21 21:44:12 +00:00
2018-10-01 22:46:12 +00:00
struct evbuffer * inbuf = bufferevent_get_input ( bev ) ;
struct evbuffer * outbuf = bufferevent_get_output ( ctx - > dst . bev ) ;
2018-09-23 21:41:00 +00:00
size_t inbuf_size = evbuffer_get_length ( inbuf ) ;
2018-10-01 22:46:12 +00:00
ctx - > thr - > intif_in_bytes + = inbuf_size ;
2018-10-03 23:56:02 +00:00
if ( pxy_log_content_inbuf ( ctx , inbuf , 1 ) = = - 1 ) {
return ;
}
2018-10-01 22:46:12 +00:00
size_t header_len = strlen ( ctx - > header_str ) ;
size_t packet_size = inbuf_size ;
// +2 is for \r\n
unsigned char * packet = malloc ( packet_size + header_len + 2 ) ;
if ( ! packet ) {
// @todo Should we just set enomem?
ctx - > enomem = 1 ;
pxy_conn_free ( ctx , 1 ) ;
2017-07-21 21:44:12 +00:00
return ;
}
2017-05-29 09:22:23 +00:00
2018-10-01 22:46:12 +00:00
if ( evbuffer_remove ( inbuf , packet , packet_size ) = = - 1 ) {
log_err_printf ( " pxy_bev_readcb_autossl_src: evbuffer_remove failed, fd=%d \n " , ctx - > fd ) ;
}
2018-09-22 20:14:49 +00:00
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-01 22:46:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_autossl_src: ORIG packet (size=%zu), fd=%d: \n %.*s \n " ,
packet_size , ctx - > fd , ( int ) packet_size , packet ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2018-10-01 22:46:12 +00:00
if ( ctx - > clienthello_search ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-01 22:46:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_autossl_src: clienthello_search Duping packet to srv_dst (size=%zu), fd=%d: \n %.*s \n " ,
packet_size , ctx - > fd , ( int ) packet_size , packet ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2018-10-01 22:46:12 +00:00
// Dup packet to server while searching for clienthello in autossl mode, without adding SSLproxy specific header
if ( evbuffer_add ( bufferevent_get_output ( ctx - > srv_dst . bev ) , packet , packet_size ) = = - 1 ) {
log_err_printf ( " pxy_bev_readcb_autossl_src: clienthello_search srv_dst evbuffer_add failed, fd=%d \n " , ctx - > fd ) ;
}
}
2017-06-13 09:42:10 +00:00
2018-10-05 13:55:02 +00:00
pxy_insert_sslproxy_header ( ctx , packet , & packet_size ) ;
2018-10-01 22:46:12 +00:00
if ( evbuffer_add ( outbuf , packet , packet_size ) = = - 1 ) {
log_err_printf ( " pxy_bev_readcb_autossl_src: evbuffer_add failed, fd=%d \n " , ctx - > fd ) ;
}
2017-06-13 09:42:10 +00:00
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-01 22:46:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_autossl_src: NEW packet (size=%zu), fd=%d: \n %.*s \n " ,
packet_size , ctx - > fd , ( int ) packet_size , packet ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2018-10-01 22:46:12 +00:00
free ( packet ) ;
pxy_set_watermark ( bev , ctx , ctx - > dst . bev ) ;
}
static void
pxy_bev_readcb_autossl_dst ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
{
2018-09-26 19:13:07 +00:00
# ifdef DEBUG_PROXY
2018-10-01 22:46:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_autossl_dst: ENTER %s, fd=%d, size=%zu \n " ,
pxy_get_event_name ( bev , ctx ) , ctx - > fd , evbuffer_get_length ( bufferevent_get_input ( bev ) ) ) ;
2018-09-26 19:13:07 +00:00
# endif /* DEBUG_PROXY */
2018-10-05 01:55:24 +00:00
if ( ctx - > clienthello_search ) {
if ( pxy_conn_autossl_peek_and_upgrade ( ctx ) ) {
return ;
}
}
2018-10-05 13:55:02 +00:00
if ( ctx - > src . closed ) {
pxy_discard_inbuf ( bev ) ;
2018-10-01 22:46:12 +00:00
return ;
}
2017-07-18 19:07:29 +00:00
2018-10-01 22:46:12 +00:00
struct evbuffer * inbuf = bufferevent_get_input ( bev ) ;
struct evbuffer * outbuf = bufferevent_get_output ( ctx - > src . bev ) ;
size_t inbuf_size = evbuffer_get_length ( inbuf ) ;
ctx - > thr - > intif_out_bytes + = inbuf_size ;
2017-06-13 09:42:10 +00:00
2018-10-03 23:56:02 +00:00
if ( pxy_log_content_inbuf ( ctx , inbuf , 0 ) = = - 1 ) {
return ;
}
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-01 22:46:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_autossl_dst: dst packet size=%zu, fd=%d \n " , inbuf_size , ctx - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2018-10-01 22:46:12 +00:00
evbuffer_add_buffer ( outbuf , inbuf ) ;
pxy_set_watermark ( bev , ctx , ctx - > src . bev ) ;
}
static void
pxy_bev_readcb_autossl_srv_dst ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
{
2018-10-05 01:55:24 +00:00
if ( ctx - > clienthello_search ) {
if ( pxy_conn_autossl_peek_and_upgrade ( ctx ) ) {
return ;
}
}
2018-10-01 22:46:12 +00:00
struct evbuffer * inbuf = bufferevent_get_input ( bev ) ;
size_t inbuf_size = evbuffer_get_length ( inbuf ) ;
// 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
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_autossl_srv_dst: clienthello_search Discarding packet, size=%zu, fd=%d \n " ,
inbuf_size , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
if ( evbuffer_drain ( inbuf , inbuf_size ) = = - 1 ) {
log_err_printf ( " pxy_bev_readcb_autossl_srv_dst: clienthello_search evbuffer_drain failed, fd=%d \n " , ctx - > fd ) ;
}
return ;
}
static void
pxy_bev_readcb_http_src ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
{
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-01 22:46:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_http_src: ENTER %s, fd=%d, size=%zu \n " ,
pxy_get_event_name ( bev , ctx ) , ctx - > fd , evbuffer_get_length ( bufferevent_get_input ( bev ) ) ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2018-10-01 22:46:12 +00:00
2018-10-05 13:55:02 +00:00
if ( ctx - > dst . closed ) {
pxy_discard_inbuf ( bev ) ;
2018-10-01 22:46:12 +00:00
return ;
}
struct evbuffer * inbuf = bufferevent_get_input ( bev ) ;
struct evbuffer * outbuf = bufferevent_get_output ( ctx - > dst . bev ) ;
size_t inbuf_size = evbuffer_get_length ( inbuf ) ;
ctx - > thr - > intif_in_bytes + = inbuf_size ;
2018-10-03 23:56:02 +00:00
// Content logging at this point may record certain headers twice
if ( pxy_log_content_inbuf ( ctx , inbuf , 1 ) = = - 1 ) {
return ;
}
int seen_req_header_on_entry = ctx - > seen_req_header ;
2018-10-01 22:46:12 +00:00
// We insert our special header line to the first packet we get, e.g. right after the first \r\n in the case of http
// @todo Should we look for GET/POST or Host header lines to detect the first packet?
// But there is no guarantee that they will exist, due to fragmentation.
// @attention We cannot append the ssl proxy address at the end of the packet or in between the header and the content,
// because (1) the packet may be just the first fragment split somewhere not appropriate for appending a header,
// and (2) there may not be any content.
// And we are dealing pop3 and smtp also, not just http.
/* request header munging */
if ( ! ctx - > seen_req_header ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-01 22:46:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_http_src: HTTP Request Header size=%zu, fd=%d \n " , inbuf_size , ctx - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2018-10-05 13:55:02 +00:00
pxy_http_filter_request_header ( inbuf , outbuf , ctx ) ;
2018-10-01 22:46:12 +00:00
} else {
2018-09-23 21:41:00 +00:00
# ifdef DEBUG_PROXY
2018-10-01 22:46:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_http_src: HTTP Request Body size=%zu, fd=%d \n " , inbuf_size , ctx - > fd ) ;
2018-09-23 21:41:00 +00:00
# endif /* DEBUG_PROXY */
2018-10-01 22:46:12 +00:00
evbuffer_add_buffer ( outbuf , inbuf ) ;
}
pxy_set_watermark ( bev , ctx , ctx - > dst . bev ) ;
2018-10-03 23:56:02 +00:00
if ( ! seen_req_header_on_entry & & ctx - > seen_req_header & & ctx - > ocsp_denied ) {
pxy_log_content_buf ( ctx , ( unsigned char * ) ocspresp , sizeof ( ocspresp ) - 1 , 0 /*resp*/ ) ;
}
2018-10-01 22:46:12 +00:00
}
static void
pxy_bev_readcb_http_dst ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
{
2018-09-26 19:13:07 +00:00
# ifdef DEBUG_PROXY
2018-10-01 22:46:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_http_dst: ENTER %s, fd=%d, size=%zu \n " ,
pxy_get_event_name ( bev , ctx ) , ctx - > fd , evbuffer_get_length ( bufferevent_get_input ( bev ) ) ) ;
2018-09-26 19:13:07 +00:00
# endif /* DEBUG_PROXY */
2018-10-01 22:46:12 +00:00
2018-10-05 13:55:02 +00:00
if ( ctx - > src . closed ) {
pxy_discard_inbuf ( bev ) ;
2018-09-26 19:13:07 +00:00
return ;
2017-07-22 22:15:59 +00:00
}
2018-10-01 22:46:12 +00:00
struct evbuffer * inbuf = bufferevent_get_input ( bev ) ;
struct evbuffer * outbuf = bufferevent_get_output ( ctx - > src . bev ) ;
size_t inbuf_size = evbuffer_get_length ( inbuf ) ;
ctx - > thr - > intif_out_bytes + = inbuf_size ;
2018-10-03 23:56:02 +00:00
// Content logging at this point may record certain headers twice
if ( pxy_log_content_inbuf ( ctx , inbuf , 1 ) = = - 1 ) {
return ;
}
int seen_resp_header_on_entry = ctx - > seen_resp_header ;
2018-10-01 22:46:12 +00:00
if ( ! ctx - > seen_resp_header ) {
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_http_dst: HTTP Response Header size=%zu, fd=%d \n " , inbuf_size , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
2018-10-05 13:55:02 +00:00
pxy_http_filter_response_header ( inbuf , outbuf , ctx ) ;
2018-10-01 22:46:12 +00:00
} else {
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_http_dst: HTTP Response Body size=%zu, fd=%d \n " , inbuf_size , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
evbuffer_add_buffer ( outbuf , inbuf ) ;
}
pxy_set_watermark ( bev , ctx , ctx - > src . bev ) ;
2018-10-03 23:56:02 +00:00
if ( ! seen_resp_header_on_entry & & ctx - > seen_resp_header ) {
/* response header complete: log connection */
if ( WANT_CONNECT_LOG ( ctx - > conn ) | | ctx - > opts - > statslog ) {
pxy_log_connect_http ( ctx ) ;
}
}
2018-10-01 22:46:12 +00:00
}
static void
pxy_bev_readcb_http_srv_dst ( UNUSED struct bufferevent * bev , UNUSED pxy_conn_ctx_t * ctx )
{
log_err_printf ( " pxy_bev_readcb_http_srv_dst: readcb called on srv_dst \n " ) ;
}
static void
2018-10-05 13:55:02 +00:00
pxy_bev_readcb_src ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-10-01 22:46:12 +00:00
{
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_src: ENTER %s, fd=%d, size=%zu \n " ,
2018-10-01 22:46:12 +00:00
pxy_get_event_name ( bev , ctx ) , ctx - > fd , evbuffer_get_length ( bufferevent_get_input ( bev ) ) ) ;
# endif /* DEBUG_PROXY */
2018-10-05 13:55:02 +00:00
if ( ctx - > dst . closed ) {
pxy_discard_inbuf ( bev ) ;
2018-10-01 22:46:12 +00:00
return ;
}
struct evbuffer * inbuf = bufferevent_get_input ( bev ) ;
struct evbuffer * outbuf = bufferevent_get_output ( ctx - > dst . bev ) ;
size_t inbuf_size = evbuffer_get_length ( inbuf ) ;
ctx - > thr - > intif_in_bytes + = inbuf_size ;
2018-10-03 23:56:02 +00:00
if ( pxy_log_content_inbuf ( ctx , inbuf , 1 ) = = - 1 ) {
return ;
}
2018-10-01 22:46:12 +00:00
size_t header_len = strlen ( ctx - > header_str ) ;
size_t packet_size = inbuf_size ;
// +2 is for \r\n
unsigned char * packet = malloc ( packet_size + header_len + 2 ) ;
if ( ! packet ) {
// @todo Should we just set enomem?
2018-09-23 21:41:00 +00:00
ctx - > enomem = 1 ;
2018-10-01 22:46:12 +00:00
pxy_conn_free ( ctx , 1 ) ;
return ;
2015-04-18 12:26:03 +00:00
}
2018-09-23 21:41:00 +00:00
2018-10-01 22:46:12 +00:00
if ( evbuffer_remove ( inbuf , packet , packet_size ) = = - 1 ) {
2018-10-05 13:55:02 +00:00
log_err_printf ( " pxy_bev_readcb_src: evbuffer_remove failed, fd=%d \n " , ctx - > fd ) ;
2018-10-01 22:46:12 +00:00
}
2015-04-18 12:26:03 +00:00
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_src: ORIG packet (size=%zu), fd=%d: \n %.*s \n " ,
2018-10-01 22:46:12 +00:00
packet_size , ctx - > fd , ( int ) packet_size , packet ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2018-10-01 22:46:12 +00:00
2018-10-05 13:55:02 +00:00
pxy_insert_sslproxy_header ( ctx , packet , & packet_size ) ;
2018-10-01 22:46:12 +00:00
if ( evbuffer_add ( outbuf , packet , packet_size ) = = - 1 ) {
2018-10-05 13:55:02 +00:00
log_err_printf ( " pxy_bev_readcb_src: evbuffer_add failed, fd=%d \n " , ctx - > fd ) ;
2018-10-01 22:46:12 +00:00
}
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_src: NEW packet (size=%zu), fd=%d: \n %.*s \n " ,
2018-10-01 22:46:12 +00:00
packet_size , ctx - > fd , ( int ) packet_size , packet ) ;
# endif /* DEBUG_PROXY */
free ( packet ) ;
pxy_set_watermark ( bev , ctx , ctx - > dst . bev ) ;
}
static void
2018-10-05 13:55:02 +00:00
pxy_bev_readcb_dst ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-10-01 22:46:12 +00:00
{
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_dst: ENTER %s, fd=%d, size=%zu \n " ,
2018-10-01 22:46:12 +00:00
pxy_get_event_name ( bev , ctx ) , ctx - > fd , evbuffer_get_length ( bufferevent_get_input ( bev ) ) ) ;
# endif /* DEBUG_PROXY */
2018-10-05 13:55:02 +00:00
if ( ctx - > src . closed ) {
pxy_discard_inbuf ( bev ) ;
2018-10-01 22:46:12 +00:00
return ;
}
struct evbuffer * inbuf = bufferevent_get_input ( bev ) ;
struct evbuffer * outbuf = bufferevent_get_output ( ctx - > src . bev ) ;
size_t inbuf_size = evbuffer_get_length ( inbuf ) ;
ctx - > thr - > intif_out_bytes + = inbuf_size ;
2018-10-03 23:56:02 +00:00
if ( pxy_log_content_inbuf ( ctx , inbuf , 0 ) = = - 1 ) {
return ;
}
2018-10-01 22:46:12 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_dst: packet size=%zu, fd=%d \n " , inbuf_size , ctx - > fd ) ;
2018-10-01 22:46:12 +00:00
# endif /* DEBUG_PROXY */
evbuffer_add_buffer ( outbuf , inbuf ) ;
pxy_set_watermark ( bev , ctx , ctx - > src . bev ) ;
}
static void
2018-10-05 13:55:02 +00:00
pxy_bev_readcb_srv_dst ( UNUSED struct bufferevent * bev , UNUSED pxy_conn_ctx_t * ctx )
2018-10-01 22:46:12 +00:00
{
2018-10-05 13:55:02 +00:00
log_err_printf ( " pxy_bev_readcb_srv_dst: readcb called on srv_dst \n " ) ;
2018-10-01 22:46:12 +00:00
}
2018-10-05 01:55:24 +00:00
enum conn_end {
SRC = 0 ,
DST = 1 ,
SRV_DST = 2 ,
UNKWN_CONN_END = 3 ,
} ;
static enum conn_end
get_conn_end ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-10-01 22:46:12 +00:00
{
if ( bev = = ctx - > src . bev ) {
2018-10-05 01:55:24 +00:00
return SRC ;
2018-10-01 22:46:12 +00:00
} else if ( bev = = ctx - > dst . bev ) {
2018-10-05 01:55:24 +00:00
return DST ;
2018-10-01 22:46:12 +00:00
} else if ( bev = = ctx - > srv_dst . bev ) {
2018-10-05 01:55:24 +00:00
return SRV_DST ;
2018-10-01 22:46:12 +00:00
} else {
2018-10-05 01:55:24 +00:00
log_err_printf ( " get_conn_end: unknown bev \n " ) ;
return UNKWN_CONN_END ;
2018-10-01 22:46:12 +00:00
}
}
/*
* Callback for read events on the up - and downstream connection bufferevents .
* Called when there is data ready in the input evbuffer .
*/
static void
pxy_bev_readcb ( struct bufferevent * bev , void * arg )
{
pxy_conn_ctx_t * ctx = arg ;
ctx - > atime = time ( NULL ) ;
if ( ! ctx - > connected ) {
log_err_level_printf ( LOG_CRIT , " pxy_bev_readcb: readcb called when other end not connected - aborting. \n " ) ;
log_exceptcb ( ) ;
return ;
}
2018-10-05 01:55:24 +00:00
enum conn_end ce = get_conn_end ( bev , ctx ) ;
if ( ce ! = UNKWN_CONN_END ) {
callback_func_t readcb = readcb_funcs [ ctx - > proto ] [ ce ] ;
if ( readcb ) {
readcb ( bev , ctx ) ;
} else {
log_err_printf ( " pxy_bev_readcb: NULL readcb on %d \n " , ce ) ;
}
2018-10-01 22:46:12 +00:00
} else {
2018-10-05 01:55:24 +00:00
log_err_printf ( " pxy_bev_readcb: UNKWN conn end \n " ) ;
2017-07-21 21:44:12 +00:00
}
2017-05-29 09:22:23 +00:00
}
static void
2017-07-07 14:18:01 +00:00
pxy_bev_readcb_child ( struct bufferevent * bev , void * arg )
2017-05-29 09:22:23 +00:00
{
2017-07-11 22:45:15 +00:00
pxy_conn_child_ctx_t * ctx = arg ;
2017-07-21 21:44:12 +00:00
2018-09-22 23:02:15 +00:00
ctx - > conn - > atime = time ( NULL ) ;
2017-07-20 14:55:00 +00:00
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
char * event_name = pxy_get_event_name_child ( bev , ctx ) ;
2018-09-24 00:09:05 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_child: ENTER %s fd=%d, conn fd=%d, size=%zu \n " ,
2018-09-23 21:41:00 +00:00
event_name , ctx - > fd , ctx - > conn - > fd , evbuffer_get_length ( bufferevent_get_input ( bev ) ) ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-08-01 11:57:49 +00:00
2017-07-21 21:44:12 +00:00
if ( ! ctx - > connected ) {
2018-09-23 21:41:00 +00:00
log_err_level_printf ( LOG_CRIT , " pxy_bev_readcb_child: readcb called when other end not connected - aborting. \n " ) ;
2017-07-25 13:07:39 +00:00
log_exceptcb ( ) ;
return ;
2017-07-21 21:44:12 +00:00
}
2017-07-05 19:32:10 +00:00
2018-09-26 19:13:07 +00:00
// Autossl upgrade on child connections follows the findings of parent
if ( ctx - > conn - > clienthello_found & & ! ctx - > dst . ssl ) {
if ( OPTS_DEBUG ( ctx - > conn - > opts ) ) {
log_dbg_printf ( " Completing autossl upgrade on child conn \n " ) ;
}
ctx - > dst . ssl = pxy_dstssl_create ( ctx - > conn ) ;
if ( ! ctx - > dst . ssl ) {
log_err_level_printf ( LOG_CRIT , " pxy_bev_readcb_child: Error creating SSL for upgrade \n " ) ;
ctx - > enomem = 1 ;
pxy_conn_free ( ctx - > conn , 1 ) ;
return ;
}
ctx - > dst . bev = bufferevent_openssl_filter_new ( ctx - > conn - > evbase , ctx - > dst . bev , ctx - > dst . ssl ,
BUFFEREVENT_SSL_CONNECTING , BEV_OPT_DEFER_CALLBACKS ) ;
if ( ! ctx - > dst . bev ) {
2018-09-26 20:45:52 +00:00
log_err_level_printf ( LOG_CRIT , " pxy_bev_readcb_child: Error creating bufferevent \n " ) ;
2018-09-26 19:13:07 +00:00
ctx - > enomem = 1 ;
2018-09-26 20:45:52 +00:00
if ( ctx - > dst . ssl ) {
SSL_free ( ctx - > dst . ssl ) ;
ctx - > dst . ssl = NULL ;
}
2018-09-26 19:13:07 +00:00
pxy_conn_free ( ctx - > conn , 1 ) ;
return ;
}
2018-09-26 20:45:52 +00:00
bufferevent_setcb ( ctx - > dst . bev , pxy_bev_readcb_child , pxy_bev_writecb_child , pxy_bev_eventcb_child , ctx ) ;
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_child: Enabling dst, fd=%d \n " , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
2018-09-26 19:13:07 +00:00
bufferevent_enable ( ctx - > dst . bev , EV_READ | EV_WRITE ) ;
if ( OPTS_DEBUG ( ctx - > conn - > opts ) ) {
log_err_level_printf ( LOG_INFO , " pxy_bev_readcb_child: Replaced dst bufferevent, new one is %p \n " , ( void * ) ctx - > dst . bev ) ;
}
return ;
}
2017-07-21 21:44:12 +00:00
struct evbuffer * inbuf = bufferevent_get_input ( bev ) ;
2018-09-23 21:41:00 +00:00
pxy_conn_desc_t * other = ( bev = = ctx - > src . bev ) ? & ctx - > dst : & ctx - > src ;
2017-07-21 21:44:12 +00:00
struct evbuffer * outbuf = bufferevent_get_output ( other - > bev ) ;
2017-07-20 14:55:00 +00:00
2018-09-23 21:41:00 +00:00
size_t inbuf_size = evbuffer_get_length ( inbuf ) ;
2017-07-21 21:44:12 +00:00
if ( other - > closed ) {
2018-09-23 21:41:00 +00:00
log_dbg_printf ( " Warning: Drained %zu bytes (conn closed) \n " , inbuf_size ) ;
evbuffer_drain ( inbuf , inbuf_size ) ;
2017-07-21 21:44:12 +00:00
return ;
}
2017-07-18 19:07:29 +00:00
2017-07-21 21:44:12 +00:00
if ( bev = = ctx - > src . bev ) {
2018-09-23 21:41:00 +00:00
ctx - > conn - > thr - > extif_out_bytes + = inbuf_size ;
2017-07-29 21:34:46 +00:00
2017-07-21 21:44:12 +00:00
/* request header munging */
2018-09-22 23:02:15 +00:00
if ( ctx - > conn - > spec - > http ) {
2017-07-21 21:44:12 +00:00
if ( ! ctx - > seen_req_header ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-09-23 21:41:00 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_child: HTTP Request Header size=%zu, fd=%d \n " , inbuf_size , ctx - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2018-10-05 13:55:02 +00:00
pxy_http_filter_request_header ( inbuf , outbuf , ( pxy_conn_ctx_t * ) ctx ) ;
2018-09-23 21:41:00 +00:00
// Transfered packet to outbuf and logged content, just check watermark
goto watermark ;
2017-07-21 21:44:12 +00:00
} else {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-09-23 21:41:00 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_child: HTTP Request Body size=%zu, fd=%d \n " , inbuf_size , ctx - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-21 21:44:12 +00:00
}
} else {
2018-09-23 21:41:00 +00:00
size_t packet_size = inbuf_size ;
unsigned char * packet = malloc ( packet_size ) ;
2017-07-21 21:44:12 +00:00
if ( ! packet ) {
ctx - > enomem = 1 ;
2018-09-22 23:02:15 +00:00
pxy_conn_free ( ctx - > conn , 1 ) ;
2017-07-21 21:44:12 +00:00
return ;
}
2017-06-15 09:00:53 +00:00
2018-09-23 21:41:00 +00:00
if ( evbuffer_remove ( inbuf , packet , packet_size ) = = - 1 ) {
log_err_printf ( " pxy_bev_readcb_child: src evbuffer_remove failed, fd=%d \n " , ctx - > fd ) ;
2017-07-23 13:44:32 +00:00
}
2017-06-13 09:42:10 +00:00
2018-09-22 23:02:15 +00:00
size_t header_len = strlen ( ctx - > conn - > header_str ) ;
2018-09-23 21:41:00 +00:00
unsigned char * pos = memmem ( packet , packet_size , ctx - > conn - > header_str , header_len ) ;
2017-08-03 11:55:57 +00:00
if ( pos ) {
2017-08-11 12:01:51 +00:00
memmove ( pos , pos + header_len + 2 , packet_size - ( pos - packet ) - ( header_len + 2 ) ) ;
packet_size - = header_len + 2 ;
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-09-23 21:41:00 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " pxy_bev_readcb_child: REMOVED SSLproxy header, fd=%d \n " , ctx - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-08-03 11:55:57 +00:00
}
2018-09-23 21:41:00 +00:00
if ( evbuffer_add ( outbuf , packet , packet_size ) = = - 1 ) {
log_err_printf ( " pxy_bev_readcb_child: src evbuffer_add failed, fd=%d \n " , ctx - > fd ) ;
2017-07-23 13:44:32 +00:00
}
2017-07-18 19:07:29 +00:00
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-09-23 21:41:00 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_child: src packet (size=%zu), fd=%d, conn fd=%d: \n %.*s \n " ,
packet_size , ctx - > fd , ctx - > conn - > fd , ( int ) packet_size , packet ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-05 19:32:10 +00:00
2018-10-01 22:46:12 +00:00
pxy_log_content_buf ( ( pxy_conn_ctx_t * ) ctx , packet , packet_size , 1 ) ;
2017-07-21 21:44:12 +00:00
free ( packet ) ;
2018-10-01 22:46:12 +00:00
2018-09-23 21:41:00 +00:00
goto watermark ;
2017-07-21 21:44:12 +00:00
}
2018-09-23 21:41:00 +00:00
} else if ( bev = = ctx - > dst . bev ) {
ctx - > conn - > thr - > extif_in_bytes + = inbuf_size ;
2017-07-29 21:34:46 +00:00
2018-09-22 23:02:15 +00:00
if ( ctx - > conn - > spec - > http ) {
2017-07-21 21:44:12 +00:00
if ( ! ctx - > seen_resp_header ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-09-23 21:41:00 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_child: HTTP Response Header size=%zu, fd=%d \n " , inbuf_size , ctx - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2018-10-05 13:55:02 +00:00
pxy_http_filter_response_header ( inbuf , outbuf , ( pxy_conn_ctx_t * ) ctx ) ;
2018-09-23 21:41:00 +00:00
// Transfered packet to outbuf and logged content, just check watermark
goto watermark ;
2017-07-21 21:44:12 +00:00
} else {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-09-23 21:41:00 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_child: HTTP Response Body size=%zu, fd=%d \n " , inbuf_size , ctx - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-05 19:32:10 +00:00
}
2017-05-29 09:22:23 +00:00
} else {
2018-09-23 21:41:00 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_readcb_child: dst packet size=%zu, fd=%d \n " , inbuf_size , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
2012-04-13 12:47:30 +00:00
}
}
2018-10-01 22:46:12 +00:00
pxy_log_content_inbuf ( ( pxy_conn_ctx_t * ) ctx , inbuf , ( bev = = ctx - > src . bev ) ) ;
2018-09-23 21:41:00 +00:00
2017-07-22 22:15:59 +00:00
evbuffer_add_buffer ( outbuf , inbuf ) ;
2018-10-01 22:46:12 +00:00
watermark :
if ( evbuffer_get_length ( outbuf ) > = OUTBUF_LIMIT ) {
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " pxy_bev_readcb_child: setwatermark, conn fd=%d \n " , ctx - > conn - > fd ) ;
# endif /* DEBUG_PROXY */
/* temporarily disable data source;
* set an appropriate watermark . */
bufferevent_setwatermark ( other - > bev , EV_WRITE , OUTBUF_LIMIT / 2 , OUTBUF_LIMIT ) ;
bufferevent_disable ( bev , EV_READ ) ;
ctx - > conn - > thr - > set_watermarks + + ;
}
}
static void
pxy_unset_watermark ( struct bufferevent * bev , pxy_conn_ctx_t * ctx , pxy_conn_desc_t * other )
{
if ( other - > bev & & ! ( bufferevent_get_enabled ( other - > bev ) & EV_READ ) ) {
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " pxy_unset_watermark: %s, fd=%d \n " , pxy_get_event_name ( bev , ctx ) , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
/* data source temporarily disabled;
* re - enable and reset watermark to 0. */
bufferevent_setwatermark ( bev , EV_WRITE , 0 , 0 ) ;
bufferevent_enable ( other - > bev , EV_READ ) ;
ctx - > thr - > unset_watermarks + + ;
}
}
static void
2018-10-05 13:55:02 +00:00
pxy_connect_dst ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-10-01 22:46:12 +00:00
{
if ( ! ctx - > dst_connected ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " pxy_connect_dst: writecb before connected, fd=%d \n " , ctx - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2018-10-01 22:46:12 +00:00
// @attention Sometimes dst write cb fires but not event cb, especially if the listener cb is not finished yet, so the conn stalls.
// This is a workaround for this error condition, nothing else seems to work.
// @attention Do not try to free the conn here, since the listener cb may not be finished yet, which causes multithreading issues
// XXX: Workaround, should find the real cause: BEV_OPT_DEFER_CALLBACKS?
pxy_bev_eventcb ( bev , BEV_EVENT_CONNECTED , ctx ) ;
2017-07-21 21:44:12 +00:00
}
2017-07-07 14:18:01 +00:00
}
2018-10-01 22:46:12 +00:00
static void
2018-10-05 13:55:02 +00:00
pxy_connect_srv_dst ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-09-24 00:09:05 +00:00
{
2018-10-01 22:46:12 +00:00
if ( ! ctx - > srv_dst_connected ) {
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " pxy_connect_srv_dst: writecb before connected, fd=%d \n " , ctx - > fd ) ;
2018-10-01 22:46:12 +00:00
# endif /* DEBUG_PROXY */
// @attention Sometimes dst write cb fires but not event cb, especially if the listener cb is not finished yet, so the conn stalls.
// This is a workaround for this error condition, nothing else seems to work.
// @attention Do not try to free the conn here, since the listener cb may not be finished yet, which causes multithreading issues
// XXX: Workaround, should find the real cause: BEV_OPT_DEFER_CALLBACKS?
pxy_bev_eventcb ( bev , BEV_EVENT_CONNECTED , ctx ) ;
}
}
2018-09-24 00:09:05 +00:00
2018-10-01 22:46:12 +00:00
static int
pxy_close_conn_end_ifnodata ( pxy_conn_desc_t * conn_end , pxy_conn_ctx_t * ctx , void ( * free_and_close_fd_func ) ( struct bufferevent * , pxy_conn_ctx_t * ) )
{
/* if the other end is still open and doesn't have data
* to send , close it , otherwise its writecb will close
* it after writing what ' s left in the output buffer */
if ( evbuffer_get_length ( bufferevent_get_output ( conn_end - > bev ) ) = = 0 ) {
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_close_conn_end_ifnodata: evbuffer_get_length(outbuf) == 0, terminate conn, fd=%d \n " , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
free_and_close_fd_func ( conn_end - > bev , ctx ) ;
conn_end - > bev = NULL ;
conn_end - > closed = 1 ;
return 1 ;
2018-09-24 00:09:05 +00:00
}
2018-10-01 22:46:12 +00:00
return 0 ;
2018-09-24 00:09:05 +00:00
}
2017-07-14 19:34:15 +00:00
static void
2018-10-01 22:46:12 +00:00
pxy_bev_writecb_passthrough_src ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2017-07-14 19:34:15 +00:00
{
2018-10-01 22:46:12 +00:00
// @attention srv_dst.bev may be NULL
2018-09-24 00:09:05 +00:00
# ifdef DEBUG_PROXY
2018-10-01 22:46:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_writecb_passthrough_src: ENTER, fd=%d \n " , ctx - > fd ) ;
2018-09-24 00:09:05 +00:00
# endif /* DEBUG_PROXY */
2018-10-01 22:46:12 +00:00
if ( ctx - > srv_dst . closed ) {
if ( pxy_close_conn_end_ifnodata ( & ctx - > src , ctx , & bufferevent_free_and_close_fd_nonssl ) ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-01 22:46:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_writecb_passthrough_src: other->closed, terminate conn, fd=%d \n " , ctx - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2018-10-01 22:46:12 +00:00
pxy_conn_free ( ctx , 1 ) ;
}
2018-09-24 00:09:05 +00:00
return ;
}
2018-10-01 22:46:12 +00:00
pxy_unset_watermark ( bev , ctx , & ctx - > srv_dst ) ;
}
2018-09-24 00:09:05 +00:00
2018-10-01 22:46:12 +00:00
static void
pxy_bev_writecb_passthrough_srv_dst ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
{
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_writecb_passthrough_srv_dst: ENTER, fd=%d \n " , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
2018-09-24 00:09:05 +00:00
2018-10-05 13:55:02 +00:00
pxy_connect_srv_dst ( bev , ctx ) ;
2017-07-14 19:34:15 +00:00
2018-10-01 22:46:12 +00:00
if ( ctx - > src . closed ) {
if ( pxy_close_conn_end_ifnodata ( & ctx - > srv_dst , ctx , & bufferevent_free_and_close_fd_nonssl ) = = 1 ) {
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_writecb_passthrough_srv_dst: other->closed, terminate conn, fd=%d \n " , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
pxy_conn_free ( ctx , 0 ) ;
}
2017-07-14 19:34:15 +00:00
return ;
}
2018-10-01 22:46:12 +00:00
pxy_unset_watermark ( bev , ctx , & ctx - > src ) ;
}
2017-07-14 19:34:15 +00:00
2018-10-01 22:46:12 +00:00
static void
2018-10-05 13:55:02 +00:00
pxy_bev_writecb_src ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-10-01 22:46:12 +00:00
{
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_writecb: ENTER, fd=%d \n " , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
2018-09-26 19:13:07 +00:00
2018-10-01 22:46:12 +00:00
if ( ctx - > dst . closed ) {
if ( pxy_close_conn_end_ifnodata ( & ctx - > src , ctx , & bufferevent_free_and_close_fd ) = = 1 ) {
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_writecb_src: other->closed, terminate conn, fd=%d \n " , ctx - > fd ) ;
2018-10-01 22:46:12 +00:00
# endif /* DEBUG_PROXY */
pxy_conn_free ( ctx , 1 ) ;
}
2017-07-14 19:34:15 +00:00
return ;
}
2018-10-01 22:46:12 +00:00
pxy_unset_watermark ( bev , ctx , & ctx - > dst ) ;
2017-07-14 19:34:15 +00:00
}
static void
2018-10-05 13:55:02 +00:00
pxy_bev_writecb_dst ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2017-07-14 19:34:15 +00:00
{
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_writecb_dst: ENTER, fd=%d \n " , ctx - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-14 19:34:15 +00:00
2018-10-05 13:55:02 +00:00
pxy_connect_dst ( bev , ctx ) ;
2018-07-05 22:09:37 +00:00
2018-10-01 22:46:12 +00:00
if ( ctx - > src . closed ) {
if ( pxy_close_conn_end_ifnodata ( & ctx - > dst , ctx , & bufferevent_free_and_close_fd_nonssl ) = = 1 ) {
2018-09-24 00:09:05 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_writecb_dst: other->closed, terminate conn, fd=%d \n " , ctx - > fd ) ;
2018-09-24 00:09:05 +00:00
# endif /* DEBUG_PROXY */
2018-10-01 22:46:12 +00:00
pxy_conn_free ( ctx , 0 ) ;
}
2017-07-14 19:34:15 +00:00
return ;
}
2018-10-01 22:46:12 +00:00
pxy_unset_watermark ( bev , ctx , & ctx - > src ) ;
}
static void
2018-10-05 13:55:02 +00:00
pxy_bev_writecb_srv_dst ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-10-01 22:46:12 +00:00
{
2018-09-24 00:09:05 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_writecb_srv_dst: ENTER, fd=%d \n " , ctx - > fd ) ;
2018-09-24 00:09:05 +00:00
# endif /* DEBUG_PROXY */
2018-10-05 13:55:02 +00:00
pxy_connect_srv_dst ( bev , ctx ) ;
2018-10-01 22:46:12 +00:00
}
2018-09-24 00:09:05 +00:00
2018-10-01 22:46:12 +00:00
/*
* Callback for write events on the up - and downstream connection bufferevents .
* Called when either all data from the output evbuffer has been written ,
* or if the outbuf is only half full again after having been full .
*/
static void
pxy_bev_writecb ( struct bufferevent * bev , void * arg )
{
pxy_conn_ctx_t * ctx = arg ;
ctx - > atime = time ( NULL ) ;
2017-07-14 19:34:15 +00:00
2018-10-05 01:55:24 +00:00
enum conn_end ce = get_conn_end ( bev , ctx ) ;
if ( ce ! = UNKWN_CONN_END ) {
callback_func_t writecb = writecb_funcs [ ctx - > proto ] [ ce ] ;
if ( writecb ) {
writecb ( bev , ctx ) ;
} else {
log_err_printf ( " pxy_bev_writecb: NULL writecb on %d \n " , ce ) ;
}
2018-10-01 22:46:12 +00:00
} else {
2018-10-05 01:55:24 +00:00
log_err_printf ( " pxy_bev_writecb: UNKWN conn end \n " ) ;
2018-09-24 00:09:05 +00:00
}
2017-07-14 19:34:15 +00:00
}
2017-07-07 14:18:01 +00:00
static void
2018-09-24 00:09:05 +00:00
pxy_bev_writecb_child ( struct bufferevent * bev , void * arg )
2017-07-07 14:18:01 +00:00
{
2018-09-24 00:09:05 +00:00
pxy_conn_child_ctx_t * ctx = arg ;
2017-07-11 22:45:15 +00:00
2018-09-24 00:09:05 +00:00
# ifdef DEBUG_PROXY
char * event_name = pxy_get_event_name_child ( bev , ctx ) ;
2018-09-25 09:24:23 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_writecb_child: ENTER %s, fd=%d, conn fd=%d \n " , event_name , ctx - > fd , ctx - > conn - > fd ) ;
2018-09-24 00:09:05 +00:00
# endif /* DEBUG_PROXY */
ctx - > conn - > atime = time ( NULL ) ;
2017-07-07 14:18:01 +00:00
2018-09-24 00:09:05 +00:00
if ( bev = = ctx - > dst . bev & & ! ctx - > connected ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-09-25 09:24:23 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " pxy_bev_writecb_child: writecb before connected %s, fd=%d, conn fd=%d \n " , event_name , ctx - > fd , ctx - > conn - > fd ) ;
2018-09-24 00:09:05 +00:00
# endif /* DEBUG_PROXY */
pxy_bev_eventcb_child ( bev , BEV_EVENT_CONNECTED , ctx ) ;
}
2018-09-25 09:24:23 +00:00
pxy_conn_desc_t * this = ( bev = = ctx - > src . bev ) ? & ctx - > src : & ctx - > dst ;
void ( * this_free_and_close_fd_func ) ( struct bufferevent * , pxy_conn_ctx_t * ) = ( bev = = ctx - > src . bev ) ? & bufferevent_free_and_close_fd_nonssl : & bufferevent_free_and_close_fd ;
pxy_conn_desc_t * other = ( bev = = ctx - > src . bev ) ? & ctx - > dst : & ctx - > src ;
2017-07-07 14:18:01 +00:00
2018-09-24 00:09:05 +00:00
if ( other - > closed ) {
struct evbuffer * outbuf = bufferevent_get_output ( bev ) ;
if ( evbuffer_get_length ( outbuf ) = = 0 ) {
# ifdef DEBUG_PROXY
2018-09-25 09:24:23 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_writecb_child: other->closed, terminate conn %s, fd=%d, conn fd=%d \n " , event_name , ctx - > fd , ctx - > conn - > fd ) ;
2018-09-24 00:09:05 +00:00
# endif /* DEBUG_PROXY */
/* finished writing and other end is closed;
* close this end too and clean up memory */
this - > closed = 1 ;
this_free_and_close_fd_func ( bev , ctx - > conn ) ;
this - > bev = NULL ;
pxy_conn_free_child ( ctx ) ;
}
return ;
2017-07-07 14:18:01 +00:00
}
2018-09-24 00:09:05 +00:00
if ( other - > bev & & ! ( bufferevent_get_enabled ( other - > bev ) & EV_READ ) ) {
# ifdef DEBUG_PROXY
2018-09-25 09:24:23 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " pxy_bev_writecb_child: unset watermark %s, fd=%d, conn fd=%d \n " , event_name , ctx - > fd , ctx - > conn - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2018-09-24 00:09:05 +00:00
/* data source temporarily disabled;
* re - enable and reset watermark to 0. */
bufferevent_setwatermark ( bev , EV_WRITE , 0 , 0 ) ;
bufferevent_enable ( other - > bev , EV_READ ) ;
ctx - > conn - > thr - > unset_watermarks + + ;
}
2017-05-29 09:22:23 +00:00
}
static int
2018-10-03 23:56:02 +00:00
pxy_prepare_logging_local_procinfo ( UNUSED pxy_conn_ctx_t * ctx )
2018-09-29 20:47:18 +00:00
{
# ifdef HAVE_LOCAL_PROCINFO
2018-10-03 23:56:02 +00:00
if ( ctx - > opts - > lprocinfo ) {
/* fetch process info */
if ( proc_pid_for_addr ( & ctx - > lproc . pid ,
( struct sockaddr * ) & ctx - > lproc . srcaddr ,
ctx - > lproc . srcaddrlen ) = = 0 & &
ctx - > lproc . pid ! = - 1 & &
proc_get_info ( ctx - > lproc . pid ,
& ctx - > lproc . exec_path ,
& ctx - > lproc . uid ,
& ctx - > lproc . gid ) = = 0 ) {
/* fetch user/group names */
ctx - > lproc . user = sys_user_str (
ctx - > lproc . uid ) ;
ctx - > lproc . group = sys_group_str (
ctx - > lproc . gid ) ;
if ( ! ctx - > lproc . user | |
! ctx - > lproc . group ) {
ctx - > enomem = 1 ;
pxy_conn_free ( ctx , 1 ) ;
return - 1 ;
2018-09-29 20:47:18 +00:00
}
}
2018-10-03 23:56:02 +00:00
}
2018-09-29 20:47:18 +00:00
# endif /* HAVE_LOCAL_PROCINFO */
2018-10-03 23:56:02 +00:00
return 0 ;
}
static int
2018-10-05 13:55:02 +00:00
pxy_prepare_passthrough_logging ( pxy_conn_ctx_t * ctx )
2018-10-03 23:56:02 +00:00
{
/* prepare logging, part 2 */
if ( WANT_CONNECT_LOG ( ctx ) ) {
return pxy_prepare_logging_local_procinfo ( ctx ) ;
}
return 0 ;
}
static int
2018-10-05 13:55:02 +00:00
pxy_prepare_logging ( pxy_conn_ctx_t * ctx )
2018-10-03 23:56:02 +00:00
{
/* prepare logging, part 2 */
if ( WANT_CONNECT_LOG ( ctx ) | | WANT_CONTENT_LOG ( ctx ) ) {
return pxy_prepare_logging_local_procinfo ( ctx ) ;
2018-09-29 20:47:18 +00:00
}
if ( WANT_CONTENT_LOG ( ctx ) ) {
if ( log_content_open ( & ctx - > logctx , ctx - > opts ,
STRORDASH ( ctx - > srchost_str ) , STRORDASH ( ctx - > srcport_str ) ,
STRORDASH ( ctx - > dsthost_str ) , STRORDASH ( ctx - > dstport_str ) ,
# ifdef HAVE_LOCAL_PROCINFO
ctx - > lproc . exec_path ,
ctx - > lproc . user ,
ctx - > lproc . group
# else /* HAVE_LOCAL_PROCINFO */
NULL , NULL , NULL
# endif /* HAVE_LOCAL_PROCINFO */
) = = - 1 ) {
if ( errno = = ENOMEM )
ctx - > enomem = 1 ;
pxy_conn_free ( ctx , 1 ) ;
return - 1 ;
}
}
return 0 ;
}
static void
2018-10-05 13:55:02 +00:00
pxy_log_passthrough_connect_type ( pxy_conn_ctx_t * ctx )
2018-09-29 20:47:18 +00:00
{
if ( OPTS_DEBUG ( ctx - > opts ) ) {
/* for TCP, we get only a dst connect event,
* since src was already connected from the
* beginning ; mirror SSL debug output anyway
* in order not to confuse anyone who might be
* looking closely at the output */
2018-10-05 13:55:02 +00:00
log_dbg_printf ( " pxy_log_passthrough_connect_type: TCP connected to [%s]:%s \n " ,
2018-09-29 20:47:18 +00:00
STRORDASH ( ctx - > dsthost_str ) , STRORDASH ( ctx - > dstport_str ) ) ;
2018-10-05 13:55:02 +00:00
log_dbg_printf ( " pxy_log_passthrough_connect_type: TCP connected from [%s]:%s \n " ,
2018-09-29 20:47:18 +00:00
STRORDASH ( ctx - > srchost_str ) , STRORDASH ( ctx - > srcport_str ) ) ;
}
}
static void
2018-10-05 13:55:02 +00:00
pxy_log_passthrough_connect_src ( pxy_conn_ctx_t * ctx )
2017-05-29 09:22:23 +00:00
{
2018-09-29 23:43:48 +00:00
if ( WANT_CONNECT_LOG ( ctx ) | | ctx - > opts - > statslog ) {
pxy_log_connect_nonhttp ( ctx ) ;
}
2018-10-05 13:55:02 +00:00
pxy_log_passthrough_connect_type ( ctx ) ;
2018-09-29 23:43:48 +00:00
}
2017-07-16 14:10:18 +00:00
2018-09-29 23:43:48 +00:00
static void
2018-10-05 13:55:02 +00:00
pxy_bev_eventcb_passthrough_connected_src ( UNUSED struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-09-29 23:43:48 +00:00
{
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_passthrough_connected_src: ENTER, fd=%d \n " , ctx - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2018-10-05 13:55:02 +00:00
pxy_log_passthrough_connect_src ( ctx ) ;
2018-09-29 23:43:48 +00:00
}
static int
2018-10-05 13:55:02 +00:00
pxy_passthrough_enable_src ( pxy_conn_ctx_t * ctx )
2018-09-29 23:43:48 +00:00
{
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_passthrough_enable_src: ENTER, fd=%d \n " , ctx - > fd ) ;
2018-09-29 23:43:48 +00:00
# endif /* DEBUG_PROXY */
2017-05-29 09:22:23 +00:00
2018-10-05 13:55:02 +00:00
ctx - > connected = 1 ;
2017-05-29 09:22:23 +00:00
2018-10-05 13:55:02 +00:00
ctx - > src . bev = pxy_bufferevent_setup ( ctx , ctx - > fd , ctx - > src . ssl ) ;
if ( ! ctx - > src . bev ) {
log_err_level_printf ( LOG_CRIT , " Error creating bufferevent \n " ) ;
if ( ctx - > src . ssl ) {
SSL_free ( ctx - > src . ssl ) ;
ctx - > src . ssl = NULL ;
2017-07-15 18:51:20 +00:00
}
2018-10-05 13:55:02 +00:00
pxy_conn_free ( ctx , 1 ) ;
return - 1 ;
}
bufferevent_setcb ( ctx - > src . bev , pxy_bev_readcb , pxy_bev_writecb , pxy_bev_eventcb , ctx ) ;
2017-07-15 18:51:20 +00:00
2018-10-05 13:55:02 +00:00
if ( sys_sockaddr_str ( ( struct sockaddr * ) & ctx - > addr , ctx - > addrlen ,
& ctx - > dsthost_str , & ctx - > dstport_str ) ! = 0 ) {
ctx - > enomem = 1 ;
pxy_conn_free ( ctx , 1 ) ;
return - 1 ;
}
2017-06-10 18:50:03 +00:00
2018-10-05 13:55:02 +00:00
if ( pxy_prepare_passthrough_logging ( ctx ) = = - 1 ) {
return - 1 ;
}
2017-08-03 11:55:57 +00:00
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_passthrough_enable_src: Enabling src, %s, fd=%d, child_fd=%d \n " , ctx - > header_str , ctx - > fd , ctx - > child_fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2018-10-05 13:55:02 +00:00
// Now open the gates
bufferevent_enable ( ctx - > src . bev , EV_READ | EV_WRITE ) ;
2018-09-29 23:43:48 +00:00
return 0 ;
2018-09-29 20:47:18 +00:00
}
2018-09-29 23:43:48 +00:00
static void
2018-10-05 13:55:02 +00:00
pxy_bev_eventcb_passthrough_connected_srv_dst ( UNUSED struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-09-29 20:47:18 +00:00
{
2018-09-29 23:43:48 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_passthrough_connected_srv_dst: ENTER, fd=%d \n " , ctx - > fd ) ;
2018-09-29 23:43:48 +00:00
# endif /* DEBUG_PROXY */
2017-07-15 18:51:20 +00:00
2018-09-29 23:43:48 +00:00
if ( ! ctx - > srv_dst_connected ) {
ctx - > srv_dst_connected = 1 ;
ctx - > srv_dst_fd = bufferevent_getfd ( ctx - > srv_dst . bev ) ;
ctx - > thr - > max_fd = MAX ( ctx - > thr - > max_fd , ctx - > srv_dst_fd ) ;
}
2018-02-27 19:20:58 +00:00
2018-10-05 13:55:02 +00:00
if ( ctx - > srv_dst_connected & & ! ctx - > connected ) {
if ( pxy_passthrough_enable_src ( ctx ) = = - 1 ) {
return ;
}
2018-09-29 23:43:48 +00:00
}
2018-10-05 13:55:02 +00:00
pxy_log_passthrough_connect_type ( ctx ) ;
2018-09-29 23:43:48 +00:00
}
2017-07-15 18:51:20 +00:00
2018-09-29 20:47:18 +00:00
static int
2018-10-05 13:55:02 +00:00
pxy_setup_child_listener ( pxy_conn_ctx_t * ctx )
2012-04-13 12:47:30 +00:00
{
2018-09-29 20:47:18 +00:00
// @attention Defer child setup and evcl creation until after parent init is complete, otherwise (1) causes multithreading issues (proxy_listener_acceptcb is
// running on a different thread from the conn, and we only have thrmgr mutex), and (2) we need to clean up less upon errors.
// Child evcls use the evbase of the parent thread, otherwise we would get multithreading issues.
if ( ( ctx - > child_fd = privsep_client_opensock_child ( ctx - > clisock , ctx - > spec ) ) = = - 1 ) {
log_err_level_printf ( LOG_CRIT , " Error opening child socket: %s (%i) \n " , strerror ( errno ) , errno ) ;
pxy_conn_free ( ctx , 1 ) ;
return - 1 ;
2017-07-21 21:44:12 +00:00
}
2018-09-29 20:47:18 +00:00
ctx - > thr - > max_fd = MAX ( ctx - > thr - > max_fd , ctx - > child_fd ) ;
2017-06-30 21:29:39 +00:00
2018-09-29 20:47:18 +00:00
// @attention Do not pass NULL as user-supplied pointer
struct evconnlistener * child_evcl = evconnlistener_new ( ctx - > thr - > evbase , proxy_listener_acceptcb_child , ctx , LEV_OPT_CLOSE_ON_FREE , 1024 , ctx - > child_fd ) ;
if ( ! child_evcl ) {
log_err_level_printf ( LOG_CRIT , " Error creating child evconnlistener: %s \n " , strerror ( errno ) ) ;
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " pxy_setup_child_listener: Error creating child evconnlistener: %s, fd=%d, child_fd=%d \n " , strerror ( errno ) , ctx - > fd , ctx - > child_fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2018-09-29 20:47:18 +00:00
// @attention Cannot call proxy_listener_ctx_free() on child_evcl, child_evcl does not have any ctx with next listener
// @attention Close child fd separately, because child evcl does not exist yet, hence fd would not be closed by calling pxy_conn_free()
evutil_closesocket ( ctx - > child_fd ) ;
pxy_conn_free ( ctx , 1 ) ;
return - 1 ;
}
ctx - > child_evcl = child_evcl ;
2018-09-24 00:09:05 +00:00
2018-09-29 20:47:18 +00:00
evconnlistener_set_error_cb ( child_evcl , proxy_listener_errorcb ) ;
2018-09-24 00:09:05 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " pxy_setup_child_listener: Finished setting up child, fd=%d, NEW child_fd=%d \n " , ctx - > fd , ctx - > child_fd ) ;
2018-09-24 00:09:05 +00:00
# endif /* DEBUG_PROXY */
2018-09-29 20:47:18 +00:00
struct sockaddr_in child_listener_addr ;
socklen_t child_listener_len = sizeof ( child_listener_addr ) ;
if ( getsockname ( ctx - > child_fd , ( struct sockaddr * ) & child_listener_addr , & child_listener_len ) < 0 ) {
log_err_level_printf ( LOG_CRIT , " Error in getsockname: %s \n " , strerror ( errno ) ) ;
// @todo If getsockname() fails, should we really terminate the connection?
// @attention Do not close the child fd here, because child evcl exists now, hence pxy_conn_free() will close it while freeing child_evcl
pxy_conn_free ( ctx , 1 ) ;
return - 1 ;
2017-05-29 09:22:23 +00:00
}
2013-08-23 13:07:07 +00:00
2018-09-29 20:47:18 +00:00
// @attention Children are always listening on an IPv4 loopback address
char addr [ INET_ADDRSTRLEN ] ;
if ( ! inet_ntop ( AF_INET , & child_listener_addr . sin_addr , addr , INET_ADDRSTRLEN ) ) {
pxy_conn_free ( ctx , 1 ) ;
return - 1 ;
}
2017-07-21 10:46:44 +00:00
2018-09-29 20:47:18 +00:00
// SSLproxy: [127.0.0.1]:34649,[192.168.3.24]:47286,[74.125.206.108]:465,s
// @todo Port may be less than 5 chars
// SSLproxy: + + [ + addr + ] + : + p + , + [ + srchost_str + ] + : + srcport_str + , + [ + dsthost_str + ] + : + dstport_str + , + s + NULL
// SSLPROXY_KEY_LEN + 1 + 1 + strlen(addr) + 1 + 1 + 5 + 1 + 1 + strlen(ctx->srchost_str) + 1 + 1 + strlen(ctx->srcport_str) + 1 + 1 + strlen(ctx->dsthost_str) + 1 + 1 + strlen(ctx->dstport_str) + 1 + 1 + 1
int header_len = SSLPROXY_KEY_LEN + strlen ( addr ) + strlen ( ctx - > srchost_str ) + strlen ( ctx - > srcport_str ) + strlen ( ctx - > dsthost_str ) + strlen ( ctx - > dstport_str ) + 20 ;
// @todo Always check malloc retvals. Should we close the conn if malloc fails?
ctx - > header_str = malloc ( header_len ) ;
if ( ! ctx - > header_str ) {
pxy_conn_free ( ctx , 1 ) ;
return - 1 ;
2018-09-19 21:52:24 +00:00
}
2018-09-29 20:47:18 +00:00
snprintf ( ctx - > header_str , header_len , " %s [%s]:%u,[%s]:%s,[%s]:%s,%s " ,
SSLPROXY_KEY , addr , ntohs ( child_listener_addr . sin_port ) , STRORNONE ( ctx - > srchost_str ) , STRORNONE ( ctx - > srcport_str ) ,
STRORNONE ( ctx - > dsthost_str ) , STRORNONE ( ctx - > dstport_str ) , ctx - > spec - > ssl ? " s " : " p " ) ;
return 0 ;
}
2017-07-21 10:46:44 +00:00
2018-09-29 20:47:18 +00:00
static void
2018-10-05 13:55:02 +00:00
pxy_close_srv_dst ( pxy_conn_ctx_t * ctx )
2018-09-29 20:47:18 +00:00
{
// @attention Free the srv_dst of the conn asap, we don't need it anymore, but we need its fd
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " pxy_close_srv_dst: Closing srv_dst, fd=%d, srv_dst fd=%d \n " , ctx - > fd , bufferevent_getfd ( ctx - > srv_dst . bev ) ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2018-09-29 20:47:18 +00:00
// So save its ssl info for logging
if ( ctx - > srv_dst . ssl ) {
ctx - > srv_dst_ssl_version = strdup ( SSL_get_version ( ctx - > srv_dst . ssl ) ) ;
ctx - > srv_dst_ssl_cipher = strdup ( SSL_get_cipher ( ctx - > srv_dst . ssl ) ) ;
}
2017-07-10 12:48:57 +00:00
2018-09-29 20:47:18 +00:00
// @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.
bufferevent_free_and_close_fd ( ctx - > srv_dst . bev , ctx ) ;
ctx - > srv_dst . bev = NULL ;
ctx - > srv_dst . closed = 1 ;
}
static void
2018-10-05 13:55:02 +00:00
pxy_engage_passthrough_mode ( pxy_conn_ctx_t * ctx )
2018-09-29 20:47:18 +00:00
{
2018-09-29 23:43:48 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " pxy_engage_passthrough_mode: ENTER, fd=%d \n " , ctx - > fd ) ;
2018-09-29 23:43:48 +00:00
# endif /* DEBUG_PROXY */
2018-09-29 20:47:18 +00:00
// @attention Do not call bufferevent_free_and_close_fd(), otherwise connection stalls due to ssl shutdown
// We get srv_dst writecb while ssl shutdown is still in progress, and srv_dst readcb never fires
//bufferevent_free_and_close_fd(ctx->srv_dst.bev, ctx);
SSL_free ( ctx - > srv_dst . ssl ) ;
bufferevent_free_and_close_fd_nonssl ( ctx - > srv_dst . bev , ctx ) ;
ctx - > srv_dst . bev = NULL ;
ctx - > srv_dst . ssl = NULL ;
ctx - > passthrough = 1 ;
2018-10-05 01:55:24 +00:00
ctx - > proto = PASSTHROUGH ;
2018-09-29 20:47:18 +00:00
ctx - > connected = 0 ;
ctx - > srv_dst_connected = 0 ;
// Close and free dst if open
if ( ! ctx - > dst . closed ) {
ctx - > dst . closed = 1 ;
bufferevent_free_and_close_fd_nonssl ( ctx - > dst . bev , ctx ) ;
ctx - > dst . bev = NULL ;
ctx - > dst_fd = 0 ;
}
pxy_fd_readcb ( ctx - > fd , 0 , ctx ) ;
}
static int
2018-10-05 13:55:02 +00:00
pxy_set_dstaddr ( pxy_conn_ctx_t * ctx )
2018-09-29 20:47:18 +00:00
{
if ( sys_sockaddr_str ( ( struct sockaddr * ) & ctx - > addr , ctx - > addrlen , & ctx - > dsthost_str , & ctx - > dstport_str ) ! = 0 ) {
ctx - > enomem = 1 ;
pxy_conn_free ( ctx , 1 ) ;
return - 1 ;
}
return 0 ;
}
static int
2018-09-29 23:43:48 +00:00
pxy_log_masterkey ( pxy_conn_ctx_t * ctx , pxy_conn_desc_t * this )
{
if ( this - > ssl ) {
/* log master key */
if ( ctx - > opts - > masterkeylog ) {
char * keystr ;
keystr = ssl_ssl_masterkey_to_str ( this - > ssl ) ;
if ( ( keystr = = NULL ) | |
( log_masterkey_print_free ( keystr ) = = - 1 ) ) {
if ( errno = = ENOMEM )
ctx - > enomem = 1 ;
pxy_conn_free ( ctx , 1 ) ;
return - 1 ;
}
}
}
return 0 ;
}
static void
2018-10-03 23:56:02 +00:00
pxy_log_dbg_connect_type ( pxy_conn_ctx_t * ctx , pxy_conn_desc_t * this )
2018-09-29 20:47:18 +00:00
{
2018-09-29 23:43:48 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
if ( this - > ssl ) {
char * keystr ;
/* for SSL, we get two connect events */
log_dbg_printf ( " pxy_log_connect_type: SSL connected to [%s]:%s %s %s \n " ,
STRORDASH ( ctx - > dsthost_str ) , STRORDASH ( ctx - > dstport_str ) ,
SSL_get_version ( this - > ssl ) , SSL_get_cipher ( this - > ssl ) ) ;
keystr = ssl_ssl_masterkey_to_str ( this - > ssl ) ;
if ( keystr ) {
log_dbg_print_free ( keystr ) ;
}
} else {
/* for TCP, we get only a dst connect event,
* since src was already connected from the
* beginning ; mirror SSL debug output anyway
* in order not to confuse anyone who might be
* looking closely at the output */
log_dbg_printf ( " pxy_log_connect_type: TCP connected to [%s]:%s \n " ,
STRORDASH ( ctx - > dsthost_str ) , STRORDASH ( ctx - > dstport_str ) ) ;
log_dbg_printf ( " pxy_log_connect_type: TCP connected from [%s]:%s \n " ,
STRORDASH ( ctx - > srchost_str ) , STRORDASH ( ctx - > srcport_str ) ) ;
}
}
}
2017-07-28 09:52:53 +00:00
2018-09-29 23:43:48 +00:00
static void
pxy_log_connect_src ( pxy_conn_ctx_t * ctx )
{
/* log connection if we don't analyze any headers */
if ( ! ctx - > spec - > http & & ( WANT_CONNECT_LOG ( ctx ) | | ctx - > opts - > statslog ) ) {
pxy_log_connect_nonhttp ( ctx ) ;
}
2018-09-29 20:47:18 +00:00
2018-09-29 23:43:48 +00:00
if ( ctx - > src . ssl & & ctx - > opts - > certgendir ) {
/* write SSL certificates to gendir */
pxy_srccert_write ( ctx ) ;
}
2018-09-29 20:47:18 +00:00
2018-09-29 23:43:48 +00:00
if ( pxy_log_masterkey ( ctx , & ctx - > src ) = = - 1 ) {
return ;
2018-09-24 00:09:05 +00:00
}
2018-10-03 23:56:02 +00:00
pxy_log_dbg_connect_type ( ctx , & ctx - > src ) ;
2018-09-29 23:43:48 +00:00
}
static void
pxy_log_connect_srv_dst ( pxy_conn_ctx_t * ctx )
{
// @attention srv_dst.bev may be NULL, if its writecb fires first
if ( ctx - > srv_dst . bev ) {
/* log connection if we don't analyze any headers */
if ( ! ctx - > srv_dst . ssl & & ! ctx - > spec - > http & & ( WANT_CONNECT_LOG ( ctx ) | | ctx - > opts - > statslog ) ) {
pxy_log_connect_nonhttp ( ctx ) ;
}
if ( pxy_log_masterkey ( ctx , & ctx - > srv_dst ) = = - 1 ) {
return ;
}
2018-10-03 23:56:02 +00:00
pxy_log_dbg_connect_type ( ctx , & ctx - > srv_dst ) ;
2018-09-29 20:47:18 +00:00
}
2018-09-29 23:43:48 +00:00
}
static int
2018-10-05 13:55:02 +00:00
pxy_autossl_enable_src ( pxy_conn_ctx_t * ctx )
2018-09-29 23:43:48 +00:00
{
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_autossl_enable_src: ENTER, fd=%d \n " , ctx - > fd ) ;
2018-09-29 23:43:48 +00:00
# endif /* DEBUG_PROXY */
2018-09-24 00:09:05 +00:00
2018-10-05 13:55:02 +00:00
ctx - > connected = 1 ;
2017-07-10 09:27:46 +00:00
2018-10-05 13:55:02 +00:00
if ( ctx - > clienthello_found ) {
ctx - > src . ssl = pxy_srcssl_create ( ctx , ctx - > srv_dst . ssl ) ;
if ( ! ctx - > src . ssl ) {
if ( ctx - > opts - > passthrough & & ! ctx - > enomem ) {
log_err_level_printf ( LOG_WARNING , " No cert found; falling back to passthrough, fd=%d \n " , ctx - > fd ) ;
pxy_engage_passthrough_mode ( ctx ) ;
// return success
return 0 ;
2018-09-29 20:47:18 +00:00
}
pxy_conn_free ( ctx , 1 ) ;
return - 1 ;
}
2018-10-05 13:55:02 +00:00
}
2018-09-29 20:47:18 +00:00
2018-10-05 13:55:02 +00:00
// Create and set up src.bev
if ( ctx - > clienthello_found ) {
// ctx->src.bev must have already been created at this point
if ( OPTS_DEBUG ( ctx - > opts ) ) {
log_dbg_printf ( " Completing autossl upgrade \n " ) ;
2018-09-29 20:47:18 +00:00
}
2018-10-05 13:55:02 +00:00
ctx - > src . bev = bufferevent_openssl_filter_new ( ctx - > evbase , ctx - > src . bev , ctx - > src . ssl ,
BUFFEREVENT_SSL_ACCEPTING , BEV_OPT_DEFER_CALLBACKS ) ;
} else {
ctx - > src . bev = pxy_bufferevent_setup ( ctx , ctx - > fd , ctx - > src . ssl ) ;
}
if ( ! ctx - > src . bev ) {
log_err_level_printf ( LOG_CRIT , " Error creating bufferevent \n " ) ;
if ( ctx - > src . ssl ) {
SSL_free ( ctx - > src . ssl ) ;
ctx - > src . ssl = NULL ;
2018-09-29 20:47:18 +00:00
}
2018-10-05 13:55:02 +00:00
pxy_conn_free ( ctx , 1 ) ;
return - 1 ;
}
bufferevent_setcb ( ctx - > src . bev , pxy_bev_readcb , pxy_bev_writecb , pxy_bev_eventcb , ctx ) ;
2018-09-29 20:47:18 +00:00
2018-10-05 13:55:02 +00:00
if ( pxy_set_dstaddr ( ctx ) = = - 1 ) {
return - 1 ;
}
2018-09-29 20:47:18 +00:00
2018-10-05 13:55:02 +00:00
if ( pxy_prepare_logging ( ctx ) = = - 1 ) {
return - 1 ;
}
if ( ctx - > srv_dst . bev & & ! ctx - > clienthello_search ) {
pxy_close_srv_dst ( ctx ) ;
}
// Skip child listener setup if completing autossl upgrade, after finding clienthello
if ( ctx - > clienthello_search ) {
if ( pxy_setup_child_listener ( ctx ) = = - 1 ) {
return - 1 ;
2018-09-29 20:47:18 +00:00
}
2018-10-05 13:55:02 +00:00
}
2018-09-29 20:47:18 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_autossl_enable_src: Enabling src, %s, fd=%d, child_fd=%d \n " , ctx - > header_str , ctx - > fd , ctx - > child_fd ) ;
2018-09-29 20:47:18 +00:00
# endif /* DEBUG_PROXY */
2018-10-05 13:55:02 +00:00
// Now open the gates, perhaps for a second time if in autossl mode
bufferevent_enable ( ctx - > src . bev , EV_READ | EV_WRITE ) ;
2018-09-29 20:47:18 +00:00
return 0 ;
}
2018-09-29 23:43:48 +00:00
static void
2018-10-05 13:55:02 +00:00
pxy_bev_eventcb_autssl_connected_src ( UNUSED struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-09-29 20:47:18 +00:00
{
2018-09-29 23:43:48 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_autssl_connected_src: ENTER, fd=%d \n " , ctx - > fd ) ;
2018-09-29 23:43:48 +00:00
# endif /* DEBUG_PROXY */
pxy_log_connect_src ( ctx ) ;
}
2018-09-29 20:47:18 +00:00
2018-09-29 23:43:48 +00:00
static void
2018-10-05 13:55:02 +00:00
pxy_bev_eventcb_autssl_connected_dst ( UNUSED struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-09-29 23:43:48 +00:00
{
2018-09-29 20:47:18 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_autssl_connected_dst: ENTER, fd=%d \n " , ctx - > fd ) ;
2018-09-29 20:47:18 +00:00
# endif /* DEBUG_PROXY */
2018-09-29 23:43:48 +00:00
ctx - > dst_connected = 1 ;
2018-10-05 13:55:02 +00:00
if ( ctx - > srv_dst_connected & & ctx - > dst_connected & & ( ! ctx - > connected | | ( ctx - > clienthello_found & & ctx - > srv_dst . bev ) ) ) {
pxy_autossl_enable_src ( ctx ) ;
}
2018-09-29 23:43:48 +00:00
}
static void
2018-10-05 13:55:02 +00:00
pxy_bev_eventcb_autssl_connected_srv_dst ( UNUSED struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-09-29 23:43:48 +00:00
{
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_autssl_connected_srv_dst: ENTER, fd=%d \n " , ctx - > fd ) ;
2018-09-29 23:43:48 +00:00
# endif /* DEBUG_PROXY */
// srv_dst may be already connected while upgrading to ssl
if ( ! ctx - > srv_dst_connected ) {
2018-09-29 20:47:18 +00:00
ctx - > srv_dst_connected = 1 ;
ctx - > srv_dst_fd = bufferevent_getfd ( ctx - > srv_dst . bev ) ;
ctx - > thr - > max_fd = MAX ( ctx - > thr - > max_fd , ctx - > srv_dst_fd ) ;
// @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-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " pxy_bev_eventcb_autssl_connected_srv_dst: FAILED bufferevent_socket_connect for dst, fd=%d \n " , ctx - > fd ) ;
2018-09-29 20:47:18 +00:00
# endif /* DEBUG_PROXY */
pxy_conn_free ( ctx , 1 ) ;
2018-09-29 23:43:48 +00:00
return ;
2018-09-29 20:47:18 +00:00
}
ctx - > dst_fd = bufferevent_getfd ( ctx - > dst . bev ) ;
ctx - > thr - > max_fd = MAX ( ctx - > thr - > max_fd , ctx - > dst_fd ) ;
}
2018-10-05 13:55:02 +00:00
if ( ctx - > srv_dst_connected & & ctx - > dst_connected & & ( ! ctx - > connected | | ( ctx - > clienthello_found & & ctx - > srv_dst . bev ) ) ) {
if ( pxy_autossl_enable_src ( ctx ) = = - 1 ) {
return ;
}
2018-09-29 20:47:18 +00:00
}
2018-10-03 23:56:02 +00:00
2018-09-29 23:43:48 +00:00
pxy_log_connect_srv_dst ( ctx ) ;
}
2018-09-29 20:47:18 +00:00
2018-09-29 23:43:48 +00:00
static int
2018-10-05 13:55:02 +00:00
pxy_enable_src ( pxy_conn_ctx_t * ctx )
2018-09-29 23:43:48 +00:00
{
2018-10-05 13:55:02 +00:00
ctx - > connected = 1 ;
2018-09-29 20:47:18 +00:00
2018-10-05 13:55:02 +00:00
if ( ctx - > spec - > ssl ) {
ctx - > src . ssl = pxy_srcssl_create ( ctx , ctx - > srv_dst . ssl ) ;
if ( ! ctx - > src . ssl ) {
if ( ctx - > opts - > passthrough & & ! ctx - > enomem ) {
log_err_level_printf ( LOG_WARNING , " No cert found; falling back to passthrough, fd=%d \n " , ctx - > fd ) ;
pxy_engage_passthrough_mode ( ctx ) ;
// return success
return 0 ;
2018-09-29 20:47:18 +00:00
}
pxy_conn_free ( ctx , 1 ) ;
return - 1 ;
}
2018-10-05 13:55:02 +00:00
}
2018-09-29 20:47:18 +00:00
2018-10-05 13:55:02 +00:00
ctx - > src . bev = pxy_bufferevent_setup ( ctx , ctx - > fd , ctx - > src . ssl ) ;
if ( ! ctx - > src . bev ) {
log_err_level_printf ( LOG_CRIT , " Error creating bufferevent \n " ) ;
if ( ctx - > src . ssl ) {
SSL_free ( ctx - > src . ssl ) ;
ctx - > src . ssl = NULL ;
2018-09-29 20:47:18 +00:00
}
2018-10-05 13:55:02 +00:00
pxy_conn_free ( ctx , 1 ) ;
return - 1 ;
}
bufferevent_setcb ( ctx - > src . bev , pxy_bev_readcb , pxy_bev_writecb , pxy_bev_eventcb , ctx ) ;
2018-09-29 20:47:18 +00:00
2018-10-05 13:55:02 +00:00
if ( pxy_set_dstaddr ( ctx ) = = - 1 ) {
return - 1 ;
}
2018-09-29 20:47:18 +00:00
2018-10-05 13:55:02 +00:00
if ( pxy_prepare_logging ( ctx ) = = - 1 ) {
return - 1 ;
}
2018-09-29 20:47:18 +00:00
2018-10-05 13:55:02 +00:00
pxy_close_srv_dst ( ctx ) ;
if ( pxy_setup_child_listener ( ctx ) = = - 1 ) {
return - 1 ;
}
2018-09-29 20:47:18 +00:00
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_enable_src: Enabling src, %s, fd=%d, child_fd=%d \n " , ctx - > header_str , ctx - > fd , ctx - > child_fd ) ;
2018-09-29 20:47:18 +00:00
# endif /* DEBUG_PROXY */
2018-10-05 13:55:02 +00:00
// Now open the gates
bufferevent_enable ( ctx - > src . bev , EV_READ | EV_WRITE ) ;
2018-09-29 20:47:18 +00:00
return 0 ;
}
2018-09-29 23:43:48 +00:00
static void
2018-10-05 13:55:02 +00:00
pxy_bev_eventcb_connected_src ( UNUSED struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-09-29 23:43:48 +00:00
{
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_connected_src: ENTER, fd=%d \n " , ctx - > fd ) ;
2018-09-29 23:43:48 +00:00
# endif /* DEBUG_PROXY */
pxy_log_connect_src ( ctx ) ;
}
static void
2018-10-05 13:55:02 +00:00
pxy_bev_eventcb_connected_dst ( UNUSED struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-09-29 23:43:48 +00:00
{
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_connected_dst: ENTER, fd=%d \n " , ctx - > fd ) ;
2018-09-29 23:43:48 +00:00
# endif /* DEBUG_PROXY */
ctx - > dst_connected = 1 ;
2018-10-05 13:55:02 +00:00
if ( ctx - > srv_dst_connected & & ctx - > dst_connected & & ! ctx - > connected ) {
pxy_enable_src ( ctx ) ;
}
2018-09-29 23:43:48 +00:00
}
static void
2018-10-05 13:55:02 +00:00
pxy_bev_eventcb_connected_srv_dst ( UNUSED struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-09-29 23:43:48 +00:00
{
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_connected_srv_dst: ENTER, fd=%d \n " , ctx - > fd ) ;
2018-09-29 23:43:48 +00:00
# endif /* DEBUG_PROXY */
ctx - > srv_dst_connected = 1 ;
ctx - > srv_dst_fd = bufferevent_getfd ( ctx - > srv_dst . bev ) ;
ctx - > thr - > max_fd = MAX ( ctx - > thr - > max_fd , ctx - > srv_dst_fd ) ;
// @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-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " pxy_bev_eventcb_connected_srv_dst: FAILED bufferevent_socket_connect for dst, fd=%d \n " , ctx - > fd ) ;
2018-09-29 23:43:48 +00:00
# endif /* DEBUG_PROXY */
pxy_conn_free ( ctx , 1 ) ;
return ;
}
ctx - > dst_fd = bufferevent_getfd ( ctx - > dst . bev ) ;
ctx - > thr - > max_fd = MAX ( ctx - > thr - > max_fd , ctx - > dst_fd ) ;
2018-10-05 13:55:02 +00:00
if ( ctx - > srv_dst_connected & & ctx - > dst_connected & & ! ctx - > connected ) {
if ( pxy_enable_src ( ctx ) = = - 1 ) {
return ;
}
2018-09-29 23:43:48 +00:00
}
2018-10-03 23:56:02 +00:00
2018-09-29 23:43:48 +00:00
pxy_log_connect_srv_dst ( ctx ) ;
}
2018-09-29 20:47:18 +00:00
static void
2018-10-03 23:56:02 +00:00
pxy_log_err_ssl_error ( struct bufferevent * bev , UNUSED pxy_conn_ctx_t * ctx )
2018-09-29 20:47:18 +00:00
{
unsigned long sslerr ;
/* Can happen for socket errs, ssl errs;
* may happen for unclean ssl socket shutdowns . */
sslerr = bufferevent_get_openssl_error ( bev ) ;
if ( ! errno & & ! sslerr ) {
# if LIBEVENT_VERSION_NUMBER >= 0x02010000
/* We have disabled notification for unclean shutdowns
* so this should not happen ; log a warning . */
log_err_level_printf ( LOG_WARNING , " Spurious error from bufferevent (errno=0,sslerr=0) \n " ) ;
# else /* LIBEVENT_VERSION_NUMBER < 0x02010000 */
/* Older versions of libevent will report these. */
if ( OPTS_DEBUG ( ctx - > opts ) ) {
log_dbg_printf ( " Unclean SSL shutdown, fd=%d \n " , ctx - > fd ) ;
}
# endif /* LIBEVENT_VERSION_NUMBER < 0x02010000 */
} else if ( ERR_GET_REASON ( sslerr ) = = SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE ) {
/* these can happen due to client cert auth,
* only log error if debugging is activated */
log_dbg_printf ( " Error from bufferevent: %i:%s %lu:%i:%s:%i:%s:%i:%s \n " ,
errno , errno ? strerror ( errno ) : " - " , sslerr ,
ERR_GET_REASON ( sslerr ) , sslerr ? ERR_reason_error_string ( sslerr ) : " - " ,
ERR_GET_LIB ( sslerr ) , sslerr ? ERR_lib_error_string ( sslerr ) : " - " ,
ERR_GET_FUNC ( sslerr ) , sslerr ? ERR_func_error_string ( sslerr ) : " - " ) ;
while ( ( sslerr = bufferevent_get_openssl_error ( bev ) ) ) {
log_dbg_printf ( " Additional SSL error: %lu:%i:%s:%i:%s:%i:%s \n " ,
sslerr ,
ERR_GET_REASON ( sslerr ) , ERR_reason_error_string ( sslerr ) ,
ERR_GET_LIB ( sslerr ) , ERR_lib_error_string ( sslerr ) ,
ERR_GET_FUNC ( sslerr ) , ERR_func_error_string ( sslerr ) ) ;
}
} else {
/* real errors */
log_err_printf ( " Error from bufferevent: %i:%s %lu:%i:%s:%i:%s:%i:%s \n " ,
errno , errno ? strerror ( errno ) : " - " ,
sslerr ,
ERR_GET_REASON ( sslerr ) , sslerr ? ERR_reason_error_string ( sslerr ) : " - " ,
ERR_GET_LIB ( sslerr ) , sslerr ? ERR_lib_error_string ( sslerr ) : " - " ,
ERR_GET_FUNC ( sslerr ) , sslerr ? ERR_func_error_string ( sslerr ) : " - " ) ;
while ( ( sslerr = bufferevent_get_openssl_error ( bev ) ) ) {
log_err_printf ( " Additional SSL error: %lu:%i:%s:%i:%s:%i:%s \n " ,
sslerr ,
ERR_GET_REASON ( sslerr ) , ERR_reason_error_string ( sslerr ) ,
ERR_GET_LIB ( sslerr ) , ERR_lib_error_string ( sslerr ) ,
ERR_GET_FUNC ( sslerr ) , ERR_func_error_string ( sslerr ) ) ;
}
}
}
static void
2018-10-03 23:56:02 +00:00
pxy_log_dbg_evbuf_info ( UNUSED pxy_conn_ctx_t * ctx , UNUSED pxy_conn_desc_t * this , UNUSED pxy_conn_desc_t * other )
2018-09-29 20:47:18 +00:00
{
# ifdef DEBUG_PROXY
if ( OPTS_DEBUG ( ctx - > opts ) ) {
log_dbg_printf ( " evbuffer size at EOF: i:%zu o:%zu i:%zu o:%zu \n " ,
evbuffer_get_length ( bufferevent_get_input ( this - > bev ) ) ,
evbuffer_get_length ( bufferevent_get_output ( this - > bev ) ) ,
other - > closed ? 0 : evbuffer_get_length ( bufferevent_get_input ( other - > bev ) ) ,
other - > closed ? 0 : evbuffer_get_length ( bufferevent_get_output ( other - > bev ) ) ) ;
}
# endif /* DEBUG_PROXY */
}
static void
2018-10-05 13:55:02 +00:00
pxy_consume_last_input ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-09-29 20:47:18 +00:00
{
/* if there is data pending in the closed connection,
* handle it here , otherwise it will be lost . */
if ( evbuffer_get_length ( bufferevent_get_input ( bev ) ) ) {
# ifdef DEBUG_PROXY
2018-09-29 23:43:48 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_process_last_input: evbuffer_get_length(inbuf) > 0, terminate conn, fd=%d \n " , ctx - > fd ) ;
2018-09-29 20:47:18 +00:00
# endif /* DEBUG_PROXY */
pxy_bev_readcb ( bev , ctx ) ;
}
}
static void
2018-10-03 23:56:02 +00:00
pxy_log_dbg_disconnect ( pxy_conn_ctx_t * ctx )
2018-09-29 20:47:18 +00:00
{
// On parent connections, ctx->src.ssl is enough to know the type of connection
2017-07-21 21:44:12 +00:00
/* we only get a single disconnect event here for both connections */
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2018-09-29 20:47:18 +00:00
log_dbg_printf ( " pxy_log_disconnect: %s disconnected to [%s]:%s, fd=%d \n " ,
ctx - > src . ssl ? " SSL " : " TCP " ,
2017-10-26 15:57:46 +00:00
STRORDASH ( ctx - > dsthost_str ) , STRORDASH ( ctx - > dstport_str ) , ctx - > fd ) ;
2018-09-29 20:47:18 +00:00
log_dbg_printf ( " pxy_log_disconnect: %s disconnected from [%s]:%s, fd=%d \n " ,
ctx - > src . ssl ? " SSL " : " TCP " ,
2017-10-26 15:57:46 +00:00
STRORDASH ( ctx - > srchost_str ) , STRORDASH ( ctx - > srcport_str ) , ctx - > fd ) ;
2017-07-21 21:44:12 +00:00
}
2018-09-29 20:47:18 +00:00
}
2017-07-21 21:44:12 +00:00
2018-09-29 20:47:18 +00:00
static void
pxy_disconnect ( struct bufferevent * bev , pxy_conn_ctx_t * ctx , pxy_conn_desc_t * this ,
void ( * this_free_and_close_fd_func ) ( struct bufferevent * , pxy_conn_ctx_t * ) , pxy_conn_desc_t * other , int is_requestor )
{
2018-09-25 09:24:23 +00:00
// @attention srv_dst should never reach here unless in passthrough mode, its bev may be NULL
2017-07-21 21:44:12 +00:00
this - > closed = 1 ;
this_free_and_close_fd_func ( bev , ctx ) ;
this - > bev = NULL ;
if ( other - > closed ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-09-29 20:47:18 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_disconnect: other->closed, terminate conn, fd=%d \n " , ctx - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-25 13:07:39 +00:00
pxy_conn_free ( ctx , is_requestor ) ;
2017-07-21 21:44:12 +00:00
}
2017-05-29 09:22:23 +00:00
}
2012-04-13 12:47:30 +00:00
2018-09-29 20:47:18 +00:00
static void
2018-10-05 13:55:02 +00:00
pxy_bev_eventcb_passthrough_eof_src ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-09-29 20:47:18 +00:00
{
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_passthrough_eof_src: EOF, fd=%d \n " , ctx - > fd ) ;
2018-09-29 20:47:18 +00:00
# endif /* DEBUG_PROXY */
2018-10-03 23:56:02 +00:00
pxy_log_dbg_evbuf_info ( ctx , & ctx - > src , & ctx - > srv_dst ) ;
2018-09-29 20:47:18 +00:00
if ( ! ctx - > connected ) {
log_err_level_printf ( LOG_WARNING , " EOF on outbound connection before connection establishment \n " ) ;
ctx - > srv_dst . closed = 1 ;
} else if ( ! ctx - > srv_dst . closed ) {
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_passthrough_eof_src: !other->closed, terminate conn, fd=%d \n " , ctx - > fd ) ;
2018-09-29 20:47:18 +00:00
# endif /* DEBUG_PROXY */
2018-10-05 13:55:02 +00:00
pxy_consume_last_input ( bev , ctx ) ;
2018-09-29 23:43:48 +00:00
pxy_close_conn_end_ifnodata ( & ctx - > srv_dst , ctx , & bufferevent_free_and_close_fd_nonssl ) ;
2018-09-29 20:47:18 +00:00
}
2018-10-03 23:56:02 +00:00
pxy_log_dbg_disconnect ( ctx ) ;
2018-09-29 20:47:18 +00:00
pxy_disconnect ( bev , ctx , & ctx - > src , & bufferevent_free_and_close_fd_nonssl , & ctx - > srv_dst , 1 ) ;
}
static void
2018-10-05 13:55:02 +00:00
pxy_bev_eventcb_passthrough_eof_srv_dst ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-09-29 20:47:18 +00:00
{
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_passthrough_eof_srv_dst: EOF, fd=%d \n " , ctx - > fd ) ;
2018-09-29 20:47:18 +00:00
# endif /* DEBUG_PROXY */
2018-10-03 23:56:02 +00:00
pxy_log_dbg_evbuf_info ( ctx , & ctx - > srv_dst , & ctx - > src ) ;
2018-09-29 20:47:18 +00:00
if ( ! ctx - > connected ) {
log_err_level_printf ( LOG_WARNING , " EOF on outbound connection before connection establishment \n " ) ;
ctx - > src . closed = 1 ;
} else if ( ! ctx - > src . closed ) {
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_passthrough_eof_srv_dst: !other->closed, terminate conn, fd=%d \n " , ctx - > fd ) ;
2018-09-29 20:47:18 +00:00
# endif /* DEBUG_PROXY */
2018-10-05 13:55:02 +00:00
pxy_consume_last_input ( bev , ctx ) ;
2018-09-29 23:43:48 +00:00
pxy_close_conn_end_ifnodata ( & ctx - > src , ctx , & bufferevent_free_and_close_fd_nonssl ) ;
2018-09-29 20:47:18 +00:00
}
2018-10-03 23:56:02 +00:00
pxy_log_dbg_disconnect ( ctx ) ;
2018-09-29 20:47:18 +00:00
pxy_disconnect ( bev , ctx , & ctx - > srv_dst , & bufferevent_free_and_close_fd_nonssl , & ctx - > src , 0 ) ;
}
static void
2018-10-05 13:55:02 +00:00
pxy_bev_eventcb_eof_src ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-09-29 20:47:18 +00:00
{
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_eof_src: EOF, fd=%d \n " , ctx - > fd ) ;
2018-09-29 20:47:18 +00:00
# endif /* DEBUG_PROXY */
2018-10-03 23:56:02 +00:00
pxy_log_dbg_evbuf_info ( ctx , & ctx - > src , & ctx - > dst ) ;
2018-09-29 20:47:18 +00:00
if ( ! ctx - > connected ) {
log_err_level_printf ( LOG_WARNING , " EOF on outbound connection before connection establishment \n " ) ;
ctx - > dst . closed = 1 ;
} else if ( ! ctx - > dst . closed ) {
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_eof_src: !other->closed, terminate conn, fd=%d \n " , ctx - > fd ) ;
2018-09-29 20:47:18 +00:00
# endif /* DEBUG_PROXY */
2018-10-05 13:55:02 +00:00
pxy_consume_last_input ( bev , ctx ) ;
2018-09-29 23:43:48 +00:00
pxy_close_conn_end_ifnodata ( & ctx - > dst , ctx , & bufferevent_free_and_close_fd_nonssl ) ;
2018-09-29 20:47:18 +00:00
}
2018-10-03 23:56:02 +00:00
pxy_log_dbg_disconnect ( ctx ) ;
2018-09-29 20:47:18 +00:00
pxy_disconnect ( bev , ctx , & ctx - > src , & bufferevent_free_and_close_fd , & ctx - > dst , 1 ) ;
}
static void
2018-10-05 13:55:02 +00:00
pxy_bev_eventcb_eof_dst ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-09-29 20:47:18 +00:00
{
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_eof_dst: EOF, fd=%d \n " , ctx - > fd ) ;
2018-09-29 20:47:18 +00:00
# endif /* DEBUG_PROXY */
2018-10-03 23:56:02 +00:00
pxy_log_dbg_evbuf_info ( ctx , & ctx - > dst , & ctx - > src ) ;
2018-09-29 20:47:18 +00:00
if ( ! ctx - > connected ) {
log_err_level_printf ( LOG_WARNING , " EOF on outbound connection before connection establishment \n " ) ;
ctx - > src . closed = 1 ;
} else if ( ! ctx - > src . closed ) {
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_eof_dst: !other->closed, terminate conn, fd=%d \n " , ctx - > fd ) ;
2018-09-29 20:47:18 +00:00
# endif /* DEBUG_PROXY */
2018-10-05 13:55:02 +00:00
pxy_consume_last_input ( bev , ctx ) ;
2018-09-29 23:43:48 +00:00
pxy_close_conn_end_ifnodata ( & ctx - > src , ctx , & bufferevent_free_and_close_fd ) ;
2018-09-29 20:47:18 +00:00
}
2018-10-03 23:56:02 +00:00
pxy_log_dbg_disconnect ( ctx ) ;
2018-09-29 20:47:18 +00:00
pxy_disconnect ( bev , ctx , & ctx - > dst , & bufferevent_free_and_close_fd_nonssl , & ctx - > src , 0 ) ;
}
static void
2018-10-05 13:55:02 +00:00
pxy_bev_eventcb_eof_srv_dst ( UNUSED struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-09-29 20:47:18 +00:00
{
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_eof_srv_dst: EOF, fd=%d \n " , ctx - > fd ) ;
2018-09-29 20:47:18 +00:00
# endif /* DEBUG_PROXY */
log_err_level_printf ( LOG_WARNING , " EOF on outbound connection before connection establishment on srv_dst \n " ) ;
pxy_conn_free ( ctx , 0 ) ;
}
static void
2018-10-05 13:55:02 +00:00
pxy_bev_eventcb_passthrough_error_src ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-09-29 20:47:18 +00:00
{
// Passthrough packets are transfered between src and srv_dst
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " pxy_bev_eventcb_passthrough_error_src: BEV_EVENT_ERROR %s, fd=%d \n " , pxy_get_event_name ( bev , ctx ) , ctx - > fd ) ;
2018-09-29 20:47:18 +00:00
# endif /* DEBUG_PROXY */
2018-10-05 13:55:02 +00:00
log_err_printf ( " pxy_bev_eventcb_passthrough_error_src: Client-side BEV_EVENT_ERROR \n " ) ;
2018-10-05 01:55:24 +00:00
pxy_log_err_ssl_error ( bev , ctx ) ;
ctx - > thr - > errors + + ;
2018-09-29 20:47:18 +00:00
if ( ! ctx - > connected ) {
ctx - > srv_dst . closed = 1 ;
} else if ( ! ctx - > srv_dst . closed ) {
2018-09-29 23:43:48 +00:00
pxy_close_conn_end_ifnodata ( & ctx - > srv_dst , ctx , & bufferevent_free_and_close_fd_nonssl ) ;
2018-09-29 20:47:18 +00:00
}
2018-10-03 23:56:02 +00:00
pxy_log_dbg_disconnect ( ctx ) ;
2018-09-29 20:47:18 +00:00
pxy_disconnect ( bev , ctx , & ctx - > src , & bufferevent_free_and_close_fd_nonssl , & ctx - > srv_dst , 1 ) ;
}
static void
2018-10-05 13:55:02 +00:00
pxy_bev_eventcb_passthrough_error_srv_dst ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-09-29 20:47:18 +00:00
{
// Passthrough packets are transfered between src and srv_dst
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " pxy_bev_eventcb_passthrough_error_srv_dst: BEV_EVENT_ERROR %s, fd=%d \n " , pxy_get_event_name ( bev , ctx ) , ctx - > fd ) ;
2018-09-29 20:47:18 +00:00
# endif /* DEBUG_PROXY */
2018-10-05 13:55:02 +00:00
log_err_printf ( " pxy_bev_eventcb_passthrough_error_srv_dst: Client-side BEV_EVENT_ERROR \n " ) ;
2018-10-05 01:55:24 +00:00
pxy_log_err_ssl_error ( bev , ctx ) ;
ctx - > thr - > errors + + ;
2018-09-29 20:47:18 +00:00
if ( ! ctx - > connected ) {
ctx - > src . closed = 1 ;
} else if ( ! ctx - > src . closed ) {
2018-09-29 23:43:48 +00:00
pxy_close_conn_end_ifnodata ( & ctx - > src , ctx , & bufferevent_free_and_close_fd_nonssl ) ;
2018-09-29 20:47:18 +00:00
}
2018-10-03 23:56:02 +00:00
pxy_log_dbg_disconnect ( ctx ) ;
2018-09-29 20:47:18 +00:00
pxy_disconnect ( bev , ctx , & ctx - > srv_dst , & bufferevent_free_and_close_fd_nonssl , & ctx - > src , 0 ) ;
}
static void
2018-10-05 13:55:02 +00:00
pxy_bev_eventcb_error_src ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-09-29 20:47:18 +00:00
{
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " pxy_bev_eventcb_error_src: BEV_EVENT_ERROR, fd=%d \n " , ctx - > fd ) ;
2018-09-29 20:47:18 +00:00
# endif /* DEBUG_PROXY */
2018-10-05 13:55:02 +00:00
log_err_printf ( " pxy_bev_eventcb_error_src: Client-side BEV_EVENT_ERROR \n " ) ;
2018-10-05 01:55:24 +00:00
pxy_log_err_ssl_error ( bev , ctx ) ;
ctx - > thr - > errors + + ;
2018-09-29 20:47:18 +00:00
if ( ! ctx - > connected ) {
ctx - > dst . closed = 1 ;
} else if ( ! ctx - > dst . closed ) {
2018-09-29 23:43:48 +00:00
pxy_close_conn_end_ifnodata ( & ctx - > dst , ctx , & bufferevent_free_and_close_fd_nonssl ) ;
2018-09-29 20:47:18 +00:00
}
2018-10-03 23:56:02 +00:00
pxy_log_dbg_disconnect ( ctx ) ;
2018-09-29 20:47:18 +00:00
pxy_disconnect ( bev , ctx , & ctx - > src , & bufferevent_free_and_close_fd , & ctx - > dst , 1 ) ;
}
static void
2018-10-05 13:55:02 +00:00
pxy_bev_eventcb_error_dst ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-09-29 20:47:18 +00:00
{
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " pxy_bev_eventcb_error_dst: BEV_EVENT_ERROR, fd=%d \n " , ctx - > fd ) ;
2018-09-29 20:47:18 +00:00
# endif /* DEBUG_PROXY */
2018-10-05 13:55:02 +00:00
log_err_printf ( " pxy_bev_eventcb_error_dst: Client-side BEV_EVENT_ERROR \n " ) ;
2018-10-05 01:55:24 +00:00
pxy_log_err_ssl_error ( bev , ctx ) ;
ctx - > thr - > errors + + ;
2018-09-29 20:47:18 +00:00
if ( ! ctx - > connected ) {
ctx - > src . closed = 1 ;
} else if ( ! ctx - > src . closed ) {
2018-09-29 23:43:48 +00:00
pxy_close_conn_end_ifnodata ( & ctx - > src , ctx , & bufferevent_free_and_close_fd ) ;
2018-09-29 20:47:18 +00:00
}
2018-10-03 23:56:02 +00:00
pxy_log_dbg_disconnect ( ctx ) ;
2018-09-29 20:47:18 +00:00
pxy_disconnect ( bev , ctx , & ctx - > dst , & bufferevent_free_and_close_fd_nonssl , & ctx - > src , 0 ) ;
}
static void
2018-10-05 13:55:02 +00:00
pxy_bev_eventcb_error_srv_dst ( struct bufferevent * bev , pxy_conn_ctx_t * ctx )
2018-09-29 20:47:18 +00:00
{
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " pxy_bev_eventcb_error_srv_dst: BEV_EVENT_ERROR, fd=%d \n " , ctx - > fd ) ;
2018-09-29 20:47:18 +00:00
# endif /* DEBUG_PROXY */
2018-10-05 13:55:02 +00:00
log_err_printf ( " pxy_bev_eventcb_error_srv_dst: Client-side BEV_EVENT_ERROR \n " ) ;
2018-10-05 01:55:24 +00:00
pxy_log_err_ssl_error ( bev , ctx ) ;
ctx - > thr - > errors + + ;
2018-09-29 20:47:18 +00:00
if ( ! ctx - > connected ) {
# ifdef DEBUG_PROXY
2018-10-05 13:55:02 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " pxy_bev_eventcb_error_srv_dst: ERROR !ctx->connected, fd=%d \n " , ctx - > fd ) ;
2018-09-29 20:47:18 +00:00
# endif /* DEBUG_PROXY */
/* the callout to the original destination failed,
* e . g . because it asked for client cert auth , so
* close the accepted socket and clean up */
if ( ctx - > srv_dst . ssl & & ctx - > opts - > passthrough & & bufferevent_get_openssl_error ( bev ) ) {
/* ssl callout failed, fall back to plain TCP passthrough of SSL connection */
log_err_level_printf ( LOG_WARNING , " SSL srv_dst connection failed; falling back to passthrough, fd=%d \n " , ctx - > fd ) ;
2018-10-05 13:55:02 +00:00
pxy_engage_passthrough_mode ( ctx ) ;
2018-09-29 20:47:18 +00:00
return ;
}
pxy_conn_free ( ctx , 0 ) ;
}
}
2018-10-05 01:55:24 +00:00
enum bev_event {
EVENT_CONNECTED = 0 ,
EVENT_EOF = 1 ,
EVENT_ERROR = 2 ,
UNKWN_EVENT = 3 ,
} ;
2018-09-29 20:47:18 +00:00
2018-10-05 01:55:24 +00:00
static enum bev_event
get_event ( short events )
2018-09-29 20:47:18 +00:00
{
if ( events & BEV_EVENT_CONNECTED ) {
2018-10-05 01:55:24 +00:00
return EVENT_CONNECTED ;
2018-09-29 20:47:18 +00:00
} else if ( events & BEV_EVENT_EOF ) {
2018-10-05 01:55:24 +00:00
return EVENT_EOF ;
2018-09-29 20:47:18 +00:00
} else if ( events & BEV_EVENT_ERROR ) {
2018-10-05 01:55:24 +00:00
return EVENT_ERROR ;
} else {
return UNKWN_EVENT ;
2018-09-29 20:47:18 +00:00
}
}
/*
* Callback for meta events on the up - and downstream connection bufferevents .
* Called when EOF has been reached , a connection has been made , and on errors .
*/
static void
pxy_bev_eventcb ( struct bufferevent * bev , short events , void * arg )
{
pxy_conn_ctx_t * ctx = arg ;
ctx - > atime = time ( NULL ) ;
2018-10-05 01:55:24 +00:00
enum bev_event event = get_event ( events ) ;
if ( event ! = UNKWN_EVENT ) {
enum conn_end ce = get_conn_end ( bev , ctx ) ;
if ( ce ! = UNKWN_CONN_END ) {
callback_func_t eventcb = eventcb_funcs [ ctx - > proto ] [ event ] [ ce ] ;
if ( eventcb ) {
eventcb ( bev , ctx ) ;
} else {
log_err_printf ( " pxy_bev_eventcb: NULL eventcb on %d \n " , ce ) ;
}
} else {
log_err_printf ( " pxy_bev_eventcb: UNKWN conn end \n " ) ;
}
2018-09-29 20:47:18 +00:00
} else {
2018-10-05 01:55:24 +00:00
log_err_printf ( " pxy_bev_eventcb: UNKWN event \n " ) ;
2018-09-29 20:47:18 +00:00
}
}
2017-05-29 09:22:23 +00:00
static void
2017-07-07 14:18:01 +00:00
pxy_bev_eventcb_child ( struct bufferevent * bev , short events , void * arg )
2017-05-29 09:22:23 +00:00
{
2017-07-11 22:45:15 +00:00
pxy_conn_child_ctx_t * ctx = arg ;
2014-01-10 11:04:41 +00:00
2018-09-22 23:02:15 +00:00
ctx - > conn - > atime = time ( NULL ) ;
2017-07-10 12:48:57 +00:00
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2017-07-11 22:45:15 +00:00
char * event_name = pxy_get_event_name_child ( bev , ctx ) ;
2018-09-24 00:09:05 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_child: ENTER %s, fd=%d, conn fd=%d \n " , event_name , ctx - > fd , ctx - > conn - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2014-12-13 01:36:45 +00:00
2018-09-27 14:36:52 +00:00
pxy_conn_desc_t * this = ( bev = = ctx - > src . bev ) ? & ctx - > src : & ctx - > dst ;
void ( * this_free_and_close_fd_func ) ( struct bufferevent * , pxy_conn_ctx_t * ) = ( this - > bev = = ctx - > src . bev ) ? & bufferevent_free_and_close_fd_nonssl : & bufferevent_free_and_close_fd ;
2018-09-24 00:09:05 +00:00
2018-09-27 14:36:52 +00:00
pxy_conn_desc_t * other = ( bev = = ctx - > src . bev ) ? & ctx - > dst : & ctx - > src ;
void ( * other_free_and_close_fd_func ) ( struct bufferevent * , pxy_conn_ctx_t * ) = ( other - > bev = = ctx - > dst . bev ) ? & bufferevent_free_and_close_fd : & bufferevent_free_and_close_fd_nonssl ;
2017-07-21 21:44:12 +00:00
2017-05-29 09:22:23 +00:00
if ( events & BEV_EVENT_CONNECTED ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-09-24 00:09:05 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_child: Connected %s, fd=%d, conn fd=%d \n " , event_name , ctx - > fd , ctx - > conn - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-21 21:44:12 +00:00
if ( bev = = ctx - > dst . bev ) {
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-09-26 19:13:07 +00:00
// Check if we have come here right after autossl upgrade, which may be triggered by readcb on src
// 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 ( ctx - > conn - > clienthello_found & & evbuffer_get_length ( bufferevent_get_input ( ctx - > src . bev ) ) ) {
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_child: clienthello_found src inbuf len > 0, Calling pxy_bev_readcb_child for src, fd=%d, conn fd=%d \n " , ctx - > fd , ctx - > conn - > fd ) ;
# endif /* DEBUG_PROXY */
pxy_bev_readcb_child ( ctx - > src . bev , ctx ) ;
}
2017-07-21 21:44:12 +00:00
}
2018-09-22 23:02:15 +00:00
ctx - > conn - > thr - > max_fd = MAX ( ctx - > conn - > thr - > max_fd , MAX ( bufferevent_getfd ( ctx - > src . bev ) , bufferevent_getfd ( ctx - > dst . bev ) ) ) ;
2012-04-13 12:47:30 +00:00
2018-09-24 00:09:05 +00:00
if ( ! ( events & ( BEV_EVENT_EOF | BEV_EVENT_ERROR ) ) ) {
// Do not fall through unless there are other events, otherwise connection is terminated
return ;
}
2017-08-19 22:46:57 +00:00
# ifdef DEBUG_PROXY
2018-09-24 00:09:05 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " pxy_bev_eventcb_child: BEV_EVENT_CONNECTED with %s %s %s, fd=%d, conn fd=%d \n " , event_name ,
( events & BEV_EVENT_EOF ) ? " BEV_EVENT_EOF " : " " , ( events & BEV_EVENT_ERROR ) ? " BEV_EVENT_ERROR " : " " , ctx - > fd , ctx - > conn - > fd ) ;
2017-08-19 22:46:57 +00:00
# endif /* DEBUG_PROXY */
2017-05-29 09:22:23 +00:00
}
2012-04-13 12:47:30 +00:00
2017-07-10 12:48:57 +00:00
if ( events & BEV_EVENT_EOF ) {
2017-07-25 13:07:39 +00:00
# ifdef DEBUG_PROXY
2018-09-24 00:09:05 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_child: EOF %s, fd=%d, conn fd=%d \n " , event_name , ctx - > fd , ctx - > conn - > fd ) ;
2017-08-13 01:36:33 +00:00
2018-09-22 23:02:15 +00:00
if ( OPTS_DEBUG ( ctx - > conn - > opts ) ) {
2017-07-25 13:07:39 +00:00
log_dbg_printf ( " evbuffer size at EOF: "
" i:%zu o:%zu i:%zu o:%zu \n " ,
evbuffer_get_length (
bufferevent_get_input ( bev ) ) ,
evbuffer_get_length (
bufferevent_get_output ( bev ) ) ,
2017-07-28 18:15:22 +00:00
other - > closed ? 0 : evbuffer_get_length (
2017-07-25 13:07:39 +00:00
bufferevent_get_input ( other - > bev ) ) ,
2017-07-28 18:15:22 +00:00
other - > closed ? 0 : evbuffer_get_length (
2017-07-25 13:07:39 +00:00
bufferevent_get_output ( other - > bev ) )
) ;
}
# endif /* DEBUG_PROXY */
2017-07-10 12:48:57 +00:00
// @todo How to handle the following case?
if ( ! ctx - > connected ) {
2017-10-14 22:39:30 +00:00
log_err_level_printf ( LOG_WARNING , " EOF on outbound connection before connection establishment \n " ) ;
2017-08-19 22:46:57 +00:00
# ifdef DEBUG_PROXY
2018-09-24 00:09:05 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " pxy_bev_eventcb_child: EOF on outbound connection before connection establishment, fd=%d, conn fd=%d \n " , ctx - > fd , ctx - > conn - > fd ) ;
2017-08-19 22:46:57 +00:00
# endif /* DEBUG_PROXY */
2017-07-10 12:48:57 +00:00
other - > closed = 1 ;
} else if ( ! other - > closed ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-09-24 00:09:05 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_child: !other->closed, terminate conn, fd=%d, conn fd=%d \n " , ctx - > fd , ctx - > conn - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-25 13:07:39 +00:00
/* if there is data pending in the closed connection,
* handle it here , otherwise it will be lost . */
if ( evbuffer_get_length ( bufferevent_get_input ( bev ) ) ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-09-24 00:09:05 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_child: evbuffer_get_length(inbuf) > 0, terminate conn, fd=%d, conn fd=%d \n " , ctx - > fd , ctx - > conn - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-27 14:50:45 +00:00
pxy_bev_readcb_child ( bev , ctx ) ;
2017-07-25 13:07:39 +00:00
}
/* if the other end is still open and doesn't
* have data to send , close it , otherwise its
* writecb will close it after writing what ' s
* left in the output buffer . */
if ( evbuffer_get_length ( bufferevent_get_output ( other - > bev ) ) = = 0 ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-09-24 00:09:05 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_child: evbuffer_get_length(outbuf) == 0, terminate conn, fd=%d, conn fd=%d \n " , ctx - > fd , ctx - > conn - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-25 13:07:39 +00:00
other - > closed = 1 ;
2018-09-22 23:02:15 +00:00
other_free_and_close_fd_func ( other - > bev , ctx - > conn ) ;
2017-07-25 13:07:39 +00:00
other - > bev = NULL ;
2017-07-10 12:48:57 +00:00
}
}
2017-07-21 21:44:12 +00:00
}
2017-07-10 12:48:57 +00:00
2018-09-24 00:09:05 +00:00
if ( events & BEV_EVENT_ERROR ) {
log_err_printf ( " Server-side BEV_EVENT_ERROR \n " ) ;
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " pxy_bev_eventcb_child: BEV_EVENT_ERROR %s, fd=%d, conn fd=%d \n " , event_name , ctx - > fd , ctx - > conn - > fd ) ;
# endif /* DEBUG_PROXY */
2018-10-03 23:56:02 +00:00
pxy_log_err_ssl_error ( bev , ctx - > conn ) ;
2018-09-24 00:09:05 +00:00
ctx - > conn - > thr - > errors + + ;
if ( ! ctx - > connected ) {
/* the callout to the original destination failed,
* e . g . because it asked for client cert auth , so
* close the accepted socket and clean up */
other - > closed = 1 ;
} else if ( ! other - > closed ) {
/* if the other end is still open and doesn't have data
* to send , close it , otherwise its writecb will close
* it after writing what ' s left in the output buffer */
struct evbuffer * outbuf ;
outbuf = bufferevent_get_output ( other - > bev ) ;
if ( evbuffer_get_length ( outbuf ) = = 0 ) {
other_free_and_close_fd_func ( other - > bev , ctx - > conn ) ;
other - > bev = NULL ;
other - > closed = 1 ;
}
}
}
2017-07-21 21:44:12 +00:00
/* we only get a single disconnect event here for both connections */
2018-09-22 23:02:15 +00:00
if ( OPTS_DEBUG ( ctx - > conn - > opts ) ) {
2018-09-24 00:09:05 +00:00
log_dbg_printf ( " pxy_bev_eventcb_child: %s disconnected to [%s]:%s, fd=%d, conn fd=%d \n " ,
2017-07-21 21:44:12 +00:00
this - > ssl ? " SSL " : " TCP " ,
2018-09-22 23:02:15 +00:00
STRORDASH ( ctx - > conn - > dsthost_str ) , STRORDASH ( ctx - > conn - > dstport_str ) , ctx - > fd , ctx - > conn - > fd ) ;
2018-09-24 00:09:05 +00:00
log_dbg_printf ( " pxy_bev_eventcb_child: %s disconnected from [%s]:%s, fd=%d, conn fd=%d \n " ,
2017-07-21 21:44:12 +00:00
this - > ssl ? " SSL " : " TCP " ,
2018-09-22 23:02:15 +00:00
STRORDASH ( ctx - > conn - > srchost_str ) , STRORDASH ( ctx - > conn - > srcport_str ) , ctx - > fd , ctx - > conn - > fd ) ;
2017-07-21 21:44:12 +00:00
}
2017-07-10 12:48:57 +00:00
2017-07-21 21:44:12 +00:00
this - > closed = 1 ;
2018-09-22 23:02:15 +00:00
this_free_and_close_fd_func ( bev , ctx - > conn ) ;
2017-07-21 21:44:12 +00:00
this - > bev = NULL ;
if ( other - > closed ) {
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
2018-09-24 00:09:05 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_bev_eventcb_child: other->closed, terminate conn, fd=%d, conn fd=%d \n " , ctx - > fd , ctx - > conn - > fd ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-21 21:44:12 +00:00
pxy_conn_free_child ( ctx ) ;
2012-04-13 12:47:30 +00:00
}
}
/*
* Complete the connection . This gets called after finding out where to
* connect to .
*/
static void
pxy_conn_connect ( pxy_conn_ctx_t * ctx )
{
2017-07-16 14:10:18 +00:00
evutil_socket_t fd = ctx - > fd ;
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_conn_connect: ENTER fd=%d \n " , fd ) ;
# endif /* DEBUG_PROXY */
2012-04-13 12:47:30 +00:00
if ( ! ctx - > addrlen ) {
2017-10-14 22:39:30 +00:00
log_err_level_printf ( LOG_CRIT , " No target address; aborting connection \n " ) ;
2017-07-16 14:10:18 +00:00
evutil_closesocket ( fd ) ;
2017-07-25 13:07:39 +00:00
pxy_conn_ctx_free ( ctx , 1 ) ;
2012-04-13 12:47:30 +00:00
return ;
}
2018-09-19 21:52:24 +00:00
if ( ! ctx - > passthrough ) {
ctx - > dst . ssl = NULL ;
ctx - > dst . bev = pxy_bufferevent_setup ( ctx , - 1 , ctx - > dst . ssl ) ;
if ( ! ctx - > dst . bev ) {
log_err_level_printf ( LOG_CRIT , " Error creating parent dst \n " ) ;
evutil_closesocket ( fd ) ;
pxy_conn_ctx_free ( ctx , 1 ) ;
return ;
}
2017-06-29 21:38:37 +00:00
2018-09-19 21:52:24 +00:00
bufferevent_setcb ( ctx - > dst . bev , pxy_bev_readcb , pxy_bev_writecb , pxy_bev_eventcb , ctx ) ;
bufferevent_enable ( ctx - > dst . bev , EV_READ | EV_WRITE ) ;
2017-06-29 21:38:37 +00:00
2018-09-19 21:52:24 +00:00
/* create server-side socket and eventbuffer */
if ( ctx - > spec - > ssl ) {
ctx - > srv_dst . ssl = pxy_dstssl_create ( ctx ) ;
if ( ! ctx - > srv_dst . ssl ) {
log_err_level_printf ( LOG_CRIT , " Error creating SSL for srv_dst \n " ) ;
pxy_conn_free ( ctx , 1 ) ;
return ;
}
2012-04-13 12:47:30 +00:00
}
}
2017-05-29 09:22:23 +00:00
2017-07-12 19:37:36 +00:00
ctx - > srv_dst . bev = pxy_bufferevent_setup ( ctx , - 1 , ctx - > srv_dst . ssl ) ;
if ( ! ctx - > srv_dst . bev ) {
if ( ctx - > srv_dst . ssl ) {
SSL_free ( ctx - > srv_dst . ssl ) ;
ctx - > srv_dst . ssl = NULL ;
2012-04-13 12:47:30 +00:00
}
2017-07-25 13:07:39 +00:00
pxy_conn_free ( ctx , 1 ) ;
2012-04-13 12:47:30 +00:00
return ;
}
2017-07-10 09:27:46 +00:00
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2015-03-15 16:10:25 +00:00
char * host , * port ;
if ( sys_sockaddr_str ( ( struct sockaddr * ) & ctx - > addr ,
ctx - > addrlen , & host , & port ) ! = 0 ) {
log_dbg_printf ( " Connecting to [?]:? \n " ) ;
} else {
log_dbg_printf ( " Connecting to [%s]:%s \n " , host , port ) ;
free ( host ) ;
free ( port ) ;
}
2013-05-26 22:03:05 +00:00
}
2017-07-16 14:10:18 +00:00
// @attention Sometimes dst write cb fires but not event cb, especially if this listener cb is not finished yet, so the conn stalls.
// @todo Why does event cb not fire sometimes?
2017-07-17 09:47:42 +00:00
// @attention BEV_OPT_DEFER_CALLBACKS seems responsible for the issue with srv_dst, libevent acts as if we call event connect() ourselves.
// @see Launching connections on socket-based bufferevents at http://www.wangafu.net/~nickm/libevent-book/Ref6_bufferevent.html
2018-09-26 19:13:07 +00:00
if ( ctx - > passthrough | | ctx - > clienthello_search ) {
// Enable srv_dst r cb for passthrough and autossl modes
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 ) ;
} else {
2018-09-19 21:52:24 +00:00
// Disable and NULL r cb, we do nothing for srv_dst in r cb
bufferevent_setcb ( ctx - > srv_dst . bev , NULL , pxy_bev_writecb , pxy_bev_eventcb , ctx ) ;
bufferevent_enable ( ctx - > srv_dst . bev , EV_WRITE ) ;
}
2017-07-16 14:10:18 +00:00
2012-04-13 12:47:30 +00:00
/* initiate connection */
2017-07-16 14:10:18 +00:00
if ( bufferevent_socket_connect ( ctx - > srv_dst . bev , ( struct sockaddr * ) & ctx - > addr , ctx - > addrlen ) = = - 1 ) {
2017-10-14 22:39:30 +00:00
log_err_level_printf ( LOG_CRIT , " pxy_conn_connect: bufferevent_socket_connect for srv_dst failed \n " ) ;
2017-08-19 22:46:57 +00:00
# ifdef DEBUG_PROXY
2017-08-24 18:52:56 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " pxy_conn_connect: bufferevent_socket_connect for srv_dst failed, fd=%d \n " , fd ) ;
2017-08-19 22:46:57 +00:00
# endif /* DEBUG_PROXY */
2018-07-05 22:09:37 +00:00
// @attention Do not try to close the conn here, otherwise both pxy_conn_connect() and eventcb try to free the conn using pxy_conn_free(),
2017-07-17 09:47:42 +00:00
// they are running on different threads, causing multithreading issues, e.g. signal 10.
// @todo Should we use thrmgr->mutex? Can we?
2017-07-16 14:10:18 +00:00
}
2017-05-29 09:22:23 +00:00
2017-07-16 14:10:18 +00:00
// @attention Do not do anything else with the ctx after connecting socket, otherwise if pxy_bev_eventcb fires on error, such as due to "No route to host",
// the conn is closed and freed up, and we get multithreading issues, e.g. signal 11. We are on the thrmgr thread. So, just return.
2017-06-27 14:09:01 +00:00
}
2012-04-13 12:47:30 +00:00
# ifndef OPENSSL_NO_TLSEXT
/*
* The SNI hostname has been resolved . Fill the first resolved address into
* the context and continue connecting .
*/
static void
pxy_sni_resolve_cb ( int errcode , struct evutil_addrinfo * ai , void * arg )
{
pxy_conn_ctx_t * ctx = arg ;
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_sni_resolve_cb: ENTER fd=%d \n " , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
2012-04-13 12:47:30 +00:00
if ( errcode ) {
2018-09-27 14:36:52 +00:00
log_err_printf ( " Cannot resolve SNI hostname '%s': %s \n " , ctx - > sni , evutil_gai_strerror ( errcode ) ) ;
2017-07-15 01:07:42 +00:00
evutil_closesocket ( ctx - > fd ) ;
2017-07-25 13:07:39 +00:00
pxy_conn_ctx_free ( ctx , 1 ) ;
2012-04-13 12:47:30 +00:00
return ;
}
memcpy ( & ctx - > addr , ai - > ai_addr , ai - > ai_addrlen ) ;
ctx - > addrlen = ai - > ai_addrlen ;
evutil_freeaddrinfo ( ai ) ;
pxy_conn_connect ( ctx ) ;
}
# endif /* !OPENSSL_NO_TLSEXT */
/*
* The src fd is readable . This is used to sneak - preview the SNI on SSL
* connections . If ctx - > ev is NULL , it was called manually for a non - SSL
* connection . If ctx - > passthrough is set , it was called a second time
* after the first ssl callout failed because of client cert auth .
*/
# ifndef OPENSSL_NO_TLSEXT
# define MAYBE_UNUSED
# else /* OPENSSL_NO_TLSEXT */
# define MAYBE_UNUSED UNUSED
# endif /* OPENSSL_NO_TLSEXT */
static void
pxy_fd_readcb ( MAYBE_UNUSED evutil_socket_t fd , UNUSED short what , void * arg )
# undef MAYBE_UNUSED
{
pxy_conn_ctx_t * ctx = arg ;
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_fd_readcb: ENTER fd=%d \n " , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
2012-04-13 12:47:30 +00:00
2017-07-15 10:04:13 +00:00
ctx - > atime = time ( NULL ) ;
2017-06-29 21:38:37 +00:00
2012-04-13 12:47:30 +00:00
# ifndef OPENSSL_NO_TLSEXT
2017-07-12 19:37:36 +00:00
// Child connections will use the sni info obtained by the parent conn
2015-05-17 18:23:25 +00:00
/* for SSL, peek ClientHello and parse SNI from it */
2018-09-27 14:36:52 +00:00
if ( ctx - > spec - > ssl & & ! ctx - > passthrough ) {
2012-04-13 12:47:30 +00:00
unsigned char buf [ 1024 ] ;
ssize_t n ;
2015-05-17 18:23:25 +00:00
const unsigned char * chello ;
int rv ;
2012-04-13 12:47:30 +00:00
n = recv ( fd , buf , sizeof ( buf ) , MSG_PEEK ) ;
if ( n = = - 1 ) {
2017-10-14 22:39:30 +00:00
log_err_printf ( " Error peeking on fd, aborting connection \n " ) ;
2017-08-19 22:46:57 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " ERROR: Error peeking on fd, aborting connection, fd=%d \n " , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
2012-04-13 12:47:30 +00:00
evutil_closesocket ( fd ) ;
2017-07-25 13:07:39 +00:00
pxy_conn_ctx_free ( ctx , 1 ) ;
2012-04-13 12:47:30 +00:00
return ;
}
if ( n = = 0 ) {
/* socket got closed while we were waiting */
2017-10-14 22:39:30 +00:00
log_err_printf ( " Socket got closed while waiting \n " ) ;
2017-08-19 22:46:57 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " ERROR: Socket got closed while waiting, fd=%d \n " , ctx - > fd ) ;
# endif /* DEBUG_PROXY */
2012-04-13 12:47:30 +00:00
evutil_closesocket ( fd ) ;
2017-07-25 13:07:39 +00:00
pxy_conn_ctx_free ( ctx , 1 ) ;
2012-04-13 12:47:30 +00:00
return ;
}
2017-07-15 01:07:42 +00:00
rv = ssl_tls_clienthello_parse ( buf , n , 0 , & chello , & ctx - > sni ) ;
2015-05-17 18:23:25 +00:00
if ( ( rv = = 1 ) & & ! chello ) {
2018-09-27 14:36:52 +00:00
log_err_printf ( " Peeking did not yield a (truncated) ClientHello message, aborting connection \n " ) ;
2017-08-19 22:46:57 +00:00
# ifdef DEBUG_PROXY
2018-09-27 14:36:52 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " ERROR: Peeking did not yield a (truncated) ClientHello message, aborting connection, fd=%d \n " , ctx - > fd ) ;
2017-08-19 22:46:57 +00:00
# endif /* DEBUG_PROXY */
2015-05-17 18:23:25 +00:00
evutil_closesocket ( fd ) ;
2017-07-25 13:07:39 +00:00
pxy_conn_ctx_free ( ctx , 1 ) ;
2015-05-17 18:23:25 +00:00
return ;
}
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2018-09-27 14:36:52 +00:00
log_dbg_printf ( " SNI peek: [%s] [%s], fd=%d \n " , ctx - > sni ? ctx - > sni : " n/a " ,
( ( rv = = 1 ) & & chello ) ? " incomplete " : " complete " , ctx - > fd ) ;
2012-04-13 12:47:30 +00:00
}
2015-05-17 18:23:25 +00:00
if ( ( rv = = 1 ) & & chello & & ( ctx - > sni_peek_retries + + < 50 ) ) {
/* ssl_tls_clienthello_parse indicates that we
2012-04-13 12:47:30 +00:00
* should retry later when we have more data , and we
* haven ' t reached the maximum retry count yet .
* Reschedule this event as timeout - only event in
* order to prevent busy looping over the read event .
* Because we only peeked at the pending bytes and
* never actually read them , fd is still ready for
* reading now . We use 25 * 0.2 s = 5 s timeout . */
struct timeval retry_delay = { 0 , 100 } ;
event_free ( ctx - > ev ) ;
2018-09-27 14:36:52 +00:00
ctx - > ev = event_new ( ctx - > evbase , fd , 0 , pxy_fd_readcb , ctx ) ;
2012-04-13 12:47:30 +00:00
if ( ! ctx - > ev ) {
2017-10-14 22:39:30 +00:00
log_err_level_printf ( LOG_CRIT , " Error creating retry event, aborting connection \n " ) ;
2017-08-19 22:46:57 +00:00
# ifdef DEBUG_PROXY
2017-08-24 18:52:56 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " Error creating retry event, aborting connection, fd=%d \n " , ctx - > fd ) ;
2017-08-19 22:46:57 +00:00
# endif /* DEBUG_PROXY */
2012-04-13 12:47:30 +00:00
evutil_closesocket ( fd ) ;
2017-07-25 13:07:39 +00:00
pxy_conn_ctx_free ( ctx , 1 ) ;
2012-04-13 12:47:30 +00:00
return ;
}
event_add ( ctx - > ev , & retry_delay ) ;
return ;
}
event_free ( ctx - > ev ) ;
ctx - > ev = NULL ;
}
2017-07-15 01:07:42 +00:00
if ( ctx - > sni & & ! ctx - > addrlen & & ctx - > spec - > sni_port ) {
2012-04-13 12:47:30 +00:00
char sniport [ 6 ] ;
struct evutil_addrinfo hints ;
memset ( & hints , 0 , sizeof ( hints ) ) ;
hints . ai_family = ctx - > af ;
hints . ai_flags = EVUTIL_AI_ADDRCONFIG ;
hints . ai_socktype = SOCK_STREAM ;
hints . ai_protocol = IPPROTO_TCP ;
2017-07-15 01:07:42 +00:00
snprintf ( sniport , sizeof ( sniport ) , " %i " , ctx - > spec - > sni_port ) ;
2018-09-27 14:36:52 +00:00
evdns_getaddrinfo ( ctx - > dnsbase , ctx - > sni , sniport , & hints , pxy_sni_resolve_cb , ctx ) ;
2012-04-13 12:47:30 +00:00
return ;
}
# endif /* !OPENSSL_NO_TLSEXT */
pxy_conn_connect ( ctx ) ;
}
/*
* Callback for accept events on the socket listener bufferevent .
* Called when a new incoming connection has been accepted .
* Initiates the connection to the server . The incoming connection
* from the client is not being activated until we have a successful
* connection to the server , because we need the server ' s certificate
* in order to set up the SSL session to the client .
* For consistency , plain TCP works the same way , even if we could
* start reading from the client while waiting on the connection to
* the server to connect .
*/
2017-07-11 22:45:15 +00:00
void
2012-04-13 12:47:30 +00:00
pxy_conn_setup ( evutil_socket_t fd ,
struct sockaddr * peeraddr , int peeraddrlen ,
2017-07-11 22:45:15 +00:00
pxy_thrmgr_ctx_t * thrmgr ,
proxyspec_t * spec , opts_t * opts ,
evutil_socket_t clisock )
2012-04-13 12:47:30 +00:00
{
2018-02-20 17:46:08 +00:00
int dtable_count = getdtablecount ( ) ;
2017-08-13 01:36:33 +00:00
# ifdef DEBUG_PROXY
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_conn_setup: ENTER fd=%d \n " , fd ) ;
2017-05-29 09:22:23 +00:00
2017-07-11 22:45:15 +00:00
char * host , * port ;
2017-08-13 01:36:33 +00:00
if ( sys_sockaddr_str ( peeraddr , peeraddrlen , & host , & port ) = = 0 ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_conn_setup: Peer=[%s]:%s, fd=%d \n " , host , port , fd ) ;
2017-07-11 22:45:15 +00:00
free ( host ) ;
free ( port ) ;
}
2017-09-04 10:05:51 +00:00
2018-02-20 17:46:08 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " pxy_conn_setup: descriptor_table_size=%d, current fd count=%d, reserve=%d \n " , descriptor_table_size , dtable_count , FD_RESERVE ) ;
2017-08-13 01:36:33 +00:00
# endif /* DEBUG_PROXY */
2017-07-11 22:45:15 +00:00
2017-09-04 10:05:51 +00:00
// Close the conn if we are out of file descriptors, or libevent will crash us
2018-07-05 22:09:37 +00:00
// @attention We cannot guess the number of children in a connection at conn setup time. So, FD_RESERVE is just a ball park figure.
// But what if a connection passes the check below, but eventually tries to create more children than FD_RESERVE allows for? This will crash us the same.
// Beware, this applies to all current conns, not just the last connection setup.
// For example, 20x conns pass the check below before creating any children, at which point we reach at the last FD_RESERVE fds,
// then they all start creating children, which crashes us again.
// So, no matter how large an FD_RESERVE we choose, there will always be a risk of running out of fds, if we check the number of fds here only.
// If we are left with less than FD_RESERVE fds, we should not create more children than FD_RESERVE allows for either.
2018-09-24 00:09:05 +00:00
// Therefore, we check if we are out of fds in proxy_listener_acceptcb_child() and close the conn there too.
2018-07-05 22:09:37 +00:00
// @attention These checks are expected to slow us further down, but it is critical to avoid a crash in case we run out of fds.
2018-02-20 17:46:08 +00:00
if ( dtable_count + FD_RESERVE > = descriptor_table_size ) {
2017-09-04 10:05:51 +00:00
errno = EMFILE ;
2017-10-14 22:39:30 +00:00
log_err_level_printf ( LOG_CRIT , " Out of file descriptors \n " ) ;
2017-09-04 10:05:51 +00:00
evutil_closesocket ( fd ) ;
return ;
}
2017-07-14 19:34:15 +00:00
/* create per connection state and attach to thread */
pxy_conn_ctx_t * ctx = pxy_conn_ctx_new ( fd , thrmgr , spec , opts , clisock ) ;
2012-04-13 12:47:30 +00:00
if ( ! ctx ) {
2017-10-14 22:39:30 +00:00
log_err_level_printf ( LOG_CRIT , " Error allocating memory \n " ) ;
2017-07-25 13:07:39 +00:00
evutil_closesocket ( fd ) ;
2017-07-11 22:45:15 +00:00
return ;
2012-04-13 12:47:30 +00:00
}
2017-07-29 21:34:46 +00:00
2012-04-13 12:47:30 +00:00
ctx - > af = peeraddr - > sa_family ;
2017-07-29 21:34:46 +00:00
ctx - > thr - > max_fd = MAX ( ctx - > thr - > max_fd , ctx - > fd ) ;
2012-04-13 12:47:30 +00:00
/* determine original destination of connection */
if ( spec - > natlookup ) {
/* NAT engine lookup */
ctx - > addrlen = sizeof ( struct sockaddr_storage ) ;
2018-09-27 14:36:52 +00:00
if ( spec - > natlookup ( ( struct sockaddr * ) & ctx - > addr , & ctx - > addrlen , fd , peeraddr , peeraddrlen ) = = - 1 ) {
log_err_printf ( " Connection not found in NAT state table, aborting connection \n " ) ;
2012-04-13 12:47:30 +00:00
evutil_closesocket ( fd ) ;
2017-07-25 13:07:39 +00:00
pxy_conn_ctx_free ( ctx , 1 ) ;
2017-07-11 22:45:15 +00:00
return ;
2012-04-13 12:47:30 +00:00
}
} else if ( spec - > connect_addrlen > 0 ) {
/* static forwarding */
ctx - > addrlen = spec - > connect_addrlen ;
memcpy ( & ctx - > addr , & spec - > connect_addr , ctx - > addrlen ) ;
} else {
/* SNI mode */
2017-07-15 01:07:42 +00:00
if ( ! ctx - > spec - > ssl ) {
2012-04-13 12:47:30 +00:00
/* if this happens, the proxyspec parser is broken */
2018-09-27 14:36:52 +00:00
log_err_printf ( " SNI mode used for non-SSL connection; aborting connection \n " ) ;
2012-04-13 12:47:30 +00:00
evutil_closesocket ( fd ) ;
2017-07-25 13:07:39 +00:00
pxy_conn_ctx_free ( ctx , 1 ) ;
2017-07-11 22:45:15 +00:00
return ;
2012-04-13 12:47:30 +00:00
}
}
2018-09-27 14:36:52 +00:00
if ( sys_sockaddr_str ( peeraddr , peeraddrlen , & ctx - > srchost_str , & ctx - > srcport_str ) ! = 0 ) {
2017-08-11 13:53:46 +00:00
goto memout ;
}
2017-07-11 22:45:15 +00:00
/* prepare logging, part 1 */
if ( WANT_CONNECT_LOG ( ctx ) | | WANT_CONTENT_LOG ( ctx ) ) {
# ifdef HAVE_LOCAL_PROCINFO
2017-07-15 01:07:42 +00:00
if ( ctx - > opts - > lprocinfo ) {
2017-07-11 22:45:15 +00:00
memcpy ( & ctx - > lproc . srcaddr , peeraddr , peeraddrlen ) ;
ctx - > lproc . srcaddrlen = peeraddrlen ;
}
# endif /* HAVE_LOCAL_PROCINFO */
}
2017-06-10 18:50:03 +00:00
/* for SSL, defer dst connection setup to initial_readcb */
2017-07-15 01:07:42 +00:00
if ( ctx - > spec - > ssl ) {
ctx - > ev = event_new ( ctx - > evbase , fd , EV_READ , pxy_fd_readcb , ctx ) ;
2017-06-27 14:09:01 +00:00
if ( ! ctx - > ev )
2017-07-11 22:45:15 +00:00
goto memout ;
2017-06-10 18:50:03 +00:00
event_add ( ctx - > ev , NULL ) ;
} else {
pxy_fd_readcb ( fd , 0 , ctx ) ;
}
2017-07-12 13:46:51 +00:00
return ;
2017-06-27 14:09:01 +00:00
2017-07-11 22:45:15 +00:00
memout :
2017-10-14 22:39:30 +00:00
log_err_level_printf ( LOG_CRIT , " Aborting connection setup (out of memory)! \n " ) ;
2017-07-11 22:45:15 +00:00
evutil_closesocket ( fd ) ;
2017-07-25 13:07:39 +00:00
pxy_conn_ctx_free ( ctx , 1 ) ;
2017-05-29 09:22:23 +00:00
}
2017-07-07 14:18:01 +00:00
2018-10-05 01:55:24 +00:00
callback_func_t readcb_funcs [ ] [ 3 ] = {
/* SRC, DST, SRV_DST */
{ pxy_bev_readcb_passthrough_src , NULL , pxy_bev_readcb_passthrough_srv_dst } , /* PASSTHROUGH */
{ pxy_bev_readcb_http_src , pxy_bev_readcb_http_dst , pxy_bev_readcb_http_srv_dst } , /* HTTP */
{ pxy_bev_readcb_autossl_src , pxy_bev_readcb_autossl_dst , pxy_bev_readcb_autossl_srv_dst } , /* AUTOSSL */
2018-10-05 13:55:02 +00:00
{ pxy_bev_readcb_src , pxy_bev_readcb_dst , pxy_bev_readcb_srv_dst } , /* DEFAULT */
2018-10-05 01:55:24 +00:00
} ;
callback_func_t writecb_funcs [ ] [ 3 ] = {
/* SRC, DST, SRV_DST */
{ pxy_bev_writecb_passthrough_src , NULL , pxy_bev_writecb_passthrough_srv_dst } , /* PASSTHROUGH */
2018-10-05 13:55:02 +00:00
{ pxy_bev_writecb_src , pxy_bev_writecb_dst , pxy_bev_writecb_srv_dst } , /* HTTP */
{ pxy_bev_writecb_src , pxy_bev_writecb_dst , pxy_bev_writecb_srv_dst } , /* AUTOSSL */
{ pxy_bev_writecb_src , pxy_bev_writecb_dst , pxy_bev_writecb_srv_dst } , /* DEFAULT */
2018-10-05 01:55:24 +00:00
} ;
callback_func_t eventcb_funcs [ ] [ 3 ] [ 3 ] = {
{ /* PASSTHROUGH */
/* SRC, DST, SRV_DST */
2018-10-05 13:55:02 +00:00
{ pxy_bev_eventcb_passthrough_connected_src , NULL , pxy_bev_eventcb_passthrough_connected_srv_dst } , /* BEV_EVENT_CONNECTED */
{ pxy_bev_eventcb_passthrough_eof_src , NULL , pxy_bev_eventcb_passthrough_eof_srv_dst } , /* BEV_EVENT_EOF */
{ pxy_bev_eventcb_passthrough_error_src , NULL , pxy_bev_eventcb_passthrough_error_srv_dst } /* BEV_EVENT_ERROR */
2018-10-05 01:55:24 +00:00
} ,
{ /* HTTP */
2018-10-05 13:55:02 +00:00
{ pxy_bev_eventcb_connected_src , pxy_bev_eventcb_connected_dst , pxy_bev_eventcb_connected_srv_dst } , /* BEV_EVENT_CONNECTED */
{ pxy_bev_eventcb_eof_src , pxy_bev_eventcb_eof_dst , pxy_bev_eventcb_eof_srv_dst } , /* BEV_EVENT_EOF */
{ pxy_bev_eventcb_error_src , pxy_bev_eventcb_error_dst , pxy_bev_eventcb_error_srv_dst } /* BEV_EVENT_ERROR */
2018-10-05 01:55:24 +00:00
} ,
{ /* AUTOSSL */
2018-10-05 13:55:02 +00:00
{ pxy_bev_eventcb_autssl_connected_src , pxy_bev_eventcb_autssl_connected_dst , pxy_bev_eventcb_autssl_connected_srv_dst } , /* BEV_EVENT_CONNECTED */
{ pxy_bev_eventcb_eof_src , pxy_bev_eventcb_eof_dst , pxy_bev_eventcb_eof_srv_dst } , /* BEV_EVENT_EOF */
{ pxy_bev_eventcb_error_src , pxy_bev_eventcb_error_dst , pxy_bev_eventcb_error_srv_dst } /* BEV_EVENT_ERROR */
2018-10-05 01:55:24 +00:00
} ,
{ /* DEFAULT */
2018-10-05 13:55:02 +00:00
{ pxy_bev_eventcb_connected_src , pxy_bev_eventcb_connected_dst , pxy_bev_eventcb_connected_srv_dst } , /* BEV_EVENT_CONNECTED */
{ pxy_bev_eventcb_eof_src , pxy_bev_eventcb_eof_dst , pxy_bev_eventcb_eof_srv_dst } , /* BEV_EVENT_EOF */
{ pxy_bev_eventcb_error_src , pxy_bev_eventcb_error_dst , pxy_bev_eventcb_error_srv_dst } /* BEV_EVENT_ERROR */
2018-10-05 01:55:24 +00:00
} ,
} ;
2012-04-13 12:47:30 +00:00
/* vim: set noet ft=c: */