整理目录结构,调整框架部分实现,初步编译通过。

This commit is contained in:
Lu
2018-08-21 16:11:50 +08:00
parent db055eeac8
commit 768235920a
28 changed files with 1809 additions and 2984 deletions

View File

@@ -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)

View File

@@ -1,20 +1,25 @@
enum e_future_error enum e_future_error
{ {
FUTURE_ERROR_CANCEL, FUTURE_ERROR_CANCEL,
FUTURE_ERROR_EXCEPTION, FUTURE_ERROR_EXCEPTION,
FUTURE_ERROR_TIMEOUT FUTURE_ERROR_TIMEOUT
}; };
struct promise; struct promise;
struct future; 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);

View File

@@ -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 enum tfe_session_proto
{ {
SESSION_PROTO_PLAIN=0, SESSION_PROTO_PLAIN = 0,
SESSION_PROTO_SSL, SESSION_PROTO_SSL,
SESSION_PROTO_QUIC, SESSION_PROTO_QUIC,
SESSION_PROTO_SPDY SESSION_PROTO_SPDY
}; };
enum tfe_app_proto enum tfe_app_proto
{ {
APP_PROTO_HTTP1, APP_PROTO_HTTP1,
APP_PROTO_HTTP2, APP_PROTO_HTTP2,
APP_PROTO_WS, //websocket APP_PROTO_WS, //websocket
APP_PROTO_QUIC //QUIC is a protocol that cross session layer and application layer. APP_PROTO_QUIC //QUIC is a protocol that cross session layer and application layer.
}; };
enum tfe_conn_dir enum tfe_conn_dir
{ {
CONN_DIR_DOWNSTREAM=0, //From client to proxy, aka client-side. CONN_DIR_DOWNSTREAM = 0, //From client to proxy, aka client-side.
CONN_DIR_UPSTREAM //From proxy to server, aka server-side. CONN_DIR_UPSTREAM //From proxy to server, aka server-side.
}; };
enum tfe_conn_status enum tfe_conn_status
{ {
CONN_STATUS_NONE, CONN_STATUS_NONE,
@@ -32,8 +41,8 @@ struct tfe_conn
{ {
struct layer_addr addr; struct layer_addr addr;
enum tfe_conn_status status; enum tfe_conn_status status;
struct bufferevent *bev; struct bufferevent * bev;
} ; };
struct tfe_stream struct tfe_stream
{ {
@@ -42,68 +51,69 @@ struct tfe_stream
struct tfe_conn downstream; struct tfe_conn downstream;
}; };
enum tfe_stream_action enum tfe_stream_action
{ {
ACTION_FORWARD_DATA, ACTION_FORWARD_DATA,
ACTION_DEFER_DATA, ACTION_DEFER_DATA,
ACTION_DROP_DATA ACTION_DROP_DATA
}; };
enum tfe_stream_action_opt enum tfe_stream_action_opt
{ {
ACTION_OPT_FOWARD_BYTES, //value is size_t, default: forward 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_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_DEFER_BYTES, //value is size_t, default: defer entire data
ACTION_OPT_DROP_BYTES //value is size_t, default: drop entire data ACTION_OPT_DROP_BYTES //value is size_t, default: drop entire data
}; };
enum tfe_stream_close_reason enum tfe_stream_close_reason
{ {
REASON_PASSIVE_CLOSED, REASON_PASSIVE_CLOSED,
REASON_ACTIVE_CLOSED, REASON_ACTIVE_CLOSED,
REASON_ERROR 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 @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. //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 @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); 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); void tfe_stream_write_frag_end(struct tfe_stream_write_ctx * w_ctx);
//Return 1 for identify as its traffic; //Return 1 for identify as its traffic;
//Return 0 for unknown 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_open_cb_t(const struct tfe_stream * stream, unsigned int thread_id,
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); 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); typedef tfe_stream_action stream_data_cb_t(const struct tfe_stream * stream, unsigned int thread_id,
int tfe_stream_preempt(const struct tfe_stream* stream); 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); struct promise * tfe_stream_suspend(const struct tfe_stream * stream);
void tfe_stream_resume(struct promisc * promisc); void tfe_stream_resume(struct promisc * promisc);
int stream_shutdown(const struct tfe_stream* stream);//close both sides of the stream. //close both sides of the stream.
int stream_shutdown_dir(const struct tfe_stream* stream, enum tfe_conn_dir dir); int stream_shutdown(const struct tfe_stream * stream);
//typedef int proto_onwrite_cb_t(struct tfe_stream*, struct evbuffer *data, void **pme); int stream_shutdown_dir(const struct tfe_stream * stream, enum tfe_conn_dir dir);
struct tfe_plugin struct tfe_plugin
{ {
char symbol[TFE_SYMBOL_MAX]; char symbol[TFE_SYMBOL_MAX];
enum tfe_app_proto proto; enum tfe_app_proto proto;
stream_open_cb_t* on_open; stream_open_cb_t * on_open;
stream_data_cb_t* on_data; stream_data_cb_t * on_data;
stream_close_cb_t* on_close; stream_close_cb_t * on_close;
// proto_onwrite_cb_t *onwrite;
}; };
int tfe_io_write(struct pxy_conn_desc* dest,int dir,struct evbuffer *data);
int tfe_xxx_proto_init(struct tfe_plugin*m);

View File

@@ -1,9 +1,8 @@
#pragma once
#include <stdint.h> #include <stdint.h>
#include <netinet/in.h> //defines struct in_addr #include <netinet/in.h> //defines struct in_addr
#define __TFE_STRING_MAX 2048
#define MAX_FILENAME_SIZE 256
/* network-order */ /* network-order */
struct stream_tuple4_v4{ struct stream_tuple4_v4{
struct in_addr saddr; /* network order */ struct in_addr saddr; /* network order */
@@ -25,15 +24,12 @@ struct stream_tuple4_v6
in_port_t dest; /* network order */ in_port_t dest; /* network order */
}; };
#define GRE_TAG_LEN (4) #define GRE_TAG_LEN (4)
struct layer_addr_gre struct layer_addr_gre
{ {
uint16_t gre_id; uint16_t gre_id;
}; };
#define VLAN_ID_MASK (0x0FFF) #define VLAN_ID_MASK (0x0FFF)
#define VLAN_TAG_LEN (4) #define VLAN_TAG_LEN (4)
struct layer_addr_vlan struct layer_addr_vlan
@@ -140,4 +136,3 @@ struct layer_addr
}; };
uint8_t addrlen; /* 地址结构长度 */ uint8_t addrlen; /* 地址结构长度 */
}; };

View File

@@ -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);

View 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
View 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;
}

View File

@@ -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 add_executable(tfe src/cert.cpp src/future.cpp src/kni.cpp src/tfe_stream.cpp src/main.cpp src/proxy.cpp)
src/ssl_stream.cpp src/tfe_main.cpp src/tfe_proxy.cpp src/tfe_stream.cpp src/tfe_util.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)

View File

@@ -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 #ifndef CERT_H
#define CERT_H #define CERT_H
#include "attrib.h"
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <pthread.h> #include <pthread.h>
typedef struct cert { struct cert{};
EVP_PKEY *key; typedef struct cert cert_t;
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_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; void cert_free(cert_t * cert);
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);
#endif /* !CERT_H */ #endif /* !CERT_H */
/* vim: set noet ft=c: */

View 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);

View File

@@ -29,8 +29,6 @@
#ifndef SSL_H #ifndef SSL_H
#define SSL_H #define SSL_H
#include "tfe_types.h"
#include <openssl/opensslv.h> #include <openssl/opensslv.h>
#include <openssl/ssl.h> #include <openssl/ssl.h>
#include <openssl/err.h> #include <openssl/err.h>
@@ -38,31 +36,6 @@
#include <openssl/x509.h> #include <openssl/x509.h>
#include <openssl/x509v3.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. * 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 #define CONST_SSL_METHOD const SSL_METHOD
#endif /* >= OpensSL 1.0.0 */ #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 * 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 */ #endif /* !HAVE_TLSV12 */
#define SSL_PROTO_SUPPORT_S SSL2_S SSL3_S TLS10_S TLS11_S TLS12_S #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); void ssl_openssl_version(void);
int ssl_init(void) WUNRES; int ssl_init(void);
int ssl_reinit(void) WUNRES; int ssl_reinit(void);
void ssl_fini(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_state_to_str(SSL *);
char * ssl_ssl_masterkey_to_str(SSL *) NONNULL(1) MALLOC; char * ssl_ssl_masterkey_to_str(SSL *);
#ifndef OPENSSL_NO_DH DH * ssl_tmp_dh_callback(SSL *, int, int);
DH * ssl_tmp_dh_callback(SSL *, int, int) NONNULL(1) MALLOC; DH * ssl_dh_load(const char *);
DH * ssl_dh_load(const char *) NONNULL(1) MALLOC; void ssl_dh_refcount_inc(DH *);
void ssl_dh_refcount_inc(DH *) NONNULL(1);
#endif /* !OPENSSL_NO_DH */
#ifndef OPENSSL_NO_EC EC_KEY * ssl_ec_by_name(const char *);
EC_KEY * ssl_ec_by_name(const char *) MALLOC;
#endif /* !OPENSSL_NO_EC */
EVP_PKEY * ssl_key_load(const char *) NONNULL(1) MALLOC; EVP_PKEY * ssl_key_load(const char *);
EVP_PKEY * ssl_key_genrsa(const int) MALLOC; EVP_PKEY * ssl_key_genrsa(const int);
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;
#ifndef OPENSSL_NO_TLSEXT void ssl_key_refcount_inc(EVP_PKEY *);
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);
int ssl_x509chain_load(X509 **, STACK_OF(X509) **, const char *) NONNULL(2,3); int ssl_key_identifier_sha1(EVP_PKEY *, unsigned char *);
void ssl_x509chain_use(SSL_CTX *, X509 *, STACK_OF(X509) *) NONNULL(1,2,3); char * ssl_key_identifier(EVP_PKEY *, int);
char * ssl_session_to_str(SSL_SESSION *) NONNULL(1) MALLOC; int ssl_x509_v3ext_add(X509V3_CTX *, X509 *, char *, char *);
int ssl_session_is_valid(SSL_SESSION *) NONNULL(1); 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, int ssl_tls_clienthello_parse(const unsigned char *, ssize_t, int,
const unsigned char **, char **) const unsigned char **, char **);
NONNULL(1,4) WUNRES;
int ssl_dnsname_match(const char *, size_t, const char *, size_t) int ssl_dnsname_match(const char *, size_t, const char *, size_t);
NONNULL(1,3) WUNRES; char * ssl_wildcardify(const char *);
char * ssl_wildcardify(const char *) NONNULL(1) MALLOC;
#endif /* !SSL_H */ #endif /* !SSL_H */
/* vim: set noet ft=c: */

View 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);

View File

@@ -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

View File

@@ -1,37 +1,8 @@
/*- #include <cert.h>
* 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 <string.h> #include <string.h>
#include <ssl.h>
#if 0
/* /*
* Certificate, including private key and certificate chain. * Certificate, including private key and certificate chain.
*/ */
@@ -338,5 +309,4 @@ void cert_manager_free(cert_t * cert)
cert_free(cert); cert_free(cert);
return; return;
} }
#endif
/* vim: set noet ft=c: */

View File

@@ -1,70 +1,83 @@
#include "future.h" #include <stdlib.h>
struct promise #include <stdio.h>
{ #include <string.h>
struct future f;
void * ctx; #include <tfe_future.h>
promise_ctx_destroy_cb* cb_ctx_destroy; #include <tfe_utils.h>
};
struct future struct future
{ {
void * user; void * user;
future_success_cb * cb_success; future_success_cb * cb_success;
future_failed_cb * cb_failed; future_failed_cb * cb_failed;
}; };
inline struct future* promise_to_future(struct promise* p) struct promise
{ {
return p->f; struct future f;
} void * ctx;
inline struct promise* future_to_promise(struct future* f) 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); return (struct promise *) f;
p->f.user=user;
p->f.cb_success=cb_success;
p->f.cb_failed=cb_failed;
return p->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) void future_destroy(struct future * f)
{ {
struct promise* promise=future_to_promise(f); struct promise * promise = future_to_promise(f);
if(promise->cb_ctx_destroy!=NULL) if (promise->cb_ctx_destroy != NULL)
{ {
promise->cb_ctx_destroy(promise); promise->cb_ctx_destroy(promise);
} }
memset(promise,0,sizeof(struct promise));
memset(promise, 0, sizeof(struct promise));
free(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; 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); p->f.cb_success(result, p->f.user);
return; 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->ctx = ctx;
p->cb_ctx_destroy=cb; p->cb_ctx_destroy = cb;
return; return;
} }
void* promise_get_ctx(struct promise* p)
void * promise_get_ctx(struct promise * p)
{ {
return p->ctx; return p->ctx;
} }
void* promise_dettach_ctx(struct promise* p)
void * promise_dettach_ctx(struct promise * p)
{ {
void* ctx=p->ctx; void * ctx = p->ctx;
p->ctx=NULL; p->ctx = NULL;
p->cb_ctx_destroy=NULL; p->cb_ctx_destroy = NULL;
return ctx; return ctx;
} }

24
platform/src/main.cpp Normal file
View 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";

View File

@@ -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
View 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);
}

View File

@@ -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)
{
}

View File

@@ -1,18 +1,30 @@
#include "ssl.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>
#include <event2/bufferevent.h>
#include <event2/bufferevent_ssl.h>
#include <event2/buffer.h>
#include <event2/thread.h>
#include <event2/dns.h>
/* forward declaration of OpenSSL callbacks */ #include <openssl/ssl.h>
#ifndef OPENSSL_NO_TLSEXT #include <openssl/err.h>
static int pxy_ossl_servername_cb(SSL * ssl, int * al, void * arg); #include <openssl/rand.h>
#endif /* !OPENSSL_NO_TLSEXT */ #include <openssl/x509.h>
static int pxy_ossl_sessnew_cb(SSL *, SSL_SESSION *); #include <openssl/x509v3.h>
static void pxy_ossl_sessremove_cb(SSL_CTX *, SSL_SESSION *);
#if OPENSSL_VERSION_NUMBER < 0x10100000L #include <tfe_stream.h>
static SSL_SESSION * pxy_ossl_sessget_cb(SSL *, unsigned char *, int, int *); #include <tfe_utils.h>
#else /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ #include <tfe_future.h>
static SSL_SESSION * pxy_ossl_sessget_cb(SSL *, const unsigned char *, int, #include <stream.h>
int *); #include <cert.h>
#endif /* OPENSSL_VERSION_NUMBER >= 0x10100000L */ #include <ssl.h>
struct peek_sni_ctx struct peek_sni_ctx
{ {
@@ -23,6 +35,7 @@ struct peek_sni_ctx
struct event_base* evbase; struct event_base* evbase;
}; };
void peek_sni_ctx_free(void* ctx) void peek_sni_ctx_free(void* ctx)
{ {
struct peek_sni_ctx * _ctx=(struct peek_sni_ctx *)ctx; struct peek_sni_ctx * _ctx=(struct peek_sni_ctx *)ctx;
@@ -39,6 +52,7 @@ static void peek_sni_cb(evutil_socket_t fd, short what, void * arg)
struct promise* promise=(struct promise*)arg; struct promise* promise=(struct promise*)arg;
struct peek_sni_ctx* ctx= (struct peek_sni_ctx*)promise->ctx; struct peek_sni_ctx* ctx= (struct peek_sni_ctx*)promise->ctx;
unsigned char buf[1024]; unsigned char buf[1024];
ssize_t n=0; ssize_t n=0;
const unsigned char * chello=NULL; const unsigned char * chello=NULL;
@@ -47,7 +61,7 @@ static void peek_sni_cb(evutil_socket_t fd, short what, void * arg)
n = recv(fd, buf, sizeof(buf), MSG_PEEK); n = recv(fd, buf, sizeof(buf), MSG_PEEK);
if (n == -1) if (n == -1)
{ {
{ TFE_LOG_ERROR("Error peeking on fd, aborting connection\n");
goto promise_failed; goto promise_failed;
} }
@@ -59,7 +73,7 @@ static void peek_sni_cb(evutil_socket_t fd, short what, void * arg)
rv = ssl_tls_clienthello_parse(buf, n, 0, &chello, &ctx->sni); rv = ssl_tls_clienthello_parse(buf, n, 0, &chello, &ctx->sni);
if ((rv == 1) && !chello) if ((rv == 1) && !chello)
{ {
{ TFE_LOG_ERROR("Peeking did not yield a (truncated) ClientHello message, aborting connection\n");
goto promise_failed; goto promise_failed;
} }
@@ -81,10 +95,10 @@ static void peek_sni_cb(evutil_socket_t fd, short what, void * arg)
event_add(ctx->ev, &retry_delay); event_add(ctx->ev, &retry_delay);
return; return;
} }
promise_set_ctx(promise, NULL, NULL); promise_set_ctx(promise, NULL, NULL);
promise->f.cb_success(ctx->sni,promise->f.user); promise->f.cb_success(ctx->sni,promise->f.user);
peek_sni_ctx_free(ctx); peek_sni_ctx_free(ctx);
peek_sni_ctx_free(ctx);
return; return;
promise_failed: promise_failed:
@@ -92,7 +106,6 @@ promise_failed:
peek_sni_ctx_free(ctx); peek_sni_ctx_free(ctx);
promise_set_ctx(promise, NULL,NULL); promise_set_ctx(promise, NULL,NULL);
return; return;
return;
} }
void ssl_async_peek_sni( struct future* future, evutil_socket_t fd, struct event_base *evbase) void ssl_async_peek_sni( struct future* future, evutil_socket_t fd, struct event_base *evbase)
@@ -103,6 +116,7 @@ void ssl_async_peek_sni( struct future* future, evutil_socket_t fd, struct even
ctx->ev = event_new(evbase, fd, EV_READ, peek_sni_cb, p); ctx->ev = event_new(evbase, fd, EV_READ, peek_sni_cb, p);
event_add(evbase, NULL); event_add(evbase, NULL);
promise_set_ctx(p, ctx,peek_sni_ctx_free); promise_set_ctx(p, ctx,peek_sni_ctx_free);
return; return;
} }
@@ -152,7 +166,8 @@ static void ssl_connect_origin_eventcb(struct bufferevent * bev, short events, v
return return
} }
void ssl_async_connect_origin(struct future* future, evutil_socket_t fd, const char* sni,
struct event_base *evbase, struct tfe_config *opts)
{ {
struct promise* p=future_to_promise(future); struct promise* p=future_to_promise(future);
struct ssl_connect_origin_ctx* ctx=ALLOC(struct ssl_connect_origin_ctx, 1); struct ssl_connect_origin_ctx* ctx=ALLOC(struct ssl_connect_origin_ctx, 1);
@@ -812,7 +827,7 @@ static int pxy_ossl_servername_cb(SSL * ssl, UNUSED int * al, void * arg)
* Create new SSL context for outgoing connections to the original destination. * Create new SSL context for outgoing connections to the original destination.
* If hostname sni is provided, use it for Server Name Indication. * If hostname sni is provided, use it for Server Name Indication.
*/ */
*/ static SSL* upstream_ssl_create(tfe_config*opts, const char* sni)
{ {
SSL_CTX* sslctx=NULL; SSL_CTX* sslctx=NULL;
SSL* ssl=NULL; SSL* ssl=NULL;
@@ -882,6 +897,7 @@ struct ssl_upstream* ssl_upstream_create(tfe_config*opts, const char* sni)
upstream->ssl=ssl; upstream->ssl=ssl;
return upstream; return upstream;
}*/ }*/
void ssl_upstream_free(struct ssl_upstream* p) void ssl_upstream_free(struct ssl_upstream* p)
{ {
X509_free(p->orig_cert); X509_free(p->orig_cert);

View File

@@ -1 +0,0 @@

View File

@@ -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);
}

View File

@@ -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: */

View File

@@ -1,15 +1,10 @@
#include "tfe_stream.h"
#include "tfe_util.h"
#include "opts.h"
#include "attrib.h"
#include <netinet/in.h> #include <netinet/in.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <assert.h>
#include <event2/event.h> #include <event2/event.h>
#include <event2/listener.h> #include <event2/listener.h>
@@ -25,17 +20,23 @@
#include <openssl/x509.h> #include <openssl/x509.h>
#include <openssl/x509v3.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 * Maximum size of data to buffer per connection direction before
* temporarily stopping to read data from the other end. * temporarily stopping to read data from the other end.
*/ */
#define OUTBUF_LIMIT (1024*1024) #define OUTBUF_LIMIT (1024*1024)
/* /*
* Print helper for logging code. * Print helper for logging code.
*/ */
#define STRORDASH(x) (((x)&&*(x))?(x):"-") #define STRORDASH(x) (((x)&&*(x))?(x):"-")
/* /*
* Context used for all server http_sessions_. * Context used for all server http_sessions_.
@@ -44,85 +45,108 @@
static unsigned long ssl_session_context = 0x31415926; static unsigned long ssl_session_context = 0x31415926;
#endif /* USE_SSL_SESSION_ID_CONTEXT */ #endif /* USE_SSL_SESSION_ID_CONTEXT */
/* forward declaration of libevent callbacks */ /* forward declaration of libevent callbacks */
static void tfe_stream_readcb(struct bufferevent *, void *); static void tfe_stream_readcb(struct bufferevent *, void *);
static void tfe_stream_writecb(struct bufferevent *, void *); static void tfe_stream_writecb(struct bufferevent *, void *);
static void tfe_stream_eventcb(struct bufferevent *, short, void *); static void tfe_stream_eventcb(struct bufferevent *, short, void *);
static void stream_fd_readcb(evutil_socket_t, short, void *); static void stream_fd_readcb(evutil_socket_t, short, void *);
static void tfe_stream_free(struct tfe_stream_private * stream)
void tfe_stream_detach(const struct tfe_stream* stream)
{ {
struct tfe_stream_private* _stream=(struct tfe_stream_private*)stream; struct tfe_thread_ctx * thread = stream->thrmgr_ref;
int plug_id=_stream->calling_idx; thread->load--;
_stream->plug_ctx[plug_id].state=PLUG_STATE_DETACHED;
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; 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; struct tfe_stream_private * _stream = (struct tfe_stream_private *) stream;
int plug_id=_stream->calling_idx; int plug_id = _stream->calling_idx;
int i=0; _stream->plug_ctx[plug_id].state = PLUG_STATE_DETACHED;
for(i=0;i<_stream->plugin_num;i++) 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; return -1;
} }
} }
_stream->plug_ctx[plug_id].state=PLUG_STATE_PREEPTION; _stream->plug_ctx[plug_id].state = PLUG_STATE_PREEPTION;
return 0; 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; struct tfe_conn_private * this_conn = NULL;
this_conn=((dir==CONN_DIR_UPSTREAM)? &(_stream->conn_downstream):&(_stream->conn_upstream)); this_conn = ((dir == CONN_DIR_UPSTREAM) ? &(_stream->conn_downstream) : &(_stream->conn_upstream));
return this_conn; 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; struct tfe_conn_private * peer_conn = NULL;
peer_conn=(dir==CONN_DIR_UPSTREAM)? &(_stream->conn_downstream):&(_stream->conn_upstream); peer_conn = (dir == CONN_DIR_UPSTREAM) ? &(_stream->conn_downstream) : &(_stream->conn_upstream);
return peer_conn; 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_stream_private * _stream = (struct tfe_stream_private *) stream;
struct tfe_conn_private* this_conn=__this_conn(_stream, dir); struct tfe_conn_private * this_conn = __this_conn(_stream, dir);
struct tfe_conn_private* peer_conn=__peer_conn(_stream, dir); struct tfe_conn_private * peer_conn = __peer_conn(_stream, dir);
if(this_conn->on_writing==1) if (this_conn->on_writing == 1)
{ {
return NULL; return NULL;
} }
this_conn->w_ctx.dir=dir; this_conn->w_ctx.dir = dir;
this_conn->w_ctx._stream=_stream; this_conn->w_ctx._stream = _stream;
this_conn->on_writing=1; this_conn->on_writing = 1;
bufferevent_disable(peer_conn->bev, EV_READ); bufferevent_disable(peer_conn->bev, EV_READ);
return &(this_conn->w_ctx); 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);; struct tfe_conn_private * this_conn = __this_conn(w_ctx->_stream, w_ctx->dir);;
int ret=bufferevent_write(this_conn->bev, data, size); int ret = bufferevent_write(this_conn->bev, data, size);
return ret; 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 * this_conn = __this_conn(w_ctx->_stream, w_ctx->dir);
struct tfe_conn_private* peer_conn=__peer_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; this_conn->on_writing = 0;
bufferevent_enable(peer_conn->bev, EV_READ); bufferevent_enable(peer_conn->bev, EV_READ);
return; 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; int ret = 0;
struct tfe_stream_write_ctx* wctx=tfe_stream_write_frag_start( stream, dir); struct tfe_stream_write_ctx * wctx = tfe_stream_write_frag_start(stream, dir);
ret=tfe_stream_write_frag(wctx, data, size); ret = tfe_stream_write_frag(wctx, data, size);
tfe_stream_write_frag_end(wctx); tfe_stream_write_frag_end(wctx);
return ret; return ret;
} }
@@ -209,50 +233,55 @@ enum tfe_stream_action tfe_stream_call_plugin(struct tfe_stream_private* _stream
static void tfe_stream_readcb(struct bufferevent * bev, void * arg) static void tfe_stream_readcb(struct bufferevent * bev, void * arg)
{ {
struct tfe_stream_private* _stream=(struct tfe_stream_private*)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; 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 * this_conn = __this_conn(_stream, dir);
struct tfe_conn_private* peer_conn= __peer_conn(_stream, dir); struct tfe_conn_private * peer_conn = __peer_conn(_stream, dir);
int i=0,ret=0; int i = 0, ret = 0;
enum tfe_stream_action action_tmp=ACTION_FORWARD_DATA, action_final=ACTION_FORWARD_DATA; 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;
const struct tfe_plugin* plugins=_stream->thrmgr_ref->modules; int plug_num = _stream->thrmgr_ref->nr_modules;
struct plugin_ctx* plug_ctx=NULL;
int plug_num=_stream->thrmgr_ref->module_num;
struct evbuffer * inbuf = bufferevent_get_input(bev); struct evbuffer * inbuf = bufferevent_get_input(bev);
struct evbuffer * outbuf = bufferevent_get_output(peer_conn->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); size_t contigous_len = evbuffer_get_length(inbuf), drain_size = 0;
_stream->defere_bytes=0; const unsigned char * contiguous_data = (const unsigned char *)evbuffer_pullup(inbuf, contigous_len);
_stream->drop_bytes=0;
_stream->forward_bytes=0; _stream->defere_bytes = 0;
for(i=0;i<plug_num;i++) _stream->drop_bytes = 0;
_stream->forward_bytes = 0;
for (i = 0; i < plug_num; i++)
{ {
_stream->calling_idx=i; _stream->calling_idx = i;
plug_ctx=_stream->plug_ctx+i; plug_ctx = _stream->plug_ctx + i;
if(_stream->is_plugin_opened==0)
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)); action_tmp = plugins[i].on_open(&_stream->head, _stream->thrmgr_ref->thread_id,
_stream->is_plugin_opened=1; dir, contiguous_data, contigous_len, &(plug_ctx->pme));
_stream->is_plugin_opened = 1;
} }
else 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: case ACTION_FORWARD_DATA:
if(_stream->forward_bytes>0) if (_stream->forward_bytes > 0)
{ {
evbuffer_remove_buffer(inbuf, outbuf, _stream->forward_bytes); evbuffer_remove_buffer(inbuf, outbuf, _stream->forward_bytes);
} }
@@ -262,17 +291,17 @@ static void tfe_stream_readcb(struct bufferevent * bev, void * arg)
} }
break; break;
case ACTION_DROP_DATA: 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 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: case ACTION_DEFER_DATA:
if(_stream->defere_bytes>0) if (_stream->defere_bytes > 0)
{ {
bufferevent_setwatermark(bev, EV_WRITE, _stream->defere_bytes, 0); bufferevent_setwatermark(bev, EV_WRITE, _stream->defere_bytes, 0);
} }
@@ -281,7 +310,8 @@ static void tfe_stream_readcb(struct bufferevent * bev, void * arg)
assert(0); assert(0);
break; break;
} }
if(evbuffer_get_length(inbuf) != 0)
if (evbuffer_get_length(inbuf) != 0)
{ {
bufferevent_trigger(bev, EV_READ, BEV_OPT_DEFER_CALLBACKS); bufferevent_trigger(bev, EV_READ, BEV_OPT_DEFER_CALLBACKS);
} }
@@ -304,10 +334,10 @@ static void tfe_stream_readcb(struct bufferevent * bev, void * arg)
*/ */
static void tfe_stream_writecb(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; 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; 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 * this_conn = __this_conn(_stream, dir);
struct tfe_conn_private* peer_conn= __peer_conn(_stream, dir); struct tfe_conn_private * peer_conn = __peer_conn(_stream, dir);
struct evbuffer * outbuf = bufferevent_get_output(bev); 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) static void tfe_stream_eventcb(struct bufferevent * bev, short events, void * arg)
{ {
struct tfe_stream_private* _stream=(struct tfe_stream_private*)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; 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 * this_conn = __this_conn(_stream, dir);
struct tfe_conn_private* peer_conn= __peer_conn(_stream, dir); struct tfe_conn_private * peer_conn = __peer_conn(_stream, dir);
const struct tfe_plugin* plugins=_stream->thrmgr_ref->modules; const struct tfe_plugin * plugins = _stream->thrmgr_ref->modules;
struct plugin_ctx* plug_ctx=NULL; struct plugin_ctx * plug_ctx = NULL;
int plug_num=_stream->thrmgr_ref->module_num,i=0; int plug_num = _stream->thrmgr_ref->nr_modules, i = 0;
enum tfe_stream_close_reason reason=REASON_PASSIVE_CLOSED; enum tfe_stream_close_reason reason = REASON_PASSIVE_CLOSED;
if (events & BEV_EVENT_ERROR) if (events & BEV_EVENT_ERROR)
{ {
this_conn->closed=1; this_conn->closed = 1;
reason=REASON_ERROR; reason = REASON_ERROR;
goto call_plugin_close; 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. //generate a 0 size read callback to notify plugins.
tfe_stream_readcb(bev, arg); 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; goto call_plugin_close;
} }
return; return;
call_plugin_close: call_plugin_close:
for(i=0;i<plug_num;i++) for (i = 0; i < plug_num; i++)
{ {
_stream->calling_idx=i; _stream->calling_idx = i;
plug_ctx=_stream->plug_ctx+i; plug_ctx = _stream->plug_ctx + i;
plugins[i].on_close(&(_stream.head), _stream->thrmgr_ref->thread_id, reason, &(plug_ctx->pme)); plugins[i].on_close(&(_stream->head), _stream->thrmgr_ref->thread_id, reason, &(plug_ctx->pme));
} }
tfe_stream_free(_stream); tfe_stream_free(_stream);
return; 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) void ssl_get_cert_on_succ(void * result, void * user)
{ {
cert_t* cert=(cert_t*)result; cert_t * cert = (cert_t *) result;
struct tfe_stream_private* _stream=(struct tfe_stream_private*)user; 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);
//_stream->ssl_downstream->ssl = downstream_ssl_create(_stream);
cert_free(cert); cert_free(cert);
bufferevent_setcb(_stream->head.upstream.bev, tfe_stream_readcb, tfe_stream_writecb, tfe_stream_eventcb, _stream); 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_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.upstream.bev, EV_READ | EV_WRITE);
bufferevent_enable(_stream->head.downstream.bev, EV_READ | EV_WRITE); bufferevent_enable(_stream->head.downstream.bev, EV_READ | EV_WRITE);
future_destroy(_stream->ssl_downstream->future_get_cert); future_destroy(_stream->ssl_downstream->future_get_cert);
_stream->ssl_downstream->future_get_cert=NULL; _stream->ssl_downstream->future_get_cert = NULL;
return; return;
} }
void ssl_get_cert_on_fail(enum e_future_error err, const char * what, void * user) void ssl_get_cert_on_fail(enum e_future_error err, const char * what, void * user)
{ {
//todo
assert(0); assert(0);
} }
void ssl_conn_origin_on_succ(void * result, void * user) void ssl_conn_origin_on_succ(void * result, void * user)
{ {
struct bufferevent *bev=(struct bufferevent *)result; struct bufferevent * bev = (struct bufferevent *) result;
struct tfe_stream_private* _stream=(struct tfe_stream_private*)user; struct tfe_stream_private * _stream = (struct tfe_stream_private *) user;
_stream->head.upstream.bev=bev; _stream->head.upstream.bev = bev;
_stream->ssl_upstream->ssl=bufferevent_openssl_get_ssl(bev); /* does not inc refc */ _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_upstream->orig_cert = SSL_get_peer_certificate(_stream->ssl_upstream->ssl);
session_cache_set(_stream->thrmgr_ref->dsess_cache, struct sockaddr * addr, addrlen,_stream->ssl_downstream->sni, SSL_get0_session(_stream->ssl_upstream->ssl)); #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); _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, #if 0
_stream->ssl_downstream->sni, cert_mgr_async_get(_stream->ssl_downstream->future_get_cert,
_stream->ssl_downstream->keyring_id, _stream->thrmgr_ref->cert_mgr,
_stream->ssl_upstream->orig_cert); _stream->ssl_downstream->sni,
_stream->ssl_downstream->keyring_id,
_stream->ssl_upstream->orig_cert);
#endif
future_destroy(_stream->ssl_upstream->conn_ssl_srv); future_destroy(_stream->ssl_upstream->conn_ssl_srv);
_stream->ssl_upstream->conn_ssl_srv=NULL; _stream->ssl_upstream->conn_ssl_srv = NULL;
return;
} }
void ssl_conn_origin_on_fail(enum e_future_error err, const char * what, void * user) void ssl_conn_origin_on_fail(enum e_future_error err, const char * what, void * user)
{ {
//todo //TODO:
assert(0); 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; struct tfe_stream_private * _stream = (struct tfe_stream_private *) user;
assert(_stream->session_type==SESSION_PROTO_SSL); assert(_stream->session_type == SESSION_PROTO_SSL);
_stream->ssl_downstream->sni=tfe_strdup((const char *)result);
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); future_destroy(ssl_downstream->future_sni_peek);
ssl_downstream->future_sni_peek=NULL; 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);
_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) void peek_sni_on_fail(enum e_future_error err, const char * what, void * user)
{ {
//todo //TODO:
assert(0); assert(0);
} }
/* /*
* Callback for accept events on the socket listener bufferevent. * Callback for accept events on the socket listener bufferevent.
* Called when a new incoming connection has been accepted. * 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 * start reading from the client while waiting on the connection to
* the server to connect. * 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; struct future * f_sni = NULL;
tfe_thread_ctx* thread=_stream->thrmgr_ref; tfe_thread_ctx * thread = _stream->thrmgr_ref;
switch (_stream->session_type) switch (_stream->session_type)
{ {
case SESSION_PROTO_SSL: case SESSION_PROTO_SSL:
// for SSL, defer dst connection setup to initial_readcb // for SSL, defer dst connection setup to initial_readcb
_stream->ssl_downstream=ssl_downstream_create(); _stream->ssl_downstream = ssl_downstream_create();
_stream->async_future=future_create(peek_sni_on_succ, peek_sni_on_fail, _stream); _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); ssl_async_peek_sni(_stream->ssl_downstream->future_sni_peek, _stream->fd_downstream,
_stream->thrmgr_ref->evbase);
thread->stat.value[SSL_NUM]++; thread->stat.value[SSL_NUM]++;
break break;
default: default:
//todo: //todo:
stream_fd_readcb(_stream->fd_downstream, 0, _stream); stream_fd_readcb(_stream->fd_downstream, 0, _stream);
break; break;
} }
return; return;
} }
struct tfe_stream_private* tfe_stream_create(evutil_socket_t fd_downstream, evutil_socket_t fd_upstream, 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)
enum tfe_session_proto session_type, tfe_thread_ctx* thread)
{ {
struct tfe_stream_private* conn_private=NULL; struct tfe_stream_private * conn_private = NULL;
struct tfe_stream* conn_public=NULL; struct tfe_stream * conn_public = NULL;
conn_private= ALLOC(struct tfe_stream_private, 1); conn_private = ALLOC(struct tfe_stream_private, 1);
conn_private->session_type=session_type; conn_private->session_type = session_type;
conn_private->fd_downstream=fd_downstream; conn_private->fd_downstream = fd_downstream;
conn_private->fd_upstream=fd_upstream; conn_private->fd_upstream = fd_upstream;
conn_private->thrmgr_ref=thread; conn_private->thrmgr_ref = thread;
conn_private->is_plugin_opened=0; conn_private->is_plugin_opened = 0;
conn_public=&(conn_private->head); conn_public = &(conn_private->head);
//todo
addr_sock2layer(conn_public->downstream.addr,peeraddr,peeraddrlen);
thread->stat.value[STREAM_NUM]++; thread->stat.value[STREAM_NUM]++;
return conn_private; return conn_private;
} }

View File

@@ -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;
};

View File

@@ -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;
}