整理目录结构,调整框架部分实现,初步编译通过。
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
|
||||
add_library(common src/tfe_stat.cpp src/tfe_utils.cpp)
|
||||
target_include_directories(common PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
|
||||
enum e_future_error
|
||||
{
|
||||
FUTURE_ERROR_CANCEL,
|
||||
FUTURE_ERROR_EXCEPTION,
|
||||
FUTURE_ERROR_TIMEOUT
|
||||
FUTURE_ERROR_CANCEL,
|
||||
FUTURE_ERROR_EXCEPTION,
|
||||
FUTURE_ERROR_TIMEOUT
|
||||
};
|
||||
|
||||
struct promise;
|
||||
struct future;
|
||||
typedef void (*future_success_cb)(void * result, void * user);
|
||||
typedef void (*future_failed_cb)(enum e_future_error err, const char * what, void * user);
|
||||
typedef void (*promise_ctx_destroy_cb)(struct promise* p);
|
||||
|
||||
struct future* future_create(future_success_cb * cb_success, future_failed_cb * cb_failed, void * user);
|
||||
|
||||
struct future* promise_to_future(struct promise* p);
|
||||
struct promise* future_to_promise(struct future* f);
|
||||
|
||||
typedef void (future_success_cb)(void * result, void * user);
|
||||
typedef void (future_failed_cb)(enum e_future_error err, const char * what, void * user);
|
||||
typedef void (promise_ctx_destroy_cb)(struct promise * p);
|
||||
|
||||
struct future * future_create(future_success_cb * cb_success, future_failed_cb * cb_failed, void * user);
|
||||
struct future * promise_to_future(struct promise * p);
|
||||
struct promise * future_to_promise(struct future * f);
|
||||
|
||||
void future_destroy(struct future * f);
|
||||
void promise_failed(struct promise * p, enum e_future_error error, const char * what);
|
||||
void promise_success(struct promise * p, void * result);
|
||||
void promise_set_ctx(struct promise * p, void * ctx, promise_ctx_destroy_cb * cb);
|
||||
void * promise_get_ctx(struct promise * p);
|
||||
void * promise_dettach_ctx(struct promise * p);
|
||||
|
||||
@@ -1,25 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <tfe_types.h>
|
||||
|
||||
#define TFE_STRING_MAX 2048
|
||||
#define TFE_SYMBOL_MAX 64
|
||||
|
||||
#define TFE_STRING_MAX 2048
|
||||
#define TFE_SYMBOL_MAX 64
|
||||
enum tfe_session_proto
|
||||
{
|
||||
SESSION_PROTO_PLAIN=0,
|
||||
SESSION_PROTO_PLAIN = 0,
|
||||
SESSION_PROTO_SSL,
|
||||
SESSION_PROTO_QUIC,
|
||||
SESSION_PROTO_SPDY
|
||||
};
|
||||
|
||||
enum tfe_app_proto
|
||||
{
|
||||
APP_PROTO_HTTP1,
|
||||
APP_PROTO_HTTP2,
|
||||
APP_PROTO_WS, //websocket
|
||||
APP_PROTO_QUIC //QUIC is a protocol that cross session layer and application layer.
|
||||
APP_PROTO_WS, //websocket
|
||||
APP_PROTO_QUIC //QUIC is a protocol that cross session layer and application layer.
|
||||
};
|
||||
|
||||
enum tfe_conn_dir
|
||||
{
|
||||
CONN_DIR_DOWNSTREAM=0, //From client to proxy, aka client-side.
|
||||
CONN_DIR_UPSTREAM //From proxy to server, aka server-side.
|
||||
CONN_DIR_DOWNSTREAM = 0, //From client to proxy, aka client-side.
|
||||
CONN_DIR_UPSTREAM //From proxy to server, aka server-side.
|
||||
};
|
||||
|
||||
enum tfe_conn_status
|
||||
{
|
||||
CONN_STATUS_NONE,
|
||||
@@ -32,78 +41,79 @@ struct tfe_conn
|
||||
{
|
||||
struct layer_addr addr;
|
||||
enum tfe_conn_status status;
|
||||
struct bufferevent *bev;
|
||||
} ;
|
||||
struct bufferevent * bev;
|
||||
};
|
||||
|
||||
struct tfe_stream
|
||||
{
|
||||
|
||||
struct tfe_conn upstream;
|
||||
struct tfe_conn upstream;
|
||||
struct tfe_conn downstream;
|
||||
};
|
||||
|
||||
|
||||
enum tfe_stream_action
|
||||
{
|
||||
ACTION_FORWARD_DATA,
|
||||
ACTION_DEFER_DATA,
|
||||
ACTION_DROP_DATA
|
||||
};
|
||||
|
||||
enum tfe_stream_action_opt
|
||||
{
|
||||
ACTION_OPT_FOWARD_BYTES, //value is size_t, default: forward entire data
|
||||
ACTION_OPT_DEFER_TIME_TV, //value is "struct timeval " which defines in <time.h>, default: time defer is not enabled
|
||||
ACTION_OPT_DEFER_BYTES, //value is size_t, default: defer entire data
|
||||
ACTION_OPT_DROP_BYTES //value is size_t, default: drop entire data
|
||||
ACTION_OPT_FOWARD_BYTES, //value is size_t, default: forward entire data
|
||||
ACTION_OPT_DEFER_TIME_TV, //value is "struct timeval " which defines in <time.h>, default: time defer is not enabled
|
||||
ACTION_OPT_DEFER_BYTES, //value is size_t, default: defer entire data
|
||||
ACTION_OPT_DROP_BYTES //value is size_t, default: drop entire data
|
||||
};
|
||||
|
||||
enum tfe_stream_close_reason
|
||||
{
|
||||
REASON_PASSIVE_CLOSED,
|
||||
REASON_ACTIVE_CLOSED,
|
||||
REASON_ERROR
|
||||
};
|
||||
int tfe_stream_action_set_opt(const struct tfe_stream* stream,enum tfe_stream_action_opt type, void* value, size_t size);
|
||||
|
||||
int tfe_stream_action_set_opt(const struct tfe_stream * stream, enum tfe_stream_action_opt type,
|
||||
void * value, size_t size);
|
||||
/*
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
*/
|
||||
int tfe_stream_write(const struct tfe_stream * stream, enum tfe_conn_dir dir, const unsigned char * data, size_t len);
|
||||
|
||||
int tfe_stream_write(const struct tfe_stream* stream, enum tfe_conn_dir dir, const unsigned char *data, size_t len);
|
||||
|
||||
struct tfe_stream_write_ctx{};
|
||||
struct tfe_stream_write_ctx;
|
||||
//following tfe_stream_write_xx functions are NOT thread safe, MUST be called in the stream process thread.
|
||||
struct tfe_stream_write_ctx* tfe_stream_write_frag_start(const struct tfe_stream* stream, enum tfe_conn_dir dir);
|
||||
struct tfe_stream_write_ctx * tfe_stream_write_frag_start(const struct tfe_stream * stream, enum tfe_conn_dir dir);
|
||||
/*
|
||||
@return 0 if successful, or -1 if an error occurred
|
||||
*/
|
||||
int tfe_stream_write_frag(struct tfe_stream_write_ctx* w_ctx,const unsigned char *data, size_t size);
|
||||
void tfe_stream_write_frag_end(struct tfe_stream_write_ctx* w_ctx);
|
||||
int tfe_stream_write_frag(struct tfe_stream_write_ctx * w_ctx, const unsigned char * data, size_t size);
|
||||
void tfe_stream_write_frag_end(struct tfe_stream_write_ctx * w_ctx);
|
||||
|
||||
//Return 1 for identify as its traffic;
|
||||
//Return 0 for unknown traffic;
|
||||
typedef tfe_stream_action stream_open_cb_t(const struct tfe_stream* stream, unsigned int thread_id, enum tfe_conn_dir dir, const unsigned char *data, size_t len, void **pme);
|
||||
typedef tfe_stream_action stream_data_cb_t(const struct tfe_stream* stream, unsigned int thread_id, enum tfe_conn_dir dir, const unsigned char *data, size_t len, void **pme);
|
||||
typedef void stream_close_cb_t(const struct tfe_stream* stream, unsigned int thread_id, enum tfe_stream_close_reason reason, void **pme);
|
||||
typedef tfe_stream_action stream_open_cb_t(const struct tfe_stream * stream, unsigned int thread_id,
|
||||
enum tfe_conn_dir dir, const unsigned char * data, size_t len, void ** pme);
|
||||
|
||||
void tfe_stream_detach(const struct tfe_stream* stream);
|
||||
int tfe_stream_preempt(const struct tfe_stream* stream);
|
||||
typedef tfe_stream_action stream_data_cb_t(const struct tfe_stream * stream, unsigned int thread_id,
|
||||
enum tfe_conn_dir dir, const unsigned char * data, size_t len, void ** pme);
|
||||
|
||||
typedef void stream_close_cb_t(const struct tfe_stream * stream, unsigned int thread_id,
|
||||
enum tfe_stream_close_reason reason, void ** pme);
|
||||
|
||||
void tfe_stream_detach(const struct tfe_stream * stream);
|
||||
int tfe_stream_preempt(const struct tfe_stream * stream);
|
||||
struct promise * tfe_stream_suspend(const struct tfe_stream * stream);
|
||||
void tfe_stream_resume(struct promisc * promisc);
|
||||
|
||||
int stream_shutdown(const struct tfe_stream* stream);//close both sides of the stream.
|
||||
int stream_shutdown_dir(const struct tfe_stream* stream, enum tfe_conn_dir dir);
|
||||
//typedef int proto_onwrite_cb_t(struct tfe_stream*, struct evbuffer *data, void **pme);
|
||||
//close both sides of the stream.
|
||||
int stream_shutdown(const struct tfe_stream * stream);
|
||||
int stream_shutdown_dir(const struct tfe_stream * stream, enum tfe_conn_dir dir);
|
||||
|
||||
struct tfe_plugin
|
||||
{
|
||||
char symbol[TFE_SYMBOL_MAX];
|
||||
enum tfe_app_proto proto;
|
||||
stream_open_cb_t* on_open;
|
||||
stream_data_cb_t* on_data;
|
||||
stream_close_cb_t* on_close;
|
||||
// proto_onwrite_cb_t *onwrite;
|
||||
|
||||
stream_open_cb_t * on_open;
|
||||
stream_data_cb_t * on_data;
|
||||
stream_close_cb_t * on_close;
|
||||
};
|
||||
int tfe_io_write(struct pxy_conn_desc* dest,int dir,struct evbuffer *data);
|
||||
|
||||
int tfe_xxx_proto_init(struct tfe_plugin*m);
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <netinet/in.h> //defines struct in_addr
|
||||
|
||||
#define __TFE_STRING_MAX 2048
|
||||
#define MAX_FILENAME_SIZE 256
|
||||
|
||||
/* network-order */
|
||||
struct stream_tuple4_v4{
|
||||
struct in_addr saddr; /* network order */
|
||||
@@ -25,15 +24,12 @@ struct stream_tuple4_v6
|
||||
in_port_t dest; /* network order */
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define GRE_TAG_LEN (4)
|
||||
struct layer_addr_gre
|
||||
{
|
||||
uint16_t gre_id;
|
||||
};
|
||||
|
||||
|
||||
#define VLAN_ID_MASK (0x0FFF)
|
||||
#define VLAN_TAG_LEN (4)
|
||||
struct layer_addr_vlan
|
||||
@@ -140,4 +136,3 @@ struct layer_addr
|
||||
};
|
||||
uint8_t addrlen; /* 地址结构长度 */
|
||||
};
|
||||
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
//#define ALLOC(t,n) (t *)calloc(sizeof(t),(n))
|
||||
|
||||
/* Allocates an array of objects using malloc() */
|
||||
#define ALLOC(type, number) \
|
||||
((type *)calloc(sizeof(type), number))
|
||||
|
||||
#define log_err_printf(fmt, args...) \
|
||||
fprintf(stderr, "file %s, line %d, " fmt, \
|
||||
__FILE__, __LINE__, ##args)
|
||||
#define log_dbg_printf(fmt, args...) \
|
||||
fprintf(stdout, "file %s, line %d, " fmt, \
|
||||
__FILE__, __LINE__, ##args)
|
||||
#define likely(expr) __builtin_expect((expr), 1)
|
||||
#define unlikely(expr) __builtin_expect((expr), 0)
|
||||
|
||||
int addr_sock2layer(struct sockaddr * sock_addr, int sockaddrlen, struct layer_addr* layer_addr);
|
||||
int addr_layer2sock(struct layer_addr* layer_addr,struct sockaddr * sock_addr);
|
||||
char* tfe_strdup(const char* s);
|
||||
|
||||
|
||||
17
common/include/tfe_utils.h
Normal file
17
common/include/tfe_utils.h
Normal file
@@ -0,0 +1,17 @@
|
||||
//#define ALLOC(t,n) (t *)calloc(sizeof(t),(n))
|
||||
|
||||
/* Allocates an array of objects using malloc() */
|
||||
#define ALLOC(type, number) \
|
||||
((type *)calloc(sizeof(type), number))
|
||||
|
||||
#define likely(expr) __builtin_expect((expr), 1)
|
||||
#define unlikely(expr) __builtin_expect((expr), 0)
|
||||
|
||||
int addr_sock_to_layer(struct sockaddr * sock_addr, int sockaddrlen, struct layer_addr * layer_addr);
|
||||
int addr_layer_to_sock(struct layer_addr * layer_addr, struct sockaddr * sock_addr);
|
||||
char* tfe_strdup(const char* s);
|
||||
|
||||
|
||||
#define TFE_LOG_ERROR
|
||||
#define TFE_LOG_INFO
|
||||
#define TFE_LOG_DEBUG
|
||||
30
common/src/tfe_utils.cpp
Normal file
30
common/src/tfe_utils.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <tfe_utils.h>
|
||||
|
||||
int addr_sock_to_layer(struct sockaddr * sock_addr, int sockaddrlen, struct layer_addr * layer_addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int addr_layer_to_sock(struct layer_addr * layer_addr, struct sockaddr * sock_addr)
|
||||
{
|
||||
int sockaddrlen=-1;
|
||||
return sockaddrlen;
|
||||
}
|
||||
|
||||
//functioned as strdup, for dictator compatible.
|
||||
char* tfe_strdup(const char* s)
|
||||
{
|
||||
char*d=NULL;
|
||||
if(s==NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
d=(char*)malloc(strlen(s)+1);
|
||||
memcpy(d,s,strlen(s)+1);
|
||||
return d;
|
||||
}
|
||||
@@ -1,3 +1,8 @@
|
||||
|
||||
add_executable(tfe src/cert.cpp src/future.cpp src/io_module_kni.cpp src/session_cache.cpp src/ssl.cc
|
||||
src/ssl_stream.cpp src/tfe_main.cpp src/tfe_proxy.cpp src/tfe_stream.cpp src/tfe_util.cpp)
|
||||
add_executable(tfe src/cert.cpp src/future.cpp src/kni.cpp src/tfe_stream.cpp src/main.cpp src/proxy.cpp)
|
||||
target_include_directories(tfe PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include/external)
|
||||
target_include_directories(tfe PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include/internal)
|
||||
|
||||
target_link_libraries(tfe common)
|
||||
target_link_libraries(tfe pthread dl openssl-ssl-static openssl-crypto-static pthread libevent-static
|
||||
libevent-static-openssl libevent-static-pthreads MESA_handle_logger MESA_prof_load wiredcfg)
|
||||
|
||||
@@ -1,62 +1,18 @@
|
||||
/*-
|
||||
* SSLsplit - transparent SSL/TLS interception
|
||||
* https://www.roe.ch/SSLsplit
|
||||
*
|
||||
* Copyright (c) 2009-2018, Daniel Roethlisberger <daniel@roe.ch>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef CERT_H
|
||||
#define CERT_H
|
||||
|
||||
#include "attrib.h"
|
||||
|
||||
#include <openssl/ssl.h>
|
||||
#include <pthread.h>
|
||||
|
||||
typedef struct cert {
|
||||
EVP_PKEY *key;
|
||||
X509 *crt;
|
||||
STACK_OF(X509) * chain;
|
||||
pthread_mutex_t mutex;
|
||||
size_t references;
|
||||
} cert_t;
|
||||
struct cert_mgr{};
|
||||
struct cert_mgr* cert_manager_init(const char* profile);
|
||||
void cert_mgr_async_get(struct future* future, struct cert_mgr* mgr, int keyring_id, X509* origin_cert, struct event_base* evbase);
|
||||
struct cert{};
|
||||
typedef struct cert cert_t;
|
||||
|
||||
struct cert_mgr;
|
||||
struct cert_mgr * cert_manager_init(const char * profile);
|
||||
|
||||
void cert_mgr_async_get(struct future * future, struct cert_mgr * mgr, int keyring_id,
|
||||
X509 * origin_cert, struct event_base * evbase);
|
||||
|
||||
cert_t * cert_new(void) MALLOC;
|
||||
cert_t * cert_new_load(const char *) MALLOC;
|
||||
cert_t * cert_new3(EVP_PKEY *, X509 *, STACK_OF(X509) *) MALLOC;
|
||||
cert_t * cert_new3_copy(EVP_PKEY *, X509 *, STACK_OF(X509) *) MALLOC;
|
||||
void cert_refcount_inc(cert_t *) NONNULL(1);
|
||||
void cert_set_key(cert_t *, EVP_PKEY *) NONNULL(1);
|
||||
void cert_set_crt(cert_t *, X509 *) NONNULL(1);
|
||||
void cert_set_chain(cert_t *, STACK_OF(X509) *) NONNULL(1);
|
||||
void cert_free(cert_t *) NONNULL(1);
|
||||
void cert_free(cert_t * cert);
|
||||
|
||||
#endif /* !CERT_H */
|
||||
|
||||
/* vim: set noet ft=c: */
|
||||
|
||||
7
platform/include/internal/sescache.h
Normal file
7
platform/include/internal/sescache.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
struct sess_cache;
|
||||
struct sess_cache * session_cache_init();
|
||||
|
||||
void session_cache_set(struct sess_cache * cache, struct sockaddr * addr,
|
||||
socklen_t addrlen, const char * sni, SSL_SESSION * session);
|
||||
@@ -29,8 +29,6 @@
|
||||
#ifndef SSL_H
|
||||
#define SSL_H
|
||||
|
||||
#include "tfe_types.h"
|
||||
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
@@ -38,31 +36,6 @@
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h>
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x10000000L) && !defined(OPENSSL_NO_THREADID)
|
||||
#define OPENSSL_NO_THREADID
|
||||
#endif
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x0090806FL) && !defined(OPENSSL_NO_TLSEXT)
|
||||
#define OPENSSL_NO_TLSEXT
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ECDH is disabled when building against OpenSSL < 1.0.0e due to issues with
|
||||
* thread-safety and security in server mode ephemereal ECDH cipher suites.
|
||||
* http://www.openssl.org/news/secadv_20110906.txt
|
||||
*/
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x1000005FL) && !defined(OPENSSL_NO_ECDH)
|
||||
#define OPENSSL_NO_ECDH
|
||||
#endif
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x0090802FL) && !defined(OPENSSL_NO_ECDSA)
|
||||
#define OPENSSL_NO_ECDSA
|
||||
#endif
|
||||
|
||||
#if (OPENSSL_VERSION_NUMBER < 0x0090802FL) && !defined(OPENSSL_NO_EC)
|
||||
#define OPENSSL_NO_EC
|
||||
#endif
|
||||
|
||||
/*
|
||||
* SHA0 was removed in OpenSSL 1.1.0, including OPENSSL_NO_SHA0.
|
||||
*/
|
||||
@@ -87,23 +60,6 @@ int DH_set0_pqg(DH *, BIGNUM *, BIGNUM *, BIGNUM *);
|
||||
#define CONST_SSL_METHOD const SSL_METHOD
|
||||
#endif /* >= OpensSL 1.0.0 */
|
||||
|
||||
/*
|
||||
* Workaround for bug in OpenSSL 0.9.8y, 1.0.0k and 1.0.1e
|
||||
* http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=703031
|
||||
* http://openssl.6102.n7.nabble.com/NULL-ptr-deref-when-calling-SSL-get-certificate-with-1-0-0k-td43636.html
|
||||
*/
|
||||
#if (OPENSSL_VERSION_NUMBER == 0x0090819fL) || \
|
||||
(OPENSSL_VERSION_NUMBER == 0x100000bfL) || \
|
||||
(OPENSSL_VERSION_NUMBER == 0x1000105fL)
|
||||
#define SSL_get_certificate(x) ssl_ssl_cert_get(x)
|
||||
X509 * ssl_ssl_cert_get(SSL *);
|
||||
#endif /* OpenSSL 0.9.8y or 1.0.0k or 1.0.1e */
|
||||
|
||||
#ifdef OPENSSL_NO_TLSEXT
|
||||
#ifndef TLSEXT_MAXLEN_host_name
|
||||
#define TLSEXT_MAXLEN_host_name 255
|
||||
#endif /* !TLSEXT_MAXLEN_host_name */
|
||||
#endif /* OPENSSL_NO_TLSEXT */
|
||||
|
||||
/*
|
||||
* SSL_OP_NO_* is used as an indication that OpenSSL is sufficiently recent
|
||||
@@ -159,72 +115,67 @@ X509 * ssl_ssl_cert_get(SSL *);
|
||||
#endif /* !HAVE_TLSV12 */
|
||||
#define SSL_PROTO_SUPPORT_S SSL2_S SSL3_S TLS10_S TLS11_S TLS12_S
|
||||
|
||||
#define SSL_KEY_IDSZ 20
|
||||
#define SSL_X509_FPRSZ 20
|
||||
|
||||
void ssl_openssl_version(void);
|
||||
int ssl_init(void) WUNRES;
|
||||
int ssl_reinit(void) WUNRES;
|
||||
int ssl_init(void);
|
||||
int ssl_reinit(void);
|
||||
void ssl_fini(void);
|
||||
|
||||
char * ssl_sha1_to_str(unsigned char *, int) NONNULL(1) MALLOC;
|
||||
char * ssl_sha1_to_str(unsigned char *, int);
|
||||
|
||||
char * ssl_ssl_state_to_str(SSL *) NONNULL(1) MALLOC;
|
||||
char * ssl_ssl_masterkey_to_str(SSL *) NONNULL(1) MALLOC;
|
||||
char * ssl_ssl_state_to_str(SSL *);
|
||||
char * ssl_ssl_masterkey_to_str(SSL *);
|
||||
|
||||
#ifndef OPENSSL_NO_DH
|
||||
DH * ssl_tmp_dh_callback(SSL *, int, int) NONNULL(1) MALLOC;
|
||||
DH * ssl_dh_load(const char *) NONNULL(1) MALLOC;
|
||||
void ssl_dh_refcount_inc(DH *) NONNULL(1);
|
||||
#endif /* !OPENSSL_NO_DH */
|
||||
DH * ssl_tmp_dh_callback(SSL *, int, int);
|
||||
DH * ssl_dh_load(const char *);
|
||||
void ssl_dh_refcount_inc(DH *);
|
||||
|
||||
#ifndef OPENSSL_NO_EC
|
||||
EC_KEY * ssl_ec_by_name(const char *) MALLOC;
|
||||
#endif /* !OPENSSL_NO_EC */
|
||||
EC_KEY * ssl_ec_by_name(const char *);
|
||||
|
||||
EVP_PKEY * ssl_key_load(const char *) NONNULL(1) MALLOC;
|
||||
EVP_PKEY * ssl_key_genrsa(const int) MALLOC;
|
||||
void ssl_key_refcount_inc(EVP_PKEY *) NONNULL(1);
|
||||
#define SSL_KEY_IDSZ 20
|
||||
int ssl_key_identifier_sha1(EVP_PKEY *, unsigned char *) NONNULL(1,2);
|
||||
char * ssl_key_identifier(EVP_PKEY *, int) NONNULL(1) MALLOC;
|
||||
EVP_PKEY * ssl_key_load(const char *);
|
||||
EVP_PKEY * ssl_key_genrsa(const int);
|
||||
|
||||
#ifndef OPENSSL_NO_TLSEXT
|
||||
int ssl_x509_v3ext_add(X509V3_CTX *, X509 *, char *, char *) NONNULL(1,2,3,4);
|
||||
int ssl_x509_v3ext_copy_by_nid(X509 *, X509 *, int) NONNULL(1,2);
|
||||
#endif /* !OPENSSL_NO_TLSEXT */
|
||||
int ssl_x509_serial_copyrand(X509 *, X509 *) NONNULL(1,2);
|
||||
X509 * ssl_x509_forge(X509 *, EVP_PKEY *, X509 *, EVP_PKEY *,
|
||||
const char *, const char *)
|
||||
NONNULL(1,2,3,4) MALLOC;
|
||||
X509 * ssl_x509_load(const char *) NONNULL(1) MALLOC;
|
||||
char * ssl_x509_subject(X509 *) NONNULL(1) MALLOC;
|
||||
char * ssl_x509_subject_cn(X509 *, size_t *) NONNULL(1,2) MALLOC;
|
||||
#define SSL_X509_FPRSZ 20
|
||||
int ssl_x509_fingerprint_sha1(X509 *, unsigned char *) NONNULL(1,2);
|
||||
char * ssl_x509_fingerprint(X509 *, int) NONNULL(1) MALLOC;
|
||||
char ** ssl_x509_names(X509 *) NONNULL(1) MALLOC;
|
||||
int ssl_x509_names_match(X509 *, const char *) NONNULL(1,2);
|
||||
char * ssl_x509_names_to_str(X509 *) NONNULL(1) MALLOC;
|
||||
char ** ssl_x509_aias(X509 *, const int) NONNULL(1) MALLOC;
|
||||
char ** ssl_x509_ocsps(X509 *) NONNULL(1) MALLOC;
|
||||
int ssl_x509_is_valid(X509 *) NONNULL(1) WUNRES;
|
||||
char * ssl_x509_to_str(X509 *) NONNULL(1) MALLOC;
|
||||
char * ssl_x509_to_pem(X509 *) NONNULL(1) MALLOC;
|
||||
void ssl_x509_refcount_inc(X509 *) NONNULL(1);
|
||||
void ssl_key_refcount_inc(EVP_PKEY *);
|
||||
|
||||
int ssl_x509chain_load(X509 **, STACK_OF(X509) **, const char *) NONNULL(2,3);
|
||||
void ssl_x509chain_use(SSL_CTX *, X509 *, STACK_OF(X509) *) NONNULL(1,2,3);
|
||||
int ssl_key_identifier_sha1(EVP_PKEY *, unsigned char *);
|
||||
char * ssl_key_identifier(EVP_PKEY *, int);
|
||||
|
||||
char * ssl_session_to_str(SSL_SESSION *) NONNULL(1) MALLOC;
|
||||
int ssl_session_is_valid(SSL_SESSION *) NONNULL(1);
|
||||
int ssl_x509_v3ext_add(X509V3_CTX *, X509 *, char *, char *);
|
||||
int ssl_x509_v3ext_copy_by_nid(X509 *, X509 *, int);
|
||||
|
||||
int ssl_is_ocspreq(const unsigned char *, size_t) NONNULL(1) WUNRES;
|
||||
int ssl_x509_serial_copyrand(X509 *, X509 *);
|
||||
X509 * ssl_x509_forge(X509 *, EVP_PKEY *, X509 *, EVP_PKEY *, const char *, const char *);
|
||||
|
||||
X509 * ssl_x509_load(const char *);
|
||||
char * ssl_x509_subject(X509 *);
|
||||
char * ssl_x509_subject_cn(X509 *, size_t *);
|
||||
|
||||
int ssl_x509_fingerprint_sha1(X509 *, unsigned char *);
|
||||
char * ssl_x509_fingerprint(X509 *, int);
|
||||
char ** ssl_x509_names(X509 *);
|
||||
int ssl_x509_names_match(X509 *, const char *);
|
||||
char * ssl_x509_names_to_str(X509 *);
|
||||
char ** ssl_x509_aias(X509 *, const int);
|
||||
char ** ssl_x509_ocsps(X509 *);
|
||||
int ssl_x509_is_valid(X509 *);
|
||||
char * ssl_x509_to_str(X509 *);
|
||||
char * ssl_x509_to_pem(X509 *);
|
||||
void ssl_x509_refcount_inc(X509 *);
|
||||
|
||||
int ssl_x509chain_load(X509 **, STACK_OF(X509) **, const char *);
|
||||
void ssl_x509chain_use(SSL_CTX *, X509 *, STACK_OF(X509) *);
|
||||
|
||||
char * ssl_session_to_str(SSL_SESSION *);
|
||||
int ssl_session_is_valid(SSL_SESSION *);
|
||||
|
||||
int ssl_is_ocspreq(const unsigned char *, size_t);
|
||||
|
||||
int ssl_tls_clienthello_parse(const unsigned char *, ssize_t, int,
|
||||
const unsigned char **, char **)
|
||||
NONNULL(1,4) WUNRES;
|
||||
int ssl_dnsname_match(const char *, size_t, const char *, size_t)
|
||||
NONNULL(1,3) WUNRES;
|
||||
char * ssl_wildcardify(const char *) NONNULL(1) MALLOC;
|
||||
const unsigned char **, char **);
|
||||
|
||||
int ssl_dnsname_match(const char *, size_t, const char *, size_t);
|
||||
char * ssl_wildcardify(const char *);
|
||||
|
||||
#endif /* !SSL_H */
|
||||
|
||||
/* vim: set noet ft=c: */
|
||||
126
platform/include/internal/stream.h
Normal file
126
platform/include/internal/stream.h
Normal file
@@ -0,0 +1,126 @@
|
||||
#pragma once
|
||||
|
||||
#include <openssl/ossl_typ.h>
|
||||
#include <event2/event.h>
|
||||
|
||||
#include <tfe_stream.h>
|
||||
#include <tfe_stat.h>
|
||||
#include <cert.h>
|
||||
|
||||
struct tfe_thread_ctx
|
||||
{
|
||||
pthread_t thr;
|
||||
unsigned int thread_id;
|
||||
size_t load;
|
||||
|
||||
struct event_base * evbase;
|
||||
unsigned char running;
|
||||
|
||||
struct tfe_stats stat;
|
||||
struct cert_mgr * cert_mgr;
|
||||
|
||||
struct sess_cache * dsess_cache;
|
||||
struct sess_cache * ssess_cache;
|
||||
|
||||
unsigned int nr_modules;
|
||||
const struct tfe_plugin * modules;
|
||||
};
|
||||
|
||||
//Downstream: comunication form client to proxy
|
||||
//Upstream: communication form proxy to server
|
||||
struct ssl_downstream
|
||||
{
|
||||
/* server name indicated by client in SNI TLS extension */
|
||||
char * sni;
|
||||
SSL * ssl;
|
||||
X509 * fake_cert_ref;//?
|
||||
int keyring_id;
|
||||
struct future * future_sni_peek;
|
||||
struct future * future_get_cert;
|
||||
};
|
||||
|
||||
struct ssl_upstream
|
||||
{
|
||||
X509 * orig_cert;
|
||||
SSL * ssl;
|
||||
struct future * conn_ssl_srv;
|
||||
};
|
||||
|
||||
enum tfe_plugin_state
|
||||
{
|
||||
PLUG_STATE_READONLY,
|
||||
PLUG_STATE_PREEPTION,
|
||||
PLUG_STATE_DETACHED
|
||||
};
|
||||
|
||||
struct plugin_ctx
|
||||
{
|
||||
enum tfe_plugin_state state;
|
||||
void * pme;
|
||||
};
|
||||
|
||||
struct tfe_stream_write_ctx
|
||||
{
|
||||
struct tfe_stream_private * _stream;
|
||||
enum tfe_conn_dir dir;
|
||||
};
|
||||
|
||||
struct tfe_conn_private
|
||||
{
|
||||
evutil_socket_t fd;
|
||||
struct bufferevent * bev;
|
||||
uint8_t on_writing;
|
||||
uint8_t closed;
|
||||
uint8_t need_shutdown;
|
||||
struct tfe_stream_write_ctx w_ctx;
|
||||
};
|
||||
|
||||
struct tfe_stream_private
|
||||
{
|
||||
struct tfe_stream head;
|
||||
enum tfe_session_proto session_type;
|
||||
struct tfe_conn_private conn_upstream;
|
||||
struct tfe_conn_private conn_downstream;
|
||||
|
||||
union
|
||||
{
|
||||
struct ssl_downstream * ssl_downstream;
|
||||
void * raw_downstream;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
struct ssl_upstream * ssl_upstream;
|
||||
void * raw_upstream;
|
||||
};
|
||||
|
||||
uint8_t is_plugin_opened;
|
||||
int calling_idx;
|
||||
size_t forward_bytes;
|
||||
size_t defere_bytes;
|
||||
size_t drop_bytes;
|
||||
enum tfe_app_proto app_proto;
|
||||
int plugin_num;
|
||||
struct plugin_ctx * plug_ctx;
|
||||
unsigned char passthrough; /* 1 if SSL passthrough is active */
|
||||
|
||||
evutil_socket_t fd_downstream;
|
||||
evutil_socket_t fd_upstream;
|
||||
|
||||
struct tfe_thread_ctx * thrmgr_ref;
|
||||
future * async_future;
|
||||
};
|
||||
|
||||
struct tfe_stream_private * tfe_stream_create(evutil_socket_t fd_downstream, evutil_socket_t fd_upstream,
|
||||
enum tfe_session_proto session_type, tfe_thread_ctx * thread);
|
||||
|
||||
void tfe_stream_setup(struct tfe_stream_private * _stream);
|
||||
|
||||
void ssl_async_connect_origin(struct future * future, evutil_socket_t fd, const char * sni,
|
||||
struct event_base * evbase, struct tfe_config * opts);
|
||||
|
||||
void ssl_async_peek_sni(struct future * future, evutil_socket_t fd, struct event_base * evbase);
|
||||
|
||||
struct ssl_downstream * ssl_downstream_create();
|
||||
void ssl_upstream_free(struct ssl_upstream * p);
|
||||
void ssl_downstream_free(struct ssl_downstream * p);
|
||||
@@ -1,32 +0,0 @@
|
||||
VPATH=../inc/
|
||||
opt: OPTFLAGS = -O
|
||||
export OPTFLAGS
|
||||
|
||||
CC = gcc
|
||||
CCC = g++
|
||||
CFLAGS = -Wall
|
||||
CFLAGS += -g -fPIC
|
||||
CFLAGS += $(OPTFLAGS)
|
||||
MESAFramework =-lMESA_htable -lMESA_prof_load -lwiredcfg -lMESA_handle_logger
|
||||
SYS_LIB =-L./ -lpthread -levent -levent_openssl -levent_pthreads
|
||||
H_DIR = ./inc_internal/
|
||||
OBJS = tfe_main.o proxy.o io_module_kni.o
|
||||
TARGET = tfe_3a
|
||||
|
||||
.PHONY: all clean deps test opt
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
opt:
|
||||
$(MAKE) all
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) -I $(H_DIR) $<
|
||||
|
||||
.cpp.o:
|
||||
$(CCC) -c $(CFLAGS) -I $(H_DIR) $<
|
||||
clean:
|
||||
rm -f $(TARGETSLIB) $(TARGETSO) *.o core core.*
|
||||
$(TARGET): $(OBJS)
|
||||
$(CC) -o $(TARGET) $(CFLAGS) $^ $(SYS_LIB) $(MESAFramework)
|
||||
cp $@ ../bin
|
||||
|
||||
@@ -1,37 +1,8 @@
|
||||
/*-
|
||||
* SSLsplit - transparent SSL/TLS interception
|
||||
* https://www.roe.ch/SSLsplit
|
||||
*
|
||||
* Copyright (c) 2009-2018, Daniel Roethlisberger <daniel@roe.ch>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "../include/internal/cert.h"
|
||||
|
||||
#include "ssl.h"
|
||||
|
||||
#include <cert.h>
|
||||
#include <string.h>
|
||||
#include <ssl.h>
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* Certificate, including private key and certificate chain.
|
||||
*/
|
||||
@@ -338,5 +309,4 @@ void cert_manager_free(cert_t * cert)
|
||||
cert_free(cert);
|
||||
return;
|
||||
}
|
||||
|
||||
/* vim: set noet ft=c: */
|
||||
#endif
|
||||
|
||||
@@ -1,70 +1,83 @@
|
||||
#include "future.h"
|
||||
struct promise
|
||||
{
|
||||
struct future f;
|
||||
void * ctx;
|
||||
promise_ctx_destroy_cb* cb_ctx_destroy;
|
||||
};
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <tfe_future.h>
|
||||
#include <tfe_utils.h>
|
||||
|
||||
struct future
|
||||
{
|
||||
void * user;
|
||||
future_success_cb * cb_success;
|
||||
future_failed_cb * cb_failed;
|
||||
void * user;
|
||||
future_success_cb * cb_success;
|
||||
future_failed_cb * cb_failed;
|
||||
};
|
||||
|
||||
inline struct future* promise_to_future(struct promise* p)
|
||||
struct promise
|
||||
{
|
||||
return p->f;
|
||||
}
|
||||
inline struct promise* future_to_promise(struct future* f)
|
||||
struct future f;
|
||||
void * ctx;
|
||||
promise_ctx_destroy_cb * cb_ctx_destroy;
|
||||
};
|
||||
|
||||
struct future * promise_to_future(struct promise * p)
|
||||
{
|
||||
return (struct promise*)f;
|
||||
return &p->f;
|
||||
}
|
||||
struct future* future_create(future_success_cb * cb_success, future_failed_cb * cb_failed, void * user)
|
||||
|
||||
struct promise * future_to_promise(struct future * f)
|
||||
{
|
||||
struct promise* p=ALLOC(struct promise, 1);
|
||||
p->f.user=user;
|
||||
p->f.cb_success=cb_success;
|
||||
p->f.cb_failed=cb_failed;
|
||||
return p->f;
|
||||
return (struct promise *) f;
|
||||
}
|
||||
|
||||
struct future * future_create(future_success_cb * cb_success, future_failed_cb * cb_failed, void * user)
|
||||
{
|
||||
struct promise * p = ALLOC(struct promise, 1);
|
||||
p->f.user = user;
|
||||
p->f.cb_success = cb_success;
|
||||
p->f.cb_failed = cb_failed;
|
||||
return &p->f;
|
||||
}
|
||||
|
||||
void future_destroy(struct future * f)
|
||||
{
|
||||
struct promise* promise=future_to_promise(f);
|
||||
if(promise->cb_ctx_destroy!=NULL)
|
||||
struct promise * promise = future_to_promise(f);
|
||||
if (promise->cb_ctx_destroy != NULL)
|
||||
{
|
||||
promise->cb_ctx_destroy(promise);
|
||||
}
|
||||
memset(promise,0,sizeof(struct promise));
|
||||
|
||||
memset(promise, 0, sizeof(struct promise));
|
||||
free(promise);
|
||||
return;
|
||||
}
|
||||
|
||||
void promise_failed(struct promise* p, enum e_future_error error, const char* what)
|
||||
void promise_failed(struct promise * p, enum e_future_error error, const char * what)
|
||||
{
|
||||
p->f.cb_failed(error, what,p->f.user);
|
||||
p->f.cb_failed(error, what, p->f.user);
|
||||
return;
|
||||
}
|
||||
void promise_success(struct promise* p, void *result)
|
||||
|
||||
void promise_success(struct promise * p, void * result)
|
||||
{
|
||||
p->f.cb_success(result, p->f.user);
|
||||
return;
|
||||
}
|
||||
void promise_set_ctx(struct promise* p,void* ctx, promise_ctx_destroy_cb* cb)
|
||||
|
||||
void promise_set_ctx(struct promise * p, void * ctx, promise_ctx_destroy_cb * cb)
|
||||
{
|
||||
p->ctx=ctx;
|
||||
p->cb_ctx_destroy=cb;
|
||||
p->ctx = ctx;
|
||||
p->cb_ctx_destroy = cb;
|
||||
return;
|
||||
}
|
||||
void* promise_get_ctx(struct promise* p)
|
||||
|
||||
void * promise_get_ctx(struct promise * p)
|
||||
{
|
||||
return p->ctx;
|
||||
}
|
||||
void* promise_dettach_ctx(struct promise* p)
|
||||
|
||||
void * promise_dettach_ctx(struct promise * p)
|
||||
{
|
||||
void* ctx=p->ctx;
|
||||
p->ctx=NULL;
|
||||
p->cb_ctx_destroy=NULL;
|
||||
void * ctx = p->ctx;
|
||||
p->ctx = NULL;
|
||||
p->cb_ctx_destroy = NULL;
|
||||
return ctx;
|
||||
}
|
||||
|
||||
|
||||
24
platform/src/main.cpp
Normal file
24
platform/src/main.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
/*-
|
||||
* Tango Frontend Engine (TFE) 3a
|
||||
* Part of Tango Security Gateway
|
||||
*
|
||||
* Copyright (c) 2018-2023, MESA Lab, https://www.mesalab.cn
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <tfe_utils.h>
|
||||
#include <MESA/MESA_handle_logger.h>
|
||||
#include <MESA/MESA_prof_load.h>
|
||||
#include <MESA/wired_cfg.h>
|
||||
|
||||
extern struct tfe_instance __g_tfe_instance;
|
||||
extern struct tfe_config __g_tfe_config;
|
||||
|
||||
struct tfe_instance* g_tfe_instance = &__g_tfe_instance;
|
||||
struct tfe_config * g_tfe_cfg = &__g_tfe_config;
|
||||
|
||||
const char* module_name="TFE";
|
||||
|
||||
@@ -1,980 +0,0 @@
|
||||
/*-
|
||||
* SSLsplit - transparent SSL/TLS interception
|
||||
* https://www.roe.ch/SSLsplit
|
||||
*
|
||||
* Copyright (c) 2009-2018, Daniel Roethlisberger <daniel@roe.ch>.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "privsep.h"
|
||||
|
||||
#include "sys.h"
|
||||
#include "util.h"
|
||||
#include "compat.h"
|
||||
#include "attrib.h"
|
||||
#include "defaults.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <libgen.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
|
||||
/*
|
||||
* Privilege separation functionality.
|
||||
*
|
||||
* The server code has limitations on the internal functionality that can be
|
||||
* used, namely only those that are initialized before forking.
|
||||
*/
|
||||
|
||||
/* maximal message sizes */
|
||||
#define PRIVSEP_MAX_REQ_SIZE 512 /* arbitrary limit */
|
||||
#define PRIVSEP_MAX_ANS_SIZE (1+sizeof(int))
|
||||
/* command byte */
|
||||
#define PRIVSEP_REQ_CLOSE 0 /* closing command socket */
|
||||
#define PRIVSEP_REQ_OPENFILE 1 /* open content log file */
|
||||
#define PRIVSEP_REQ_OPENFILE_P 2 /* open content log file w/mkpath */
|
||||
#define PRIVSEP_REQ_OPENSOCK 3 /* open socket and pass fd */
|
||||
#define PRIVSEP_REQ_CERTFILE 4 /* open cert file in certgendir */
|
||||
/* response byte */
|
||||
#define PRIVSEP_ANS_SUCCESS 0 /* success */
|
||||
#define PRIVSEP_ANS_UNK_CMD 1 /* unknown command */
|
||||
#define PRIVSEP_ANS_INVALID 2 /* invalid message */
|
||||
#define PRIVSEP_ANS_DENIED 3 /* request denied */
|
||||
#define PRIVSEP_ANS_SYS_ERR 4 /* system error; arg=errno */
|
||||
|
||||
/* communication with signal handler */
|
||||
static volatile sig_atomic_t received_sighup;
|
||||
static volatile sig_atomic_t received_sigint;
|
||||
static volatile sig_atomic_t received_sigquit;
|
||||
static volatile sig_atomic_t received_sigterm;
|
||||
static volatile sig_atomic_t received_sigchld;
|
||||
static volatile sig_atomic_t received_sigusr1;
|
||||
/* write end of pipe used for unblocking select */
|
||||
static volatile sig_atomic_t selfpipe_wrfd;
|
||||
|
||||
static void
|
||||
privsep_server_signal_handler(int sig)
|
||||
{
|
||||
int saved_errno;
|
||||
|
||||
#ifdef DEBUG_PRIVSEP_SERVER
|
||||
log_dbg_printf("privsep_server_signal_handler\n");
|
||||
#endif /* DEBUG_PRIVSEP_SERVER */
|
||||
|
||||
saved_errno = errno;
|
||||
switch (sig) {
|
||||
case SIGHUP:
|
||||
received_sighup = 1;
|
||||
break;
|
||||
case SIGINT:
|
||||
received_sigint = 1;
|
||||
break;
|
||||
case SIGQUIT:
|
||||
received_sigquit = 1;
|
||||
break;
|
||||
case SIGTERM:
|
||||
received_sigterm = 1;
|
||||
break;
|
||||
case SIGCHLD:
|
||||
received_sigchld = 1;
|
||||
break;
|
||||
case SIGUSR1:
|
||||
received_sigusr1 = 1;
|
||||
break;
|
||||
}
|
||||
if (selfpipe_wrfd != -1) {
|
||||
ssize_t n;
|
||||
|
||||
#ifdef DEBUG_PRIVSEP_SERVER
|
||||
log_dbg_printf("writing to selfpipe_wrfd %i\n", selfpipe_wrfd);
|
||||
#endif /* DEBUG_PRIVSEP_SERVER */
|
||||
do {
|
||||
n = write(selfpipe_wrfd, "!", 1);
|
||||
} while (n == -1 && errno == EINTR);
|
||||
if (n == -1) {
|
||||
log_err_printf("Failed to write from signal handler: "
|
||||
"%s (%i)\n", strerror(errno), errno);
|
||||
/* ignore error */
|
||||
}
|
||||
#ifdef DEBUG_PRIVSEP_SERVER
|
||||
} else {
|
||||
log_dbg_printf("selfpipe_wrfd is %i - not writing\n", selfpipe_wrfd);
|
||||
#endif /* DEBUG_PRIVSEP_SERVER */
|
||||
}
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
static int WUNRES
|
||||
privsep_server_openfile_verify(tfe_config *opts, char *fn, int mkpath)
|
||||
{
|
||||
if (mkpath && !opts->contentlog_isspec)
|
||||
return -1;
|
||||
if (!mkpath && !opts->contentlog_isdir)
|
||||
return -1;
|
||||
if (strstr(fn, mkpath ? opts->contentlog_basedir
|
||||
: opts->contentlog) != fn ||
|
||||
strstr(fn, "/../"))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int WUNRES
|
||||
privsep_server_openfile(char *fn, int mkpath)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (mkpath) {
|
||||
char *filedir, *fn2;
|
||||
|
||||
fn2 = strdup(fn);
|
||||
if (!fn2) {
|
||||
log_err_printf("Could not duplicate filname: %s (%i)\n",
|
||||
strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
filedir = dirname(fn2);
|
||||
if (!filedir) {
|
||||
log_err_printf("Could not get dirname: %s (%i)\n",
|
||||
strerror(errno), errno);
|
||||
free(fn2);
|
||||
return -1;
|
||||
}
|
||||
if (sys_mkpath(filedir, DFLT_DIRMODE) == -1) {
|
||||
log_err_printf("Could not create directory '%s': %s (%i)\n",
|
||||
filedir, strerror(errno), errno);
|
||||
free(fn2);
|
||||
return -1;
|
||||
}
|
||||
free(fn2);
|
||||
}
|
||||
|
||||
fd = open(fn, O_WRONLY|O_APPEND|O_CREAT, DFLT_FILEMODE);
|
||||
if (fd == -1) {
|
||||
log_err_printf("Failed to open '%s': %s (%i)\n",
|
||||
fn, strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int WUNRES
|
||||
privsep_server_opensock_verify(tfe_config *opts, void *arg)
|
||||
{
|
||||
for (proxyspec *spec = opts->spec; spec; spec = spec->next) {
|
||||
if (spec == arg)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int WUNRES
|
||||
privsep_server_opensock(proxyspec *spec)
|
||||
{
|
||||
evutil_socket_t fd;
|
||||
int on = 1;
|
||||
int rv;
|
||||
|
||||
fd = socket(spec->listen_addr.ss_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (fd == -1) {
|
||||
log_err_printf("Error from socket(): %s (%i)\n",
|
||||
strerror(errno), errno);
|
||||
evutil_closesocket(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = evutil_make_socket_nonblocking(fd);
|
||||
if (rv == -1) {
|
||||
log_err_printf("Error making socket nonblocking: %s (%i)\n",
|
||||
strerror(errno), errno);
|
||||
evutil_closesocket(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on));
|
||||
if (rv == -1) {
|
||||
log_err_printf("Error from setsockopt(SO_KEEPALIVE): %s (%i)\n",
|
||||
strerror(errno), errno);
|
||||
evutil_closesocket(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = evutil_make_listen_socket_reuseable(fd);
|
||||
if (rv == -1) {
|
||||
log_err_printf("Error from setsockopt(SO_REUSABLE): %s\n",
|
||||
strerror(errno));
|
||||
evutil_closesocket(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (spec->natsocket && (spec->natsocket(fd) == -1)) {
|
||||
log_err_printf("Error from spec->natsocket()\n");
|
||||
evutil_closesocket(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = bind(fd, (struct sockaddr *)&spec->listen_addr,
|
||||
spec->listen_addrlen);
|
||||
if (rv == -1) {
|
||||
log_err_printf("Error from bind(): %s\n", strerror(errno));
|
||||
evutil_closesocket(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int WUNRES
|
||||
privsep_server_certfile_verify(tfe_config *opts, char *fn)
|
||||
{
|
||||
if (!opts->certgendir)
|
||||
return -1;
|
||||
if (strstr(fn, opts->certgendir) != fn || strstr(fn, "/../"))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int WUNRES
|
||||
privsep_server_certfile(char *fn)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open(fn, O_WRONLY|O_CREAT|O_EXCL, DFLT_FILEMODE);
|
||||
if (fd == -1 && errno != EEXIST) {
|
||||
log_err_printf("Failed to open '%s': %s (%i)\n",
|
||||
fn, strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle a single request on a readable server socket.
|
||||
* Returns 0 on success, 1 on EOF and -1 on error.
|
||||
*/
|
||||
static int WUNRES
|
||||
privsep_server_handle_req(tfe_config *opts, int srvsock)
|
||||
{
|
||||
char req[PRIVSEP_MAX_REQ_SIZE];
|
||||
char ans[PRIVSEP_MAX_ANS_SIZE];
|
||||
ssize_t n;
|
||||
int mkpath = 0;
|
||||
|
||||
if ((n = sys_recvmsgfd(srvsock, req, sizeof(req),
|
||||
NULL)) == -1) {
|
||||
if (errno == EPIPE || errno == ECONNRESET) {
|
||||
/* unfriendly EOF, leave server */
|
||||
return 1;
|
||||
}
|
||||
log_err_printf("Failed to receive msg: %s (%i)\n",
|
||||
strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
if (n == 0) {
|
||||
/* EOF, leave server; will not happen for SOCK_DGRAM sockets */
|
||||
return 1;
|
||||
}
|
||||
log_dbg_printf("Received privsep req type %02x sz %zd on srvsock %i\n",
|
||||
req[0], n, srvsock);
|
||||
switch (req[0]) {
|
||||
case PRIVSEP_REQ_CLOSE: {
|
||||
/* client indicates EOF through close message */
|
||||
return 1;
|
||||
}
|
||||
case PRIVSEP_REQ_OPENFILE_P:
|
||||
mkpath = 1;
|
||||
case PRIVSEP_REQ_OPENFILE: {
|
||||
char *fn;
|
||||
int fd;
|
||||
|
||||
if (n < 2) {
|
||||
ans[0] = PRIVSEP_ANS_INVALID;
|
||||
if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
|
||||
log_err_printf("Sending message failed: %s (%i"
|
||||
")\n", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (!(fn = malloc(n))) {
|
||||
ans[0] = PRIVSEP_ANS_SYS_ERR;
|
||||
*((int*)&ans[1]) = errno;
|
||||
if (sys_sendmsgfd(srvsock, ans, 1 + sizeof(int),
|
||||
-1) == -1) {
|
||||
log_err_printf("Sending message failed: %s (%i"
|
||||
")\n", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
memcpy(fn, req + 1, n - 1);
|
||||
fn[n - 1] = '\0';
|
||||
if (privsep_server_openfile_verify(opts, fn, mkpath) == -1) {
|
||||
free(fn);
|
||||
ans[0] = PRIVSEP_ANS_DENIED;
|
||||
if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
|
||||
log_err_printf("Sending message failed: %s (%i"
|
||||
")\n", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if ((fd = privsep_server_openfile(fn, mkpath)) == -1) {
|
||||
free(fn);
|
||||
ans[0] = PRIVSEP_ANS_SYS_ERR;
|
||||
*((int*)&ans[1]) = errno;
|
||||
if (sys_sendmsgfd(srvsock, ans, 1 + sizeof(int),
|
||||
-1) == -1) {
|
||||
log_err_printf("Sending message failed: %s (%i"
|
||||
")\n", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
free(fn);
|
||||
ans[0] = PRIVSEP_ANS_SUCCESS;
|
||||
if (sys_sendmsgfd(srvsock, ans, 1, fd) == -1) {
|
||||
close(fd);
|
||||
log_err_printf("Sending message failed: %s (%i"
|
||||
")\n", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
/* not reached */
|
||||
break;
|
||||
}
|
||||
case PRIVSEP_REQ_OPENSOCK: {
|
||||
proxyspec *arg;
|
||||
int s;
|
||||
|
||||
if (n != sizeof(char) + sizeof(arg)) {
|
||||
ans[0] = PRIVSEP_ANS_INVALID;
|
||||
if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
|
||||
log_err_printf("Sending message failed: %s (%i"
|
||||
")\n", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
arg = *(proxyspec**)(&req[1]);
|
||||
if (privsep_server_opensock_verify(opts, arg) == -1) {
|
||||
ans[0] = PRIVSEP_ANS_DENIED;
|
||||
if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
|
||||
log_err_printf("Sending message failed: %s (%i"
|
||||
")\n", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if ((s = privsep_server_opensock(arg)) == -1) {
|
||||
ans[0] = PRIVSEP_ANS_SYS_ERR;
|
||||
*((int*)&ans[1]) = errno;
|
||||
if (sys_sendmsgfd(srvsock, ans, 1 + sizeof(int),
|
||||
-1) == -1) {
|
||||
log_err_printf("Sending message failed: %s (%i"
|
||||
")\n", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
ans[0] = PRIVSEP_ANS_SUCCESS;
|
||||
if (sys_sendmsgfd(srvsock, ans, 1, s) == -1) {
|
||||
evutil_closesocket(s);
|
||||
log_err_printf("Sending message failed: %s (%i"
|
||||
")\n", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
evutil_closesocket(s);
|
||||
return 0;
|
||||
}
|
||||
/* not reached */
|
||||
break;
|
||||
}
|
||||
case PRIVSEP_REQ_CERTFILE: {
|
||||
char *fn;
|
||||
int fd;
|
||||
|
||||
if (n < 2) {
|
||||
ans[0] = PRIVSEP_ANS_INVALID;
|
||||
if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
|
||||
log_err_printf("Sending message failed: %s (%i"
|
||||
")\n", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (!(fn = malloc(n))) {
|
||||
ans[0] = PRIVSEP_ANS_SYS_ERR;
|
||||
*((int*)&ans[1]) = errno;
|
||||
if (sys_sendmsgfd(srvsock, ans, 1 + sizeof(int),
|
||||
-1) == -1) {
|
||||
log_err_printf("Sending message failed: %s (%i"
|
||||
")\n", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
memcpy(fn, req + 1, n - 1);
|
||||
fn[n - 1] = '\0';
|
||||
if (privsep_server_certfile_verify(opts, fn) == -1) {
|
||||
free(fn);
|
||||
ans[0] = PRIVSEP_ANS_DENIED;
|
||||
if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
|
||||
log_err_printf("Sending message failed: %s (%i"
|
||||
")\n", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if ((fd = privsep_server_certfile(fn)) == -1) {
|
||||
free(fn);
|
||||
ans[0] = PRIVSEP_ANS_SYS_ERR;
|
||||
*((int*)&ans[1]) = errno;
|
||||
if (sys_sendmsgfd(srvsock, ans, 1 + sizeof(int),
|
||||
-1) == -1) {
|
||||
log_err_printf("Sending message failed: %s (%i"
|
||||
")\n", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
free(fn);
|
||||
ans[0] = PRIVSEP_ANS_SUCCESS;
|
||||
if (sys_sendmsgfd(srvsock, ans, 1, fd) == -1) {
|
||||
close(fd);
|
||||
log_err_printf("Sending message failed: %s (%i"
|
||||
")\n", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
/* not reached */
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ans[0] = PRIVSEP_ANS_UNK_CMD;
|
||||
if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
|
||||
log_err_printf("Sending message failed: %s (%i"
|
||||
")\n", strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Privilege separation server (main privileged monitor loop)
|
||||
*
|
||||
* sigpipe is the self-pipe trick pipe used for communicating signals to
|
||||
* the main event loop and break out of select() without race conditions.
|
||||
* srvsock[] is a dynamic array of connected privsep server sockets to serve.
|
||||
* Caller is responsible for freeing memory after returning, if necessary.
|
||||
* childpid is the pid of the child process to forward signals to.
|
||||
*
|
||||
* Returns 0 on a successful clean exit and -1 on errors.
|
||||
*/
|
||||
static int
|
||||
privsep_server(tfe_config *opts, int sigpipe, int srvsock[], size_t nsrvsock,
|
||||
pid_t childpid)
|
||||
{
|
||||
int srveof[nsrvsock];
|
||||
size_t i = 0;
|
||||
|
||||
for (i = 0; i < nsrvsock; i++) {
|
||||
srveof[i] = 0;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
fd_set readfds;
|
||||
int maxfd, rv;
|
||||
|
||||
#ifdef DEBUG_PRIVSEP_SERVER
|
||||
log_dbg_printf("privsep_server select()\n");
|
||||
#endif /* DEBUG_PRIVSEP_SERVER */
|
||||
do {
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(sigpipe, &readfds);
|
||||
maxfd = sigpipe;
|
||||
for (i = 0; i < nsrvsock; i++) {
|
||||
if (!srveof[i]) {
|
||||
FD_SET(srvsock[i], &readfds);
|
||||
maxfd = util_max(maxfd, srvsock[i]);
|
||||
}
|
||||
}
|
||||
rv = select(maxfd + 1, &readfds, NULL, NULL, NULL);
|
||||
#ifdef DEBUG_PRIVSEP_SERVER
|
||||
log_dbg_printf("privsep_server woke up (1)\n");
|
||||
#endif /* DEBUG_PRIVSEP_SERVER */
|
||||
} while (rv == -1 && errno == EINTR);
|
||||
if (rv == -1) {
|
||||
log_err_printf("select() failed: %s (%i)\n",
|
||||
strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
#ifdef DEBUG_PRIVSEP_SERVER
|
||||
log_dbg_printf("privsep_server woke up (2)\n");
|
||||
#endif /* DEBUG_PRIVSEP_SERVER */
|
||||
|
||||
if (FD_ISSET(sigpipe, &readfds)) {
|
||||
char buf[16];
|
||||
ssize_t n;
|
||||
/* first drain the signal pipe, then deal with
|
||||
* all the individual signal flags */
|
||||
n = read(sigpipe, buf, sizeof(buf));
|
||||
if (n == -1) {
|
||||
log_err_printf("read(sigpipe) failed:"
|
||||
" %s (%i)\n",
|
||||
strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
if (received_sigquit) {
|
||||
if (kill(childpid, SIGQUIT) == -1) {
|
||||
log_err_printf("kill(%i,SIGQUIT) "
|
||||
"failed: %s (%i)\n",
|
||||
childpid,
|
||||
strerror(errno), errno);
|
||||
}
|
||||
received_sigquit = 0;
|
||||
}
|
||||
if (received_sigterm) {
|
||||
if (kill(childpid, SIGTERM) == -1) {
|
||||
log_err_printf("kill(%i,SIGTERM) "
|
||||
"failed: %s (%i)\n",
|
||||
childpid,
|
||||
strerror(errno), errno);
|
||||
}
|
||||
received_sigterm = 0;
|
||||
}
|
||||
if (received_sighup) {
|
||||
if (kill(childpid, SIGHUP) == -1) {
|
||||
log_err_printf("kill(%i,SIGHUP) "
|
||||
"failed: %s (%i)\n",
|
||||
childpid,
|
||||
strerror(errno), errno);
|
||||
}
|
||||
received_sighup = 0;
|
||||
}
|
||||
if (received_sigusr1) {
|
||||
if (kill(childpid, SIGUSR1) == -1) {
|
||||
log_err_printf("kill(%i,SIGUSR1) "
|
||||
"failed: %s (%i)\n",
|
||||
childpid,
|
||||
strerror(errno), errno);
|
||||
}
|
||||
received_sigusr1 = 0;
|
||||
}
|
||||
if (received_sigint) {
|
||||
/* if we don't detach from the TTY, the
|
||||
* child process receives SIGINT directly */
|
||||
if (opts->detach) {
|
||||
if (kill(childpid, SIGINT) == -1) {
|
||||
log_err_printf("kill(%i,SIGINT"
|
||||
") failed: "
|
||||
"%s (%i)\n",
|
||||
childpid,
|
||||
strerror(errno),
|
||||
errno);
|
||||
}
|
||||
}
|
||||
received_sigint = 0;
|
||||
}
|
||||
if (received_sigchld) {
|
||||
/* break the loop; because we are using
|
||||
* SOCKET_DGRAM we don't get EOF conditions
|
||||
* on the disconnected socket ends here
|
||||
* unless we attempt to write or read, so
|
||||
* we depend on SIGCHLD to notify us of
|
||||
* our child erroring out or crashing */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < nsrvsock; i++) {
|
||||
if (FD_ISSET(srvsock[i], &readfds)) {
|
||||
int rv = privsep_server_handle_req(opts,
|
||||
srvsock[i]);
|
||||
if (rv == -1) {
|
||||
log_err_printf("Failed to handle "
|
||||
"privsep req "
|
||||
"on srvsock %i\n",
|
||||
srvsock[i]);
|
||||
return -1;
|
||||
}
|
||||
if (rv == 1) {
|
||||
#ifdef DEBUG_PRIVSEP_SERVER
|
||||
log_dbg_printf("srveof[%zu]=1\n", i);
|
||||
#endif /* DEBUG_PRIVSEP_SERVER */
|
||||
srveof[i] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We cannot exit as long as we need the signal handling,
|
||||
* which is as long as the child process is running.
|
||||
* The only way out of here is receiving SIGCHLD.
|
||||
*/
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
privsep_client_openfile(int clisock, const char *fn, int mkpath)
|
||||
{
|
||||
char ans[PRIVSEP_MAX_ANS_SIZE];
|
||||
char req[1 + strlen(fn)];
|
||||
int fd = -1;
|
||||
ssize_t n;
|
||||
|
||||
req[0] = mkpath ? PRIVSEP_REQ_OPENFILE_P : PRIVSEP_REQ_OPENFILE;
|
||||
memcpy(req + 1, fn, sizeof(req) - 1);
|
||||
|
||||
if (sys_sendmsgfd(clisock, req, sizeof(req), -1) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((n = sys_recvmsgfd(clisock, ans, sizeof(ans), &fd)) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (n < 1) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (ans[0]) {
|
||||
case PRIVSEP_ANS_SUCCESS:
|
||||
break;
|
||||
case PRIVSEP_ANS_DENIED:
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
case PRIVSEP_ANS_SYS_ERR:
|
||||
if (n < (ssize_t)(1 + sizeof(int))) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
errno = *((int*)&ans[1]);
|
||||
return -1;
|
||||
case PRIVSEP_ANS_UNK_CMD:
|
||||
case PRIVSEP_ANS_INVALID:
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int
|
||||
privsep_client_opensock(int clisock, const proxyspec *spec)
|
||||
{
|
||||
char ans[PRIVSEP_MAX_ANS_SIZE];
|
||||
char req[1 + sizeof(spec)];
|
||||
int fd = -1;
|
||||
ssize_t n;
|
||||
|
||||
req[0] = PRIVSEP_REQ_OPENSOCK;
|
||||
*((const proxyspec **)&req[1]) = spec;
|
||||
|
||||
if (sys_sendmsgfd(clisock, req, sizeof(req), -1) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((n = sys_recvmsgfd(clisock, ans, sizeof(ans), &fd)) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (n < 1) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (ans[0]) {
|
||||
case PRIVSEP_ANS_SUCCESS:
|
||||
break;
|
||||
case PRIVSEP_ANS_DENIED:
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
case PRIVSEP_ANS_SYS_ERR:
|
||||
if (n < (ssize_t)(1 + sizeof(int))) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
errno = *((int*)&ans[1]);
|
||||
return -1;
|
||||
case PRIVSEP_ANS_UNK_CMD:
|
||||
case PRIVSEP_ANS_INVALID:
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int
|
||||
privsep_client_certfile(int clisock, const char *fn)
|
||||
{
|
||||
char ans[PRIVSEP_MAX_ANS_SIZE];
|
||||
char req[1 + strlen(fn)];
|
||||
int fd = -1;
|
||||
ssize_t n;
|
||||
|
||||
req[0] = PRIVSEP_REQ_CERTFILE;
|
||||
memcpy(req + 1, fn, sizeof(req) - 1);
|
||||
|
||||
if (sys_sendmsgfd(clisock, req, sizeof(req), -1) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((n = sys_recvmsgfd(clisock, ans, sizeof(ans), &fd)) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (n < 1) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (ans[0]) {
|
||||
case PRIVSEP_ANS_SUCCESS:
|
||||
break;
|
||||
case PRIVSEP_ANS_DENIED:
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
case PRIVSEP_ANS_SYS_ERR:
|
||||
if (n < (ssize_t)(1 + sizeof(int))) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
errno = *((int*)&ans[1]);
|
||||
return -1;
|
||||
case PRIVSEP_ANS_UNK_CMD:
|
||||
case PRIVSEP_ANS_INVALID:
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int
|
||||
privsep_client_close(int clisock)
|
||||
{
|
||||
char req[1];
|
||||
|
||||
req[0] = PRIVSEP_REQ_CLOSE;
|
||||
|
||||
if (sys_sendmsgfd(clisock, req, sizeof(req), -1) == -1) {
|
||||
close(clisock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(clisock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fork and set up privilege separated monitor process.
|
||||
* Returns -1 on error before forking, 1 as parent, or 0 as child.
|
||||
* The array of clisock's will get filled with nclisock privsep client
|
||||
* sockets only for the child; on error and in the parent process it
|
||||
* will not be touched.
|
||||
*/
|
||||
int
|
||||
privsep_fork(tfe_config *opts, int clisock[], size_t nclisock)
|
||||
{
|
||||
int selfpipev[2]; /* self-pipe trick: signal handler -> select */
|
||||
int chldpipev[2]; /* el cheapo interprocess sync early after fork */
|
||||
int sockcliv[nclisock][2];
|
||||
pid_t pid;
|
||||
|
||||
received_sigquit = 0;
|
||||
received_sighup = 0;
|
||||
received_sigint = 0;
|
||||
received_sigchld = 0;
|
||||
received_sigusr1 = 0;
|
||||
|
||||
if (pipe(selfpipev) == -1) {
|
||||
log_err_printf("Failed to create self-pipe: %s (%i)\n",
|
||||
strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
log_dbg_printf("Created self-pipe [r=%i,w=%i]\n",
|
||||
selfpipev[0], selfpipev[1]);
|
||||
|
||||
if (pipe(chldpipev) == -1) {
|
||||
log_err_printf("Failed to create chld-pipe: %s (%i)\n",
|
||||
strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
log_dbg_printf("Created chld-pipe [r=%i,w=%i]\n",
|
||||
chldpipev[0], chldpipev[1]);
|
||||
|
||||
for (size_t i = 0; i < nclisock; i++) {
|
||||
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockcliv[i]) == -1) {
|
||||
log_err_printf("Failed to create socket pair %zu: "
|
||||
"%s (%i)\n", i, strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
log_dbg_printf("Created socketpair %zu [p=%i,c=%i]\n",
|
||||
i, sockcliv[i][0], sockcliv[i][1]);
|
||||
}
|
||||
|
||||
pid = fork();
|
||||
if (pid == -1) {
|
||||
log_err_printf("Failed to fork: %s (%i)\n",
|
||||
strerror(errno), errno);
|
||||
close(selfpipev[0]);
|
||||
close(selfpipev[1]);
|
||||
close(chldpipev[0]);
|
||||
close(chldpipev[1]);
|
||||
for (size_t i = 0; i < nclisock; i++) {
|
||||
close(sockcliv[i][0]);
|
||||
close(sockcliv[i][1]);
|
||||
}
|
||||
return -1;
|
||||
} else if (pid == 0) {
|
||||
/* child */
|
||||
close(selfpipev[0]);
|
||||
close(selfpipev[1]);
|
||||
for (size_t i = 0; i < nclisock; i++)
|
||||
close(sockcliv[i][0]);
|
||||
/* wait until parent has installed signal handlers,
|
||||
* intentionally ignoring errors */
|
||||
char buf[1];
|
||||
ssize_t n;
|
||||
close(chldpipev[1]);
|
||||
do {
|
||||
n = read(chldpipev[0], buf, sizeof(buf));
|
||||
} while (n == -1 && errno == EINTR);
|
||||
close(chldpipev[0]);
|
||||
|
||||
/* return the privsep client sockets */
|
||||
for (size_t i = 0; i < nclisock; i++)
|
||||
clisock[i] = sockcliv[i][1];
|
||||
return 0;
|
||||
}
|
||||
/* parent */
|
||||
for (size_t i = 0; i < nclisock; i++)
|
||||
close(sockcliv[i][1]);
|
||||
selfpipe_wrfd = selfpipev[1];
|
||||
|
||||
/* close file descriptors opened by preinit's only needed in client;
|
||||
* we still call the preinit's before forking in order to provide
|
||||
* better user feedback and less privsep complexity */
|
||||
nat_preinit_undo();
|
||||
|
||||
/* If the child exits before the parent installs the signal handler
|
||||
* here, we have a race condition; this is solved by the client
|
||||
* blocking on the reading end of a pipe (chldpipev[0]). */
|
||||
if (signal(SIGHUP, privsep_server_signal_handler) == SIG_ERR) {
|
||||
log_err_printf("Failed to install SIGHUP handler: %s (%i)\n",
|
||||
strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
if (signal(SIGINT, privsep_server_signal_handler) == SIG_ERR) {
|
||||
log_err_printf("Failed to install SIGINT handler: %s (%i)\n",
|
||||
strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
if (signal(SIGTERM, privsep_server_signal_handler) == SIG_ERR) {
|
||||
log_err_printf("Failed to install SIGTERM handler: %s (%i)\n",
|
||||
strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
if (signal(SIGQUIT, privsep_server_signal_handler) == SIG_ERR) {
|
||||
log_err_printf("Failed to install SIGQUIT handler: %s (%i)\n",
|
||||
strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
if (signal(SIGUSR1, privsep_server_signal_handler) == SIG_ERR) {
|
||||
log_err_printf("Failed to install SIGUSR1 handler: %s (%i)\n",
|
||||
strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
if (signal(SIGCHLD, privsep_server_signal_handler) == SIG_ERR) {
|
||||
log_err_printf("Failed to install SIGCHLD handler: %s (%i)\n",
|
||||
strerror(errno), errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* unblock the child */
|
||||
close(chldpipev[0]);
|
||||
close(chldpipev[1]);
|
||||
|
||||
int socksrv[nclisock];
|
||||
for (size_t i = 0; i < nclisock; i++)
|
||||
socksrv[i] = sockcliv[i][0];
|
||||
if (privsep_server(opts, selfpipev[0], socksrv, nclisock, pid) == -1) {
|
||||
log_err_printf("Privsep server failed: %s (%i)\n",
|
||||
strerror(errno), errno);
|
||||
/* fall through */
|
||||
}
|
||||
#ifdef DEBUG_PRIVSEP_SERVER
|
||||
log_dbg_printf("privsep_server exited\n");
|
||||
#endif /* DEBUG_PRIVSEP_SERVER */
|
||||
|
||||
for (size_t i = 0; i < nclisock; i++)
|
||||
close(sockcliv[i][0]);
|
||||
selfpipe_wrfd = -1; /* tell signal handler not to write anymore */
|
||||
close(selfpipev[0]);
|
||||
close(selfpipev[1]);
|
||||
|
||||
int status;
|
||||
wait(&status);
|
||||
if (WIFEXITED(status)) {
|
||||
if (WEXITSTATUS(status) != 0) {
|
||||
log_err_printf("Child proc %lld exited with status %d\n",
|
||||
(long long)pid, WEXITSTATUS(status));
|
||||
} else {
|
||||
log_dbg_printf("Child proc %lld exited with status %d\n",
|
||||
(long long)pid, WEXITSTATUS(status));
|
||||
}
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
log_err_printf("Child proc %lld killed by signal %d\n",
|
||||
(long long)pid, WTERMSIG(status));
|
||||
} else {
|
||||
log_err_printf("Child proc %lld neither exited nor killed\n",
|
||||
(long long)pid);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* vim: set noet ft=c: */
|
||||
|
||||
|
||||
|
||||
294
platform/src/proxy.cpp
Normal file
294
platform/src/proxy.cpp
Normal file
@@ -0,0 +1,294 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/un.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.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 <MESA/MESA_handle_logger.h>
|
||||
#include <tfe_utils.h>
|
||||
#include <tfe_stream.h>
|
||||
#include <stream.h>
|
||||
#include <kni.h>
|
||||
#include <sescache.h>
|
||||
|
||||
/*
|
||||
* Proxy engine, built around libevent 2.x.
|
||||
*/
|
||||
|
||||
#define TFE_BACKLOG_DEFAULT 20
|
||||
|
||||
const char * module_name_pxy = "TFE_PXY";
|
||||
extern struct tfe_instance * g_tfe_instance;
|
||||
|
||||
__thread int __currect_thread_id;
|
||||
|
||||
static void __dummy_event_handler(evutil_socket_t fd, short what, void * arg)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Thread entry point; runs the event loop of the event base.
|
||||
* Does not exit until the libevent loop is broken explicitly.
|
||||
*/
|
||||
static void * __tfe_thrmgr_thread_entry(void * arg)
|
||||
{
|
||||
struct tfe_thread_ctx * ctx = (struct tfe_thread_ctx *) arg;
|
||||
struct timeval timer_delay = {60, 0};
|
||||
|
||||
struct event * ev;
|
||||
ev = event_new(ctx->evbase, -1, EV_PERSIST, __dummy_event_handler, NULL);
|
||||
|
||||
if (!ev) return (void *)NULL;
|
||||
|
||||
evtimer_add(ev, &timer_delay);
|
||||
ctx->running = 1;
|
||||
|
||||
__currect_thread_id = ctx->thread_id;
|
||||
event_base_dispatch(ctx->evbase);
|
||||
event_free(ev);
|
||||
|
||||
return (void *)NULL;
|
||||
}
|
||||
|
||||
static int signals[] = {SIGTERM, SIGQUIT, SIGHUP, SIGINT, SIGPIPE, SIGUSR1};
|
||||
|
||||
struct tfe_proxy
|
||||
{
|
||||
char name[TFE_SYMBOL_MAX];
|
||||
struct event_base * evbase;
|
||||
struct event * sev[sizeof(signals) / sizeof(int)];
|
||||
struct event * gcev;
|
||||
|
||||
struct tfe_config * opts;
|
||||
void * main_logger;
|
||||
|
||||
struct sess_cache * dsess_cache;
|
||||
struct sess_cache * ssess_cache;
|
||||
|
||||
unsigned int nr_work_threads;
|
||||
struct tfe_thread_ctx * work_threads;
|
||||
|
||||
unsigned int nr_modules;
|
||||
struct tfe_plugin * modules;
|
||||
|
||||
void * io_mod;
|
||||
};
|
||||
|
||||
/*
|
||||
* Signal handler for SIGTERM, SIGQUIT, SIGINT, SIGHUP, SIGPIPE and SIGUSR1.
|
||||
*/
|
||||
static void proxy_signal_cb(evutil_socket_t fd, short what, void * arg)
|
||||
{
|
||||
tfe_proxy * ctx = (tfe_proxy *) arg;
|
||||
switch (fd)
|
||||
{
|
||||
case SIGTERM:
|
||||
case SIGQUIT:
|
||||
case SIGINT:
|
||||
case SIGHUP:
|
||||
break;
|
||||
case SIGUSR1:
|
||||
break;
|
||||
case SIGPIPE:
|
||||
TFE_LOG_ERROR("Warning: Received SIGPIPE; ignoring.\n");
|
||||
break;
|
||||
default:
|
||||
TFE_LOG_ERROR("Warning: Received unexpected signal %i\n", fd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void proxy_gc_cb(evutil_socket_t fd, short what, void * arg)
|
||||
{
|
||||
tfe_proxy * ctx = (tfe_proxy *) arg;
|
||||
(void)fd;
|
||||
(void)what;
|
||||
}
|
||||
|
||||
unsigned int select_work_thread(struct tfe_proxy * pxy)
|
||||
{
|
||||
unsigned int min_thread_id = 0;
|
||||
size_t min_load = pxy->work_threads[min_thread_id].load;
|
||||
|
||||
for (unsigned thread_id = 1; thread_id < pxy->nr_work_threads; thread_id++)
|
||||
{
|
||||
if (min_load > pxy->work_threads[thread_id].load)
|
||||
{
|
||||
min_load = pxy->work_threads[thread_id].load;
|
||||
min_thread_id = thread_id;
|
||||
}
|
||||
}
|
||||
|
||||
pxy->work_threads[min_thread_id].load++;
|
||||
return min_thread_id;
|
||||
}
|
||||
/*
|
||||
* Callback for accept events on the socket listener bufferevent.
|
||||
*/
|
||||
static void io_mod_accept_cb(evutil_socket_t upstream_fd, evutil_socket_t downstream_fd,
|
||||
enum tfe_session_proto session_type, void * arg)
|
||||
{
|
||||
struct tfe_proxy * pxy = (struct tfe_proxy *) arg;
|
||||
|
||||
unsigned int worker_tid = select_work_thread(pxy);
|
||||
tfe_thread_ctx * worker_thread_ctx = &pxy->work_threads[worker_tid];
|
||||
|
||||
struct tfe_stream_private * stream = tfe_stream_create(upstream_fd,
|
||||
downstream_fd, session_type, worker_thread_ctx);
|
||||
|
||||
assert(stream != NULL);
|
||||
return tfe_stream_setup(stream);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up the core event loop.
|
||||
* Socket clisock is the privsep client socket used for binding to ports.
|
||||
* Returns ctx on success, or NULL on error.
|
||||
*/
|
||||
struct tfe_proxy * tfe_proxy_new(tfe_config * cfg)
|
||||
{
|
||||
struct tfe_proxy * proxy = ALLOC(struct tfe_proxy, 1);
|
||||
assert(proxy != NULL);
|
||||
|
||||
struct timeval gc_delay = {60, 0};
|
||||
|
||||
/* adds locking, only required if accessed from separate threads */
|
||||
evthread_use_pthreads();
|
||||
event_enable_debug_mode();
|
||||
|
||||
proxy->evbase = event_base_new();
|
||||
proxy->dsess_cache = session_cache_init();
|
||||
proxy->ssess_cache = session_cache_init();
|
||||
|
||||
proxy->nr_modules = 2;
|
||||
proxy->modules = ALLOC(struct tfe_plugin, proxy->nr_modules);
|
||||
|
||||
proxy->modules[0].proto = APP_PROTO_HTTP1;
|
||||
proxy->modules[1].proto = APP_PROTO_HTTP2;
|
||||
|
||||
proxy->work_threads = ALLOC(struct tfe_thread_ctx, proxy->nr_work_threads);
|
||||
|
||||
for (unsigned int i = 0; i < proxy->nr_work_threads; i++)
|
||||
{
|
||||
proxy->work_threads[i].thread_id = i;
|
||||
proxy->work_threads[i].evbase = event_base_new();
|
||||
proxy->work_threads[i].dsess_cache = proxy->dsess_cache;
|
||||
proxy->work_threads[i].ssess_cache = proxy->ssess_cache;
|
||||
proxy->work_threads[i].nr_modules = proxy->nr_modules;
|
||||
proxy->work_threads[i].modules = proxy->modules;
|
||||
}
|
||||
|
||||
//Todo: Not handle signal if have mutliple proxy instance.
|
||||
for (size_t i = 0; i < (sizeof(signals) / sizeof(int)); i++)
|
||||
{
|
||||
proxy->sev[i] = evsignal_new(proxy->evbase, signals[i], proxy_signal_cb, proxy);
|
||||
if (!proxy->sev[i]) goto error_out;
|
||||
evsignal_add(proxy->sev[i], NULL);
|
||||
}
|
||||
|
||||
proxy->gcev = event_new(proxy->evbase, -1, EV_PERSIST, proxy_gc_cb, proxy);
|
||||
if (!proxy->gcev)
|
||||
goto error_out;
|
||||
|
||||
evtimer_add(proxy->gcev, &gc_delay);
|
||||
return proxy;
|
||||
|
||||
error_out:
|
||||
if (proxy->gcev)
|
||||
{
|
||||
event_free(proxy->gcev);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < (sizeof(proxy->sev) / sizeof(proxy->sev[0])); i++)
|
||||
{
|
||||
if (proxy->sev[i])
|
||||
{
|
||||
event_free(proxy->sev[i]);
|
||||
}
|
||||
}
|
||||
|
||||
for (typeof(proxy->nr_work_threads) i = 0; i < proxy->nr_work_threads; i++)
|
||||
{
|
||||
proxy->work_threads[i].thread_id = i;
|
||||
event_base_free(proxy->work_threads[i].evbase);
|
||||
}
|
||||
|
||||
event_base_free(proxy->evbase);
|
||||
|
||||
free(proxy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run the event loop. Returns when the event loop is cancelled by a signal
|
||||
* or on failure.
|
||||
*/
|
||||
void tfe_proxy_run(struct tfe_proxy * proxy)
|
||||
{
|
||||
unsigned int thread_id;
|
||||
for (thread_id = 0; thread_id < proxy->nr_work_threads; thread_id++)
|
||||
{
|
||||
if (pthread_create(&(proxy->work_threads[thread_id].thr), NULL,
|
||||
__tfe_thrmgr_thread_entry, &(proxy->work_threads[thread_id])))
|
||||
{
|
||||
MESA_handle_runtime_log(proxy->main_logger, RLOG_LV_FATAL, proxy->name, "pthread_create failed.");
|
||||
}
|
||||
|
||||
while (!proxy->work_threads[thread_id].running)
|
||||
{
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
|
||||
event_base_dispatch(proxy->evbase);
|
||||
}
|
||||
|
||||
/*
|
||||
* Break the loop of the proxy, causing the tfe_proxy_run to return.
|
||||
*/
|
||||
void proxy_loopbreak(tfe_proxy * ctx)
|
||||
{
|
||||
event_base_loopbreak(ctx->evbase);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the proxy data structures.
|
||||
*/
|
||||
void proxy_free(tfe_proxy * ctx)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char* main_profile="./conf/tfe_main.conf";
|
||||
|
||||
tfe_proxy *proxy=NULL;
|
||||
void* wcfg_handle=NULL;
|
||||
|
||||
//TODO: Initiate Local Cert Cache, Decryption Mirror, Field Stat, Logger and etc.
|
||||
//NOTICE: Maat, Cert Store,Tango Cache are initiated in bussiness plugin.
|
||||
|
||||
#if 0
|
||||
g_tfe_instance=ALLOC(struct tfe_instance,1);
|
||||
proxy=tfe_proxy_new(g_tfe_cfg);
|
||||
#endif
|
||||
|
||||
tfe_proxy_run(proxy);
|
||||
proxy_free(proxy);
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
|
||||
struct sess_cache
|
||||
{
|
||||
};
|
||||
struct sess_cache* session_cache_init()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void session_cache_set(struct sess_cache* cache, struct sockaddr *addr, socklen_t addrlen, const char* sni,SSL_SESSION* session)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*-
|
||||
* Tango Frontend Engine (TFE) 3a
|
||||
* Part of Tango Security Gateway
|
||||
*
|
||||
* Copyright (c) 2018-2023, MESA Lab, https://www.mesalab.cn
|
||||
* All rights reserved.
|
||||
*/
|
||||
#include "proxy.h"
|
||||
#include "tfe_util.h"
|
||||
#include "MESA_handle_logger.h"
|
||||
#include "MESA_prof_load.h"
|
||||
#include "wired_cfg.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
struct tfe_instance* g_tfe_instance=NULL;
|
||||
struct tfe_config * g_tfe_cfg=NULL;
|
||||
const char* module_name="TFE";
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char* main_profile="./conf/tfe_main.conf";
|
||||
|
||||
tfe_proxy *proxy=NULL;
|
||||
void* wcfg_handle=NULL;
|
||||
|
||||
wcfg_handle=wired_cfg_create(module_name, main_profile);
|
||||
wired_cfg_init(wcfg_handle);
|
||||
wired_cfg_destroy(wcfg_handle);
|
||||
g_tfe_cfg=ALLOC(struct tfe_config, 1);
|
||||
MESA_load_profile_uint_def(main_profile, "SYSTEM", "thread_num",&(g_tfe_cfg->thread_num),1);
|
||||
MESA_load_profile_uint_def(main_profile, "SYSTEM", "use_cert_store",&(g_tfe_cfg->use_cert_store),0);
|
||||
//TODO: Initiate Local Cert Cache, Decryption Mirror, Field Stat, Logger and etc.
|
||||
//NOTICE: Maat, Cert Store,Tango Cache are initiated in bussiness plugin.
|
||||
g_tfe_instance=ALLOC(struct tfe_instance,1);
|
||||
proxy=tfe_proxy_new(g_tfe_cfg);
|
||||
|
||||
//TODO: Drop privs, chroot
|
||||
tfe_proxy_run(proxy);
|
||||
proxy_free(proxy);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,407 +0,0 @@
|
||||
|
||||
#include "proxy.h"
|
||||
#include "opts.h"
|
||||
#include "attrib.h"
|
||||
#include "tfe_util.h"
|
||||
#include "tfe_stream.h"
|
||||
#include "tfe_stream_internal.h"
|
||||
#include "MESA_handle_logger.h"
|
||||
#include "io_module_kni.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <pthread.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 <sys/un.h>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
/*
|
||||
* Proxy engine, built around libevent 2.x.
|
||||
*/
|
||||
|
||||
#define TFE_BACKLOG_DEFAULT 20
|
||||
const char* module_name_pxy="TFE_PXY";
|
||||
extern struct tfe_instance* g_tfe_instance;
|
||||
|
||||
__thread int __currect_thread_id;
|
||||
|
||||
|
||||
void free_thread_manager(struct tfe_thread_manager_ctx* ctx)
|
||||
{
|
||||
free(ctx->thr_ctx);
|
||||
ctx->thr_ctx=NULL;
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
static void __dummy_event_handler(
|
||||
UNUSED evutil_socket_t fd, UNUSED short what,
|
||||
UNUSED void *arg)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
/*
|
||||
* Thread entry point; runs the event loop of the event base.
|
||||
* Does not exit until the libevent loop is broken explicitly.
|
||||
*/
|
||||
static void *__tfe_thrmgr_thread_entry(void *arg)
|
||||
{
|
||||
struct tfe_thread_ctx *ctx = (struct tfe_thread_ctx *) arg;
|
||||
struct timeval timer_delay = {60, 0};
|
||||
|
||||
struct event *ev;
|
||||
ev = event_new(ctx->evbase, -1, EV_PERSIST, __dummy_event_handler, NULL);
|
||||
|
||||
if (!ev) return NULL;
|
||||
|
||||
evtimer_add(ev, &timer_delay);
|
||||
ctx->running = 1;
|
||||
|
||||
__currect_thread_id = ctx->thread_id;
|
||||
MESA_handle_runtime_log(g_tfe_instance->main_logger, RLOG_LV_FATAL, module_name_pxy,"EventThread %d is running...", __currect_thread_id);
|
||||
|
||||
event_base_dispatch(ctx->evbase);
|
||||
event_free(ev);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int tfe_thread_manager_run(struct tfe_thread_manager_ctx *ctx)
|
||||
{
|
||||
unsigned int thread_id;
|
||||
|
||||
for (thread_id = 0; thread_id < ctx->nr_thread; thread_id++)
|
||||
{
|
||||
if (pthread_create(&(ctx->thr_ctx[thread_id].thr), NULL,
|
||||
__tfe_thrmgr_thread_entry, &(ctx->thr_ctx[thread_id])))
|
||||
{
|
||||
MESA_handle_runtime_log(g_tfe_instance->main_logger, RLOG_LV_FATAL, module_name_pxy, "pthread_create failed.");
|
||||
}
|
||||
|
||||
while (!ctx->thr_ctx[thread_id].running)
|
||||
{
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
MESA_handle_runtime_log(g_tfe_instance->main_logger, RLOG_LV_INFO, module_name_pxy,"Started %d connection handling threads\n", ctx->nr_thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int signals[] = {SIGTERM, SIGQUIT, SIGHUP, SIGINT, SIGPIPE, SIGUSR1};
|
||||
|
||||
struct tfe_proxy
|
||||
{
|
||||
char name[32];
|
||||
struct event_base * evbase;
|
||||
struct event * sev[sizeof(signals) / sizeof(int)];
|
||||
struct event * gcev;
|
||||
struct proxy_listener_ctx * lctx;
|
||||
struct tfe_config * opts;
|
||||
void* main_logger;
|
||||
unsigned int thread_num;
|
||||
struct tfe_thread_ctx* work_threads;
|
||||
void* io_mod;
|
||||
cert_mgr* cert_mgr;
|
||||
struct sess_cache* dsess_cache;
|
||||
struct sess_cache* ssess_cache;
|
||||
int module_num;
|
||||
struct tfe_plugin* modules;
|
||||
};
|
||||
|
||||
/*
|
||||
* Signal handler for SIGTERM, SIGQUIT, SIGINT, SIGHUP, SIGPIPE and SIGUSR1.
|
||||
*/
|
||||
static void
|
||||
proxy_signal_cb(evutil_socket_t fd, UNUSED short what, void * arg)
|
||||
{
|
||||
tfe_proxy * ctx = (tfe_proxy *) arg;
|
||||
if (OPTS_DEBUG(ctx->opts))
|
||||
{
|
||||
log_dbg_printf("Received signal %i\n", fd);
|
||||
}
|
||||
|
||||
switch (fd)
|
||||
{
|
||||
case SIGTERM:
|
||||
case SIGQUIT:
|
||||
case SIGINT:
|
||||
case SIGHUP: proxy_loopbreak(ctx);
|
||||
break;
|
||||
|
||||
#if 0
|
||||
case SIGUSR1:
|
||||
if (log_reopen() == -1) {
|
||||
log_err_printf("Warning: Failed to reopen logs\n");
|
||||
} else {
|
||||
log_dbg_printf("Reopened log files\n");
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case SIGPIPE: log_err_printf("Warning: Received SIGPIPE; ignoring.\n");
|
||||
break;
|
||||
default: log_err_printf("Warning: Received unexpected signal %i\n", fd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Garbage collection handler.
|
||||
*/
|
||||
static void
|
||||
proxy_gc_cb(UNUSED evutil_socket_t fd, UNUSED short what, void * arg)
|
||||
{
|
||||
tfe_proxy * ctx = (tfe_proxy *) arg;
|
||||
|
||||
if (OPTS_DEBUG(ctx->opts))
|
||||
log_dbg_printf("Garbage collecting caches started.\n");
|
||||
|
||||
// cachemgr_gc();
|
||||
|
||||
if (OPTS_DEBUG(ctx->opts))
|
||||
log_dbg_printf("Garbage collecting caches done.\n");
|
||||
}
|
||||
int select_work_thread(struct tfe_proxy *pxy)
|
||||
{
|
||||
|
||||
int min_thread_id = 0;
|
||||
size_t min_load = pxy->work_threads[min_thread_id]->load;
|
||||
|
||||
for (unsigned thread_id = 1; thread_id < pxy->thread_num; thread_id++)
|
||||
{
|
||||
if (min_load > pxy->work_threads[thread_id]->load)
|
||||
{
|
||||
min_load = pxy->work_threads[thread_id]->load;
|
||||
min_thread_id = thread_id;
|
||||
}
|
||||
}
|
||||
pxy->work_threads[min_thread_id]->load++;
|
||||
return min_thread_id;
|
||||
}
|
||||
/*
|
||||
* Callback for accept events on the socket listener bufferevent.
|
||||
*/
|
||||
static void io_mod_accept_cb( evutil_socket_t upstream_fd, evutil_socket_t downstream_fd, enum tfe_session_proto session_type,
|
||||
struct sockaddr * peeraddr, int peeraddrlen, void * arg)
|
||||
{
|
||||
struct tfe_proxy* pxy=(struct tfe_proxy* )arg;
|
||||
struct tfe_stream_private* stream=NULL;
|
||||
int tid=-1;
|
||||
tid=select_work_thread(pxy);
|
||||
stream=tfe_stream_create(upstream_fd, downstream_fd, session_type,peeraddr, peeraddrlen, pxy->work_threads+tid);
|
||||
tfe_stream_setup(stream);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up the core event loop.
|
||||
* Socket clisock is the privsep client socket used for binding to ports.
|
||||
* Returns ctx on success, or NULL on error.
|
||||
*/
|
||||
struct tfe_proxy * tfe_proxy_new(tfe_config * opts)
|
||||
{
|
||||
struct tfe_proxy * proxy=NULL;
|
||||
size_t i = 0;
|
||||
int ret=0;
|
||||
|
||||
struct timeval gc_delay = {60, 0};
|
||||
|
||||
/* adds locking, only required if accessed from separate threads */
|
||||
evthread_use_pthreads();
|
||||
|
||||
if (OPTS_DEBUG(opts))
|
||||
{
|
||||
event_enable_debug_mode();
|
||||
}
|
||||
|
||||
proxy = ALLOC(struct tfe_proxy,1);
|
||||
proxy->opts = opts;
|
||||
proxy->evbase = event_base_new();
|
||||
if (!proxy->evbase)
|
||||
{
|
||||
log_err_printf("Error getting event base\n");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
if (OPTS_DEBUG(opts))
|
||||
{
|
||||
proxy_debug_base(proxy->evbase);
|
||||
}
|
||||
switch(opts->input_io_module)
|
||||
{
|
||||
case IO_MOD_KNI:
|
||||
strcpy(proxy->name,"KNI_PXY");
|
||||
proxy->io_mod=io_kni_init(opts->kni_path,proxy->evbase);
|
||||
assert(ret>=0);
|
||||
break;
|
||||
case IO_MOD_TPROXY:
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
proxy->thread_num=opts->thread_num;
|
||||
proxy->cert_mgr=cert_manager_init();
|
||||
proxy->dsess_cache=session_cache_init();
|
||||
proxy->ssess_cache=session_cache_init();
|
||||
|
||||
proxy->module_num=2;
|
||||
proxy->modules=ALLOC(struct tfe_plugin,proxy->module_num);
|
||||
proxy->modules[0].proto=APP_PROTO_HTTP1;
|
||||
//todo: setup each protocol module.
|
||||
//proxy->modules[0].on_read=xxx;
|
||||
proxy->modules[1].proto=APP_PROTO_HTTP2;
|
||||
|
||||
proxy->work_threads=ALLOC(struct tfe_thread_ctx, proxy->thread_num);
|
||||
for(i=0;i<proxy->thread_num;i++)
|
||||
{
|
||||
proxy->work_threads[i].thread_id=i;
|
||||
proxy->work_threads[i].evbase = event_base_new();
|
||||
proxy->work_threads[i].opts=opts;
|
||||
proxy->work_threads[i].cert_mgr=proxy->cert_mgr;//reference
|
||||
proxy->work_threads[i].dsess_cache=proxy->dsess_cache;
|
||||
proxy->work_threads[i].ssess_cache=proxy->ssess_cache;
|
||||
proxy->work_threads[i].module_num=proxy->module_num;
|
||||
proxy->work_threads[i].modules=proxy->modules
|
||||
}
|
||||
//Todo: Not handle signal if have mutliple proxy instance.
|
||||
for (i = 0; i < (sizeof(signals) / sizeof(int)); i++)
|
||||
{
|
||||
proxy->sev[i] = evsignal_new(proxy->evbase, signals[i], proxy_signal_cb, proxy);
|
||||
if (!proxy->sev[i])
|
||||
goto error_out;
|
||||
evsignal_add(proxy->sev[i], NULL);
|
||||
}
|
||||
|
||||
proxy->gcev = event_new(proxy->evbase, -1, EV_PERSIST, proxy_gc_cb, proxy);
|
||||
if (!proxy->gcev)
|
||||
goto error_out;
|
||||
|
||||
evtimer_add(proxy->gcev, &gc_delay);
|
||||
return proxy;
|
||||
error_out:
|
||||
if (proxy->gcev)
|
||||
{
|
||||
event_free(proxy->gcev);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < (sizeof(proxy->sev) / sizeof(proxy->sev[0])); i++)
|
||||
{
|
||||
if (proxy->sev[i])
|
||||
{
|
||||
event_free(proxy->sev[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (proxy->lctx)
|
||||
{
|
||||
proxy_listener_ctx_free(proxy->lctx);
|
||||
}
|
||||
for(i=0;i<proxy->thread_num;i++)
|
||||
{
|
||||
proxy->work_threads[i].thread_id=i;
|
||||
event_base_free(proxy->work_threads[i].evbase);
|
||||
}
|
||||
|
||||
event_base_free(proxy->evbase);
|
||||
|
||||
free(proxy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run the event loop. Returns when the event loop is cancelled by a signal
|
||||
* or on failure.
|
||||
*/
|
||||
void tfe_proxy_run(struct tfe_proxy * proxy)
|
||||
{
|
||||
if (proxy->opts->detach)
|
||||
{
|
||||
event_reinit(proxy->evbase);
|
||||
}
|
||||
#ifndef PURIFY
|
||||
if (OPTS_DEBUG(proxy->opts))
|
||||
{
|
||||
event_base_dump_events(proxy->evbase, stderr);
|
||||
}
|
||||
#endif /* PURIFY */
|
||||
unsigned int thread_id;
|
||||
|
||||
for (thread_id = 0; thread_id < proxy->thread_num; thread_id++)
|
||||
{
|
||||
if (pthread_create(&(proxy->work_threads[thread_id].thr), NULL,
|
||||
__tfe_thrmgr_thread_entry, &(proxy->work_threads[thread_id])))
|
||||
{
|
||||
MESA_handle_runtime_log(proxy->main_logger, RLOG_LV_FATAL, proxy->name, "pthread_create failed.");
|
||||
}
|
||||
|
||||
while (!proxy->work_threads[thread_id].running)
|
||||
{
|
||||
sched_yield();
|
||||
}
|
||||
}
|
||||
MESA_handle_runtime_log(proxy->main_logger, RLOG_LV_INFO, proxy->name,"Started %d connection handling threads\n", proxy->nr_thread);
|
||||
if (OPTS_DEBUG(proxy->opts))
|
||||
{
|
||||
log_dbg_printf("Starting main event loop.\n");
|
||||
}
|
||||
event_base_dispatch(proxy->evbase);
|
||||
if (OPTS_DEBUG(proxy->opts))
|
||||
{
|
||||
log_dbg_printf("Main event loop stopped.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Break the loop of the proxy, causing the tfe_proxy_run to return.
|
||||
*/
|
||||
void
|
||||
proxy_loopbreak(tfe_proxy * ctx)
|
||||
{
|
||||
event_base_loopbreak(ctx->evbase);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the proxy data structures.
|
||||
*/
|
||||
void
|
||||
proxy_free(tfe_proxy * ctx)
|
||||
{
|
||||
if (ctx->gcev)
|
||||
{
|
||||
event_free(ctx->gcev);
|
||||
}
|
||||
if (ctx->lctx)
|
||||
{
|
||||
proxy_listener_ctx_free(ctx->lctx);
|
||||
}
|
||||
for (size_t i = 0; i < (sizeof(ctx->sev) / sizeof(ctx->sev[0])); i++)
|
||||
{
|
||||
if (ctx->sev[i])
|
||||
{
|
||||
event_free(ctx->sev[i]);
|
||||
}
|
||||
}
|
||||
if (ctx->thrmgr)
|
||||
{
|
||||
free_thread_manager(ctx->thrmgr);
|
||||
}
|
||||
if (ctx->evbase)
|
||||
{
|
||||
event_base_free(ctx->evbase);
|
||||
}
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
/* vim: set noet ft=c: */
|
||||
@@ -1,15 +1,10 @@
|
||||
|
||||
#include "tfe_stream.h"
|
||||
#include "tfe_util.h"
|
||||
#include "opts.h"
|
||||
#include "attrib.h"
|
||||
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <event2/event.h>
|
||||
#include <event2/listener.h>
|
||||
@@ -25,17 +20,23 @@
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h>
|
||||
|
||||
#define STREAM_EVBASE(s) ((s)->thrmgr_ref->evbase)
|
||||
#include <tfe_stream.h>
|
||||
#include <tfe_utils.h>
|
||||
#include <tfe_future.h>
|
||||
#include <stream.h>
|
||||
#include <cert.h>
|
||||
|
||||
#define STREAM_EVBASE(s) ((s)->thrmgr_ref->evbase)
|
||||
/*
|
||||
* Maximum size of data to buffer per connection direction before
|
||||
* temporarily stopping to read data from the other end.
|
||||
*/
|
||||
#define OUTBUF_LIMIT (1024*1024)
|
||||
#define OUTBUF_LIMIT (1024*1024)
|
||||
|
||||
/*
|
||||
* Print helper for logging code.
|
||||
*/
|
||||
#define STRORDASH(x) (((x)&&*(x))?(x):"-")
|
||||
#define STRORDASH(x) (((x)&&*(x))?(x):"-")
|
||||
|
||||
/*
|
||||
* Context used for all server http_sessions_.
|
||||
@@ -44,85 +45,108 @@
|
||||
static unsigned long ssl_session_context = 0x31415926;
|
||||
#endif /* USE_SSL_SESSION_ID_CONTEXT */
|
||||
|
||||
|
||||
/* forward declaration of libevent callbacks */
|
||||
static void tfe_stream_readcb(struct bufferevent *, void *);
|
||||
static void tfe_stream_writecb(struct bufferevent *, void *);
|
||||
static void tfe_stream_eventcb(struct bufferevent *, short, void *);
|
||||
static void stream_fd_readcb(evutil_socket_t, short, void *);
|
||||
|
||||
|
||||
void tfe_stream_detach(const struct tfe_stream* stream)
|
||||
static void tfe_stream_free(struct tfe_stream_private * stream)
|
||||
{
|
||||
struct tfe_stream_private* _stream=(struct tfe_stream_private*)stream;
|
||||
int plug_id=_stream->calling_idx;
|
||||
_stream->plug_ctx[plug_id].state=PLUG_STATE_DETACHED;
|
||||
struct tfe_thread_ctx * thread = stream->thrmgr_ref;
|
||||
thread->load--;
|
||||
|
||||
switch (stream->session_type)
|
||||
{
|
||||
case SESSION_PROTO_SSL:
|
||||
#if 0
|
||||
ssl_upstream_free(stream->ssl_upstream);
|
||||
ssl_downstream_free(stream->ssl_downstream);
|
||||
#endif
|
||||
thread->stat.value[SSL_NUM]--;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
free(stream);
|
||||
thread->stat.value[STREAM_NUM]--;
|
||||
return;
|
||||
}
|
||||
int tfe_stream_preempt(const struct tfe_stream* stream)
|
||||
|
||||
void tfe_stream_detach(const struct tfe_stream * stream)
|
||||
{
|
||||
struct tfe_stream_private* _stream=(struct tfe_stream_private*)stream;
|
||||
int plug_id=_stream->calling_idx;
|
||||
int i=0;
|
||||
for(i=0;i<_stream->plugin_num;i++)
|
||||
struct tfe_stream_private * _stream = (struct tfe_stream_private *) stream;
|
||||
int plug_id = _stream->calling_idx;
|
||||
_stream->plug_ctx[plug_id].state = PLUG_STATE_DETACHED;
|
||||
return;
|
||||
}
|
||||
|
||||
int tfe_stream_preempt(const struct tfe_stream * stream)
|
||||
{
|
||||
struct tfe_stream_private * _stream = (struct tfe_stream_private *) stream;
|
||||
int plug_id = _stream->calling_idx;
|
||||
int i = 0;
|
||||
for (i = 0; i < _stream->plugin_num; i++)
|
||||
{
|
||||
if(_stream->plug_ctx[i].state==PLUG_STATE_PREEPTION)
|
||||
if (_stream->plug_ctx[i].state == PLUG_STATE_PREEPTION)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
_stream->plug_ctx[plug_id].state=PLUG_STATE_PREEPTION;
|
||||
_stream->plug_ctx[plug_id].state = PLUG_STATE_PREEPTION;
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline struct tfe_conn_private* __this_conn(struct tfe_stream_private* _stream, enum tfe_conn_dir dir)
|
||||
static inline struct tfe_conn_private * __this_conn(struct tfe_stream_private * _stream, enum tfe_conn_dir dir)
|
||||
{
|
||||
struct tfe_conn_private* this_conn=NULL;
|
||||
this_conn=((dir==CONN_DIR_UPSTREAM)? &(_stream->conn_downstream):&(_stream->conn_upstream));
|
||||
struct tfe_conn_private * this_conn = NULL;
|
||||
this_conn = ((dir == CONN_DIR_UPSTREAM) ? &(_stream->conn_downstream) : &(_stream->conn_upstream));
|
||||
return this_conn;
|
||||
}
|
||||
inline struct tfe_conn_private* __peer_conn(struct tfe_stream_private* _stream, enum tfe_conn_dir dir)
|
||||
|
||||
static inline struct tfe_conn_private * __peer_conn(struct tfe_stream_private * _stream, enum tfe_conn_dir dir)
|
||||
{
|
||||
struct tfe_conn_private* peer_conn=NULL;
|
||||
peer_conn=(dir==CONN_DIR_UPSTREAM)? &(_stream->conn_downstream):&(_stream->conn_upstream);
|
||||
struct tfe_conn_private * peer_conn = NULL;
|
||||
peer_conn = (dir == CONN_DIR_UPSTREAM) ? &(_stream->conn_downstream) : &(_stream->conn_upstream);
|
||||
return peer_conn;
|
||||
}
|
||||
struct tfe_stream_write_ctx* tfe_stream_write_frag_start(const struct tfe_stream* stream, enum tfe_conn_dir dir)
|
||||
|
||||
struct tfe_stream_write_ctx * tfe_stream_write_frag_start(const struct tfe_stream * stream, enum tfe_conn_dir dir)
|
||||
{
|
||||
struct tfe_stream_private* _stream=(struct tfe_stream_private*)stream;
|
||||
struct tfe_conn_private* this_conn=__this_conn(_stream, dir);
|
||||
struct tfe_conn_private* peer_conn=__peer_conn(_stream, dir);
|
||||
if(this_conn->on_writing==1)
|
||||
struct tfe_stream_private * _stream = (struct tfe_stream_private *) stream;
|
||||
struct tfe_conn_private * this_conn = __this_conn(_stream, dir);
|
||||
struct tfe_conn_private * peer_conn = __peer_conn(_stream, dir);
|
||||
if (this_conn->on_writing == 1)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
this_conn->w_ctx.dir=dir;
|
||||
this_conn->w_ctx._stream=_stream;
|
||||
this_conn->on_writing=1;
|
||||
this_conn->w_ctx.dir = dir;
|
||||
this_conn->w_ctx._stream = _stream;
|
||||
this_conn->on_writing = 1;
|
||||
bufferevent_disable(peer_conn->bev, EV_READ);
|
||||
return &(this_conn->w_ctx);
|
||||
}
|
||||
|
||||
int tfe_stream_write_frag(struct tfe_stream_write_ctx* w_ctx,const unsigned char *data, size_t size)
|
||||
int tfe_stream_write_frag(struct tfe_stream_write_ctx * w_ctx, const unsigned char * data, size_t size)
|
||||
{
|
||||
struct tfe_conn_private* this_conn=__this_conn(w_ctx->_stream, w_ctx->dir);;
|
||||
int ret=bufferevent_write(this_conn->bev, data, size);
|
||||
struct tfe_conn_private * this_conn = __this_conn(w_ctx->_stream, w_ctx->dir);;
|
||||
int ret = bufferevent_write(this_conn->bev, data, size);
|
||||
return ret;
|
||||
}
|
||||
void tfe_stream_write_frag_end(struct tfe_stream_write_ctx* w_ctx)
|
||||
void tfe_stream_write_frag_end(struct tfe_stream_write_ctx * w_ctx)
|
||||
{
|
||||
struct tfe_conn_private* this_conn=__this_conn(w_ctx->_stream, w_ctx->dir);
|
||||
struct tfe_conn_private* peer_conn=__peer_conn(w_ctx->_stream, w_ctx->dir);
|
||||
this_conn->on_writing=0;
|
||||
struct tfe_conn_private * this_conn = __this_conn(w_ctx->_stream, w_ctx->dir);
|
||||
struct tfe_conn_private * peer_conn = __peer_conn(w_ctx->_stream, w_ctx->dir);
|
||||
this_conn->on_writing = 0;
|
||||
bufferevent_enable(peer_conn->bev, EV_READ);
|
||||
return;
|
||||
}
|
||||
|
||||
int tfe_stream_write(const struct tfe_stream* stream, enum tfe_conn_dir dir, const unsigned char *data, size_t size)
|
||||
int tfe_stream_write(const struct tfe_stream * stream, enum tfe_conn_dir dir, const unsigned char * data, size_t size)
|
||||
{
|
||||
int ret=0;
|
||||
struct tfe_stream_write_ctx* wctx=tfe_stream_write_frag_start( stream, dir);
|
||||
ret=tfe_stream_write_frag(wctx, data, size);
|
||||
int ret = 0;
|
||||
struct tfe_stream_write_ctx * wctx = tfe_stream_write_frag_start(stream, dir);
|
||||
ret = tfe_stream_write_frag(wctx, data, size);
|
||||
tfe_stream_write_frag_end(wctx);
|
||||
return ret;
|
||||
}
|
||||
@@ -209,70 +233,75 @@ enum tfe_stream_action tfe_stream_call_plugin(struct tfe_stream_private* _stream
|
||||
|
||||
static void tfe_stream_readcb(struct bufferevent * bev, void * arg)
|
||||
{
|
||||
struct tfe_stream_private* _stream=(struct tfe_stream_private*)arg;
|
||||
enum tfe_conn_dir dir=(bev == _stream->conn_downstream.bev)? CONN_DIR_UPSTREAM : CONN_DIR_DOWNSTREAM;
|
||||
struct tfe_conn_private* this_conn=__this_conn(_stream, dir);
|
||||
struct tfe_conn_private* peer_conn= __peer_conn(_stream, dir);
|
||||
struct tfe_stream_private * _stream = (struct tfe_stream_private *) arg;
|
||||
enum tfe_conn_dir dir = (bev == _stream->conn_downstream.bev) ? CONN_DIR_UPSTREAM : CONN_DIR_DOWNSTREAM;
|
||||
struct tfe_conn_private * this_conn = __this_conn(_stream, dir);
|
||||
struct tfe_conn_private * peer_conn = __peer_conn(_stream, dir);
|
||||
|
||||
int i=0,ret=0;
|
||||
enum tfe_stream_action action_tmp=ACTION_FORWARD_DATA, action_final=ACTION_FORWARD_DATA;
|
||||
|
||||
int i = 0, ret = 0;
|
||||
enum tfe_stream_action action_tmp = ACTION_FORWARD_DATA, action_final = ACTION_FORWARD_DATA;
|
||||
|
||||
|
||||
const struct tfe_plugin* plugins=_stream->thrmgr_ref->modules;
|
||||
struct plugin_ctx* plug_ctx=NULL;
|
||||
int plug_num=_stream->thrmgr_ref->module_num;
|
||||
const struct tfe_plugin * plugins = _stream->thrmgr_ref->modules;
|
||||
struct plugin_ctx * plug_ctx = NULL;
|
||||
int plug_num = _stream->thrmgr_ref->nr_modules;
|
||||
|
||||
struct evbuffer * inbuf = bufferevent_get_input(bev);
|
||||
struct evbuffer * outbuf = bufferevent_get_output(peer_conn->bev);
|
||||
size_t contigous_len=evbuffer_get_length(inbuf),drain_size=0;
|
||||
const char* contiguous_data=evbuffer_pullup(inbuf,contigous_len);
|
||||
_stream->defere_bytes=0;
|
||||
_stream->drop_bytes=0;
|
||||
_stream->forward_bytes=0;
|
||||
for(i=0;i<plug_num;i++)
|
||||
struct evbuffer * outbuf = bufferevent_get_output(peer_conn->bev);
|
||||
|
||||
size_t contigous_len = evbuffer_get_length(inbuf), drain_size = 0;
|
||||
const unsigned char * contiguous_data = (const unsigned char *)evbuffer_pullup(inbuf, contigous_len);
|
||||
|
||||
_stream->defere_bytes = 0;
|
||||
_stream->drop_bytes = 0;
|
||||
_stream->forward_bytes = 0;
|
||||
|
||||
for (i = 0; i < plug_num; i++)
|
||||
{
|
||||
_stream->calling_idx=i;
|
||||
plug_ctx=_stream->plug_ctx+i;
|
||||
if(_stream->is_plugin_opened==0)
|
||||
_stream->calling_idx = i;
|
||||
plug_ctx = _stream->plug_ctx + i;
|
||||
|
||||
if (_stream->is_plugin_opened == 0)
|
||||
{
|
||||
action_tmp=plugins[i].on_open(&_stream.head, _stream->thrmgr_ref->thread_id, dir, contiguous_data,contigous_len, &(plug_ctx->pme));
|
||||
_stream->is_plugin_opened=1;
|
||||
action_tmp = plugins[i].on_open(&_stream->head, _stream->thrmgr_ref->thread_id,
|
||||
dir, contiguous_data, contigous_len, &(plug_ctx->pme));
|
||||
_stream->is_plugin_opened = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
action_tmp=plugins[i].on_data(&_stream.head, _stream->thrmgr_ref->thread_id, dir, contiguous_data,contigous_len, &(plug_ctx->pme));
|
||||
action_tmp = plugins[i].on_data(&_stream->head, _stream->thrmgr_ref->thread_id,
|
||||
dir, contiguous_data, contigous_len, &(plug_ctx->pme));
|
||||
}
|
||||
if(plug_ctx->state=PLUG_STATE_PREEPTION)
|
||||
|
||||
if (plug_ctx->state == PLUG_STATE_PREEPTION)
|
||||
{
|
||||
action_final=action_tmp;
|
||||
action_final = action_tmp;
|
||||
}
|
||||
}
|
||||
switch (action_final)
|
||||
|
||||
switch (action_final)
|
||||
{
|
||||
case ACTION_FORWARD_DATA:
|
||||
if(_stream->forward_bytes>0)
|
||||
if (_stream->forward_bytes > 0)
|
||||
{
|
||||
evbuffer_remove_buffer(inbuf, outbuf, _stream->forward_bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
evbuffer_add_buffer(outbuf, inbuf);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ACTION_DROP_DATA:
|
||||
if(_stream->drop_bytes>0)
|
||||
if (_stream->drop_bytes > 0)
|
||||
{
|
||||
drain_size=_stream->drop_bytes;
|
||||
drain_size = _stream->drop_bytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
drain_size= evbuffer_get_length(inbuf);
|
||||
drain_size = evbuffer_get_length(inbuf);
|
||||
}
|
||||
evbuffer_drain(inbuf,drain_size);
|
||||
evbuffer_drain(inbuf, drain_size);
|
||||
case ACTION_DEFER_DATA:
|
||||
if(_stream->defere_bytes>0)
|
||||
if (_stream->defere_bytes > 0)
|
||||
{
|
||||
bufferevent_setwatermark(bev, EV_WRITE, _stream->defere_bytes, 0);
|
||||
}
|
||||
@@ -281,11 +310,12 @@ static void tfe_stream_readcb(struct bufferevent * bev, void * arg)
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
if(evbuffer_get_length(inbuf) != 0)
|
||||
|
||||
if (evbuffer_get_length(inbuf) != 0)
|
||||
{
|
||||
bufferevent_trigger(bev, EV_READ, BEV_OPT_DEFER_CALLBACKS);
|
||||
}
|
||||
|
||||
|
||||
if (evbuffer_get_length(outbuf) >= OUTBUF_LIMIT)
|
||||
{
|
||||
/* temporarily disable data source;
|
||||
@@ -304,10 +334,10 @@ static void tfe_stream_readcb(struct bufferevent * bev, void * arg)
|
||||
*/
|
||||
static void tfe_stream_writecb(struct bufferevent * bev, void * arg)
|
||||
{
|
||||
struct tfe_stream_private* _stream=(struct tfe_stream_private*)arg;
|
||||
enum tfe_conn_dir dir=(bev == _stream->conn_downstream.bev)? CONN_DIR_UPSTREAM : CONN_DIR_DOWNSTREAM;
|
||||
struct tfe_conn_private* this_conn=__this_conn(_stream, dir);
|
||||
struct tfe_conn_private* peer_conn= __peer_conn(_stream, dir);
|
||||
struct tfe_stream_private * _stream = (struct tfe_stream_private *) arg;
|
||||
enum tfe_conn_dir dir = (bev == _stream->conn_downstream.bev) ? CONN_DIR_UPSTREAM : CONN_DIR_DOWNSTREAM;
|
||||
struct tfe_conn_private * this_conn = __this_conn(_stream, dir);
|
||||
struct tfe_conn_private * peer_conn = __peer_conn(_stream, dir);
|
||||
|
||||
struct evbuffer * outbuf = bufferevent_get_output(bev);
|
||||
|
||||
@@ -326,20 +356,20 @@ static void tfe_stream_writecb(struct bufferevent * bev, void * arg)
|
||||
*/
|
||||
static void tfe_stream_eventcb(struct bufferevent * bev, short events, void * arg)
|
||||
{
|
||||
struct tfe_stream_private* _stream=(struct tfe_stream_private*)arg;
|
||||
enum tfe_conn_dir dir=(bev == _stream->conn_downstream.bev)? CONN_DIR_UPSTREAM : CONN_DIR_DOWNSTREAM;
|
||||
struct tfe_conn_private* this_conn=__this_conn(_stream, dir);
|
||||
struct tfe_conn_private* peer_conn= __peer_conn(_stream, dir);
|
||||
struct tfe_stream_private * _stream = (struct tfe_stream_private *) arg;
|
||||
enum tfe_conn_dir dir = (bev == _stream->conn_downstream.bev) ? CONN_DIR_UPSTREAM : CONN_DIR_DOWNSTREAM;
|
||||
struct tfe_conn_private * this_conn = __this_conn(_stream, dir);
|
||||
struct tfe_conn_private * peer_conn = __peer_conn(_stream, dir);
|
||||
|
||||
const struct tfe_plugin* plugins=_stream->thrmgr_ref->modules;
|
||||
struct plugin_ctx* plug_ctx=NULL;
|
||||
int plug_num=_stream->thrmgr_ref->module_num,i=0;
|
||||
enum tfe_stream_close_reason reason=REASON_PASSIVE_CLOSED;
|
||||
const struct tfe_plugin * plugins = _stream->thrmgr_ref->modules;
|
||||
struct plugin_ctx * plug_ctx = NULL;
|
||||
int plug_num = _stream->thrmgr_ref->nr_modules, i = 0;
|
||||
enum tfe_stream_close_reason reason = REASON_PASSIVE_CLOSED;
|
||||
|
||||
if (events & BEV_EVENT_ERROR)
|
||||
{
|
||||
this_conn->closed=1;
|
||||
reason=REASON_ERROR;
|
||||
this_conn->closed = 1;
|
||||
reason = REASON_ERROR;
|
||||
goto call_plugin_close;
|
||||
}
|
||||
|
||||
@@ -347,120 +377,110 @@ static void tfe_stream_eventcb(struct bufferevent * bev, short events, void * ar
|
||||
{
|
||||
//generate a 0 size read callback to notify plugins.
|
||||
tfe_stream_readcb(bev, arg);
|
||||
this_conn->closed=1;
|
||||
this_conn->closed = 1;
|
||||
}
|
||||
if(peer_conn->closed==1&&this_conn->closed==1)
|
||||
if (peer_conn->closed == 1 && this_conn->closed == 1)
|
||||
{
|
||||
reason=REASON_PASSIVE_CLOSED;
|
||||
reason = REASON_PASSIVE_CLOSED;
|
||||
goto call_plugin_close;
|
||||
}
|
||||
return;
|
||||
|
||||
call_plugin_close:
|
||||
for(i=0;i<plug_num;i++)
|
||||
for (i = 0; i < plug_num; i++)
|
||||
{
|
||||
_stream->calling_idx=i;
|
||||
plug_ctx=_stream->plug_ctx+i;
|
||||
plugins[i].on_close(&(_stream.head), _stream->thrmgr_ref->thread_id, reason, &(plug_ctx->pme));
|
||||
_stream->calling_idx = i;
|
||||
plug_ctx = _stream->plug_ctx + i;
|
||||
plugins[i].on_close(&(_stream->head), _stream->thrmgr_ref->thread_id, reason, &(plug_ctx->pme));
|
||||
}
|
||||
|
||||
tfe_stream_free(_stream);
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
static void tfe_stream_free(struct tfe_stream_private* stream)
|
||||
{
|
||||
pxy_conn_ctx_t * ctx;
|
||||
int by_requestor;
|
||||
struct tfe_thread_ctx* thread=stream->thrmgr_ref;
|
||||
thread->load--;
|
||||
switch (stream->session_type)
|
||||
{
|
||||
case SESSION_PROTO_SSL:
|
||||
ssl_upstream_free(stream->ssl_upstream);
|
||||
ssl_downstream_free(stream->ssl_downstream);
|
||||
thread->stat.value[SSL_NUM]--;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(stream);
|
||||
thread->stat.value[STREAM_NUM]--;
|
||||
return;
|
||||
}
|
||||
|
||||
void ssl_get_cert_on_succ(void * result, void * user)
|
||||
{
|
||||
cert_t* cert=(cert_t*)result;
|
||||
struct tfe_stream_private* _stream=(struct tfe_stream_private*)user;
|
||||
_stream->ssl_downstream->ssl=downstream_ssl_create(_stream, );
|
||||
cert_t * cert = (cert_t *) result;
|
||||
struct tfe_stream_private * _stream = (struct tfe_stream_private *) user;
|
||||
|
||||
//_stream->ssl_downstream->ssl = downstream_ssl_create(_stream);
|
||||
//_stream->ssl_downstream->ssl = downstream_ssl_create(_stream);
|
||||
cert_free(cert);
|
||||
|
||||
bufferevent_setcb(_stream->head.upstream.bev, tfe_stream_readcb, tfe_stream_writecb, tfe_stream_eventcb, _stream);
|
||||
bufferevent_setcb(_stream->head.downstream.bev, tfe_stream_readcb, tfe_stream_writecb, tfe_stream_eventcb, _stream);
|
||||
bufferevent_enable(_stream->head.upstream.bev, EV_READ | EV_WRITE);
|
||||
bufferevent_enable(_stream->head.downstream.bev, EV_READ | EV_WRITE);
|
||||
|
||||
|
||||
bufferevent_setcb(_stream->head.upstream.bev, tfe_stream_readcb, tfe_stream_writecb, tfe_stream_eventcb, _stream);
|
||||
bufferevent_setcb(_stream->head.downstream.bev, tfe_stream_readcb, tfe_stream_writecb, tfe_stream_eventcb, _stream);
|
||||
bufferevent_enable(_stream->head.upstream.bev, EV_READ | EV_WRITE);
|
||||
bufferevent_enable(_stream->head.downstream.bev, EV_READ | EV_WRITE);
|
||||
|
||||
future_destroy(_stream->ssl_downstream->future_get_cert);
|
||||
_stream->ssl_downstream->future_get_cert=NULL;
|
||||
_stream->ssl_downstream->future_get_cert = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
void ssl_get_cert_on_fail(enum e_future_error err, const char * what, void * user)
|
||||
{
|
||||
//todo
|
||||
assert(0);
|
||||
}
|
||||
|
||||
void ssl_conn_origin_on_succ(void * result, void * user)
|
||||
{
|
||||
struct bufferevent *bev=(struct bufferevent *)result;
|
||||
struct tfe_stream_private* _stream=(struct tfe_stream_private*)user;
|
||||
|
||||
_stream->head.upstream.bev=bev;
|
||||
_stream->ssl_upstream->ssl=bufferevent_openssl_get_ssl(bev); /* does not inc refc */
|
||||
_stream->ssl_upstream->orig_cert=SSL_get_peer_certificate(_stream->ssl_upstream->ssl);
|
||||
struct bufferevent * bev = (struct bufferevent *) result;
|
||||
struct tfe_stream_private * _stream = (struct tfe_stream_private *) user;
|
||||
|
||||
session_cache_set(_stream->thrmgr_ref->dsess_cache, struct sockaddr * addr, addrlen,_stream->ssl_downstream->sni, SSL_get0_session(_stream->ssl_upstream->ssl));
|
||||
_stream->head.upstream.bev = bev;
|
||||
_stream->ssl_upstream->ssl = bufferevent_openssl_get_ssl(bev); /* does not inc refc */
|
||||
_stream->ssl_upstream->orig_cert = SSL_get_peer_certificate(_stream->ssl_upstream->ssl);
|
||||
|
||||
_stream->ssl_downstream->future_get_cert=future_create(ssl_get_cert_on_succ, ssl_get_cert_on_fail, _stream);
|
||||
cert_mgr_async_get( _stream->ssl_downstream->future_get_cert,
|
||||
_stream->thrmgr_ref->cert_mgr,
|
||||
_stream->ssl_downstream->sni,
|
||||
_stream->ssl_downstream->keyring_id,
|
||||
_stream->ssl_upstream->orig_cert);
|
||||
#if 0
|
||||
session_cache_set(_stream->thrmgr_ref->dsess_cache, _stream->ssl_downstream->sni,
|
||||
SSL_get0_session(_stream->ssl_upstream->ssl));
|
||||
#endif
|
||||
|
||||
_stream->ssl_downstream->future_get_cert = future_create(ssl_get_cert_on_succ, ssl_get_cert_on_fail, _stream);
|
||||
|
||||
#if 0
|
||||
cert_mgr_async_get(_stream->ssl_downstream->future_get_cert,
|
||||
_stream->thrmgr_ref->cert_mgr,
|
||||
_stream->ssl_downstream->sni,
|
||||
_stream->ssl_downstream->keyring_id,
|
||||
_stream->ssl_upstream->orig_cert);
|
||||
#endif
|
||||
|
||||
future_destroy(_stream->ssl_upstream->conn_ssl_srv);
|
||||
_stream->ssl_upstream->conn_ssl_srv=NULL;
|
||||
return;
|
||||
_stream->ssl_upstream->conn_ssl_srv = NULL;
|
||||
}
|
||||
|
||||
void ssl_conn_origin_on_fail(enum e_future_error err, const char * what, void * user)
|
||||
{
|
||||
//todo
|
||||
//TODO:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
|
||||
void peek_sni_on_succ(void* result, void* user)
|
||||
void peek_sni_on_succ(void * result, void * user)
|
||||
{
|
||||
struct tfe_stream_private* _stream=(struct tfe_stream_private*)user;
|
||||
assert(_stream->session_type==SESSION_PROTO_SSL);
|
||||
_stream->ssl_downstream->sni=tfe_strdup((const char *)result);
|
||||
struct tfe_stream_private * _stream = (struct tfe_stream_private *) user;
|
||||
assert(_stream->session_type == SESSION_PROTO_SSL);
|
||||
|
||||
struct ssl_downstream * ssl_downstream = _stream->ssl_downstream;
|
||||
struct ssl_upstream * ssl_upstream = _stream->ssl_upstream;
|
||||
|
||||
_stream->ssl_downstream->sni = tfe_strdup((const char *) result);
|
||||
future_destroy(ssl_downstream->future_sni_peek);
|
||||
ssl_downstream->future_sni_peek=NULL;
|
||||
|
||||
_stream->ssl_upstream=ALLOC(struct ssl_upstream,1);
|
||||
_stream->ssl_upstream->conn_ssl_srv=future_create(ssl_conn_origin_on_succ, ssl_conn_origin_on_fail, _stream);
|
||||
ssl_async_connect_origin(_stream->ssl_upstream->conn_ssl_srv, _stream->fd_upstream, _stream->ssl_downstream->sni, _stream->thrmgr_ref->evbase, _stream->thrmgr_ref->opts);
|
||||
ssl_downstream->future_sni_peek = NULL;
|
||||
|
||||
_stream->ssl_upstream = ALLOC(struct ssl_upstream, 1);
|
||||
_stream->ssl_upstream->conn_ssl_srv = future_create(ssl_conn_origin_on_succ, ssl_conn_origin_on_fail, _stream);
|
||||
ssl_async_connect_origin(_stream->ssl_upstream->conn_ssl_srv, _stream->fd_upstream, _stream->ssl_downstream->sni,
|
||||
_stream->thrmgr_ref->evbase, NULL);
|
||||
}
|
||||
|
||||
void peek_sni_on_fail(enum e_future_error err, const char * what, void * user)
|
||||
{
|
||||
//todo
|
||||
//TODO:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Callback for accept events on the socket listener bufferevent.
|
||||
* Called when a new incoming connection has been accepted.
|
||||
@@ -472,42 +492,41 @@ void peek_sni_on_fail(enum e_future_error err, const char * what, void * user)
|
||||
* start reading from the client while waiting on the connection to
|
||||
* the server to connect.
|
||||
*/
|
||||
void tfe_stream_setup(struct tfe_stream_private* _stream)
|
||||
void tfe_stream_setup(struct tfe_stream_private * _stream)
|
||||
{
|
||||
struct future* f_sni=NULL;
|
||||
tfe_thread_ctx* thread=_stream->thrmgr_ref;
|
||||
struct future * f_sni = NULL;
|
||||
tfe_thread_ctx * thread = _stream->thrmgr_ref;
|
||||
switch (_stream->session_type)
|
||||
{
|
||||
case SESSION_PROTO_SSL:
|
||||
// for SSL, defer dst connection setup to initial_readcb
|
||||
_stream->ssl_downstream=ssl_downstream_create();
|
||||
_stream->async_future=future_create(peek_sni_on_succ, peek_sni_on_fail, _stream);
|
||||
ssl_async_peek_sni(_stream->ssl_downstream->future_sni_peek, _stream->fd_downstream, _stream->thrmgr_ref->evbase);
|
||||
_stream->ssl_downstream = ssl_downstream_create();
|
||||
_stream->async_future = future_create(peek_sni_on_succ, peek_sni_on_fail, _stream);
|
||||
ssl_async_peek_sni(_stream->ssl_downstream->future_sni_peek, _stream->fd_downstream,
|
||||
_stream->thrmgr_ref->evbase);
|
||||
thread->stat.value[SSL_NUM]++;
|
||||
break
|
||||
break;
|
||||
default:
|
||||
//todo:
|
||||
stream_fd_readcb(_stream->fd_downstream, 0, _stream);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
struct tfe_stream_private* tfe_stream_create(evutil_socket_t fd_downstream, evutil_socket_t fd_upstream,
|
||||
struct sockaddr * peeraddr, int peeraddrlen,
|
||||
enum tfe_session_proto session_type, tfe_thread_ctx* thread)
|
||||
struct tfe_stream_private * tfe_stream_create(evutil_socket_t fd_downstream, evutil_socket_t fd_upstream,
|
||||
enum tfe_session_proto session_type, tfe_thread_ctx * thread)
|
||||
{
|
||||
struct tfe_stream_private* conn_private=NULL;
|
||||
struct tfe_stream* conn_public=NULL;
|
||||
conn_private= ALLOC(struct tfe_stream_private, 1);
|
||||
conn_private->session_type=session_type;
|
||||
conn_private->fd_downstream=fd_downstream;
|
||||
conn_private->fd_upstream=fd_upstream;
|
||||
conn_private->thrmgr_ref=thread;
|
||||
conn_private->is_plugin_opened=0;
|
||||
conn_public=&(conn_private->head);
|
||||
//todo
|
||||
addr_sock2layer(conn_public->downstream.addr,peeraddr,peeraddrlen);
|
||||
struct tfe_stream_private * conn_private = NULL;
|
||||
struct tfe_stream * conn_public = NULL;
|
||||
conn_private = ALLOC(struct tfe_stream_private, 1);
|
||||
conn_private->session_type = session_type;
|
||||
conn_private->fd_downstream = fd_downstream;
|
||||
conn_private->fd_upstream = fd_upstream;
|
||||
conn_private->thrmgr_ref = thread;
|
||||
conn_private->is_plugin_opened = 0;
|
||||
conn_public = &(conn_private->head);
|
||||
thread->stat.value[STREAM_NUM]++;
|
||||
return conn_private;
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
#include "tfe_stream.h"
|
||||
#include "ssl_stream.h"
|
||||
#include "tfe_stat.h"
|
||||
struct tfe_thread_ctx
|
||||
{
|
||||
pthread_t thr;
|
||||
unsigned int thread_id;
|
||||
size_t load;
|
||||
struct event_base *evbase;
|
||||
unsigned char running;
|
||||
struct tfe_stats stat;
|
||||
tfe_config* opts;
|
||||
cert_mgr cert_mgr;
|
||||
struct sess_cache* dsess_cache;
|
||||
struct sess_cache* ssess_cache;
|
||||
const int module_num;
|
||||
const struct tfe_plugin* modules;
|
||||
};
|
||||
|
||||
|
||||
//Downstream: comunication form client to proxy
|
||||
//Upstream: communication form proxy to server
|
||||
struct ssl_downstream
|
||||
{
|
||||
/* server name indicated by client in SNI TLS extension */
|
||||
char *sni;
|
||||
SSL *ssl;
|
||||
X509* fake_cert_ref;//?
|
||||
int keyring_id;
|
||||
struct future* future_sni_peek;
|
||||
struct future* future_get_cert;
|
||||
|
||||
};
|
||||
|
||||
struct ssl_upstream
|
||||
{
|
||||
X509 *orig_cert;
|
||||
SSL *ssl;
|
||||
struct future* conn_ssl_srv;
|
||||
};
|
||||
enum tfe_plugin_state
|
||||
{
|
||||
PLUG_STATE_READONLY,
|
||||
PLUG_STATE_PREEPTION,
|
||||
PLUG_STATE_DETACHED
|
||||
};
|
||||
struct plugin_ctx
|
||||
{
|
||||
|
||||
enum tfe_plugin_state state;
|
||||
void *pme;
|
||||
};
|
||||
struct tfe_stream_write_ctx
|
||||
{
|
||||
struct tfe_stream_private* _stream;
|
||||
enum tfe_conn_dir dir;
|
||||
};
|
||||
struct tfe_conn_private
|
||||
{
|
||||
evutil_socket_t fd;
|
||||
struct bufferevent *bev;
|
||||
uint8_t on_writing;
|
||||
uint8_t closed;
|
||||
uint8_t need_shutdown;
|
||||
struct tfe_stream_write_ctx w_ctx;
|
||||
};
|
||||
struct tfe_stream_private
|
||||
{
|
||||
struct tfe_stream head;
|
||||
enum tfe_session_proto session_type;
|
||||
struct tfe_conn_private conn_upstream;
|
||||
struct tfe_conn_private conn_downstream;
|
||||
union
|
||||
{
|
||||
struct ssl_downstream* ssl_downstream;
|
||||
void* raw_downstream;
|
||||
};
|
||||
union
|
||||
{
|
||||
struct ssl_upstream* ssl_upstream;
|
||||
void* raw_upstream;
|
||||
};
|
||||
uint8_t is_plugin_opened;
|
||||
int calling_idx;
|
||||
size_t forward_bytes;
|
||||
size_t defere_bytes;
|
||||
size_t drop_bytes;
|
||||
enum tfe_app_proto app_proto;
|
||||
int plugin_num;
|
||||
struct plugin_ctx* plug_ctx;
|
||||
unsigned char passthrough; /* 1 if SSL passthrough is active */
|
||||
|
||||
evutil_socket_t fd_downstream, fd_upstream;
|
||||
|
||||
struct tfe_thread_ctx* thrmgr_ref;
|
||||
future* async_future;
|
||||
};
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
#include "tfe_util.h"
|
||||
int addr_sock2layer(struct sockaddr * sock_addr, int sockaddrlen, struct layer_addr* layer_addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int addr_layer2sock(struct layer_addr* layer_addr,struct sockaddr * sock_addr)
|
||||
{
|
||||
int sockaddrlen=-1;
|
||||
return sockaddrlen;
|
||||
}
|
||||
//functioned as strdup, for dictator compatible.
|
||||
char* tfe_strdup(const char* s)
|
||||
{
|
||||
char*d=NULL;
|
||||
if(s==NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
d=(char*)malloc(strlen(s)+1);
|
||||
memcpy(d,s,strlen(s)+1);
|
||||
return d;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user