2012-04-13 12:47:30 +00:00
/*
2015-02-24 18:19:20 +00:00
* SSLsplit - transparent SSL / TLS interception
2016-03-25 11:19:23 +00:00
* Copyright ( c ) 2009 - 2016 , Daniel Roethlisberger < daniel @ roe . ch >
2012-04-13 12:47:30 +00:00
* All rights reserved .
* http : //www.roe.ch/SSLsplit
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
* 1. Redistributions of source code must retain the above copyright
2015-02-24 18:19:20 +00:00
* notice , this list of conditions , and the following disclaimer .
2012-04-13 12:47:30 +00:00
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` 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 AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
*/
# include "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>
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)
/*
* Print helper for logging code .
*/
2012-04-22 11:36:44 +00:00
# define STRORDASH(x) (((x)&&*(x))?(x):"-")
2012-04-13 12:47:30 +00:00
/*
* 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-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-07-14 19:34:15 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>................... pxy_conn_ctx_new: ENTER fd=%d \n " , fd ) ;
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-07-14 19:34:15 +00:00
log_err_printf ( " Error allocating memory \n " ) ;
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
ctx - > uuid = malloc ( sizeof ( uuid_t ) ) ;
if ( ! ctx - > uuid ) {
free ( ctx ) ;
return NULL ;
}
uuid_create ( ctx - > uuid , NULL ) ;
// @todo Set this switch at compile time
# ifdef OPENBSD
char * uuid_str ;
uuid_to_string ( ctx - > uuid , & uuid_str , NULL ) ;
if ( uuid_str ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>................... pxy_conn_meta_ctx_new: uuid = %s <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< \n " , uuid_str ) ;
free ( uuid_str ) ;
}
# endif /* OPENBSD */
ctx - > fd = fd ;
ctx - > thrmgr = thrmgr ;
ctx - > spec = spec ;
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-07-15 01:07:42 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>................... pxy_conn_ctx_new: EXIT fd=%d \n " , ctx - > fd ) ;
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 )
2017-07-15 01:07:42 +00:00
pxy_conn_ctx_new_child ( evutil_socket_t fd , pxy_conn_ctx_t * parent )
2017-06-25 11:21:32 +00:00
{
2017-07-15 01:07:42 +00:00
assert ( parent ! = NULL ) ;
2017-06-27 14:09:01 +00:00
2017-07-11 22:45:15 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>................... pxy_conn_ctx_new_child: ENTER fd=%d, sizeof(pxy_conn_child_ctx_t)=%lu \n " , fd , sizeof ( pxy_conn_child_ctx_t ) ) ;
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 ;
2017-07-15 01:07:42 +00:00
ctx - > parent = parent ;
2017-07-04 15:13:34 +00:00
// @attention Child ctxs use the parent's event bases, otherwise we would get multithreading issues
2017-07-15 01:07:42 +00:00
pxy_thrmgr_attach_child ( parent ) ;
2017-06-25 11:21:32 +00:00
# ifdef DEBUG_PROXY
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( parent - > 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 */
2017-07-07 14:18:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>................... pxy_conn_ctx_new_child: EXIT fd=%d \n " , fd ) ;
2017-06-25 11:21:32 +00:00
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
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > parent - > opts ) ) {
2017-07-14 19:34:15 +00:00
log_dbg_printf ( " %p pxy_conn_ctx_free_child \n " ,
( void * ) ctx ) ;
}
# endif /* DEBUG_PROXY */
2017-07-15 01:07:42 +00:00
pxy_thrmgr_detach_child ( ctx - > parent ) ;
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 ) ;
}
2017-07-15 01:07:42 +00:00
if ( WANT_CONTENT_LOG ( ctx - > parent ) & & ctx - > logctx ) {
2017-07-14 19:34:15 +00:00
if ( log_content_close ( & ctx - > logctx ) = = - 1 ) {
log_err_printf ( " Warning: Content log close failed \n " ) ;
}
}
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 ) ;
SSL * ssl = NULL ;
2017-07-15 01:07:42 +00:00
if ( ctx - > spec - > ssl & & ! 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-07-14 19:34:15 +00:00
log_dbg_printf ( " %p free_and_close_fd = %d \n " ,
( 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 ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >############################# bufferevent_free_and_close_fd: calling pxy_ssl_shutdown, fd=%d \n " , fd ) ;
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 ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >############################# bufferevent_free_and_close_fd: evutil_closesocket FAILED, fd=%d \n " , fd ) ;
} else {
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >############################# bufferevent_free_and_close_fd: evutil_closesocket SUCCESS, fd=%d \n " , fd ) ;
}
}
}
/*
* Free bufferenvent and close underlying socket properly .
* This is for non - OpenSSL bufferevents .
*/
static void
2017-07-15 01:07:42 +00:00
bufferevent_free_and_close_fd_nonssl ( struct bufferevent * bev , 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-07-14 19:34:15 +00:00
log_dbg_printf ( " %p free_and_close_fd = %d \n " ,
( void * ) bev , fd ) ;
}
# endif /* DEBUG_PROXY */
bufferevent_free ( bev ) ; /* does not free SSL unless the option
BEV_OPT_CLOSE_ON_FREE was set */
if ( evutil_closesocket ( fd ) = = - 1 ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >----------------------------- bufferevent_free_and_close_fd_nonssl: evutil_closesocket FAILED, fd=%d \n " , fd ) ;
} else {
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >----------------------------- bufferevent_free_and_close_fd_nonssl: evutil_closesocket SUCCESS, fd=%d \n " , fd ) ;
}
}
2017-07-15 10:04:13 +00:00
static void NONNULL ( 1 , 2 )
pxy_conn_remove_child ( pxy_conn_child_ctx_t * child , pxy_conn_child_ctx_t * * head ) {
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 )
{
2017-07-15 01:07:42 +00:00
assert ( ctx - > parent ! = NULL ) ;
2017-07-14 19:34:15 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >############################# pxy_conn_free_child: ENTER \n " ) ;
evutil_socket_t fd = ctx - > fd ;
2017-07-15 01:07:42 +00:00
pxy_conn_ctx_t * parent = ctx - > parent ;
2017-07-14 19:34:15 +00:00
pxy_conn_desc_t * dst = & ctx - > dst ;
if ( dst - > bev ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " >############################# pxy_conn_free_child: evutil_closesocket dst->bev, fd=%d \n " , bufferevent_getfd ( dst - > bev ) ) ;
2017-07-15 01:07:42 +00:00
bufferevent_free_and_close_fd ( dst - > bev , ctx - > parent ) ;
2017-07-14 19:34:15 +00:00
dst - > bev = NULL ;
}
pxy_conn_desc_t * src = & ctx - > src ;
if ( src - > bev ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " >############################# pxy_conn_free_child: evutil_closesocket src->bev, fd=%d \n " , bufferevent_getfd ( src - > bev ) ) ;
2017-07-15 01:07:42 +00:00
bufferevent_free_and_close_fd_nonssl ( src - > bev , ctx - > parent ) ;
2017-07-14 19:34:15 +00:00
src - > bev = NULL ;
}
2017-07-15 10:04:13 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >############################# pxy_conn_free_child: pxy_conn_remove_child \n " ) ;
pxy_conn_remove_child ( ctx , & parent - > children ) ;
2017-07-14 19:34:15 +00:00
2017-07-15 01:07:42 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >############################# pxy_conn_free_child: FREEING CTX, fd=%d, parent fd=%d \n " , fd , parent - > fd ) ;
2017-07-14 19:34:15 +00:00
pxy_conn_ctx_free_child ( ctx ) ;
2017-07-15 10:04:13 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " >############################# pxy_conn_free_child: EXIT, fd=%d, parent fd=%d \n " , fd , parent - > fd ) ;
2017-07-14 19:34:15 +00:00
}
2014-12-13 01:36:45 +00:00
static void NONNULL ( 1 )
2012-04-13 12:47:30 +00:00
pxy_conn_ctx_free ( pxy_conn_ctx_t * ctx )
{
# 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_conn_ctx_free \n " ,
( void * ) ctx ) ;
}
# endif /* DEBUG_PROXY */
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 ) ;
}
2014-11-27 22:19:54 +00:00
if ( WANT_CONTENT_LOG ( ctx ) & & ctx - > logctx ) {
2014-11-21 16:42:10 +00:00
if ( log_content_close ( & ctx - > logctx ) = = - 1 ) {
log_err_printf ( " Warning: Content log close failed \n " ) ;
}
2012-04-13 12:47:30 +00:00
}
2017-07-15 01:07:42 +00:00
if ( ctx - > uuid ) {
free ( ctx - > uuid ) ;
2017-06-25 11:21:32 +00:00
}
2017-07-15 01:07:42 +00:00
if ( ctx - > sni ) {
free ( ctx - > sni ) ;
2017-06-25 11:21:32 +00:00
}
2017-07-15 01:07:42 +00:00
if ( ctx - > child_addr ) {
free ( ctx - > child_addr ) ;
}
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-14 19:34:15 +00:00
pxy_conn_free ( pxy_conn_ctx_t * ctx )
2017-07-01 15:08:28 +00:00
{
2017-07-15 01:07:42 +00:00
evutil_socket_t fd = ctx - > fd ;
evutil_socket_t child_fd = ctx - > child_fd ;
2017-07-14 19:34:15 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " >############################# pxy_conn_free: ENTER, fd=%d, child_fd=%d \n " , fd , child_fd ) ;
pxy_conn_desc_t * src = & ctx - > src ;
if ( ! src - > closed ) {
if ( src - > bev ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " >############################# pxy_conn_free: bufferevent_free_and_close_fd src->bev, fd=%d \n " , bufferevent_getfd ( 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 {
// @todo src fd may be open, although src.bev is NULL, where do we close the src fd?
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >############################# pxy_conn_free: evutil_closesocket on NULL src->bev, fd=%d \n " , 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 ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " >############################# pxy_conn_free: bufferevent_free_and_close_fd srv_dst->bev, fd=%d \n " , bufferevent_getfd ( 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 ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " >############################# pxy_conn_free: bufferevent_free_and_close_fd dst->bev, fd=%d \n " , bufferevent_getfd ( 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
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >############################# pxy_conn_free: FREEING Children, fd=%d, child_fd=%d \n " , fd , child_fd ) ;
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 ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >############################# pxy_conn_free: FREEING child_evcl, pfd=%d, child_fd=%d, cfd=%d \n " ,
ctx - > fd , ctx - > child_fd , ctx - > children ? ctx - > children - > fd : - 1 ) ;
// @attention child_evcl was created with LEV_OPT_CLOSE_ON_FREE, so no need to close ctx->child_fd
evconnlistener_free ( ctx - > child_evcl ) ;
ctx - > child_evcl = NULL ;
2017-07-15 01:07:42 +00:00
}
2017-07-14 19:34:15 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >############################# pxy_conn_free: FREEING ctx, fd=%d, child_fd=%d \n " , fd , child_fd ) ;
pxy_conn_ctx_free ( ctx ) ;
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " >############################# pxy_conn_free: EXIT, fd=%d, child_fd=%d \n " , fd , child_fd ) ;
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 * ) ;
static SSL_SESSION * pxy_ossl_sessget_cb ( SSL * , unsigned char * , int , int * ) ;
/*
* 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 ) ) ) {
2012-04-13 12:47:30 +00:00
log_err_printf ( " Warning: Error generating X509 fingerprint \n " ) ;
} 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 */
2016-03-27 11:49:50 +00:00
if ( ! ctx - > src . ssl ) {
2015-03-15 16:10:25 +00:00
rv = asprintf ( & msg , " %s %s %s %s %s "
2014-11-16 19:11:25 +00:00
# ifdef HAVE_LOCAL_PROCINFO
" %s "
# endif /* HAVE_LOCAL_PROCINFO */
" \n " ,
2017-07-15 01:07:42 +00:00
ctx - > passthrough ? " passthrough " : " 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 {
2016-03-27 11:49:50 +00:00
rv = asprintf ( & msg , " %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 " ,
2016-03-27 11:49:50 +00:00
ctx - > clienthello_found ? " upgrade " : " 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 ) ,
2017-07-15 18:51:20 +00:00
! ctx - > srv_dst . closed ? SSL_get_version ( ctx - > srv_dst . ssl ) : " ? " ,
! ctx - > srv_dst . closed ? SSL_get_cipher ( ctx - > srv_dst . ssl ) : " ? " ,
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 ) {
2012-04-13 12:47:30 +00:00
log_err_printf ( " %s " , msg ) ;
}
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 ) ;
log_err_printf ( " Warning: Connection logging failed \n " ) ;
}
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 ) {
2012-04-13 12:47:30 +00:00
log_err_printf ( " Warning: pxy_log_connect_http called while in "
" 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 */
2017-07-15 01:07:42 +00:00
if ( ! ctx - > spec - > ssl ) {
2015-03-15 16:10:25 +00:00
rv = asprintf ( & msg , " 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 {
2015-03-15 16:10:25 +00:00
rv = asprintf ( & msg , " 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-15 18:51:20 +00:00
! ctx - > srv_dst . closed ? SSL_get_version ( ctx - > srv_dst . ssl ) : " ? " ,
! ctx - > srv_dst . closed ? SSL_get_cipher ( ctx - > srv_dst . ssl ) : " ? " ,
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 ) {
2012-04-13 12:47:30 +00:00
log_err_printf ( " %s " , msg ) ;
}
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 ) ;
log_err_printf ( " Warning: Connection logging failed \n " ) ;
}
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 ) {
log_err_printf ( " Warning: Session resumption denied to SSLv2 "
" 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 *
pxy_ossl_sessget_cb ( UNUSED SSL * ssl , unsigned char * id , int idlen , int * copy )
{
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
2015-07-28 21:23:53 +00:00
/*
* Do not use HAVE_SSLV2 because we need to set SSL_OP_NO_SSLv2 if it
* is available and WITH_SSLV2 was not used .
*/
2014-11-05 19:06:11 +00:00
# ifdef SSL_OP_NO_SSLv2
# ifdef WITH_SSLV2
2017-07-15 01:07:42 +00:00
if ( ctx - > opts - > no_ssl2 ) {
2014-11-05 19:06:11 +00:00
# endif /* WITH_SSLV2 */
SSL_CTX_set_options ( sslctx , SSL_OP_NO_SSLv2 ) ;
# ifdef WITH_SSLV2
}
# endif /* WITH_SSLV2 */
# 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 ) ;
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 ) {
log_err_printf ( " Failed to write used certificate \n " ) ;
}
}
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 ) {
log_err_printf ( " Failed to write orig certificate \n " ) ;
}
}
}
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 ,
2012-04-13 12:47:30 +00:00
ctx - > origcrt , NULL ,
2017-07-15 01:07:42 +00:00
ctx - > opts - > key ) ;
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 */
if ( ! ctx - > immutable_cert & &
! 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 ,
sslcrt , sn , ctx - > opts - > key ) ;
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
2012-04-13 12:47:30 +00:00
SSL_CTX_set_verify ( sslctx , SSL_VERIFY_NONE , NULL ) ;
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-07-01 15:08:28 +00:00
// @todo Use this functions amap
2012-04-13 12:47:30 +00:00
struct bufferevent * bev ;
2017-07-12 13:46:51 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_bufferevent_setup: ENTER fd=%d \n " , ( int ) fd ) ;
2017-05-29 09:22:23 +00:00
2012-04-13 12:47:30 +00:00
if ( ssl ) {
2017-07-12 13:46:51 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_bufferevent_setup: bufferevent_openssl_socket_new <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< SSL \n " ) ;
2017-07-15 01:07:42 +00:00
bev = bufferevent_openssl_socket_new ( ctx - > evbase , fd , ssl ,
2017-06-10 18:50:03 +00:00
( ( fd = = - 1 ) ? BUFFEREVENT_SSL_CONNECTING : BUFFEREVENT_SSL_ACCEPTING ) ,
2012-04-13 12:47:30 +00:00
BEV_OPT_DEFER_CALLBACKS ) ;
} else {
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 ) {
log_err_printf ( " Error creating bufferevent socket \n " ) ;
return NULL ;
}
# if LIBEVENT_VERSION_NUMBER >= 0x02010000
if ( ssl ) {
2017-07-12 13:46:51 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_bufferevent_setup: bufferevent_openssl_set_allow_dirty_shutdown <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< SSL \n " ) ;
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-16 14:10:18 +00:00
// @attention Do not set callbacks here, srv_dst does not set r/w cbs
//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-07-12 13:46:51 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " >>>>> pxy_bufferevent_setup: EXIT fd=%d, bev fd=%d \n " , ( int ) fd , bufferevent_getfd ( bev ) ) ;
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
{
struct bufferevent * bev ;
2017-07-12 13:46:51 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_bufferevent_setup_child: ENTER %d \n " , ( int ) fd ) ;
2017-05-29 09:22:23 +00:00
2017-06-10 18:50:03 +00:00
if ( ssl ) {
2017-07-12 21:45:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_bufferevent_setup_child: bufferevent_openssl_socket_new <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< SSL child \n " ) ;
2017-07-15 01:07:42 +00:00
bev = bufferevent_openssl_socket_new ( ctx - > parent - > evbase , fd , ssl ,
2017-06-10 18:50:03 +00:00
( ( fd = = - 1 ) ? BUFFEREVENT_SSL_CONNECTING : BUFFEREVENT_SSL_ACCEPTING ) , BEV_OPT_DEFER_CALLBACKS ) ;
} else {
2017-07-15 01:07:42 +00:00
bev = bufferevent_socket_new ( ctx - > parent - > evbase , fd , BEV_OPT_DEFER_CALLBACKS ) ;
2017-06-10 18:50:03 +00:00
}
2017-05-29 09:22:23 +00:00
if ( ! bev ) {
log_err_printf ( " Error creating bufferevent socket \n " ) ;
return NULL ;
}
2017-07-03 23:12:17 +00:00
# if LIBEVENT_VERSION_NUMBER >= 0x02010000
if ( ssl ) {
2017-07-12 21:45:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_bufferevent_setup_child: bufferevent_openssl_set_allow_dirty_shutdown <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< SSL child \n " ) ;
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
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_bufferevent_setup_child: set callback for bev \n " ) ;
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
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > parent - > 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 */
2017-07-12 13:46:51 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " >>>>> pxy_bufferevent_setup_child: EXIT %d \n " , ( int ) fd ) ;
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 *
2013-06-29 20:35:51 +00:00
pxy_http_reqhdr_filter_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 ;
}
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 ;
2014-10-28 22:31:07 +00:00
} else if ( ! strncasecmp ( line , " Accept-Encoding: " , 16 ) | |
! strncasecmp ( line , " Keep-Alive: " , 11 ) ) {
2012-04-13 12:47:30 +00:00
return NULL ;
} 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 *
pxy_http_resphdr_filter_line ( const char * line , pxy_conn_ctx_t * ctx )
{
/* 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 ) | |
/* Alternate Protocol
* remove to prevent switching to QUIC , SPDY et al */
2014-10-28 22:31:07 +00:00
! strncasecmp ( line , " Alternate-Protocol: " , 19 ) ) {
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 ;
}
/*
* 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
pxy_ocsp_deny ( pxy_conn_ctx_t * ctx )
{
struct evbuffer * inbuf , * outbuf ;
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) */
if ( ! ctx - > http_method )
return ;
if ( ! strncasecmp ( ctx - > http_method , " GET " , 3 ) & &
2012-05-02 13:00:22 +00:00
pxy_ocsp_is_valid_uri ( ctx - > http_uri , ctx ) )
2012-04-22 17:12:38 +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 ) {
if ( WANT_CONTENT_LOG ( ctx ) ) {
logbuf_t * lb ;
lb = logbuf_new_alloc ( evbuffer_get_length ( inbuf ) ,
2014-11-21 15:10:37 +00:00
NULL , NULL ) ;
2012-04-22 17:12:38 +00:00
if ( lb & &
( evbuffer_copyout ( inbuf , lb - > buf , lb - > sz ) ! = - 1 ) ) {
2014-11-21 16:42:10 +00:00
if ( log_content_submit ( ctx - > logctx , lb ,
1 /*req*/ ) = = - 1 ) {
logbuf_free ( lb ) ;
log_err_printf ( " Warning: Content log "
" submission failed \n " ) ;
}
2012-04-22 17:12:38 +00:00
}
}
evbuffer_drain ( inbuf , evbuffer_get_length ( inbuf ) ) ;
}
2017-07-15 01:07:42 +00:00
bufferevent_free_and_close_fd ( ctx - > srv_dst . bev , ctx ) ;
2017-07-12 19:37:36 +00:00
ctx - > srv_dst . bev = NULL ;
ctx - > srv_dst . closed = 1 ;
2012-04-22 17:12:38 +00:00
evbuffer_add_printf ( outbuf , ocspresp ) ;
ctx - > ocsp_denied = 1 ;
if ( WANT_CONTENT_LOG ( ctx ) ) {
logbuf_t * lb ;
2014-11-21 15:10:37 +00:00
lb = logbuf_new_copy ( ocspresp , sizeof ( ocspresp ) - 1 ,
NULL , NULL ) ;
2012-04-22 17:12:38 +00:00
if ( lb ) {
2014-11-21 16:42:10 +00:00
if ( log_content_submit ( ctx - > logctx , lb ,
0 /*resp*/ ) = = - 1 ) {
logbuf_free ( lb ) ;
log_err_printf ( " Warning: Content log "
" submission failed \n " ) ;
}
2012-04-22 17:12:38 +00:00
}
}
}
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 ;
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 " ) ;
}
/* 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 ) ) {
2016-03-27 11:26:39 +00:00
if ( ssl_tls_clienthello_parse ( vec_out [ 0 ] . iov_base ,
vec_out [ 0 ] . iov_len ,
2017-07-15 01:07:42 +00:00
0 , & chello , & ctx - > sni ) = = 0 ) {
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
}
2017-07-12 19:37:36 +00:00
ctx - > srv_dst . ssl = pxy_dstssl_create ( ctx ) ;
if ( ! ctx - > srv_dst . ssl ) {
2016-03-27 11:26:39 +00:00
log_err_printf ( " Error creating SSL for "
" upgrade \n " ) ;
2015-04-18 12:26:03 +00:00
return 0 ;
}
2017-07-12 19:37:36 +00:00
ctx - > srv_dst . bev = bufferevent_openssl_filter_new (
2017-07-15 01:07:42 +00:00
ctx - > evbase , ctx - > srv_dst . bev , ctx - > srv_dst . ssl ,
2016-03-27 11:26:39 +00:00
BUFFEREVENT_SSL_CONNECTING , 0 ) ;
2017-07-12 19:37:36 +00:00
bufferevent_setcb ( ctx - > srv_dst . bev , pxy_bev_readcb ,
2016-03-27 11:26:39 +00:00
pxy_bev_writecb , pxy_bev_eventcb ,
ctx ) ;
2017-07-12 13:46:51 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>----------------------- pxy_conn_autossl_peek_and_upgrade: bufferevent_enable \n " ) ;
2017-07-12 19:37:36 +00:00
bufferevent_enable ( ctx - > srv_dst . bev , EV_READ | EV_WRITE ) ;
if ( ! ctx - > srv_dst . bev ) {
2015-04-18 12:26:03 +00:00
return 0 ;
}
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2017-07-14 19:34:15 +00:00
log_err_printf ( " Replaced dst bufferevent, new "
" one is %p \n " , ( void * ) ctx - > srv_dst . bev ) ;
}
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-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-07-05 22:58:21 +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-07-05 22:58:21 +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-07-12 21:45:12 +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-07-12 21:45:12 +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
}
}
2012-04-13 12:47:30 +00:00
/*
2015-04-18 10:51:28 +00:00
* Callback for read events on the up - and downstream connection bufferevents .
2012-04-13 12:47:30 +00:00
* 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 ;
2017-06-27 14:09:01 +00:00
2017-07-15 01:07:42 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>,,,,,,,,,,,,,,,,,,,,,,, pxy_bev_readcb: ENTER fd=%d, child_fd=%d \n " , ctx - > fd , ctx - > child_fd ) ;
2017-06-29 21:38:37 +00:00
2017-07-15 10:04:13 +00:00
ctx - > atime = time ( NULL ) ;
2017-06-30 21:29:39 +00:00
2017-07-05 19:32:10 +00:00
char * event_name = pxy_get_event_name ( bev , ctx ) ;
2017-07-15 01:07:42 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>,,,,,,,,,,,,,,,,,,,,,,, pxy_bev_readcb: %s, fd=%d \n " , event_name , ctx - > fd ) ;
2017-05-29 09:22:23 +00:00
if ( bev = = ctx - > src . bev ) {
2017-06-10 18:50:03 +00:00
if ( ctx - > clienthello_search ) {
if ( pxy_conn_autossl_peek_and_upgrade ( ctx ) ) {
2017-06-15 16:07:37 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>,,,,,,,,,,,,,,,,,,,,,,, pxy_bev_readcb: pxy_conn_autossl_peek_and_upgrade RETURNS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< SSL \n " ) ;
2017-06-10 18:50:03 +00:00
return ;
}
}
2017-07-10 09:27:46 +00:00
struct evbuffer * inbuf = bufferevent_get_input ( bev ) ;
2017-05-29 09:22:23 +00:00
2017-07-12 19:37:36 +00:00
if ( ctx - > dst . closed ) {
2017-07-10 09:27:46 +00:00
evbuffer_drain ( inbuf , evbuffer_get_length ( inbuf ) ) ;
goto leave ;
}
2017-05-29 09:22:23 +00:00
2017-07-12 19:37:36 +00:00
if ( ctx - > dst . bev ) {
2017-05-29 09:22:23 +00:00
char * custom_key = " \r \n SSLproxy-Addr: " ;
2017-07-15 01:07:42 +00:00
size_t custom_field_len = strlen ( custom_key ) + strlen ( ctx - > child_addr ) + 1 ;
2017-05-29 09:22:23 +00:00
2017-07-12 21:45:12 +00:00
// @todo Check malloc retvals? Should we close the conn if malloc fails?
2017-05-29 09:22:23 +00:00
char * custom_field = malloc ( custom_field_len ) ;
2017-07-15 01:07:42 +00:00
snprintf ( custom_field , custom_field_len , " %s%s " , custom_key , ctx - > child_addr ) ;
2017-05-29 09:22:23 +00:00
2017-06-15 16:07:37 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " >>>>>,,,,,,,,,,,,,,,,,,,,,,, pxy_bev_readcb: custom_field= %s \n " , custom_field ) ;
2017-05-29 09:22:23 +00:00
size_t packet_size = evbuffer_get_length ( inbuf ) ;
char * packet = malloc ( packet_size + custom_field_len ) ;
if ( ! packet ) {
ctx - > enomem = 1 ;
2017-07-05 19:32:10 +00:00
free ( custom_field ) ;
2017-05-29 09:22:23 +00:00
goto leave ;
}
int bytes_read = evbuffer_remove ( inbuf , packet , packet_size ) ;
if ( bytes_read < 0 ) {
log_err_printf ( " ERROR: evbuffer_remove cannot drain the buffer \n " ) ;
}
2017-06-15 16:07:37 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>,,,,,,,,,,,,,,,,,,,,,,, pxy_bev_readcb: src ORIG packet (size = %d), fd=%d: \n %.*s \n " ,
2017-07-15 01:07:42 +00:00
( int ) packet_size , ctx - > fd , ( int ) packet_size , packet ) ;
2017-05-29 09:22:23 +00:00
packet [ packet_size ] = ' \0 ' ;
packet_size + = custom_field_len ;
2017-06-13 09:42:10 +00:00
// XXX: We insert our special header line to each packet we get, right after the first \r\n, hence the target may get multiple copies
2017-06-25 11:21:32 +00:00
// TODO: To insert our header line to the first packet only, should we look for GET/POST or Host header lines to detect the first packet?
2017-06-13 09:42:10 +00:00
// But there is no guarantie 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
char * pos2 = strstr ( packet , " \r \n " ) ;
if ( pos2 ) {
char * header_tail = strdup ( pos2 ) ;
int header_head_len = pos2 - packet ;
char * header_head = malloc ( header_head_len + 1 ) ;
strncpy ( header_head , packet , header_head_len ) ;
header_head [ header_head_len ] = ' \0 ' ;
snprintf ( packet , packet_size , " %s%s%s " , header_head , custom_field , header_tail ) ;
free ( header_head ) ;
free ( header_tail ) ;
} else {
2017-07-10 14:26:58 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>,,,,,,,,,,,,,,,,,,,,,,, pxy_bev_readcb: No CRLF in packet \n " ) ;
2017-06-13 09:42:10 +00:00
packet_size - = custom_field_len ;
packet_size + + ;
2017-05-29 09:22:23 +00:00
}
2017-06-13 09:42:10 +00:00
2017-05-29 09:22:23 +00:00
free ( custom_field ) ;
2017-07-12 19:37:36 +00:00
struct evbuffer * outbuf = bufferevent_get_output ( ctx - > dst . bev ) ;
2017-05-29 09:22:23 +00:00
2017-06-13 09:42:10 +00:00
// Decrement packet_size to avoid copying the null termination
2017-07-05 19:32:10 +00:00
int add_result = evbuffer_add ( outbuf , packet , packet_size - 1 ) ;
2017-05-29 09:22:23 +00:00
if ( add_result < 0 ) {
log_err_printf ( " ERROR: evbuffer_add failed \n " ) ;
}
2012-04-13 12:47:30 +00:00
2017-07-05 19:32:10 +00:00
if ( evbuffer_get_length ( outbuf ) > = OUTBUF_LIMIT ) {
/* temporarily disable data source;
* set an appropriate watermark . */
2017-07-12 21:45:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>,,,,,,,,,,,,,,,,,,,,,,, pxy_bev_readcb: setwatermark for dst w, disable src r <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< WATERMARK \n " ) ;
2017-07-12 19:37:36 +00:00
bufferevent_setwatermark ( ctx - > dst . bev , EV_WRITE , OUTBUF_LIMIT / 2 , OUTBUF_LIMIT ) ;
2017-07-05 19:32:10 +00:00
bufferevent_disable ( ctx - > src . bev , EV_READ ) ;
}
2017-06-15 16:07:37 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>,,,,,,,,,,,,,,,,,,,,,,, pxy_bev_readcb: src packet (size = %d), fd=%d: \n %.*s \n " ,
2017-07-15 01:07:42 +00:00
( int ) packet_size , ctx - > fd , ( int ) packet_size , packet ) ;
2017-06-15 16:07:37 +00:00
// log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>>,,,,,,,,,,,,,,,,,,,,,,, pxy_bev_readcb: src packet (size = %d)\n", (int) packet_size);
2017-05-29 09:22:23 +00:00
free ( packet ) ;
} else {
2017-07-12 21:45:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>,,,,,,,,,,,,,,,,,,,,,,, pxy_bev_readcb: src ctx->dst.bev NULL \n " ) ;
2017-05-29 09:22:23 +00:00
}
2012-04-13 12:47:30 +00:00
}
2017-07-12 19:37:36 +00:00
else if ( bev = = ctx - > dst . bev ) {
2017-07-10 09:27:46 +00:00
struct evbuffer * inbuf = bufferevent_get_input ( bev ) ;
2012-04-13 12:47:30 +00:00
2017-07-10 09:27:46 +00:00
if ( ctx - > src . closed ) {
evbuffer_drain ( inbuf , evbuffer_get_length ( inbuf ) ) ;
goto leave ;
}
2017-07-05 19:32:10 +00:00
2017-07-10 09:27:46 +00:00
if ( ctx - > src . bev ) {
2017-05-29 09:22:23 +00:00
size_t packet_size = evbuffer_get_length ( inbuf ) ;
char * packet = malloc ( packet_size ) ;
if ( ! packet ) {
ctx - > enomem = 1 ;
goto leave ;
}
int bytes_read = evbuffer_remove ( inbuf , packet , packet_size ) ;
if ( bytes_read < 0 ) {
log_err_printf ( " ERROR: evbuffer_remove cannot drain the buffer \n " ) ;
}
struct evbuffer * outbuf = bufferevent_get_output ( ctx - > src . bev ) ;
int add_result = evbuffer_add ( outbuf , packet , packet_size ) ;
if ( add_result < 0 ) {
log_err_printf ( " ERROR: evbuffer_add failed \n " ) ;
}
2017-07-05 19:32:10 +00:00
if ( evbuffer_get_length ( outbuf ) > = OUTBUF_LIMIT ) {
/* temporarily disable data source;
* set an appropriate watermark . */
2017-07-12 21:45:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>,,,,,,,,,,,,,,,,,,,,,,, pxy_bev_readcb: setwatermark for src w, disable dst r <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< WATERMARK \n " ) ;
2017-07-05 19:32:10 +00:00
bufferevent_setwatermark ( ctx - > src . bev , EV_WRITE , OUTBUF_LIMIT / 2 , OUTBUF_LIMIT ) ;
2017-07-12 19:37:36 +00:00
bufferevent_disable ( ctx - > dst . bev , EV_READ ) ;
2017-07-05 19:32:10 +00:00
}
2017-07-12 21:45:12 +00:00
// log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>>,,,,,,,,,,,,,,,,,,,,,,, pxy_bev_readcb: dst packet (size = %d):\n%.*s\n",
2017-05-29 09:22:23 +00:00
// (int) packet_size, (int) packet_size, packet);
2017-07-12 21:45:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>,,,,,,,,,,,,,,,,,,,,,,, pxy_bev_readcb: dst packet (size = %d) \n " , ( int ) packet_size ) ;
2017-05-29 09:22:23 +00:00
free ( packet ) ;
} else {
2017-07-12 21:45:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>,,,,,,,,,,,,,,,,,,,,,,, pxy_bev_readcb: dst ctx->src.bev NULL \n " ) ;
2015-04-18 12:26:03 +00:00
}
}
2017-05-29 09:22:23 +00:00
leave :
2017-06-15 16:07:37 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>,,,,,,,,,,,,,,,,,,,,,,, pxy_bev_readcb: EXIT \n " ) ;
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-15 01:07:42 +00:00
assert ( ctx - > parent ! = NULL ) ;
2017-06-30 21:29:39 +00:00
2017-07-11 22:45:15 +00:00
char * event_name = pxy_get_event_name_child ( bev , ctx ) ;
2017-07-10 12:48:57 +00:00
2017-07-15 01:07:42 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>....................... pxy_bev_readcb_child: ENTER %s fd=%d, child_fd=%d, cfd=%d \n " , event_name , ctx - > fd , ctx - > parent - > child_fd , ctx - > fd ) ;
2017-07-15 10:04:13 +00:00
ctx - > parent - > atime = time ( NULL ) ;
2017-05-29 09:22:23 +00:00
2017-07-15 01:07:42 +00:00
evutil_socket_t pfd = ctx - > fd ;
2017-05-29 09:22:23 +00:00
struct sockaddr_in peeraddr ;
socklen_t peeraddrlen ;
peeraddrlen = sizeof ( peeraddr ) ;
getpeername ( ctx - > fd , & peeraddr , & peeraddrlen ) ;
2017-07-11 22:45:15 +00:00
if ( bev = = ctx - > src . bev ) {
struct evbuffer * inbuf = bufferevent_get_input ( ctx - > src . bev ) ;
2017-05-29 09:22:23 +00:00
2017-07-10 09:27:46 +00:00
if ( ctx - > dst . closed ) {
evbuffer_drain ( inbuf , evbuffer_get_length ( inbuf ) ) ;
goto leave ;
}
2017-07-05 19:32:10 +00:00
2017-07-10 09:27:46 +00:00
if ( ctx - > dst . bev ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>.................................................................................... pxy_bev_readcb_child: PEER [%s]:%d <<<<< fd=%d, parent fd=%d \n " , inet_ntoa ( peeraddr . sin_addr ) , ( int ) ntohs ( peeraddr . sin_port ) , ctx - > fd , pfd ) ;
2017-05-29 09:22:23 +00:00
char * custom_key = " SSLproxy-Addr: " ;
2017-07-05 19:32:10 +00:00
struct evbuffer_ptr ebp = evbuffer_search ( inbuf , custom_key , strlen ( custom_key ) , NULL ) ;
2017-05-29 09:22:23 +00:00
if ( ebp . pos ! = - 1 ) {
2017-07-07 14:18:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>....................... pxy_bev_readcb_child: evbuffer_search FOUND SSLproxy-Addr at %ld \n " , ebp . pos ) ;
2017-05-29 09:22:23 +00:00
} else {
2017-07-07 14:18:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>....................... pxy_bev_readcb_child: evbuffer_search FAILED \n " ) ;
2012-04-13 12:47:30 +00:00
}
2017-05-29 09:22:23 +00:00
2017-07-05 19:32:10 +00:00
size_t packet_size = evbuffer_get_length ( inbuf ) ;
2017-06-13 09:42:10 +00:00
// ATTENTION: +1 is for null termination
char * packet = malloc ( packet_size + 1 ) ;
2017-05-29 09:22:23 +00:00
if ( ! packet ) {
ctx - > enomem = 1 ;
goto leave ;
2012-04-13 12:47:30 +00:00
}
2017-05-29 09:22:23 +00:00
2017-07-07 14:18:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>....................... pxy_bev_readcb_child: packet_size \n " ) ;
2017-05-29 09:22:23 +00:00
if ( packet_size > 0 ) {
2017-07-05 19:32:10 +00:00
int bytes_read = evbuffer_remove ( inbuf , packet , packet_size ) ;
2017-05-29 09:22:23 +00:00
if ( bytes_read < 0 ) {
log_err_printf ( " ERROR: evbuffer_remove cannot drain the buffer \n " ) ;
2012-04-22 17:12:38 +00:00
}
2017-05-29 09:22:23 +00:00
2017-06-13 09:42:10 +00:00
packet [ packet_size ] = ' \0 ' ;
char * pos = strstr ( packet , " SSLproxy-Addr: " ) ;
if ( pos ) {
int header_head_len = pos - packet ;
char * header_head = malloc ( header_head_len + 1 ) ;
strncpy ( header_head , packet , header_head_len ) ;
header_head [ header_head_len ] = ' \0 ' ;
char * pos2 = strstr ( pos , " \r \n " ) ;
if ( pos2 ) {
char * header_tail = strdup ( pos2 + 2 ) ;
int header_tail_len = strlen ( header_tail ) ;
2017-07-07 14:18:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>....................... pxy_bev_readcb_child: REMOVED SSLproxy-Addr, packet_size old=%lu, new=%d <<<<<<<<<<<<<<<<<<<<<<<<<<<<< \n " ,
2017-06-15 09:00:53 +00:00
packet_size , header_head_len + header_tail_len ) ;
2017-07-07 14:18:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>....................... pxy_bev_readcb_child: header_head (size = %d): \n %s \n " ,
2017-06-15 09:00:53 +00:00
header_head_len , header_head ) ;
2017-07-07 14:18:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>....................... pxy_bev_readcb_child: header_tail (size = %d): \n %s \n " ,
2017-06-15 09:00:53 +00:00
header_tail_len , header_tail ) ;
2017-06-13 09:42:10 +00:00
// ATTENTION: Do not add 1 to packet_size for null termination, do that in snprintf(),
// otherwise we get an extra byte in the outbuf
packet_size = header_head_len + header_tail_len ;
snprintf ( packet , packet_size + 1 , " %s%s " , header_head , header_tail ) ;
free ( header_tail ) ;
}
free ( header_head ) ;
}
2017-07-07 14:18:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>....................... pxy_bev_readcb_child: bufferevent_get_output \n " ) ;
2017-05-29 09:22:23 +00:00
struct evbuffer * outbuf = bufferevent_get_output ( ctx - > dst . bev ) ;
int add_result = evbuffer_add ( outbuf , packet , packet_size ) ;
if ( add_result < 0 ) {
log_err_printf ( " ERROR: evbuffer_add failed \n " ) ;
2013-06-29 20:35:51 +00:00
}
2017-07-05 19:32:10 +00:00
if ( evbuffer_get_length ( outbuf ) > = OUTBUF_LIMIT ) {
/* temporarily disable data source;
* set an appropriate watermark . */
2017-07-12 21:45:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>....................... pxy_bev_readcb_child: setwatermark for dst w, disable src r <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< WATERMARK \n " ) ;
2017-07-05 19:32:10 +00:00
bufferevent_setwatermark ( ctx - > dst . bev , EV_WRITE , OUTBUF_LIMIT / 2 , OUTBUF_LIMIT ) ;
2017-07-11 22:45:15 +00:00
bufferevent_disable ( ctx - > src . bev , EV_READ ) ;
2017-07-05 19:32:10 +00:00
}
2017-05-29 09:22:23 +00:00
2017-07-12 21:45:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>....................... pxy_bev_readcb_child: src packet (size = %d), fd=%d, parent fd=%d: \n %.*s \n " ,
2017-05-29 09:22:23 +00:00
( int ) packet_size , ctx - > fd , pfd , ( int ) packet_size , packet ) ;
2017-07-12 21:45:12 +00:00
// log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>>....................... pxy_bev_readcb_child: src packet (size = %d)\n", (int) packet_size);
2013-06-29 20:35:51 +00:00
}
2017-05-29 09:22:23 +00:00
free ( packet ) ;
} else {
2017-07-12 21:45:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>....................... pxy_bev_readcb_child: src ctx->dst.bev NULL \n " ) ;
2017-05-29 09:22:23 +00:00
}
}
else if ( bev = = ctx - > dst . bev ) {
2017-07-10 09:27:46 +00:00
struct evbuffer * inbuf = bufferevent_get_input ( bev ) ;
2017-05-29 09:22:23 +00:00
2017-07-11 22:45:15 +00:00
if ( ctx - > src . closed ) {
2017-07-10 09:27:46 +00:00
evbuffer_drain ( inbuf , evbuffer_get_length ( inbuf ) ) ;
goto leave ;
}
2017-07-05 19:32:10 +00:00
2017-07-11 22:45:15 +00:00
if ( ctx - > src . bev ) {
2017-05-29 09:22:23 +00:00
size_t packet_size = evbuffer_get_length ( inbuf ) ;
char * packet = malloc ( packet_size ) ;
if ( ! packet ) {
ctx - > enomem = 1 ;
goto leave ;
2013-06-29 20:35:51 +00:00
}
2017-05-29 09:22:23 +00:00
int bytes_read = evbuffer_remove ( inbuf , packet , packet_size ) ;
if ( bytes_read < 0 ) {
log_err_printf ( " ERROR: evbuffer_remove cannot drain the buffer \n " ) ;
2012-04-13 12:47:30 +00:00
}
2017-05-29 09:22:23 +00:00
2017-07-11 22:45:15 +00:00
struct evbuffer * outbuf = bufferevent_get_output ( ctx - > src . bev ) ;
2017-05-29 09:22:23 +00:00
2017-07-05 19:32:10 +00:00
int add_result = evbuffer_add ( outbuf , packet , packet_size ) ;
2017-05-29 09:22:23 +00:00
if ( add_result < 0 ) {
log_err_printf ( " ERROR: evbuffer_add failed \n " ) ;
2014-11-21 16:42:10 +00:00
}
2017-05-29 09:22:23 +00:00
2017-07-05 19:32:10 +00:00
if ( evbuffer_get_length ( outbuf ) > = OUTBUF_LIMIT ) {
/* temporarily disable data source;
* set an appropriate watermark . */
2017-07-12 21:45:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>....................... pxy_bev_readcb_child: setwatermark for src w, disable dst r <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< WATERMARK \n " ) ;
2017-07-11 22:45:15 +00:00
bufferevent_setwatermark ( ctx - > src . bev , EV_WRITE , OUTBUF_LIMIT / 2 , OUTBUF_LIMIT ) ;
2017-07-05 19:32:10 +00:00
bufferevent_disable ( ctx - > dst . bev , EV_READ ) ;
}
2017-07-04 15:13:34 +00:00
// @todo Use a hexcode dump to print the packet?
2017-07-07 14:18:01 +00:00
// log_dbg_level_printf(LOG_DBG_MODE_FINEST, ">>>>>....................... pxy_bev_readcb_child: dst packet (size = %d):\n%.*s\n",
2017-05-29 09:22:23 +00:00
// (int) packet_size, (int) packet_size, packet);
2017-07-07 14:18:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>....................... pxy_bev_readcb_child: dst packet (size = %d) \n " , ( int ) packet_size ) ;
2017-05-29 09:22:23 +00:00
free ( packet ) ;
} else {
2017-07-12 21:45:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>....................... pxy_bev_readcb_child: dst ctx->src.bev NULL \n " ) ;
2012-04-13 12:47:30 +00:00
}
}
2017-05-29 09:22:23 +00:00
leave :
2017-07-07 14:18:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>....................... pxy_bev_readcb_child: EXIT \n " ) ;
}
2017-07-14 19:34:15 +00:00
static void
pxy_conn_connect_child ( pxy_conn_child_ctx_t * ctx )
{
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_conn_connect_child: ENTER fd=%d \n " , ctx - > fd ) ;
2017-07-15 01:07:42 +00:00
pxy_conn_ctx_t * parent = ctx - > parent ;
2017-07-14 19:34:15 +00:00
2017-07-15 01:07:42 +00:00
if ( ! parent - > addrlen ) {
2017-07-14 19:34:15 +00:00
log_err_printf ( " Child no target address; aborting connection <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< \n " ) ;
evutil_closesocket ( ctx - > fd ) ;
2017-07-15 01:07:42 +00:00
pxy_conn_free ( parent ) ;
2017-07-14 19:34:15 +00:00
return ;
}
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_conn_connect_child: pxy_bufferevent_setup_child for src.bev, fd=%d \n " , ctx - > fd ) ;
ctx - > src . ssl = NULL ;
ctx - > src . bev = pxy_bufferevent_setup_child ( ctx , ctx - > fd , ctx - > src . ssl ) ;
if ( ! ctx - > src . bev ) {
log_err_printf ( " Error creating child src \n " ) ;
evutil_closesocket ( ctx - > fd ) ;
2017-07-15 01:07:42 +00:00
pxy_conn_free ( parent ) ;
2017-07-14 19:34:15 +00:00
return ;
}
ctx - > src_fd = bufferevent_getfd ( ctx - > src . bev ) ;
2017-07-15 01:07:42 +00:00
parent - > child_src_fd = ctx - > src_fd ;
2017-07-14 19:34:15 +00:00
// @attention Do not enable src events here yet, they will be enabled after dst connects
// @todo Do we need a read watermark for the header line of SSL proxy address?
//bufferevent_setwatermark(ctx->src.bev, EV_READ, 200, OUTBUF_LIMIT);
/* create server-side socket and eventbuffer */
2017-07-15 20:42:22 +00:00
// Children rely on the findings of parent
if ( ( parent - > spec - > ssl | | parent - > clienthello_found ) & & ! parent - > passthrough ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_conn_connect_child: pxy_srcssl_create <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< SSL \n " ) ;
2017-07-15 01:07:42 +00:00
ctx - > dst . ssl = pxy_dstssl_create ( parent ) ;
2017-07-14 19:34:15 +00:00
if ( ! ctx - > dst . ssl ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>> pxy_conn_connect_child: Error creating SSL ctx->dst.ssl, fd=%d \n " , ctx - > fd ) ;
log_err_printf ( " Error creating SSL \n " ) ;
2017-07-15 10:04:13 +00:00
// pxy_conn_free()>pxy_conn_free_child() will close the fd, since we have a non-NULL src.bev now
2017-07-15 01:07:42 +00:00
pxy_conn_free ( parent ) ;
2017-07-14 19:34:15 +00:00
return ;
}
}
2017-07-15 20:42:22 +00:00
if ( parent - > clienthello_found ) {
if ( OPTS_DEBUG ( parent - > opts ) ) {
log_dbg_printf ( " Completing autossl upgrade \n " ) ;
}
ctx - > dst . bev = bufferevent_openssl_filter_new (
parent - > evbase , ctx - > dst . bev , ctx - > dst . ssl ,
BUFFEREVENT_SSL_ACCEPTING ,
BEV_OPT_DEFER_CALLBACKS ) ;
bufferevent_setcb ( ctx - > dst . bev , pxy_bev_readcb_child , pxy_bev_writecb_child , pxy_bev_eventcb_child , ctx ) ;
} else {
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_conn_connect_child: SETUP dst.bev fd=%d \n " , ctx - > fd ) ;
ctx - > dst . bev = pxy_bufferevent_setup_child ( ctx , - 1 , ctx - > dst . ssl ) ;
}
2017-07-14 19:34:15 +00:00
if ( ! ctx - > dst . bev ) {
2017-07-15 20:42:22 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>> pxy_conn_connect_child: dst.bev NULL FREEING \n " ) ;
2017-07-14 19:34:15 +00:00
if ( ctx - > dst . ssl ) {
SSL_free ( ctx - > dst . ssl ) ;
ctx - > dst . ssl = NULL ;
}
2017-07-15 01:07:42 +00:00
pxy_conn_free ( parent ) ;
2017-07-14 19:34:15 +00:00
return ;
}
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_conn_connect_child: <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< bufferevent_enable(ctx->dst.bev) \n " ) ;
bufferevent_enable ( ctx - > dst . bev , EV_READ | EV_WRITE ) ;
/* initiate connection */
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_conn_connect_child: bufferevent_socket_connect dst.bev \n " ) ;
2017-07-15 01:07:42 +00:00
bufferevent_socket_connect ( ctx - > dst . bev , ( struct sockaddr * ) & parent - > addr , parent - > addrlen ) ;
2017-07-14 19:34:15 +00:00
ctx - > dst_fd = bufferevent_getfd ( ctx - > dst . bev ) ;
2017-07-15 01:07:42 +00:00
parent - > child_dst_fd = ctx - > dst_fd ;
2017-07-14 19:34:15 +00:00
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( parent - > opts ) ) {
2017-07-14 19:34:15 +00:00
char * host , * port ;
2017-07-15 01:07:42 +00:00
if ( sys_sockaddr_str ( ( struct sockaddr * ) & parent - > addr , parent - > addrlen , & host , & port ) ! = 0 ) {
2017-07-14 19:34:15 +00:00
log_dbg_printf ( " >>>>> pxy_conn_connect_child: Connecting to [?]:? \n " ) ;
} else {
log_dbg_printf ( " >>>>> pxy_conn_connect_child: Connecting to [%s]:%s \n " , host , port ) ;
free ( host ) ;
free ( port ) ;
}
}
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_conn_connect_child: EXIT fd=%d \n " , ctx - > fd ) ;
}
static void
2017-07-15 01:07:42 +00:00
pxy_conn_setup_child ( evutil_socket_t fd , pxy_conn_ctx_t * parent )
2017-07-14 19:34:15 +00:00
{
// @todo Check and fix any issues with continuing without a parent, e.g. conn list or error clean-up?
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_conn_setup_child: ENTER fd=%d \n " , fd ) ;
2017-07-15 01:07:42 +00:00
pxy_conn_child_ctx_t * ctx = pxy_conn_ctx_new_child ( fd , parent ) ;
2017-07-14 19:34:15 +00:00
if ( ! ctx ) {
log_err_printf ( " Error allocating memory \n " ) ;
evutil_closesocket ( fd ) ;
2017-07-15 01:07:42 +00:00
pxy_conn_free ( parent ) ;
2017-07-14 19:34:15 +00:00
return ;
}
// Prepend ctx to meta ctx child list
// If the last child is deleted, the child_list may become null again
2017-07-15 01:07:42 +00:00
ctx - > next = parent - > children ;
parent - > children = ctx ;
2017-07-14 19:34:15 +00:00
2017-07-15 01:07:42 +00:00
parent - > child_count + + ;
ctx - > idx = parent - > child_count ;
2017-07-14 19:34:15 +00:00
pxy_conn_connect_child ( ctx ) ;
2017-07-15 01:07:42 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_conn_setup_child: SUCCESS EXIT fd=%d, parent fd=%d \n " , fd , parent - > fd ) ;
2017-07-14 19:34:15 +00:00
}
2017-07-07 14:18:01 +00:00
/*
* Callback for accept events on the socket listener bufferevent .
*/
static void
proxy_listener_acceptcb_child ( UNUSED struct evconnlistener * listener ,
evutil_socket_t fd ,
struct sockaddr * peeraddr , int peeraddrlen ,
void * arg )
{
2017-07-15 01:07:42 +00:00
pxy_conn_ctx_t * parent = arg ;
assert ( parent ! = NULL ) ;
2017-07-11 22:45:15 +00:00
2017-07-15 01:07:42 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>------------------------------------------------------------------------------------ proxy_listener_acceptcb_child: ENTER fd=%d, child_fd=%d \n " , parent - > fd , parent - > child_fd ) ;
2017-07-15 10:04:13 +00:00
parent - > atime = time ( NULL ) ;
2017-07-07 14:18:01 +00:00
2017-07-15 01:07:42 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>------------------------------------------------------------------------------------ proxy_listener_acceptcb_child: child fd=%d, pfd=%d \n " , fd , parent - > fd ) ;
2017-07-07 14:18:01 +00:00
char * host , * port ;
if ( sys_sockaddr_str ( peeraddr , peeraddrlen , & host , & port ) ! = 0 ) {
2017-07-12 13:46:51 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>------------------------------------------------------------------------------------ proxy_listener_acceptcb_child: PEER failed \n " ) ;
2017-07-07 14:18:01 +00:00
} else {
2017-07-15 01:07:42 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>------------------------------------------------------------------------------------ proxy_listener_acceptcb_child: PEER [%s]:%s <<<<< child fd=%d, pfd=%d \n " , host , port , fd , parent - > fd ) ;
2017-07-07 14:18:01 +00:00
free ( host ) ;
free ( port ) ;
}
2017-07-15 01:07:42 +00:00
pxy_conn_setup_child ( fd , parent ) ;
2017-07-07 14:18:01 +00:00
2017-07-12 13:46:51 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>------------------------------------------------------------------------------------ proxy_listener_acceptcb_child: EXIT \n " ) ;
2017-05-29 09:22:23 +00:00
}
static int
pxy_connected_enable ( struct bufferevent * bev , pxy_conn_ctx_t * ctx , char * event_name )
{
2017-07-16 14:10:18 +00:00
evutil_socket_t fd = ctx - > fd ;
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_connected_enable: ENTER %s fd=%d \n " , event_name , fd ) ;
2012-05-02 13:00:22 +00:00
2017-07-12 19:37:36 +00:00
if ( bev = = ctx - > srv_dst . bev & & ! ctx - > srv_dst_connected ) {
ctx - > srv_dst_connected = 1 ;
2017-07-16 14:10:18 +00:00
ctx - > srv_dst_fd = bufferevent_getfd ( ctx - > srv_dst . bev ) ;
2017-07-12 21:45:12 +00:00
// @attention Create and enable dst.bev before, but connect here, because we check if dst.bev is NULL elsewhere
2017-07-16 14:10:18 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_connected_enable: bufferevent_socket_connect for dst, fd=%d \n " , fd ) ;
2017-07-12 19:37:36 +00:00
if ( bufferevent_socket_connect ( ctx - > dst . bev ,
2017-07-15 01:07:42 +00:00
( struct sockaddr * ) & ctx - > spec - > parent_dst_addr ,
ctx - > spec - > parent_dst_addrlen ) = = - 1 ) {
2017-07-16 14:10:18 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>=================================== pxy_connected_enable: FAILED bufferevent_socket_connect for dst, fd=%d \n " , fd ) ;
evutil_closesocket ( fd ) ;
pxy_conn_free ( ctx ) ;
return 0 ;
2012-04-13 12:47:30 +00:00
}
2017-07-15 01:07:42 +00:00
ctx - > dst_fd = bufferevent_getfd ( ctx - > dst . bev ) ;
2012-04-13 12:47:30 +00:00
}
2017-05-29 09:22:23 +00:00
2017-07-12 19:37:36 +00:00
if ( bev = = ctx - > dst . bev & & ! ctx - > dst_connected ) {
ctx - > dst_connected = 1 ;
2012-04-13 12:47:30 +00:00
}
2017-05-29 09:22:23 +00:00
2017-07-12 19:37:36 +00:00
if ( ctx - > srv_dst_connected & & ctx - > dst_connected & & ! ctx - > connected ) {
2017-05-29 09:22:23 +00:00
ctx - > connected = 1 ;
2017-07-15 18:51:20 +00:00
pxy_conn_desc_t * srv_dst_ctx = & ctx - > srv_dst ;
2017-07-15 01:07:42 +00:00
if ( ( ctx - > spec - > ssl | | ctx - > clienthello_found ) & & ! ctx - > passthrough ) {
2017-07-16 14:10:18 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_connected_enable: pxy_srcssl_create <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< SSL \n " ) ;
2017-07-15 18:51:20 +00:00
ctx - > src . ssl = pxy_srcssl_create ( ctx , srv_dst_ctx - > ssl ) ;
2017-06-15 16:07:37 +00:00
if ( ! ctx - > src . ssl ) {
2017-07-15 01:07:42 +00:00
bufferevent_free_and_close_fd ( ctx - > srv_dst . bev , ctx ) ;
2017-07-12 19:37:36 +00:00
ctx - > srv_dst . bev = NULL ;
ctx - > srv_dst . ssl = NULL ;
2017-07-15 01:07:42 +00:00
if ( ctx - > opts - > passthrough & & ! ctx - > enomem ) {
ctx - > passthrough = 1 ;
2017-06-15 16:07:37 +00:00
ctx - > connected = 0 ;
log_dbg_printf ( " No cert found; "
" falling back "
" to passthrough \n " ) ;
2017-07-16 14:10:18 +00:00
pxy_fd_readcb ( fd , 0 , ctx ) ;
2017-07-01 20:17:45 +00:00
return 0 ;
2017-06-15 16:07:37 +00:00
}
2017-07-16 14:10:18 +00:00
evutil_closesocket ( fd ) ;
2017-07-14 19:34:15 +00:00
pxy_conn_free ( ctx ) ;
2017-07-01 20:17:45 +00:00
return 0 ;
2017-06-15 16:07:37 +00:00
}
2017-05-29 09:22:23 +00:00
}
2017-06-10 18:50:03 +00:00
if ( ctx - > clienthello_found ) {
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2017-07-15 18:51:20 +00:00
log_dbg_printf ( " Completing autossl upgrade \n " ) ;
2017-06-10 18:50:03 +00:00
}
ctx - > src . bev = bufferevent_openssl_filter_new (
2017-07-15 01:07:42 +00:00
ctx - > evbase , ctx - > src . bev , ctx - > src . ssl ,
2017-06-10 18:50:03 +00:00
BUFFEREVENT_SSL_ACCEPTING ,
BEV_OPT_DEFER_CALLBACKS ) ;
} else {
2017-07-16 14:10:18 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_connected_enable: SETUP src.bev fd=%d \n " , fd ) ;
ctx - > src . bev = pxy_bufferevent_setup ( ctx , fd , ctx - > src . ssl ) ;
2017-07-15 18:51:20 +00:00
}
if ( ! ctx - > src . bev ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>=================================== pxy_connected_enable: src.bev NULL FREEING \n " ) ;
if ( ctx - > src . ssl ) {
SSL_free ( ctx - > src . ssl ) ;
ctx - > src . ssl = NULL ;
}
2017-07-16 14:10:18 +00:00
evutil_closesocket ( fd ) ;
2017-07-15 18:51:20 +00:00
pxy_conn_free ( ctx ) ;
return 0 ;
}
2017-07-16 14:10:18 +00:00
bufferevent_setcb ( ctx - > src . bev , pxy_bev_readcb , pxy_bev_writecb , pxy_bev_eventcb , ctx ) ;
2017-07-15 18:51:20 +00:00
/* prepare logging, part 2 */
if ( WANT_CONNECT_LOG ( ctx ) | | WANT_CONTENT_LOG ( ctx ) ) {
if ( sys_sockaddr_str ( ( struct sockaddr * )
& ctx - > addr , ctx - > addrlen ,
& ctx - > dsthost_str ,
& ctx - > dstport_str ) ! = 0 ) {
ctx - > enomem = 1 ;
pxy_conn_free ( ctx ) ;
return 0 ;
}
# ifdef HAVE_LOCAL_PROCINFO
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 ) ;
return 0 ;
}
}
}
# endif /* HAVE_LOCAL_PROCINFO */
}
if ( WANT_CONTENT_LOG ( ctx ) ) {
if ( log_content_open ( & ctx - > logctx , ctx - > opts ,
ctx - > srchost_str , ctx - > srcport_str ,
ctx - > dsthost_str , 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 ;
2017-07-14 19:34:15 +00:00
pxy_conn_free ( ctx ) ;
2017-06-10 18:50:03 +00:00
return 0 ;
}
}
2017-07-15 20:42:22 +00:00
// @todo Closing srv_dst causes TCP conns to stall sometimes (SSL cons were ok)?
2017-07-10 09:27:46 +00:00
// @attention Free the dst of the parent ctx asap, we don't need it, but we need its fd
2017-07-15 20:42:22 +00:00
pxy_conn_desc_t * srv_dst = & ctx - > srv_dst ;
if ( srv_dst - > bev ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " >>>>>=================================== pxy_connected_enable: evutil_closesocket srv_dst->bev, fd=%d \n " , bufferevent_getfd ( srv_dst - > bev ) ) ;
bufferevent_free_and_close_fd ( srv_dst - > bev , ctx ) ;
srv_dst - > bev = NULL ;
srv_dst - > closed = 1 ;
}
2017-06-27 14:09:01 +00:00
2017-07-10 12:48:57 +00:00
// @attention Defer child setup and evcl creation until 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.
2017-07-15 01:07:42 +00:00
// Child evcls use the evbase of the parent thread, otherwise we would get multithreading issues.
2017-07-16 14:10:18 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_connected_enable: SETTING UP CHILD, fd=%d, lctx->clisock=%d \n " , fd , ctx - > clisock ) ;
2017-07-05 22:58:21 +00:00
2017-07-12 13:46:51 +00:00
evutil_socket_t cfd ;
2017-07-15 01:07:42 +00:00
if ( ( cfd = privsep_client_opensock_child ( ctx - > clisock , ctx - > spec ) ) = = - 1 ) {
2017-07-05 22:58:21 +00:00
log_err_printf ( " Error opening socket: %s (%i) \n " , strerror ( errno ) , errno ) ;
2017-07-14 19:34:15 +00:00
pxy_conn_free ( ctx ) ;
2017-07-06 12:38:32 +00:00
return 0 ;
2017-07-05 22:58:21 +00:00
}
2017-07-15 01:07:42 +00:00
ctx - > child_fd = cfd ;
2017-07-16 14:10:18 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_connected_enable: Opened child fd, fd=%d, cfd=%d \n " , fd , ctx - > child_fd ) ;
2017-07-05 22:58:21 +00:00
2017-07-15 10:04:13 +00:00
// @attention Do not pass NULL as user-supplied pointer
2017-07-15 01:07:42 +00:00
struct evconnlistener * child_evcl = evconnlistener_new ( ctx - > thr - > evbase , proxy_listener_acceptcb_child , ctx , LEV_OPT_CLOSE_ON_FREE , 1024 , ctx - > child_fd ) ;
2017-07-10 09:27:46 +00:00
if ( ! child_evcl ) {
2017-07-16 14:10:18 +00:00
log_err_printf ( " Error creating child evconnlistener: %s, fd=%d, child_fd=%d <<<<<< \n " , strerror ( errno ) , fd , ctx - > child_fd ) ;
2017-07-14 19:34:15 +00:00
// @attention Cannot call proxy_listener_ctx_free() on child_evcl, child_evcl does not have any ctx with next listener
2017-07-15 18:51:20 +00:00
// @attention Close child fd separately, because child evcl does not exist yet, hence fd would not be closed by calling pxy_conn_free()
2017-07-15 01:07:42 +00:00
evutil_closesocket ( ctx - > child_fd ) ;
2017-07-14 19:34:15 +00:00
pxy_conn_free ( ctx ) ;
2017-07-05 19:32:10 +00:00
return 0 ;
}
2017-07-15 01:07:42 +00:00
ctx - > child_evcl = child_evcl ;
2017-07-05 19:32:10 +00:00
2017-07-10 09:27:46 +00:00
evconnlistener_set_error_cb ( child_evcl , proxy_listener_errorcb ) ;
2017-07-16 14:10:18 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " >>>>>=================================== pxy_connected_enable: FINISHED SETTING UP CHILD, parent fd=%d, NEW cfd=%d \n " , fd , ctx - > child_fd ) ;
2017-07-05 19:32:10 +00:00
2017-07-12 21:45:12 +00:00
struct sockaddr_in child_listener_addr ;
socklen_t child_listener_len = sizeof ( child_listener_addr ) ;
2017-07-05 19:32:10 +00:00
2017-07-15 01:07:42 +00:00
if ( getsockname ( ctx - > child_fd , & child_listener_addr , & child_listener_len ) < 0 ) {
2017-07-05 19:32:10 +00:00
perror ( " getsockname " ) ;
2017-07-16 14:10:18 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>=================================== pxy_connected_enable: %s, getsockname ERROR=%s, fd=%d, child_fd=%d <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< \n " , event_name , strerror ( errno ) , fd , ctx - > child_fd ) ;
2017-07-10 09:27:46 +00:00
// @todo If getsockname() fails, should we really terminate the connection?
2017-07-14 19:34:15 +00:00
pxy_conn_free ( ctx ) ;
2017-07-05 19:32:10 +00:00
return 0 ;
}
2017-07-16 14:10:18 +00:00
// @todo Use inet_ntop() instead to support IPv6 too
2017-07-12 21:45:12 +00:00
char * addr = inet_ntoa ( child_listener_addr . sin_addr ) ;
2017-07-05 19:32:10 +00:00
int addr_len = strlen ( addr ) + 5 + 3 + 1 ;
2017-07-15 01:07:42 +00:00
ctx - > child_addr = malloc ( addr_len ) ;
snprintf ( ctx - > child_addr , addr_len , " [%s]:%d " , addr , ( int ) ntohs ( child_listener_addr . sin_port ) ) ;
2017-07-05 19:32:10 +00:00
2017-07-16 14:10:18 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " >>>>>=================================== pxy_connected_enable: ENABLE src, child_addr= %s, fd=%d, child_fd=%d \n " , ctx - > child_addr , fd , ctx - > child_fd ) ;
2017-07-05 19:32:10 +00:00
// Now open the gates
2017-05-29 09:22:23 +00:00
bufferevent_enable ( ctx - > src . bev , EV_READ | EV_WRITE ) ;
}
2017-07-15 18:51:20 +00:00
if ( ( bev = = ctx - > src . bev ) | | ( bev = = ctx - > srv_dst . bev ) ) {
pxy_conn_desc_t * this ;
if ( ctx - > srv_dst . bev ) {
this = ( bev = = ctx - > src . bev ) ? & ctx - > src : & ctx - > srv_dst ;
} else if ( bev = = ctx - > src . bev ) {
this = & ctx - > src ;
} else {
return 1 ;
}
/* log connection if we don't analyze any headers */
if ( ( ! this - > ssl | | ( bev = = ctx - > src . bev ) ) & &
( ! ctx - > spec - > http | | ctx - > passthrough ) & &
WANT_CONNECT_LOG ( ctx ) ) {
2017-07-16 14:10:18 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " >>>>>=================================== pxy_connected_enable: Log conn, fd=%d, child_fd=%d \n " , fd , ctx - > child_fd ) ;
2017-07-15 18:51:20 +00:00
pxy_log_connect_nonhttp ( ctx ) ;
}
/* write SSL certificates to gendir */
if ( this - > ssl & & ( bev = = ctx - > src . bev ) & &
ctx - > opts - > certgendir ) {
2017-07-16 14:10:18 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINER , " >>>>>=================================== pxy_connected_enable: Write SSL certificates to gendir, fd=%d, child_fd=%d \n " , fd , ctx - > child_fd ) ;
2017-07-15 18:51:20 +00:00
pxy_srccert_write ( ctx ) ;
}
if ( OPTS_DEBUG ( ctx - > opts ) ) {
if ( this - > ssl ) {
/* for SSL, we get two connect events */
log_dbg_printf ( " SSL connected %s [%s]:%s "
" %s %s \n " ,
bev = = ctx - > srv_dst . bev ?
" to " : " from " ,
bev = = ctx - > srv_dst . bev ?
ctx - > dsthost_str :
ctx - > srchost_str ,
bev = = ctx - > srv_dst . bev ?
ctx - > dstport_str :
ctx - > srcport_str ,
SSL_get_version ( this - > ssl ) ,
SSL_get_cipher ( this - > ssl ) ) ;
} 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 ( " TCP connected to [%s]:%s \n " ,
ctx - > dsthost_str ,
ctx - > dstport_str ) ;
log_dbg_printf ( " TCP connected from [%s]:%s \n " ,
ctx - > srchost_str ,
ctx - > srcport_str ) ;
}
}
}
2017-05-29 09:22:23 +00:00
return 1 ;
2012-04-13 12:47:30 +00:00
}
2017-07-12 19:37:36 +00:00
static void
2017-07-11 22:45:15 +00:00
pxy_connected_enable_child ( struct bufferevent * bev , pxy_conn_child_ctx_t * ctx , char * event_name )
2017-06-25 11:21:32 +00:00
{
2017-07-07 14:18:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_connected_enable_child: ENTER bev = %s \n " , event_name ) ;
2017-06-25 11:21:32 +00:00
if ( bev = = ctx - > dst . bev ) {
2017-07-10 09:27:46 +00:00
ctx - > connected = 1 ;
2017-07-12 21:45:12 +00:00
// @attention Create and enable src.bev before, but connect here, because we check if dst.bev is NULL elsewhere
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_connected_enable_child: enable callbacks for src.bev \n " ) ;
2017-07-11 22:45:15 +00:00
bufferevent_enable ( ctx - > src . bev , EV_READ | EV_WRITE ) ;
2017-06-25 11:21:32 +00:00
}
}
2012-04-13 12:47:30 +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 ;
2017-06-27 14:09:01 +00:00
2017-07-10 14:26:58 +00:00
char * event_name = pxy_get_event_name ( bev , ctx ) ;
2017-07-15 01:07:42 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>+++++++++++++++++++++++++++++++++++ pxy_bev_writecb: ENTER %s fd=%d, child_fd=%d \n " , event_name , ctx - > fd , ctx - > child_fd ) ;
2017-07-10 14:26:58 +00:00
2017-07-16 14:10:18 +00:00
ctx - > atime = time ( NULL ) ;
2017-07-10 19:08:44 +00:00
// @attention This does not work, since the listener cb is not finished yet, trying to free the conn causes multithreading issues
2017-07-16 14:10:18 +00:00
// if (bev==ctx->srv_dst.bev) {
2017-07-10 19:08:44 +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.
// // XXX: Workaround, should find the real cause
2017-07-15 18:51:20 +00:00
// log_dbg_level_printf(LOG_DBG_MODE_FINE, ">>>>>+++++++++++++++++++++++++++++++++++ pxy_bev_writecb: pxy_conn_free %s fd=%d, child_fd=%d, cfd=%d <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< DST W CB B4 CONNECTED\n", event_name, ctx->fd, ctx->child_fd, ctx->fd);
2017-07-15 01:07:42 +00:00
// pxy_conn_free(ctx);
2017-07-10 19:08:44 +00:00
// return;
// }
2017-07-16 14:10:18 +00:00
// @todo Should enable the lines below to workaround eventcb issue? Would it help?
// if (bev == ctx->srv_dst.bev && !ctx->srv_dst_connected) {
// pxy_bev_eventcb(bev, BEV_EVENT_CONNECTED, ctx);
// }
2017-07-12 19:37:36 +00:00
if ( ( bev = = ctx - > src . bev ) | | ( bev = = ctx - > dst . bev ) ) {
pxy_conn_desc_t * this = ( bev = = ctx - > src . bev ) ? & ctx - > src : & ctx - > dst ;
pxy_conn_desc_t * other = ( bev = = ctx - > src . bev ) ? & ctx - > dst : & ctx - > src ;
2017-07-15 01:07:42 +00:00
void ( * this_free_and_close_fd_func ) ( struct bufferevent * , pxy_conn_ctx_t * ) = ( bev = = ctx - > dst . bev ) ? & bufferevent_free_and_close_fd_nonssl : & bufferevent_free_and_close_fd ;
2017-07-10 09:27:46 +00:00
if ( other - > closed ) {
struct evbuffer * outbuf = bufferevent_get_output ( bev ) ;
if ( evbuffer_get_length ( outbuf ) = = 0 ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>+++++++++++++++++++++++++++++++++++ pxy_bev_writecb: other->closed <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CONN TERM \n " ) ;
/* finished writing and other end is closed;
* close this end too and clean up memory */
this - > closed = 1 ;
2017-07-15 01:07:42 +00:00
this_free_and_close_fd_func ( bev , ctx ) ;
2017-07-10 09:27:46 +00:00
this - > bev = NULL ;
2017-07-14 19:34:15 +00:00
pxy_conn_free ( ctx ) ;
2017-07-10 09:27:46 +00:00
}
goto leave ;
}
2017-07-05 19:32:10 +00:00
if ( other - > bev & & ! ( bufferevent_get_enabled ( other - > bev ) & EV_READ ) ) {
/* data source temporarily disabled;
* re - enable and reset watermark to 0. */
2017-07-05 22:58:21 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>+++++++++++++++++++++++++++++++++++ pxy_bev_writecb: remove watermark for w, enable r <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< WATERMARK \n " ) ;
2017-07-05 19:32:10 +00:00
bufferevent_setwatermark ( bev , EV_WRITE , 0 , 0 ) ;
bufferevent_enable ( other - > bev , EV_READ ) ;
}
2017-05-29 09:22:23 +00:00
}
2017-07-10 09:27:46 +00:00
leave :
2017-07-10 12:48:57 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>+++++++++++++++++++++++++++++++++++ pxy_bev_writecb: EXIT \n " ) ;
2017-05-29 09:22:23 +00:00
}
static void
2017-07-07 14:18:01 +00:00
pxy_bev_writecb_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-15 01:07:42 +00:00
assert ( ctx - > parent ! = NULL ) ;
2017-05-29 09:22:23 +00:00
2017-07-15 01:07:42 +00:00
pxy_conn_ctx_t * parent = ctx - > parent ;
2017-07-10 14:26:58 +00:00
2017-07-11 22:45:15 +00:00
char * event_name = pxy_get_event_name_child ( bev , ctx ) ;
2017-07-15 01:07:42 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>??????????????????????????? pxy_bev_writecb_child: ENTER %s fd=%d, child_fd=%d, cfd=%d \n " , event_name , parent - > fd , parent - > child_fd , ctx - > fd ) ;
2017-05-29 09:22:23 +00:00
2017-07-15 10:04:13 +00:00
parent - > atime = time ( NULL ) ;
2017-06-29 21:38:37 +00:00
2017-07-11 22:45:15 +00:00
pxy_conn_desc_t * this = ( bev = = ctx - > src . bev ) ? & ctx - > src : & ctx - > dst ;
pxy_conn_desc_t * other = ( bev = = ctx - > src . bev ) ? & ctx - > dst : & ctx - > src ;
2017-07-15 01:07:42 +00:00
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 ;
2017-07-10 09:27:46 +00:00
if ( other - > closed ) {
struct evbuffer * outbuf = bufferevent_get_output ( bev ) ;
if ( evbuffer_get_length ( outbuf ) = = 0 ) {
2017-07-14 19:34:15 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>??????????????????????????? pxy_bev_writecb_child: other->closed <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CHILD TERM \n " ) ;
2017-07-10 09:27:46 +00:00
/* finished writing and other end is closed;
* close this end too and clean up memory */
this - > closed = 1 ;
2017-07-15 01:07:42 +00:00
this_free_and_close_fd_func ( bev , ctx - > parent ) ;
2017-07-10 09:27:46 +00:00
this - > bev = NULL ;
2017-07-12 19:37:36 +00:00
pxy_conn_free_child ( ctx ) ;
2017-07-10 09:27:46 +00:00
}
goto leave ;
2017-05-29 09:22:23 +00:00
}
2015-11-08 14:44:02 +00:00
2017-07-05 19:32:10 +00:00
if ( other - > bev & & ! ( bufferevent_get_enabled ( other - > bev ) & EV_READ ) ) {
/* data source temporarily disabled;
* re - enable and reset watermark to 0. */
2017-07-07 14:18:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>??????????????????????????? pxy_bev_writecb_child: remove watermark for w, enable r <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< WATERMARK \n " ) ;
2017-07-05 19:32:10 +00:00
bufferevent_setwatermark ( bev , EV_WRITE , 0 , 0 ) ;
bufferevent_enable ( other - > bev , EV_READ ) ;
}
2017-07-10 09:27:46 +00:00
leave :
2017-07-10 12:48:57 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>??????????????????????????? pxy_bev_writecb_child: EXIT \n " ) ;
2012-04-13 12:47:30 +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 ;
2017-06-29 21:38:37 +00:00
2017-07-15 10:04:13 +00:00
ctx - > atime = time ( NULL ) ;
2017-06-30 21:29:39 +00:00
2017-07-15 01:07:42 +00:00
evutil_socket_t fd = ctx - > fd ;
2017-05-29 09:22:23 +00:00
2017-07-05 19:32:10 +00:00
char * event_name = pxy_get_event_name ( bev , ctx ) ;
2017-07-15 01:07:42 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_bev_eventcb: ENTER %s fd=%d, child_fd=%d \n " , event_name , ctx - > fd , ctx - > child_fd ) ;
2017-07-10 12:48:57 +00:00
2013-08-23 13:07:07 +00:00
if ( events & BEV_EVENT_CONNECTED ) {
2017-07-15 01:07:42 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_bev_eventcb: CONNECTED %s fd=%d \n " , event_name , ctx - > fd ) ;
2017-07-10 12:48:57 +00:00
2017-07-12 13:46:51 +00:00
if ( pxy_connected_enable ( bev , ctx , event_name ) ) {
pxy_conn_desc_t * src_ctx = & ctx - > src ;
2017-06-10 18:50:03 +00:00
2017-07-12 13:46:51 +00:00
/* write SSL certificates to gendir */
2017-07-15 01:07:42 +00:00
if ( src_ctx - > ssl & & ( bev = = ctx - > src . bev ) & & ctx - > opts - > certgendir ) {
2017-07-12 13:46:51 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_bev_eventcb: pxy_srccert_write <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< SSL \n " ) ;
pxy_srccert_write ( ctx ) ;
}
2017-06-10 18:50:03 +00:00
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2017-07-12 13:46:51 +00:00
if ( src_ctx - > ssl ) {
/* for SSL, we get two connect events */
log_dbg_printf ( " SSL connected %s [%s]:%s "
" %s %s \n " ,
2017-07-12 19:37:36 +00:00
bev = = ctx - > srv_dst . bev ?
2017-07-12 13:46:51 +00:00
" to " : " from " ,
2017-07-12 19:37:36 +00:00
bev = = ctx - > srv_dst . bev ?
2017-07-12 13:46:51 +00:00
ctx - > dsthost_str :
ctx - > srchost_str ,
2017-07-12 19:37:36 +00:00
bev = = ctx - > srv_dst . bev ?
2017-07-12 13:46:51 +00:00
ctx - > dstport_str :
ctx - > srcport_str ,
SSL_get_version ( src_ctx - > ssl ) ,
SSL_get_cipher ( src_ctx - > ssl ) ) ;
} 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 ( " TCP connected to [%s]:%s \n " ,
ctx - > dsthost_str ,
ctx - > dstport_str ) ;
log_dbg_printf ( " TCP connected from [%s]:%s \n " ,
ctx - > srchost_str ,
ctx - > srcport_str ) ;
}
2017-06-10 18:50:03 +00:00
}
}
2017-05-29 09:22:23 +00:00
}
2013-08-23 13:07:07 +00:00
2017-05-29 09:22:23 +00:00
if ( events & BEV_EVENT_ERROR ) {
2017-07-15 01:07:42 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>=================================== pxy_bev_eventcb: ERROR %s fd=%d \n " , event_name , ctx - > fd ) ;
2017-06-10 18:50:03 +00:00
unsigned long sslerr ;
int have_sslerr = 0 ;
/* Can happen for socket errs, ssl errs;
* may happen for unclean ssl socket shutdowns . */
sslerr = bufferevent_get_openssl_error ( bev ) ;
if ( sslerr )
have_sslerr = 1 ;
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_printf ( " Warning: Spurious error from "
" bufferevent (errno=0,sslerr=0) \n " ) ;
# else /* LIBEVENT_VERSION_NUMBER < 0x02010000 */
/* Older versions of libevent will report these. */
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2017-06-10 18:50:03 +00:00
log_dbg_printf ( " Unclean SSL shutdown. \n " ) ;
}
# 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 ) ) ;
}
}
pxy_conn_desc_t * src_ctx = & ctx - > src ;
/* we only get a single disconnect event here for both connections */
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2017-06-10 18:50:03 +00:00
log_dbg_printf ( " %s disconnected to [%s]:%s \n " ,
src_ctx - > ssl ? " SSL " : " TCP " ,
ctx - > dsthost_str , ctx - > dstport_str ) ;
log_dbg_printf ( " %s disconnected from [%s]:%s \n " ,
src_ctx - > ssl ? " SSL " : " TCP " ,
ctx - > srchost_str , ctx - > srcport_str ) ;
}
2017-06-25 11:21:32 +00:00
// @todo Close and free the connections upon errors
2017-07-15 18:51:20 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>=================================== pxy_bev_eventcb: ERROR pxy_conn_free %s fd=%d \n " , event_name , ctx - > fd ) ;
2017-07-14 19:34:15 +00:00
pxy_conn_free ( ctx ) ;
2017-07-12 13:46:51 +00:00
goto leave ;
2017-05-29 09:22:23 +00:00
}
2012-04-13 12:47:30 +00:00
2017-05-29 09:22:23 +00:00
if ( events & BEV_EVENT_EOF ) {
2017-07-15 01:07:42 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_bev_eventcb: EOF %s fd=%d \n " , event_name , ctx - > fd ) ;
2017-07-10 12:48:57 +00:00
2017-07-12 19:37:36 +00:00
pxy_conn_desc_t * this = ( bev = = ctx - > src . bev ) ? & ctx - > src : & ctx - > dst ;
pxy_conn_desc_t * other = ( bev = = ctx - > src . bev ) ? & ctx - > dst : & ctx - > src ;
2017-07-10 12:48:57 +00:00
2017-07-15 01:07:42 +00:00
void ( * this_free_and_close_fd_func ) ( struct bufferevent * , pxy_conn_ctx_t * ) = ( this - > bev = = ctx - > src . bev ) ? & bufferevent_free_and_close_fd : & bufferevent_free_and_close_fd_nonssl ;
void ( * other_free_and_close_fd_func ) ( struct bufferevent * , pxy_conn_ctx_t * ) = ( other - > bev = = ctx - > dst . bev ) ? & bufferevent_free_and_close_fd_nonssl : & bufferevent_free_and_close_fd ;
2017-07-10 12:48:57 +00:00
2017-07-12 19:37:36 +00:00
if ( bev = = ctx - > srv_dst . bev ) {
2017-07-15 01:07:42 +00:00
bufferevent_free_and_close_fd ( ctx - > srv_dst . bev , ctx ) ;
2017-07-12 19:37:36 +00:00
ctx - > srv_dst . bev = NULL ;
ctx - > srv_dst . closed = 1 ;
2017-07-10 09:27:46 +00:00
goto leave ;
} else {
if ( ! ctx - > connected ) {
log_dbg_printf ( " EOF on inbound connection while "
" connecting to original destination \n " ) ;
2017-07-15 01:07:42 +00:00
evutil_closesocket ( ctx - > fd ) ;
2017-07-10 09:27:46 +00:00
other - > closed = 1 ;
} else if ( ! other - > closed ) {
2017-07-10 12:48:57 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_bev_eventcb: !other->closed <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CONN TERM \n " ) ;
2017-07-10 09:27:46 +00:00
struct evbuffer * inbuf , * outbuf ;
inbuf = bufferevent_get_input ( bev ) ;
outbuf = bufferevent_get_output ( other - > bev ) ;
if ( evbuffer_get_length ( inbuf ) > 0 ) {
2017-07-10 12:48:57 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_bev_eventcb: evbuffer_get_length(inbuf) > 0 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CONN TERM \n " ) ;
2017-07-10 09:27:46 +00:00
pxy_bev_readcb ( bev , ctx ) ;
} else {
/* 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 ( outbuf ) = = 0 ) {
2017-07-10 12:48:57 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_bev_eventcb: evbuffer_get_length(inbuf) == 0 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CONN TERM \n " ) ;
2017-07-14 19:34:15 +00:00
other - > closed = 1 ;
2017-07-15 01:07:42 +00:00
other_free_and_close_fd_func ( other - > bev , ctx ) ;
2017-07-10 09:27:46 +00:00
other - > bev = NULL ;
}
}
}
2017-07-10 12:48:57 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_bev_eventcb: disconnect <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CONN TERM \n " ) ;
/* we only get a single disconnect event here for both connections */
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2017-07-10 12:48:57 +00:00
log_dbg_printf ( " %s disconnected to [%s]:%s \n " ,
this - > ssl ? " SSL " : " TCP " ,
ctx - > dsthost_str , ctx - > dstport_str ) ;
log_dbg_printf ( " %s disconnected from [%s]:%s \n " ,
this - > ssl ? " SSL " : " TCP " ,
ctx - > srchost_str , ctx - > srcport_str ) ;
}
this - > closed = 1 ;
2017-07-15 01:07:42 +00:00
this_free_and_close_fd_func ( bev , ctx ) ;
2017-07-10 12:48:57 +00:00
this - > bev = NULL ;
if ( other - > closed ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_bev_eventcb: disconnect other->closed <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CONN TERM \n " ) ;
2017-07-14 19:34:15 +00:00
pxy_conn_free ( ctx ) ;
2017-07-10 12:48:57 +00:00
}
2017-07-10 09:27:46 +00:00
}
2017-05-29 09:22:23 +00:00
}
2017-07-10 09:27:46 +00:00
2017-05-29 09:22:23 +00:00
leave :
2017-07-12 19:37:36 +00:00
// @attention ctx may have been freed now, so cannot use ctx->fd here
2017-07-10 12:48:57 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_bev_eventcb EXIT fd=%d \n " , fd ) ;
2017-05-29 09:22:23 +00:00
}
2012-04-13 12:47:30 +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 ;
2017-07-15 01:07:42 +00:00
assert ( ctx - > parent ! = NULL ) ;
2014-01-10 11:04:41 +00:00
2017-07-15 01:07:42 +00:00
pxy_conn_ctx_t * parent = ctx - > parent ;
2017-07-15 10:04:13 +00:00
parent - > atime = time ( NULL ) ;
2017-07-10 12:48:57 +00:00
evutil_socket_t fd = ctx - > fd ;
2017-07-11 22:45:15 +00:00
char * event_name = pxy_get_event_name_child ( bev , ctx ) ;
2017-07-15 01:07:42 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>--------------------- pxy_bev_eventcb_child: ENTER %s fd=%d, child_fd=%d \n " , event_name , parent - > fd , parent - > child_fd ) ;
2014-12-13 01:36:45 +00:00
2017-05-29 09:22:23 +00:00
if ( events & BEV_EVENT_CONNECTED ) {
2017-07-10 12:48:57 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>--------------------- pxy_bev_eventcb_child: CONNECTED %s fd=%d \n " , event_name , fd ) ;
2017-07-07 14:18:01 +00:00
pxy_connected_enable_child ( bev , ctx , event_name ) ;
2012-04-13 12:47:30 +00:00
}
2017-05-29 09:22:23 +00:00
if ( events & BEV_EVENT_ERROR ) {
2017-07-07 14:18:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>--------------------- pxy_bev_eventcb_child: ERROR %s fd=%d \n " , event_name , ctx - > fd ) ;
2017-07-10 12:48:57 +00:00
2017-06-10 18:50:03 +00:00
unsigned long sslerr ;
int have_sslerr = 0 ;
2017-07-04 15:13:34 +00:00
// @todo Reuse this error printing code: Make a function?
2017-06-10 18:50:03 +00:00
/* Can happen for socket errs, ssl errs;
* may happen for unclean ssl socket shutdowns . */
sslerr = bufferevent_get_openssl_error ( bev ) ;
if ( sslerr )
have_sslerr = 1 ;
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_printf ( " Warning: Spurious error from "
" bufferevent (errno=0,sslerr=0) \n " ) ;
# else /* LIBEVENT_VERSION_NUMBER < 0x02010000 */
/* Older versions of libevent will report these. */
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( parent - > opts ) ) {
2017-06-10 18:50:03 +00:00
log_dbg_printf ( " Unclean SSL shutdown. \n " ) ;
}
# 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 ) ) ;
}
}
2017-07-07 14:18:01 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>--------------------- pxy_bev_eventcb_child: ERROR pxy_conn_free_child, %s fd=%d \n " , event_name , ctx - > fd ) ;
2017-07-12 19:37:36 +00:00
pxy_conn_free_child ( ctx ) ;
2017-06-29 21:38:37 +00:00
goto leave ;
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 ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>--------------------- pxy_bev_eventcb_child: EOF %s fd=%d \n " , event_name , fd ) ;
2017-05-29 09:22:23 +00:00
2017-07-12 21:45:12 +00:00
pxy_conn_desc_t * this = ( bev = = ctx - > src . bev ) ? & ctx - > src : & ctx - > dst ;
pxy_conn_desc_t * other = ( bev = = ctx - > src . bev ) ? & ctx - > dst : & ctx - > src ;
2017-07-15 01:07:42 +00:00
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 ;
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-12 21:45:12 +00:00
2017-07-10 12:48:57 +00:00
// @todo How to handle the following case?
if ( ! ctx - > connected ) {
log_dbg_printf ( " EOF on inbound connection while "
" connecting to original destination \n " ) ;
evutil_closesocket ( ctx - > fd ) ;
other - > closed = 1 ;
} else if ( ! other - > closed ) {
2017-07-14 19:34:15 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_bev_eventcb_child: !other->closed <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CHILD TERM \n " ) ;
2017-07-10 12:48:57 +00:00
struct evbuffer * inbuf , * outbuf ;
inbuf = bufferevent_get_input ( bev ) ;
outbuf = bufferevent_get_output ( other - > bev ) ;
if ( evbuffer_get_length ( inbuf ) > 0 ) {
2017-07-14 19:34:15 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_bev_eventcb_child: evbuffer_get_length(inbuf) > 0 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CHILD TERM \n " ) ;
2017-07-10 12:48:57 +00:00
pxy_bev_readcb_child ( bev , ctx ) ;
} else {
/* 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 ( outbuf ) = = 0 ) {
2017-07-14 19:34:15 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_bev_eventcb_child: evbuffer_get_length(inbuf) == 0 <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CHILD TERM \n " ) ;
other - > closed = 1 ;
2017-07-15 01:07:42 +00:00
other_free_and_close_fd_func ( other - > bev , ctx - > parent ) ;
2017-07-10 12:48:57 +00:00
other - > bev = NULL ;
}
}
}
2017-07-14 19:34:15 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>--------------------- pxy_bev_eventcb_child: disconnect <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CHILD TERM \n " ) ;
2017-07-10 12:48:57 +00:00
/* we only get a single disconnect event here for both connections */
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( parent - > opts ) ) {
2017-07-10 12:48:57 +00:00
log_dbg_printf ( " %s disconnected to [%s]:%s \n " ,
this - > ssl ? " SSL " : " TCP " ,
ctx - > dsthost_str , ctx - > dstport_str ) ;
log_dbg_printf ( " %s disconnected from [%s]:%s \n " ,
this - > ssl ? " SSL " : " TCP " ,
ctx - > srchost_str , ctx - > srcport_str ) ;
}
this - > closed = 1 ;
2017-07-15 01:07:42 +00:00
this_free_and_close_fd_func ( bev , ctx - > parent ) ;
2017-07-10 12:48:57 +00:00
this - > bev = NULL ;
if ( other - > closed ) {
2017-07-14 19:34:15 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>--------------------- pxy_bev_eventcb_child: disconnect other->closed <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< CHILD TERM \n " ) ;
2017-07-12 19:37:36 +00:00
pxy_conn_free_child ( ctx ) ;
2017-07-10 12:48:57 +00:00
}
2012-04-13 12:47:30 +00:00
}
2017-07-10 09:27:46 +00:00
2017-07-10 12:48:57 +00:00
leave :
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>--------------------- pxy_bev_eventcb_child: EXIT \n " ) ;
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 ;
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_conn_connect: ENTER fd=%d \n " , fd ) ;
2012-04-13 12:47:30 +00:00
if ( ! ctx - > addrlen ) {
log_err_printf ( " No target address; aborting connection \n " ) ;
2017-07-16 14:10:18 +00:00
evutil_closesocket ( fd ) ;
2012-04-13 12:47:30 +00:00
pxy_conn_ctx_free ( ctx ) ;
return ;
}
2017-07-16 14:10:18 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_conn_connect: pxy_bufferevent_setup for dst, fd=%d \n " , fd ) ;
2017-07-12 19:37:36 +00:00
ctx - > dst . ssl = NULL ;
ctx - > dst . bev = pxy_bufferevent_setup ( ctx , - 1 , ctx - > dst . ssl ) ;
if ( ! ctx - > dst . bev ) {
2017-07-12 13:46:51 +00:00
log_err_printf ( " Error creating parent dst \n " ) ;
2017-07-16 14:10:18 +00:00
evutil_closesocket ( fd ) ;
2017-07-12 13:46:51 +00:00
pxy_conn_ctx_free ( ctx ) ;
2017-07-16 14:10:18 +00:00
return ;
2017-07-12 13:46:51 +00:00
}
2017-06-29 21:38:37 +00:00
2017-07-16 14:10:18 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_conn_connect: bufferevent_setcb and enable for dst, fd=%d \n " , fd ) ;
bufferevent_setcb ( ctx - > dst . bev , pxy_bev_readcb , pxy_bev_writecb , pxy_bev_eventcb , ctx ) ;
2017-07-12 19:37:36 +00:00
bufferevent_enable ( ctx - > dst . bev , EV_READ | EV_WRITE ) ;
2017-06-29 21:38:37 +00:00
2012-04-13 12:47:30 +00:00
/* create server-side socket and eventbuffer */
2017-07-15 01:07:42 +00:00
if ( ctx - > spec - > ssl & & ! ctx - > passthrough ) {
2017-07-12 19:37:36 +00:00
ctx - > srv_dst . ssl = pxy_dstssl_create ( ctx ) ;
if ( ! ctx - > srv_dst . ssl ) {
2017-07-16 14:10:18 +00:00
log_err_printf ( " Error creating SSL for srv_dst \n " ) ;
2017-07-14 19:34:15 +00:00
pxy_conn_free ( ctx ) ;
2012-04-13 12:47:30 +00:00
return ;
}
}
2017-05-29 09:22:23 +00:00
2017-07-16 14:10:18 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_conn_connect: pxy_bufferevent_setup for srv_dst, fd=%d \n " , fd ) ;
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-14 19:34:15 +00:00
pxy_conn_free ( ctx ) ;
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?
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_conn_connect: bufferevent_setcb for srv_dst, fd=%d \n " , fd ) ;
// Disable and NULL r/w cbs, we do nothing for srv_dst in r/w cbs.
bufferevent_setcb ( ctx - > srv_dst . bev , NULL , NULL , pxy_bev_eventcb , ctx ) ;
// 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);
2012-04-13 12:47:30 +00:00
/* initiate connection */
2017-07-16 14:10:18 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_conn_connect: bufferevent_socket_connect for srv_dst, fd=%d \n " , fd ) ;
if ( bufferevent_socket_connect ( ctx - > srv_dst . bev , ( struct sockaddr * ) & ctx - > addr , ctx - > addrlen ) = = - 1 ) {
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>>=================================== pxy_conn_connect: FAILED bufferevent_socket_connect for srv_dst \n " ) ;
if ( ctx - > srv_dst . ssl ) {
SSL_free ( ctx - > srv_dst . ssl ) ;
ctx - > srv_dst . ssl = NULL ;
}
pxy_conn_free ( ctx ) ;
return ;
}
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
2017-07-16 14:10:18 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_conn_connect: EXIT fd=%d \n " , fd ) ;
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-07-15 23:22:35 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_sni_resolve_cb: ENTER fd=%d \n " , ctx - > fd ) ;
2012-04-13 12:47:30 +00:00
if ( errcode ) {
log_err_printf ( " Cannot resolve SNI hostname '%s': %s \n " ,
2017-07-15 01:07:42 +00:00
ctx - > sni , evutil_gai_strerror ( errcode ) ) ;
evutil_closesocket ( ctx - > fd ) ;
2012-04-13 12:47:30 +00:00
pxy_conn_ctx_free ( ctx ) ;
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-07-15 23:22:35 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>>=================================== pxy_fd_readcb: ENTER fd=%d \n " , ctx - > fd ) ;
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 */
2017-07-15 01:07:42 +00:00
if ( ctx - > spec - > ssl & & ! ctx - > passthrough /*&& ctx->ev*/ ) {
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 ) {
log_err_printf ( " Error peeking on fd, aborting "
2017-07-15 23:22:35 +00:00
" connection, fd=%d \n " , ctx - > fd ) ;
2012-04-13 12:47:30 +00:00
evutil_closesocket ( fd ) ;
pxy_conn_ctx_free ( ctx ) ;
return ;
}
if ( n = = 0 ) {
/* socket got closed while we were waiting */
2017-07-15 23:22:35 +00:00
log_err_printf ( " Socket got closed while waiting, fd=%d \n " , ctx - > fd ) ;
2012-04-13 12:47:30 +00:00
evutil_closesocket ( fd ) ;
pxy_conn_ctx_free ( ctx ) ;
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 ) {
log_err_printf ( " Peeking did not yield a (truncated) "
" ClientHello message, "
2017-07-15 23:22:35 +00:00
" aborting connection, fd=%d \n " , ctx - > fd ) ;
2015-05-17 18:23:25 +00:00
evutil_closesocket ( fd ) ;
pxy_conn_ctx_free ( ctx ) ;
return ;
}
2017-07-15 01:07:42 +00:00
if ( OPTS_DEBUG ( ctx - > opts ) ) {
2017-07-15 23:22:35 +00:00
log_dbg_printf ( " SNI peek: [%s] [%s], fd=%d \n " ,
2017-07-15 01:07:42 +00:00
ctx - > sni ? ctx - > sni : " n/a " ,
2015-05-17 18:23:25 +00:00
( ( rv = = 1 ) & & chello ) ?
2017-07-15 23:22:35 +00:00
" 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 ) ;
2017-07-15 01:07:42 +00:00
ctx - > ev = event_new ( ctx - > evbase , fd , 0 ,
2012-04-13 12:47:30 +00:00
pxy_fd_readcb , ctx ) ;
if ( ! ctx - > ev ) {
log_err_printf ( " Error creating retry "
" event, aborting "
2017-07-15 23:22:35 +00:00
" connection, fd=%d \n " , ctx - > fd ) ;
2012-04-13 12:47:30 +00:00
evutil_closesocket ( fd ) ;
pxy_conn_ctx_free ( ctx ) ;
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 ) ;
evdns_getaddrinfo ( ctx - > dnsbase , ctx - > sni , sniport , & hints ,
2012-04-13 12:47:30 +00:00
pxy_sni_resolve_cb , ctx ) ;
return ;
}
# endif /* !OPENSSL_NO_TLSEXT */
pxy_conn_connect ( ctx ) ;
2017-07-12 21:45:12 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_fd_readcb: EXIT \n " ) ;
2012-04-13 12:47:30 +00:00
}
/*
* 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
{
2017-07-12 13:46:51 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_conn_setup: fd=%d \n " , fd ) ;
2017-05-29 09:22:23 +00:00
2017-07-11 22:45:15 +00:00
char * host , * port ;
if ( sys_sockaddr_str ( peeraddr , peeraddrlen , & host , & port ) ! = 0 ) {
2017-07-12 13:46:51 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! pxy_conn_setup: PEER failed \n " ) ;
2017-07-11 22:45:15 +00:00
} else {
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! pxy_conn_setup: PEER [%s]:%s <<<<< fd=%d \n " , host , port , fd ) ;
free ( host ) ;
free ( port ) ;
}
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-07-11 22:45:15 +00:00
return ;
2012-04-13 12:47:30 +00:00
}
2017-05-29 09:22:23 +00:00
2012-04-13 12:47:30 +00:00
ctx - > af = peeraddr - > sa_family ;
/* determine original destination of connection */
if ( spec - > natlookup ) {
/* NAT engine lookup */
ctx - > addrlen = sizeof ( struct sockaddr_storage ) ;
2017-06-15 16:07:37 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_conn_setup() natlookup \n " ) ;
2014-11-13 23:41:27 +00:00
if ( spec - > natlookup ( ( struct sockaddr * ) & ctx - > addr , & ctx - > addrlen ,
fd , peeraddr , peeraddrlen ) = = - 1 ) {
2012-04-13 12:47:30 +00:00
log_err_printf ( " Connection not found in NAT "
2017-07-11 22:45:15 +00:00
" state table, aborting connection \n " ) ;
2012-04-13 12:47:30 +00:00
evutil_closesocket ( fd ) ;
pxy_conn_ctx_free ( ctx ) ;
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 */
log_err_printf ( " SNI mode used for non-SSL connection; "
" aborting connection \n " ) ;
evutil_closesocket ( fd ) ;
pxy_conn_ctx_free ( ctx ) ;
2017-07-11 22:45:15 +00:00
return ;
2012-04-13 12:47:30 +00:00
}
}
2017-07-11 22:45:15 +00:00
/* prepare logging, part 1 */
if ( WANT_CONNECT_LOG ( ctx ) | | WANT_CONTENT_LOG ( ctx ) ) {
if ( sys_sockaddr_str ( peeraddr , peeraddrlen ,
& ctx - > srchost_str ,
& ctx - > srcport_str ) ! = 0 )
goto memout ;
# 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
log_dbg_level_printf ( LOG_DBG_MODE_FINEST , " >>>>> pxy_conn_setup: SUCCESS EXIT fd=%d \n " , fd ) ;
return ;
2017-06-27 14:09:01 +00:00
2017-07-11 22:45:15 +00:00
memout :
2017-07-12 13:46:51 +00:00
log_dbg_level_printf ( LOG_DBG_MODE_FINE , " >>>>> pxy_conn_setup: FAIL EXIT fd=%d \n " , fd ) ;
2017-07-11 22:45:15 +00:00
log_err_printf ( " Aborting connection setup (out of memory)! \n " ) ;
evutil_closesocket ( fd ) ;
pxy_conn_ctx_free ( ctx ) ;
2017-05-29 09:22:23 +00:00
}
2017-07-07 14:18:01 +00:00
2012-04-13 12:47:30 +00:00
/* vim: set noet ft=c: */