整理目录结构,调整框架部分实现,初步编译通过。
This commit is contained in:
@@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
add_library(common src/tfe_stat.cpp src/tfe_utils.cpp)
|
||||||
|
target_include_directories(common PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
|
||||||
|
|||||||
@@ -5,16 +5,21 @@ enum e_future_error
|
|||||||
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 (future_success_cb)(void * result, void * user);
|
||||||
typedef void (*promise_ctx_destroy_cb)(struct promise* p);
|
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 * future_create(future_success_cb * cb_success, future_failed_cb * cb_failed, void * user);
|
||||||
|
|
||||||
struct future * promise_to_future(struct promise * p);
|
struct future * promise_to_future(struct promise * p);
|
||||||
struct promise * future_to_promise(struct future * f);
|
struct promise * future_to_promise(struct future * f);
|
||||||
|
|
||||||
|
void future_destroy(struct future * f);
|
||||||
|
void promise_failed(struct promise * p, enum e_future_error error, const char * what);
|
||||||
|
void promise_success(struct promise * p, void * result);
|
||||||
|
void promise_set_ctx(struct promise * p, void * ctx, promise_ctx_destroy_cb * cb);
|
||||||
|
void * promise_get_ctx(struct promise * p);
|
||||||
|
void * promise_dettach_ctx(struct promise * p);
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <tfe_types.h>
|
||||||
|
|
||||||
#define TFE_STRING_MAX 2048
|
#define TFE_STRING_MAX 2048
|
||||||
#define TFE_SYMBOL_MAX 64
|
#define TFE_SYMBOL_MAX 64
|
||||||
|
|
||||||
enum tfe_session_proto
|
enum tfe_session_proto
|
||||||
{
|
{
|
||||||
SESSION_PROTO_PLAIN = 0,
|
SESSION_PROTO_PLAIN = 0,
|
||||||
@@ -8,6 +14,7 @@ enum tfe_session_proto
|
|||||||
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,
|
||||||
@@ -15,11 +22,13 @@ enum tfe_app_proto
|
|||||||
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,
|
||||||
@@ -42,13 +51,13 @@ 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
|
||||||
@@ -56,20 +65,22 @@ enum tfe_stream_action_opt
|
|||||||
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);
|
||||||
/*
|
/*
|
||||||
@@ -77,20 +88,26 @@ struct tfe_stream_write_ctx* tfe_stream_write_frag_start(const struct tfe_stream
|
|||||||
*/
|
*/
|
||||||
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);
|
|
||||||
|
typedef tfe_stream_action stream_data_cb_t(const struct tfe_stream * stream, unsigned int thread_id,
|
||||||
|
enum tfe_conn_dir dir, const unsigned char * data, size_t len, void ** pme);
|
||||||
|
|
||||||
|
typedef void stream_close_cb_t(const struct tfe_stream * stream, unsigned int thread_id,
|
||||||
|
enum tfe_stream_close_reason reason, void ** pme);
|
||||||
|
|
||||||
void tfe_stream_detach(const struct tfe_stream * stream);
|
void tfe_stream_detach(const struct tfe_stream * stream);
|
||||||
int tfe_stream_preempt(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(const struct tfe_stream * stream);
|
||||||
int stream_shutdown_dir(const struct tfe_stream * stream, enum tfe_conn_dir dir);
|
int stream_shutdown_dir(const struct tfe_stream * stream, enum tfe_conn_dir dir);
|
||||||
//typedef int proto_onwrite_cb_t(struct tfe_stream*, struct evbuffer *data, void **pme);
|
|
||||||
|
|
||||||
struct tfe_plugin
|
struct tfe_plugin
|
||||||
{
|
{
|
||||||
@@ -99,11 +116,4 @@ struct tfe_plugin
|
|||||||
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);
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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; /* 地址结构长度 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
//#define ALLOC(t,n) (t *)calloc(sizeof(t),(n))
|
|
||||||
|
|
||||||
/* Allocates an array of objects using malloc() */
|
|
||||||
#define ALLOC(type, number) \
|
|
||||||
((type *)calloc(sizeof(type), number))
|
|
||||||
|
|
||||||
#define log_err_printf(fmt, args...) \
|
|
||||||
fprintf(stderr, "file %s, line %d, " fmt, \
|
|
||||||
__FILE__, __LINE__, ##args)
|
|
||||||
#define log_dbg_printf(fmt, args...) \
|
|
||||||
fprintf(stdout, "file %s, line %d, " fmt, \
|
|
||||||
__FILE__, __LINE__, ##args)
|
|
||||||
#define likely(expr) __builtin_expect((expr), 1)
|
|
||||||
#define unlikely(expr) __builtin_expect((expr), 0)
|
|
||||||
|
|
||||||
int addr_sock2layer(struct sockaddr * sock_addr, int sockaddrlen, struct layer_addr* layer_addr);
|
|
||||||
int addr_layer2sock(struct layer_addr* layer_addr,struct sockaddr * sock_addr);
|
|
||||||
char* tfe_strdup(const char* s);
|
|
||||||
|
|
||||||
|
|
||||||
17
common/include/tfe_utils.h
Normal file
17
common/include/tfe_utils.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
//#define ALLOC(t,n) (t *)calloc(sizeof(t),(n))
|
||||||
|
|
||||||
|
/* Allocates an array of objects using malloc() */
|
||||||
|
#define ALLOC(type, number) \
|
||||||
|
((type *)calloc(sizeof(type), number))
|
||||||
|
|
||||||
|
#define likely(expr) __builtin_expect((expr), 1)
|
||||||
|
#define unlikely(expr) __builtin_expect((expr), 0)
|
||||||
|
|
||||||
|
int addr_sock_to_layer(struct sockaddr * sock_addr, int sockaddrlen, struct layer_addr * layer_addr);
|
||||||
|
int addr_layer_to_sock(struct layer_addr * layer_addr, struct sockaddr * sock_addr);
|
||||||
|
char* tfe_strdup(const char* s);
|
||||||
|
|
||||||
|
|
||||||
|
#define TFE_LOG_ERROR
|
||||||
|
#define TFE_LOG_INFO
|
||||||
|
#define TFE_LOG_DEBUG
|
||||||
30
common/src/tfe_utils.cpp
Normal file
30
common/src/tfe_utils.cpp
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <tfe_utils.h>
|
||||||
|
|
||||||
|
int addr_sock_to_layer(struct sockaddr * sock_addr, int sockaddrlen, struct layer_addr * layer_addr)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int addr_layer_to_sock(struct layer_addr * layer_addr, struct sockaddr * sock_addr)
|
||||||
|
{
|
||||||
|
int sockaddrlen=-1;
|
||||||
|
return sockaddrlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
//functioned as strdup, for dictator compatible.
|
||||||
|
char* tfe_strdup(const char* s)
|
||||||
|
{
|
||||||
|
char*d=NULL;
|
||||||
|
if(s==NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
d=(char*)malloc(strlen(s)+1);
|
||||||
|
memcpy(d,s,strlen(s)+1);
|
||||||
|
return d;
|
||||||
|
}
|
||||||
@@ -1,3 +1,8 @@
|
|||||||
|
|
||||||
add_executable(tfe src/cert.cpp src/future.cpp src/io_module_kni.cpp src/session_cache.cpp src/ssl.cc
|
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)
|
||||||
|
|||||||
@@ -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;
|
struct cert_mgr;
|
||||||
pthread_mutex_t mutex;
|
|
||||||
size_t references;
|
|
||||||
} cert_t;
|
|
||||||
struct cert_mgr{};
|
|
||||||
struct cert_mgr * cert_manager_init(const char * profile);
|
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);
|
|
||||||
|
|
||||||
|
void cert_mgr_async_get(struct future * future, struct cert_mgr * mgr, int keyring_id,
|
||||||
|
X509 * origin_cert, struct event_base * evbase);
|
||||||
|
|
||||||
|
void cert_free(cert_t * cert);
|
||||||
cert_t * cert_new(void) MALLOC;
|
|
||||||
cert_t * cert_new_load(const char *) MALLOC;
|
|
||||||
cert_t * cert_new3(EVP_PKEY *, X509 *, STACK_OF(X509) *) MALLOC;
|
|
||||||
cert_t * cert_new3_copy(EVP_PKEY *, X509 *, STACK_OF(X509) *) MALLOC;
|
|
||||||
void cert_refcount_inc(cert_t *) NONNULL(1);
|
|
||||||
void cert_set_key(cert_t *, EVP_PKEY *) NONNULL(1);
|
|
||||||
void cert_set_crt(cert_t *, X509 *) NONNULL(1);
|
|
||||||
void cert_set_chain(cert_t *, STACK_OF(X509) *) NONNULL(1);
|
|
||||||
void cert_free(cert_t *) NONNULL(1);
|
|
||||||
|
|
||||||
#endif /* !CERT_H */
|
#endif /* !CERT_H */
|
||||||
|
|
||||||
/* vim: set noet ft=c: */
|
|
||||||
|
|||||||
7
platform/include/internal/sescache.h
Normal file
7
platform/include/internal/sescache.h
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct sess_cache;
|
||||||
|
struct sess_cache * session_cache_init();
|
||||||
|
|
||||||
|
void session_cache_set(struct sess_cache * cache, struct sockaddr * addr,
|
||||||
|
socklen_t addrlen, const char * sni, SSL_SESSION * session);
|
||||||
@@ -29,8 +29,6 @@
|
|||||||
#ifndef SSL_H
|
#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: */
|
|
||||||
126
platform/include/internal/stream.h
Normal file
126
platform/include/internal/stream.h
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <openssl/ossl_typ.h>
|
||||||
|
#include <event2/event.h>
|
||||||
|
|
||||||
|
#include <tfe_stream.h>
|
||||||
|
#include <tfe_stat.h>
|
||||||
|
#include <cert.h>
|
||||||
|
|
||||||
|
struct tfe_thread_ctx
|
||||||
|
{
|
||||||
|
pthread_t thr;
|
||||||
|
unsigned int thread_id;
|
||||||
|
size_t load;
|
||||||
|
|
||||||
|
struct event_base * evbase;
|
||||||
|
unsigned char running;
|
||||||
|
|
||||||
|
struct tfe_stats stat;
|
||||||
|
struct cert_mgr * cert_mgr;
|
||||||
|
|
||||||
|
struct sess_cache * dsess_cache;
|
||||||
|
struct sess_cache * ssess_cache;
|
||||||
|
|
||||||
|
unsigned int nr_modules;
|
||||||
|
const struct tfe_plugin * modules;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Downstream: comunication form client to proxy
|
||||||
|
//Upstream: communication form proxy to server
|
||||||
|
struct ssl_downstream
|
||||||
|
{
|
||||||
|
/* server name indicated by client in SNI TLS extension */
|
||||||
|
char * sni;
|
||||||
|
SSL * ssl;
|
||||||
|
X509 * fake_cert_ref;//?
|
||||||
|
int keyring_id;
|
||||||
|
struct future * future_sni_peek;
|
||||||
|
struct future * future_get_cert;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ssl_upstream
|
||||||
|
{
|
||||||
|
X509 * orig_cert;
|
||||||
|
SSL * ssl;
|
||||||
|
struct future * conn_ssl_srv;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum tfe_plugin_state
|
||||||
|
{
|
||||||
|
PLUG_STATE_READONLY,
|
||||||
|
PLUG_STATE_PREEPTION,
|
||||||
|
PLUG_STATE_DETACHED
|
||||||
|
};
|
||||||
|
|
||||||
|
struct plugin_ctx
|
||||||
|
{
|
||||||
|
enum tfe_plugin_state state;
|
||||||
|
void * pme;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tfe_stream_write_ctx
|
||||||
|
{
|
||||||
|
struct tfe_stream_private * _stream;
|
||||||
|
enum tfe_conn_dir dir;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tfe_conn_private
|
||||||
|
{
|
||||||
|
evutil_socket_t fd;
|
||||||
|
struct bufferevent * bev;
|
||||||
|
uint8_t on_writing;
|
||||||
|
uint8_t closed;
|
||||||
|
uint8_t need_shutdown;
|
||||||
|
struct tfe_stream_write_ctx w_ctx;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tfe_stream_private
|
||||||
|
{
|
||||||
|
struct tfe_stream head;
|
||||||
|
enum tfe_session_proto session_type;
|
||||||
|
struct tfe_conn_private conn_upstream;
|
||||||
|
struct tfe_conn_private conn_downstream;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct ssl_downstream * ssl_downstream;
|
||||||
|
void * raw_downstream;
|
||||||
|
};
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct ssl_upstream * ssl_upstream;
|
||||||
|
void * raw_upstream;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t is_plugin_opened;
|
||||||
|
int calling_idx;
|
||||||
|
size_t forward_bytes;
|
||||||
|
size_t defere_bytes;
|
||||||
|
size_t drop_bytes;
|
||||||
|
enum tfe_app_proto app_proto;
|
||||||
|
int plugin_num;
|
||||||
|
struct plugin_ctx * plug_ctx;
|
||||||
|
unsigned char passthrough; /* 1 if SSL passthrough is active */
|
||||||
|
|
||||||
|
evutil_socket_t fd_downstream;
|
||||||
|
evutil_socket_t fd_upstream;
|
||||||
|
|
||||||
|
struct tfe_thread_ctx * thrmgr_ref;
|
||||||
|
future * async_future;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tfe_stream_private * tfe_stream_create(evutil_socket_t fd_downstream, evutil_socket_t fd_upstream,
|
||||||
|
enum tfe_session_proto session_type, tfe_thread_ctx * thread);
|
||||||
|
|
||||||
|
void tfe_stream_setup(struct tfe_stream_private * _stream);
|
||||||
|
|
||||||
|
void ssl_async_connect_origin(struct future * future, evutil_socket_t fd, const char * sni,
|
||||||
|
struct event_base * evbase, struct tfe_config * opts);
|
||||||
|
|
||||||
|
void ssl_async_peek_sni(struct future * future, evutil_socket_t fd, struct event_base * evbase);
|
||||||
|
|
||||||
|
struct ssl_downstream * ssl_downstream_create();
|
||||||
|
void ssl_upstream_free(struct ssl_upstream * p);
|
||||||
|
void ssl_downstream_free(struct ssl_downstream * p);
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
VPATH=../inc/
|
|
||||||
opt: OPTFLAGS = -O
|
|
||||||
export OPTFLAGS
|
|
||||||
|
|
||||||
CC = gcc
|
|
||||||
CCC = g++
|
|
||||||
CFLAGS = -Wall
|
|
||||||
CFLAGS += -g -fPIC
|
|
||||||
CFLAGS += $(OPTFLAGS)
|
|
||||||
MESAFramework =-lMESA_htable -lMESA_prof_load -lwiredcfg -lMESA_handle_logger
|
|
||||||
SYS_LIB =-L./ -lpthread -levent -levent_openssl -levent_pthreads
|
|
||||||
H_DIR = ./inc_internal/
|
|
||||||
OBJS = tfe_main.o proxy.o io_module_kni.o
|
|
||||||
TARGET = tfe_3a
|
|
||||||
|
|
||||||
.PHONY: all clean deps test opt
|
|
||||||
|
|
||||||
all: $(TARGET)
|
|
||||||
|
|
||||||
opt:
|
|
||||||
$(MAKE) all
|
|
||||||
.c.o:
|
|
||||||
$(CC) -c $(CFLAGS) -I $(H_DIR) $<
|
|
||||||
|
|
||||||
.cpp.o:
|
|
||||||
$(CCC) -c $(CFLAGS) -I $(H_DIR) $<
|
|
||||||
clean:
|
|
||||||
rm -f $(TARGETSLIB) $(TARGETSO) *.o core core.*
|
|
||||||
$(TARGET): $(OBJS)
|
|
||||||
$(CC) -o $(TARGET) $(CFLAGS) $^ $(SYS_LIB) $(MESAFramework)
|
|
||||||
cp $@ ../bin
|
|
||||||
|
|
||||||
@@ -1,37 +1,8 @@
|
|||||||
/*-
|
#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: */
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#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;
|
||||||
@@ -12,22 +12,32 @@ struct future
|
|||||||
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;
|
||||||
|
promise_ctx_destroy_cb * cb_ctx_destroy;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct future * promise_to_future(struct promise * p)
|
||||||
|
{
|
||||||
|
return &p->f;
|
||||||
}
|
}
|
||||||
inline struct promise* future_to_promise(struct future* f)
|
|
||||||
|
struct promise * future_to_promise(struct future * f)
|
||||||
{
|
{
|
||||||
return (struct promise *) f;
|
return (struct promise *) f;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct future * future_create(future_success_cb * cb_success, future_failed_cb * cb_failed, void * user)
|
struct future * future_create(future_success_cb * cb_success, future_failed_cb * cb_failed, void * user)
|
||||||
{
|
{
|
||||||
struct promise * p = ALLOC(struct promise, 1);
|
struct promise * p = ALLOC(struct promise, 1);
|
||||||
p->f.user = user;
|
p->f.user = user;
|
||||||
p->f.cb_success = cb_success;
|
p->f.cb_success = cb_success;
|
||||||
p->f.cb_failed = cb_failed;
|
p->f.cb_failed = cb_failed;
|
||||||
return p->f;
|
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);
|
||||||
@@ -35,9 +45,9 @@ void future_destroy(struct future * f)
|
|||||||
{
|
{
|
||||||
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)
|
||||||
@@ -45,21 +55,25 @@ void promise_failed(struct promise* p, enum e_future_error error, const char* wh
|
|||||||
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;
|
||||||
@@ -67,4 +81,3 @@ void* promise_dettach_ctx(struct promise* p)
|
|||||||
p->cb_ctx_destroy = NULL;
|
p->cb_ctx_destroy = NULL;
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
24
platform/src/main.cpp
Normal file
24
platform/src/main.cpp
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/*-
|
||||||
|
* Tango Frontend Engine (TFE) 3a
|
||||||
|
* Part of Tango Security Gateway
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018-2023, MESA Lab, https://www.mesalab.cn
|
||||||
|
* All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <tfe_utils.h>
|
||||||
|
#include <MESA/MESA_handle_logger.h>
|
||||||
|
#include <MESA/MESA_prof_load.h>
|
||||||
|
#include <MESA/wired_cfg.h>
|
||||||
|
|
||||||
|
extern struct tfe_instance __g_tfe_instance;
|
||||||
|
extern struct tfe_config __g_tfe_config;
|
||||||
|
|
||||||
|
struct tfe_instance* g_tfe_instance = &__g_tfe_instance;
|
||||||
|
struct tfe_config * g_tfe_cfg = &__g_tfe_config;
|
||||||
|
|
||||||
|
const char* module_name="TFE";
|
||||||
|
|
||||||
@@ -1,980 +0,0 @@
|
|||||||
/*-
|
|
||||||
* SSLsplit - transparent SSL/TLS interception
|
|
||||||
* https://www.roe.ch/SSLsplit
|
|
||||||
*
|
|
||||||
* Copyright (c) 2009-2018, Daniel Roethlisberger <daniel@roe.ch>.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions are met:
|
|
||||||
* 1. Redistributions of source code must retain the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
* this list of conditions and the following disclaimer in the documentation
|
|
||||||
* and/or other materials provided with the distribution.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS ``AS IS''
|
|
||||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
||||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "privsep.h"
|
|
||||||
|
|
||||||
#include "sys.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "compat.h"
|
|
||||||
#include "attrib.h"
|
|
||||||
#include "defaults.h"
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/select.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <libgen.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Privilege separation functionality.
|
|
||||||
*
|
|
||||||
* The server code has limitations on the internal functionality that can be
|
|
||||||
* used, namely only those that are initialized before forking.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* maximal message sizes */
|
|
||||||
#define PRIVSEP_MAX_REQ_SIZE 512 /* arbitrary limit */
|
|
||||||
#define PRIVSEP_MAX_ANS_SIZE (1+sizeof(int))
|
|
||||||
/* command byte */
|
|
||||||
#define PRIVSEP_REQ_CLOSE 0 /* closing command socket */
|
|
||||||
#define PRIVSEP_REQ_OPENFILE 1 /* open content log file */
|
|
||||||
#define PRIVSEP_REQ_OPENFILE_P 2 /* open content log file w/mkpath */
|
|
||||||
#define PRIVSEP_REQ_OPENSOCK 3 /* open socket and pass fd */
|
|
||||||
#define PRIVSEP_REQ_CERTFILE 4 /* open cert file in certgendir */
|
|
||||||
/* response byte */
|
|
||||||
#define PRIVSEP_ANS_SUCCESS 0 /* success */
|
|
||||||
#define PRIVSEP_ANS_UNK_CMD 1 /* unknown command */
|
|
||||||
#define PRIVSEP_ANS_INVALID 2 /* invalid message */
|
|
||||||
#define PRIVSEP_ANS_DENIED 3 /* request denied */
|
|
||||||
#define PRIVSEP_ANS_SYS_ERR 4 /* system error; arg=errno */
|
|
||||||
|
|
||||||
/* communication with signal handler */
|
|
||||||
static volatile sig_atomic_t received_sighup;
|
|
||||||
static volatile sig_atomic_t received_sigint;
|
|
||||||
static volatile sig_atomic_t received_sigquit;
|
|
||||||
static volatile sig_atomic_t received_sigterm;
|
|
||||||
static volatile sig_atomic_t received_sigchld;
|
|
||||||
static volatile sig_atomic_t received_sigusr1;
|
|
||||||
/* write end of pipe used for unblocking select */
|
|
||||||
static volatile sig_atomic_t selfpipe_wrfd;
|
|
||||||
|
|
||||||
static void
|
|
||||||
privsep_server_signal_handler(int sig)
|
|
||||||
{
|
|
||||||
int saved_errno;
|
|
||||||
|
|
||||||
#ifdef DEBUG_PRIVSEP_SERVER
|
|
||||||
log_dbg_printf("privsep_server_signal_handler\n");
|
|
||||||
#endif /* DEBUG_PRIVSEP_SERVER */
|
|
||||||
|
|
||||||
saved_errno = errno;
|
|
||||||
switch (sig) {
|
|
||||||
case SIGHUP:
|
|
||||||
received_sighup = 1;
|
|
||||||
break;
|
|
||||||
case SIGINT:
|
|
||||||
received_sigint = 1;
|
|
||||||
break;
|
|
||||||
case SIGQUIT:
|
|
||||||
received_sigquit = 1;
|
|
||||||
break;
|
|
||||||
case SIGTERM:
|
|
||||||
received_sigterm = 1;
|
|
||||||
break;
|
|
||||||
case SIGCHLD:
|
|
||||||
received_sigchld = 1;
|
|
||||||
break;
|
|
||||||
case SIGUSR1:
|
|
||||||
received_sigusr1 = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (selfpipe_wrfd != -1) {
|
|
||||||
ssize_t n;
|
|
||||||
|
|
||||||
#ifdef DEBUG_PRIVSEP_SERVER
|
|
||||||
log_dbg_printf("writing to selfpipe_wrfd %i\n", selfpipe_wrfd);
|
|
||||||
#endif /* DEBUG_PRIVSEP_SERVER */
|
|
||||||
do {
|
|
||||||
n = write(selfpipe_wrfd, "!", 1);
|
|
||||||
} while (n == -1 && errno == EINTR);
|
|
||||||
if (n == -1) {
|
|
||||||
log_err_printf("Failed to write from signal handler: "
|
|
||||||
"%s (%i)\n", strerror(errno), errno);
|
|
||||||
/* ignore error */
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_PRIVSEP_SERVER
|
|
||||||
} else {
|
|
||||||
log_dbg_printf("selfpipe_wrfd is %i - not writing\n", selfpipe_wrfd);
|
|
||||||
#endif /* DEBUG_PRIVSEP_SERVER */
|
|
||||||
}
|
|
||||||
errno = saved_errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int WUNRES
|
|
||||||
privsep_server_openfile_verify(tfe_config *opts, char *fn, int mkpath)
|
|
||||||
{
|
|
||||||
if (mkpath && !opts->contentlog_isspec)
|
|
||||||
return -1;
|
|
||||||
if (!mkpath && !opts->contentlog_isdir)
|
|
||||||
return -1;
|
|
||||||
if (strstr(fn, mkpath ? opts->contentlog_basedir
|
|
||||||
: opts->contentlog) != fn ||
|
|
||||||
strstr(fn, "/../"))
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int WUNRES
|
|
||||||
privsep_server_openfile(char *fn, int mkpath)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
if (mkpath) {
|
|
||||||
char *filedir, *fn2;
|
|
||||||
|
|
||||||
fn2 = strdup(fn);
|
|
||||||
if (!fn2) {
|
|
||||||
log_err_printf("Could not duplicate filname: %s (%i)\n",
|
|
||||||
strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
filedir = dirname(fn2);
|
|
||||||
if (!filedir) {
|
|
||||||
log_err_printf("Could not get dirname: %s (%i)\n",
|
|
||||||
strerror(errno), errno);
|
|
||||||
free(fn2);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (sys_mkpath(filedir, DFLT_DIRMODE) == -1) {
|
|
||||||
log_err_printf("Could not create directory '%s': %s (%i)\n",
|
|
||||||
filedir, strerror(errno), errno);
|
|
||||||
free(fn2);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
free(fn2);
|
|
||||||
}
|
|
||||||
|
|
||||||
fd = open(fn, O_WRONLY|O_APPEND|O_CREAT, DFLT_FILEMODE);
|
|
||||||
if (fd == -1) {
|
|
||||||
log_err_printf("Failed to open '%s': %s (%i)\n",
|
|
||||||
fn, strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int WUNRES
|
|
||||||
privsep_server_opensock_verify(tfe_config *opts, void *arg)
|
|
||||||
{
|
|
||||||
for (proxyspec *spec = opts->spec; spec; spec = spec->next) {
|
|
||||||
if (spec == arg)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int WUNRES
|
|
||||||
privsep_server_opensock(proxyspec *spec)
|
|
||||||
{
|
|
||||||
evutil_socket_t fd;
|
|
||||||
int on = 1;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
fd = socket(spec->listen_addr.ss_family, SOCK_STREAM, IPPROTO_TCP);
|
|
||||||
if (fd == -1) {
|
|
||||||
log_err_printf("Error from socket(): %s (%i)\n",
|
|
||||||
strerror(errno), errno);
|
|
||||||
evutil_closesocket(fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = evutil_make_socket_nonblocking(fd);
|
|
||||||
if (rv == -1) {
|
|
||||||
log_err_printf("Error making socket nonblocking: %s (%i)\n",
|
|
||||||
strerror(errno), errno);
|
|
||||||
evutil_closesocket(fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on));
|
|
||||||
if (rv == -1) {
|
|
||||||
log_err_printf("Error from setsockopt(SO_KEEPALIVE): %s (%i)\n",
|
|
||||||
strerror(errno), errno);
|
|
||||||
evutil_closesocket(fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = evutil_make_listen_socket_reuseable(fd);
|
|
||||||
if (rv == -1) {
|
|
||||||
log_err_printf("Error from setsockopt(SO_REUSABLE): %s\n",
|
|
||||||
strerror(errno));
|
|
||||||
evutil_closesocket(fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spec->natsocket && (spec->natsocket(fd) == -1)) {
|
|
||||||
log_err_printf("Error from spec->natsocket()\n");
|
|
||||||
evutil_closesocket(fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = bind(fd, (struct sockaddr *)&spec->listen_addr,
|
|
||||||
spec->listen_addrlen);
|
|
||||||
if (rv == -1) {
|
|
||||||
log_err_printf("Error from bind(): %s\n", strerror(errno));
|
|
||||||
evutil_closesocket(fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int WUNRES
|
|
||||||
privsep_server_certfile_verify(tfe_config *opts, char *fn)
|
|
||||||
{
|
|
||||||
if (!opts->certgendir)
|
|
||||||
return -1;
|
|
||||||
if (strstr(fn, opts->certgendir) != fn || strstr(fn, "/../"))
|
|
||||||
return -1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int WUNRES
|
|
||||||
privsep_server_certfile(char *fn)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
fd = open(fn, O_WRONLY|O_CREAT|O_EXCL, DFLT_FILEMODE);
|
|
||||||
if (fd == -1 && errno != EEXIST) {
|
|
||||||
log_err_printf("Failed to open '%s': %s (%i)\n",
|
|
||||||
fn, strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Handle a single request on a readable server socket.
|
|
||||||
* Returns 0 on success, 1 on EOF and -1 on error.
|
|
||||||
*/
|
|
||||||
static int WUNRES
|
|
||||||
privsep_server_handle_req(tfe_config *opts, int srvsock)
|
|
||||||
{
|
|
||||||
char req[PRIVSEP_MAX_REQ_SIZE];
|
|
||||||
char ans[PRIVSEP_MAX_ANS_SIZE];
|
|
||||||
ssize_t n;
|
|
||||||
int mkpath = 0;
|
|
||||||
|
|
||||||
if ((n = sys_recvmsgfd(srvsock, req, sizeof(req),
|
|
||||||
NULL)) == -1) {
|
|
||||||
if (errno == EPIPE || errno == ECONNRESET) {
|
|
||||||
/* unfriendly EOF, leave server */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
log_err_printf("Failed to receive msg: %s (%i)\n",
|
|
||||||
strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (n == 0) {
|
|
||||||
/* EOF, leave server; will not happen for SOCK_DGRAM sockets */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
log_dbg_printf("Received privsep req type %02x sz %zd on srvsock %i\n",
|
|
||||||
req[0], n, srvsock);
|
|
||||||
switch (req[0]) {
|
|
||||||
case PRIVSEP_REQ_CLOSE: {
|
|
||||||
/* client indicates EOF through close message */
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
case PRIVSEP_REQ_OPENFILE_P:
|
|
||||||
mkpath = 1;
|
|
||||||
case PRIVSEP_REQ_OPENFILE: {
|
|
||||||
char *fn;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
if (n < 2) {
|
|
||||||
ans[0] = PRIVSEP_ANS_INVALID;
|
|
||||||
if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
|
|
||||||
log_err_printf("Sending message failed: %s (%i"
|
|
||||||
")\n", strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!(fn = malloc(n))) {
|
|
||||||
ans[0] = PRIVSEP_ANS_SYS_ERR;
|
|
||||||
*((int*)&ans[1]) = errno;
|
|
||||||
if (sys_sendmsgfd(srvsock, ans, 1 + sizeof(int),
|
|
||||||
-1) == -1) {
|
|
||||||
log_err_printf("Sending message failed: %s (%i"
|
|
||||||
")\n", strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
memcpy(fn, req + 1, n - 1);
|
|
||||||
fn[n - 1] = '\0';
|
|
||||||
if (privsep_server_openfile_verify(opts, fn, mkpath) == -1) {
|
|
||||||
free(fn);
|
|
||||||
ans[0] = PRIVSEP_ANS_DENIED;
|
|
||||||
if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
|
|
||||||
log_err_printf("Sending message failed: %s (%i"
|
|
||||||
")\n", strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if ((fd = privsep_server_openfile(fn, mkpath)) == -1) {
|
|
||||||
free(fn);
|
|
||||||
ans[0] = PRIVSEP_ANS_SYS_ERR;
|
|
||||||
*((int*)&ans[1]) = errno;
|
|
||||||
if (sys_sendmsgfd(srvsock, ans, 1 + sizeof(int),
|
|
||||||
-1) == -1) {
|
|
||||||
log_err_printf("Sending message failed: %s (%i"
|
|
||||||
")\n", strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
free(fn);
|
|
||||||
ans[0] = PRIVSEP_ANS_SUCCESS;
|
|
||||||
if (sys_sendmsgfd(srvsock, ans, 1, fd) == -1) {
|
|
||||||
close(fd);
|
|
||||||
log_err_printf("Sending message failed: %s (%i"
|
|
||||||
")\n", strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* not reached */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PRIVSEP_REQ_OPENSOCK: {
|
|
||||||
proxyspec *arg;
|
|
||||||
int s;
|
|
||||||
|
|
||||||
if (n != sizeof(char) + sizeof(arg)) {
|
|
||||||
ans[0] = PRIVSEP_ANS_INVALID;
|
|
||||||
if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
|
|
||||||
log_err_printf("Sending message failed: %s (%i"
|
|
||||||
")\n", strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
arg = *(proxyspec**)(&req[1]);
|
|
||||||
if (privsep_server_opensock_verify(opts, arg) == -1) {
|
|
||||||
ans[0] = PRIVSEP_ANS_DENIED;
|
|
||||||
if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
|
|
||||||
log_err_printf("Sending message failed: %s (%i"
|
|
||||||
")\n", strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if ((s = privsep_server_opensock(arg)) == -1) {
|
|
||||||
ans[0] = PRIVSEP_ANS_SYS_ERR;
|
|
||||||
*((int*)&ans[1]) = errno;
|
|
||||||
if (sys_sendmsgfd(srvsock, ans, 1 + sizeof(int),
|
|
||||||
-1) == -1) {
|
|
||||||
log_err_printf("Sending message failed: %s (%i"
|
|
||||||
")\n", strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
ans[0] = PRIVSEP_ANS_SUCCESS;
|
|
||||||
if (sys_sendmsgfd(srvsock, ans, 1, s) == -1) {
|
|
||||||
evutil_closesocket(s);
|
|
||||||
log_err_printf("Sending message failed: %s (%i"
|
|
||||||
")\n", strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
evutil_closesocket(s);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* not reached */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PRIVSEP_REQ_CERTFILE: {
|
|
||||||
char *fn;
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
if (n < 2) {
|
|
||||||
ans[0] = PRIVSEP_ANS_INVALID;
|
|
||||||
if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
|
|
||||||
log_err_printf("Sending message failed: %s (%i"
|
|
||||||
")\n", strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!(fn = malloc(n))) {
|
|
||||||
ans[0] = PRIVSEP_ANS_SYS_ERR;
|
|
||||||
*((int*)&ans[1]) = errno;
|
|
||||||
if (sys_sendmsgfd(srvsock, ans, 1 + sizeof(int),
|
|
||||||
-1) == -1) {
|
|
||||||
log_err_printf("Sending message failed: %s (%i"
|
|
||||||
")\n", strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
memcpy(fn, req + 1, n - 1);
|
|
||||||
fn[n - 1] = '\0';
|
|
||||||
if (privsep_server_certfile_verify(opts, fn) == -1) {
|
|
||||||
free(fn);
|
|
||||||
ans[0] = PRIVSEP_ANS_DENIED;
|
|
||||||
if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
|
|
||||||
log_err_printf("Sending message failed: %s (%i"
|
|
||||||
")\n", strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if ((fd = privsep_server_certfile(fn)) == -1) {
|
|
||||||
free(fn);
|
|
||||||
ans[0] = PRIVSEP_ANS_SYS_ERR;
|
|
||||||
*((int*)&ans[1]) = errno;
|
|
||||||
if (sys_sendmsgfd(srvsock, ans, 1 + sizeof(int),
|
|
||||||
-1) == -1) {
|
|
||||||
log_err_printf("Sending message failed: %s (%i"
|
|
||||||
")\n", strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
free(fn);
|
|
||||||
ans[0] = PRIVSEP_ANS_SUCCESS;
|
|
||||||
if (sys_sendmsgfd(srvsock, ans, 1, fd) == -1) {
|
|
||||||
close(fd);
|
|
||||||
log_err_printf("Sending message failed: %s (%i"
|
|
||||||
")\n", strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* not reached */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
ans[0] = PRIVSEP_ANS_UNK_CMD;
|
|
||||||
if (sys_sendmsgfd(srvsock, ans, 1, -1) == -1) {
|
|
||||||
log_err_printf("Sending message failed: %s (%i"
|
|
||||||
")\n", strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Privilege separation server (main privileged monitor loop)
|
|
||||||
*
|
|
||||||
* sigpipe is the self-pipe trick pipe used for communicating signals to
|
|
||||||
* the main event loop and break out of select() without race conditions.
|
|
||||||
* srvsock[] is a dynamic array of connected privsep server sockets to serve.
|
|
||||||
* Caller is responsible for freeing memory after returning, if necessary.
|
|
||||||
* childpid is the pid of the child process to forward signals to.
|
|
||||||
*
|
|
||||||
* Returns 0 on a successful clean exit and -1 on errors.
|
|
||||||
*/
|
|
||||||
static int
|
|
||||||
privsep_server(tfe_config *opts, int sigpipe, int srvsock[], size_t nsrvsock,
|
|
||||||
pid_t childpid)
|
|
||||||
{
|
|
||||||
int srveof[nsrvsock];
|
|
||||||
size_t i = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < nsrvsock; i++) {
|
|
||||||
srveof[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
fd_set readfds;
|
|
||||||
int maxfd, rv;
|
|
||||||
|
|
||||||
#ifdef DEBUG_PRIVSEP_SERVER
|
|
||||||
log_dbg_printf("privsep_server select()\n");
|
|
||||||
#endif /* DEBUG_PRIVSEP_SERVER */
|
|
||||||
do {
|
|
||||||
FD_ZERO(&readfds);
|
|
||||||
FD_SET(sigpipe, &readfds);
|
|
||||||
maxfd = sigpipe;
|
|
||||||
for (i = 0; i < nsrvsock; i++) {
|
|
||||||
if (!srveof[i]) {
|
|
||||||
FD_SET(srvsock[i], &readfds);
|
|
||||||
maxfd = util_max(maxfd, srvsock[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rv = select(maxfd + 1, &readfds, NULL, NULL, NULL);
|
|
||||||
#ifdef DEBUG_PRIVSEP_SERVER
|
|
||||||
log_dbg_printf("privsep_server woke up (1)\n");
|
|
||||||
#endif /* DEBUG_PRIVSEP_SERVER */
|
|
||||||
} while (rv == -1 && errno == EINTR);
|
|
||||||
if (rv == -1) {
|
|
||||||
log_err_printf("select() failed: %s (%i)\n",
|
|
||||||
strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_PRIVSEP_SERVER
|
|
||||||
log_dbg_printf("privsep_server woke up (2)\n");
|
|
||||||
#endif /* DEBUG_PRIVSEP_SERVER */
|
|
||||||
|
|
||||||
if (FD_ISSET(sigpipe, &readfds)) {
|
|
||||||
char buf[16];
|
|
||||||
ssize_t n;
|
|
||||||
/* first drain the signal pipe, then deal with
|
|
||||||
* all the individual signal flags */
|
|
||||||
n = read(sigpipe, buf, sizeof(buf));
|
|
||||||
if (n == -1) {
|
|
||||||
log_err_printf("read(sigpipe) failed:"
|
|
||||||
" %s (%i)\n",
|
|
||||||
strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (received_sigquit) {
|
|
||||||
if (kill(childpid, SIGQUIT) == -1) {
|
|
||||||
log_err_printf("kill(%i,SIGQUIT) "
|
|
||||||
"failed: %s (%i)\n",
|
|
||||||
childpid,
|
|
||||||
strerror(errno), errno);
|
|
||||||
}
|
|
||||||
received_sigquit = 0;
|
|
||||||
}
|
|
||||||
if (received_sigterm) {
|
|
||||||
if (kill(childpid, SIGTERM) == -1) {
|
|
||||||
log_err_printf("kill(%i,SIGTERM) "
|
|
||||||
"failed: %s (%i)\n",
|
|
||||||
childpid,
|
|
||||||
strerror(errno), errno);
|
|
||||||
}
|
|
||||||
received_sigterm = 0;
|
|
||||||
}
|
|
||||||
if (received_sighup) {
|
|
||||||
if (kill(childpid, SIGHUP) == -1) {
|
|
||||||
log_err_printf("kill(%i,SIGHUP) "
|
|
||||||
"failed: %s (%i)\n",
|
|
||||||
childpid,
|
|
||||||
strerror(errno), errno);
|
|
||||||
}
|
|
||||||
received_sighup = 0;
|
|
||||||
}
|
|
||||||
if (received_sigusr1) {
|
|
||||||
if (kill(childpid, SIGUSR1) == -1) {
|
|
||||||
log_err_printf("kill(%i,SIGUSR1) "
|
|
||||||
"failed: %s (%i)\n",
|
|
||||||
childpid,
|
|
||||||
strerror(errno), errno);
|
|
||||||
}
|
|
||||||
received_sigusr1 = 0;
|
|
||||||
}
|
|
||||||
if (received_sigint) {
|
|
||||||
/* if we don't detach from the TTY, the
|
|
||||||
* child process receives SIGINT directly */
|
|
||||||
if (opts->detach) {
|
|
||||||
if (kill(childpid, SIGINT) == -1) {
|
|
||||||
log_err_printf("kill(%i,SIGINT"
|
|
||||||
") failed: "
|
|
||||||
"%s (%i)\n",
|
|
||||||
childpid,
|
|
||||||
strerror(errno),
|
|
||||||
errno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
received_sigint = 0;
|
|
||||||
}
|
|
||||||
if (received_sigchld) {
|
|
||||||
/* break the loop; because we are using
|
|
||||||
* SOCKET_DGRAM we don't get EOF conditions
|
|
||||||
* on the disconnected socket ends here
|
|
||||||
* unless we attempt to write or read, so
|
|
||||||
* we depend on SIGCHLD to notify us of
|
|
||||||
* our child erroring out or crashing */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < nsrvsock; i++) {
|
|
||||||
if (FD_ISSET(srvsock[i], &readfds)) {
|
|
||||||
int rv = privsep_server_handle_req(opts,
|
|
||||||
srvsock[i]);
|
|
||||||
if (rv == -1) {
|
|
||||||
log_err_printf("Failed to handle "
|
|
||||||
"privsep req "
|
|
||||||
"on srvsock %i\n",
|
|
||||||
srvsock[i]);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (rv == 1) {
|
|
||||||
#ifdef DEBUG_PRIVSEP_SERVER
|
|
||||||
log_dbg_printf("srveof[%zu]=1\n", i);
|
|
||||||
#endif /* DEBUG_PRIVSEP_SERVER */
|
|
||||||
srveof[i] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We cannot exit as long as we need the signal handling,
|
|
||||||
* which is as long as the child process is running.
|
|
||||||
* The only way out of here is receiving SIGCHLD.
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
privsep_client_openfile(int clisock, const char *fn, int mkpath)
|
|
||||||
{
|
|
||||||
char ans[PRIVSEP_MAX_ANS_SIZE];
|
|
||||||
char req[1 + strlen(fn)];
|
|
||||||
int fd = -1;
|
|
||||||
ssize_t n;
|
|
||||||
|
|
||||||
req[0] = mkpath ? PRIVSEP_REQ_OPENFILE_P : PRIVSEP_REQ_OPENFILE;
|
|
||||||
memcpy(req + 1, fn, sizeof(req) - 1);
|
|
||||||
|
|
||||||
if (sys_sendmsgfd(clisock, req, sizeof(req), -1) == -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((n = sys_recvmsgfd(clisock, ans, sizeof(ans), &fd)) == -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n < 1) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ans[0]) {
|
|
||||||
case PRIVSEP_ANS_SUCCESS:
|
|
||||||
break;
|
|
||||||
case PRIVSEP_ANS_DENIED:
|
|
||||||
errno = EACCES;
|
|
||||||
return -1;
|
|
||||||
case PRIVSEP_ANS_SYS_ERR:
|
|
||||||
if (n < (ssize_t)(1 + sizeof(int))) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
errno = *((int*)&ans[1]);
|
|
||||||
return -1;
|
|
||||||
case PRIVSEP_ANS_UNK_CMD:
|
|
||||||
case PRIVSEP_ANS_INVALID:
|
|
||||||
default:
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
privsep_client_opensock(int clisock, const proxyspec *spec)
|
|
||||||
{
|
|
||||||
char ans[PRIVSEP_MAX_ANS_SIZE];
|
|
||||||
char req[1 + sizeof(spec)];
|
|
||||||
int fd = -1;
|
|
||||||
ssize_t n;
|
|
||||||
|
|
||||||
req[0] = PRIVSEP_REQ_OPENSOCK;
|
|
||||||
*((const proxyspec **)&req[1]) = spec;
|
|
||||||
|
|
||||||
if (sys_sendmsgfd(clisock, req, sizeof(req), -1) == -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((n = sys_recvmsgfd(clisock, ans, sizeof(ans), &fd)) == -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n < 1) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ans[0]) {
|
|
||||||
case PRIVSEP_ANS_SUCCESS:
|
|
||||||
break;
|
|
||||||
case PRIVSEP_ANS_DENIED:
|
|
||||||
errno = EACCES;
|
|
||||||
return -1;
|
|
||||||
case PRIVSEP_ANS_SYS_ERR:
|
|
||||||
if (n < (ssize_t)(1 + sizeof(int))) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
errno = *((int*)&ans[1]);
|
|
||||||
return -1;
|
|
||||||
case PRIVSEP_ANS_UNK_CMD:
|
|
||||||
case PRIVSEP_ANS_INVALID:
|
|
||||||
default:
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
privsep_client_certfile(int clisock, const char *fn)
|
|
||||||
{
|
|
||||||
char ans[PRIVSEP_MAX_ANS_SIZE];
|
|
||||||
char req[1 + strlen(fn)];
|
|
||||||
int fd = -1;
|
|
||||||
ssize_t n;
|
|
||||||
|
|
||||||
req[0] = PRIVSEP_REQ_CERTFILE;
|
|
||||||
memcpy(req + 1, fn, sizeof(req) - 1);
|
|
||||||
|
|
||||||
if (sys_sendmsgfd(clisock, req, sizeof(req), -1) == -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((n = sys_recvmsgfd(clisock, ans, sizeof(ans), &fd)) == -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (n < 1) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (ans[0]) {
|
|
||||||
case PRIVSEP_ANS_SUCCESS:
|
|
||||||
break;
|
|
||||||
case PRIVSEP_ANS_DENIED:
|
|
||||||
errno = EACCES;
|
|
||||||
return -1;
|
|
||||||
case PRIVSEP_ANS_SYS_ERR:
|
|
||||||
if (n < (ssize_t)(1 + sizeof(int))) {
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
errno = *((int*)&ans[1]);
|
|
||||||
return -1;
|
|
||||||
case PRIVSEP_ANS_UNK_CMD:
|
|
||||||
case PRIVSEP_ANS_INVALID:
|
|
||||||
default:
|
|
||||||
errno = EINVAL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
privsep_client_close(int clisock)
|
|
||||||
{
|
|
||||||
char req[1];
|
|
||||||
|
|
||||||
req[0] = PRIVSEP_REQ_CLOSE;
|
|
||||||
|
|
||||||
if (sys_sendmsgfd(clisock, req, sizeof(req), -1) == -1) {
|
|
||||||
close(clisock);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
close(clisock);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Fork and set up privilege separated monitor process.
|
|
||||||
* Returns -1 on error before forking, 1 as parent, or 0 as child.
|
|
||||||
* The array of clisock's will get filled with nclisock privsep client
|
|
||||||
* sockets only for the child; on error and in the parent process it
|
|
||||||
* will not be touched.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
privsep_fork(tfe_config *opts, int clisock[], size_t nclisock)
|
|
||||||
{
|
|
||||||
int selfpipev[2]; /* self-pipe trick: signal handler -> select */
|
|
||||||
int chldpipev[2]; /* el cheapo interprocess sync early after fork */
|
|
||||||
int sockcliv[nclisock][2];
|
|
||||||
pid_t pid;
|
|
||||||
|
|
||||||
received_sigquit = 0;
|
|
||||||
received_sighup = 0;
|
|
||||||
received_sigint = 0;
|
|
||||||
received_sigchld = 0;
|
|
||||||
received_sigusr1 = 0;
|
|
||||||
|
|
||||||
if (pipe(selfpipev) == -1) {
|
|
||||||
log_err_printf("Failed to create self-pipe: %s (%i)\n",
|
|
||||||
strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
log_dbg_printf("Created self-pipe [r=%i,w=%i]\n",
|
|
||||||
selfpipev[0], selfpipev[1]);
|
|
||||||
|
|
||||||
if (pipe(chldpipev) == -1) {
|
|
||||||
log_err_printf("Failed to create chld-pipe: %s (%i)\n",
|
|
||||||
strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
log_dbg_printf("Created chld-pipe [r=%i,w=%i]\n",
|
|
||||||
chldpipev[0], chldpipev[1]);
|
|
||||||
|
|
||||||
for (size_t i = 0; i < nclisock; i++) {
|
|
||||||
if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockcliv[i]) == -1) {
|
|
||||||
log_err_printf("Failed to create socket pair %zu: "
|
|
||||||
"%s (%i)\n", i, strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
log_dbg_printf("Created socketpair %zu [p=%i,c=%i]\n",
|
|
||||||
i, sockcliv[i][0], sockcliv[i][1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
pid = fork();
|
|
||||||
if (pid == -1) {
|
|
||||||
log_err_printf("Failed to fork: %s (%i)\n",
|
|
||||||
strerror(errno), errno);
|
|
||||||
close(selfpipev[0]);
|
|
||||||
close(selfpipev[1]);
|
|
||||||
close(chldpipev[0]);
|
|
||||||
close(chldpipev[1]);
|
|
||||||
for (size_t i = 0; i < nclisock; i++) {
|
|
||||||
close(sockcliv[i][0]);
|
|
||||||
close(sockcliv[i][1]);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
} else if (pid == 0) {
|
|
||||||
/* child */
|
|
||||||
close(selfpipev[0]);
|
|
||||||
close(selfpipev[1]);
|
|
||||||
for (size_t i = 0; i < nclisock; i++)
|
|
||||||
close(sockcliv[i][0]);
|
|
||||||
/* wait until parent has installed signal handlers,
|
|
||||||
* intentionally ignoring errors */
|
|
||||||
char buf[1];
|
|
||||||
ssize_t n;
|
|
||||||
close(chldpipev[1]);
|
|
||||||
do {
|
|
||||||
n = read(chldpipev[0], buf, sizeof(buf));
|
|
||||||
} while (n == -1 && errno == EINTR);
|
|
||||||
close(chldpipev[0]);
|
|
||||||
|
|
||||||
/* return the privsep client sockets */
|
|
||||||
for (size_t i = 0; i < nclisock; i++)
|
|
||||||
clisock[i] = sockcliv[i][1];
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/* parent */
|
|
||||||
for (size_t i = 0; i < nclisock; i++)
|
|
||||||
close(sockcliv[i][1]);
|
|
||||||
selfpipe_wrfd = selfpipev[1];
|
|
||||||
|
|
||||||
/* close file descriptors opened by preinit's only needed in client;
|
|
||||||
* we still call the preinit's before forking in order to provide
|
|
||||||
* better user feedback and less privsep complexity */
|
|
||||||
nat_preinit_undo();
|
|
||||||
|
|
||||||
/* If the child exits before the parent installs the signal handler
|
|
||||||
* here, we have a race condition; this is solved by the client
|
|
||||||
* blocking on the reading end of a pipe (chldpipev[0]). */
|
|
||||||
if (signal(SIGHUP, privsep_server_signal_handler) == SIG_ERR) {
|
|
||||||
log_err_printf("Failed to install SIGHUP handler: %s (%i)\n",
|
|
||||||
strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (signal(SIGINT, privsep_server_signal_handler) == SIG_ERR) {
|
|
||||||
log_err_printf("Failed to install SIGINT handler: %s (%i)\n",
|
|
||||||
strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (signal(SIGTERM, privsep_server_signal_handler) == SIG_ERR) {
|
|
||||||
log_err_printf("Failed to install SIGTERM handler: %s (%i)\n",
|
|
||||||
strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (signal(SIGQUIT, privsep_server_signal_handler) == SIG_ERR) {
|
|
||||||
log_err_printf("Failed to install SIGQUIT handler: %s (%i)\n",
|
|
||||||
strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (signal(SIGUSR1, privsep_server_signal_handler) == SIG_ERR) {
|
|
||||||
log_err_printf("Failed to install SIGUSR1 handler: %s (%i)\n",
|
|
||||||
strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (signal(SIGCHLD, privsep_server_signal_handler) == SIG_ERR) {
|
|
||||||
log_err_printf("Failed to install SIGCHLD handler: %s (%i)\n",
|
|
||||||
strerror(errno), errno);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* unblock the child */
|
|
||||||
close(chldpipev[0]);
|
|
||||||
close(chldpipev[1]);
|
|
||||||
|
|
||||||
int socksrv[nclisock];
|
|
||||||
for (size_t i = 0; i < nclisock; i++)
|
|
||||||
socksrv[i] = sockcliv[i][0];
|
|
||||||
if (privsep_server(opts, selfpipev[0], socksrv, nclisock, pid) == -1) {
|
|
||||||
log_err_printf("Privsep server failed: %s (%i)\n",
|
|
||||||
strerror(errno), errno);
|
|
||||||
/* fall through */
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_PRIVSEP_SERVER
|
|
||||||
log_dbg_printf("privsep_server exited\n");
|
|
||||||
#endif /* DEBUG_PRIVSEP_SERVER */
|
|
||||||
|
|
||||||
for (size_t i = 0; i < nclisock; i++)
|
|
||||||
close(sockcliv[i][0]);
|
|
||||||
selfpipe_wrfd = -1; /* tell signal handler not to write anymore */
|
|
||||||
close(selfpipev[0]);
|
|
||||||
close(selfpipev[1]);
|
|
||||||
|
|
||||||
int status;
|
|
||||||
wait(&status);
|
|
||||||
if (WIFEXITED(status)) {
|
|
||||||
if (WEXITSTATUS(status) != 0) {
|
|
||||||
log_err_printf("Child proc %lld exited with status %d\n",
|
|
||||||
(long long)pid, WEXITSTATUS(status));
|
|
||||||
} else {
|
|
||||||
log_dbg_printf("Child proc %lld exited with status %d\n",
|
|
||||||
(long long)pid, WEXITSTATUS(status));
|
|
||||||
}
|
|
||||||
} else if (WIFSIGNALED(status)) {
|
|
||||||
log_err_printf("Child proc %lld killed by signal %d\n",
|
|
||||||
(long long)pid, WTERMSIG(status));
|
|
||||||
} else {
|
|
||||||
log_err_printf("Child proc %lld neither exited nor killed\n",
|
|
||||||
(long long)pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* vim: set noet ft=c: */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
294
platform/src/proxy.cpp
Normal file
294
platform/src/proxy.cpp
Normal file
@@ -0,0 +1,294 @@
|
|||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include <event2/event.h>
|
||||||
|
#include <event2/listener.h>
|
||||||
|
#include <event2/bufferevent.h>
|
||||||
|
#include <event2/bufferevent_ssl.h>
|
||||||
|
#include <event2/buffer.h>
|
||||||
|
#include <event2/thread.h>
|
||||||
|
|
||||||
|
#include <MESA/MESA_handle_logger.h>
|
||||||
|
#include <tfe_utils.h>
|
||||||
|
#include <tfe_stream.h>
|
||||||
|
#include <stream.h>
|
||||||
|
#include <kni.h>
|
||||||
|
#include <sescache.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Proxy engine, built around libevent 2.x.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define TFE_BACKLOG_DEFAULT 20
|
||||||
|
|
||||||
|
const char * module_name_pxy = "TFE_PXY";
|
||||||
|
extern struct tfe_instance * g_tfe_instance;
|
||||||
|
|
||||||
|
__thread int __currect_thread_id;
|
||||||
|
|
||||||
|
static void __dummy_event_handler(evutil_socket_t fd, short what, void * arg)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Thread entry point; runs the event loop of the event base.
|
||||||
|
* Does not exit until the libevent loop is broken explicitly.
|
||||||
|
*/
|
||||||
|
static void * __tfe_thrmgr_thread_entry(void * arg)
|
||||||
|
{
|
||||||
|
struct tfe_thread_ctx * ctx = (struct tfe_thread_ctx *) arg;
|
||||||
|
struct timeval timer_delay = {60, 0};
|
||||||
|
|
||||||
|
struct event * ev;
|
||||||
|
ev = event_new(ctx->evbase, -1, EV_PERSIST, __dummy_event_handler, NULL);
|
||||||
|
|
||||||
|
if (!ev) return (void *)NULL;
|
||||||
|
|
||||||
|
evtimer_add(ev, &timer_delay);
|
||||||
|
ctx->running = 1;
|
||||||
|
|
||||||
|
__currect_thread_id = ctx->thread_id;
|
||||||
|
event_base_dispatch(ctx->evbase);
|
||||||
|
event_free(ev);
|
||||||
|
|
||||||
|
return (void *)NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int signals[] = {SIGTERM, SIGQUIT, SIGHUP, SIGINT, SIGPIPE, SIGUSR1};
|
||||||
|
|
||||||
|
struct tfe_proxy
|
||||||
|
{
|
||||||
|
char name[TFE_SYMBOL_MAX];
|
||||||
|
struct event_base * evbase;
|
||||||
|
struct event * sev[sizeof(signals) / sizeof(int)];
|
||||||
|
struct event * gcev;
|
||||||
|
|
||||||
|
struct tfe_config * opts;
|
||||||
|
void * main_logger;
|
||||||
|
|
||||||
|
struct sess_cache * dsess_cache;
|
||||||
|
struct sess_cache * ssess_cache;
|
||||||
|
|
||||||
|
unsigned int nr_work_threads;
|
||||||
|
struct tfe_thread_ctx * work_threads;
|
||||||
|
|
||||||
|
unsigned int nr_modules;
|
||||||
|
struct tfe_plugin * modules;
|
||||||
|
|
||||||
|
void * io_mod;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Signal handler for SIGTERM, SIGQUIT, SIGINT, SIGHUP, SIGPIPE and SIGUSR1.
|
||||||
|
*/
|
||||||
|
static void proxy_signal_cb(evutil_socket_t fd, short what, void * arg)
|
||||||
|
{
|
||||||
|
tfe_proxy * ctx = (tfe_proxy *) arg;
|
||||||
|
switch (fd)
|
||||||
|
{
|
||||||
|
case SIGTERM:
|
||||||
|
case SIGQUIT:
|
||||||
|
case SIGINT:
|
||||||
|
case SIGHUP:
|
||||||
|
break;
|
||||||
|
case SIGUSR1:
|
||||||
|
break;
|
||||||
|
case SIGPIPE:
|
||||||
|
TFE_LOG_ERROR("Warning: Received SIGPIPE; ignoring.\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
TFE_LOG_ERROR("Warning: Received unexpected signal %i\n", fd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void proxy_gc_cb(evutil_socket_t fd, short what, void * arg)
|
||||||
|
{
|
||||||
|
tfe_proxy * ctx = (tfe_proxy *) arg;
|
||||||
|
(void)fd;
|
||||||
|
(void)what;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int select_work_thread(struct tfe_proxy * pxy)
|
||||||
|
{
|
||||||
|
unsigned int min_thread_id = 0;
|
||||||
|
size_t min_load = pxy->work_threads[min_thread_id].load;
|
||||||
|
|
||||||
|
for (unsigned thread_id = 1; thread_id < pxy->nr_work_threads; thread_id++)
|
||||||
|
{
|
||||||
|
if (min_load > pxy->work_threads[thread_id].load)
|
||||||
|
{
|
||||||
|
min_load = pxy->work_threads[thread_id].load;
|
||||||
|
min_thread_id = thread_id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pxy->work_threads[min_thread_id].load++;
|
||||||
|
return min_thread_id;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Callback for accept events on the socket listener bufferevent.
|
||||||
|
*/
|
||||||
|
static void io_mod_accept_cb(evutil_socket_t upstream_fd, evutil_socket_t downstream_fd,
|
||||||
|
enum tfe_session_proto session_type, void * arg)
|
||||||
|
{
|
||||||
|
struct tfe_proxy * pxy = (struct tfe_proxy *) arg;
|
||||||
|
|
||||||
|
unsigned int worker_tid = select_work_thread(pxy);
|
||||||
|
tfe_thread_ctx * worker_thread_ctx = &pxy->work_threads[worker_tid];
|
||||||
|
|
||||||
|
struct tfe_stream_private * stream = tfe_stream_create(upstream_fd,
|
||||||
|
downstream_fd, session_type, worker_thread_ctx);
|
||||||
|
|
||||||
|
assert(stream != NULL);
|
||||||
|
return tfe_stream_setup(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set up the core event loop.
|
||||||
|
* Socket clisock is the privsep client socket used for binding to ports.
|
||||||
|
* Returns ctx on success, or NULL on error.
|
||||||
|
*/
|
||||||
|
struct tfe_proxy * tfe_proxy_new(tfe_config * cfg)
|
||||||
|
{
|
||||||
|
struct tfe_proxy * proxy = ALLOC(struct tfe_proxy, 1);
|
||||||
|
assert(proxy != NULL);
|
||||||
|
|
||||||
|
struct timeval gc_delay = {60, 0};
|
||||||
|
|
||||||
|
/* adds locking, only required if accessed from separate threads */
|
||||||
|
evthread_use_pthreads();
|
||||||
|
event_enable_debug_mode();
|
||||||
|
|
||||||
|
proxy->evbase = event_base_new();
|
||||||
|
proxy->dsess_cache = session_cache_init();
|
||||||
|
proxy->ssess_cache = session_cache_init();
|
||||||
|
|
||||||
|
proxy->nr_modules = 2;
|
||||||
|
proxy->modules = ALLOC(struct tfe_plugin, proxy->nr_modules);
|
||||||
|
|
||||||
|
proxy->modules[0].proto = APP_PROTO_HTTP1;
|
||||||
|
proxy->modules[1].proto = APP_PROTO_HTTP2;
|
||||||
|
|
||||||
|
proxy->work_threads = ALLOC(struct tfe_thread_ctx, proxy->nr_work_threads);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < proxy->nr_work_threads; i++)
|
||||||
|
{
|
||||||
|
proxy->work_threads[i].thread_id = i;
|
||||||
|
proxy->work_threads[i].evbase = event_base_new();
|
||||||
|
proxy->work_threads[i].dsess_cache = proxy->dsess_cache;
|
||||||
|
proxy->work_threads[i].ssess_cache = proxy->ssess_cache;
|
||||||
|
proxy->work_threads[i].nr_modules = proxy->nr_modules;
|
||||||
|
proxy->work_threads[i].modules = proxy->modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Todo: Not handle signal if have mutliple proxy instance.
|
||||||
|
for (size_t i = 0; i < (sizeof(signals) / sizeof(int)); i++)
|
||||||
|
{
|
||||||
|
proxy->sev[i] = evsignal_new(proxy->evbase, signals[i], proxy_signal_cb, proxy);
|
||||||
|
if (!proxy->sev[i]) goto error_out;
|
||||||
|
evsignal_add(proxy->sev[i], NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy->gcev = event_new(proxy->evbase, -1, EV_PERSIST, proxy_gc_cb, proxy);
|
||||||
|
if (!proxy->gcev)
|
||||||
|
goto error_out;
|
||||||
|
|
||||||
|
evtimer_add(proxy->gcev, &gc_delay);
|
||||||
|
return proxy;
|
||||||
|
|
||||||
|
error_out:
|
||||||
|
if (proxy->gcev)
|
||||||
|
{
|
||||||
|
event_free(proxy->gcev);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < (sizeof(proxy->sev) / sizeof(proxy->sev[0])); i++)
|
||||||
|
{
|
||||||
|
if (proxy->sev[i])
|
||||||
|
{
|
||||||
|
event_free(proxy->sev[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (typeof(proxy->nr_work_threads) i = 0; i < proxy->nr_work_threads; i++)
|
||||||
|
{
|
||||||
|
proxy->work_threads[i].thread_id = i;
|
||||||
|
event_base_free(proxy->work_threads[i].evbase);
|
||||||
|
}
|
||||||
|
|
||||||
|
event_base_free(proxy->evbase);
|
||||||
|
|
||||||
|
free(proxy);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Run the event loop. Returns when the event loop is cancelled by a signal
|
||||||
|
* or on failure.
|
||||||
|
*/
|
||||||
|
void tfe_proxy_run(struct tfe_proxy * proxy)
|
||||||
|
{
|
||||||
|
unsigned int thread_id;
|
||||||
|
for (thread_id = 0; thread_id < proxy->nr_work_threads; thread_id++)
|
||||||
|
{
|
||||||
|
if (pthread_create(&(proxy->work_threads[thread_id].thr), NULL,
|
||||||
|
__tfe_thrmgr_thread_entry, &(proxy->work_threads[thread_id])))
|
||||||
|
{
|
||||||
|
MESA_handle_runtime_log(proxy->main_logger, RLOG_LV_FATAL, proxy->name, "pthread_create failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!proxy->work_threads[thread_id].running)
|
||||||
|
{
|
||||||
|
sched_yield();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event_base_dispatch(proxy->evbase);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Break the loop of the proxy, causing the tfe_proxy_run to return.
|
||||||
|
*/
|
||||||
|
void proxy_loopbreak(tfe_proxy * ctx)
|
||||||
|
{
|
||||||
|
event_base_loopbreak(ctx->evbase);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free the proxy data structures.
|
||||||
|
*/
|
||||||
|
void proxy_free(tfe_proxy * ctx)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
const char* main_profile="./conf/tfe_main.conf";
|
||||||
|
|
||||||
|
tfe_proxy *proxy=NULL;
|
||||||
|
void* wcfg_handle=NULL;
|
||||||
|
|
||||||
|
//TODO: Initiate Local Cert Cache, Decryption Mirror, Field Stat, Logger and etc.
|
||||||
|
//NOTICE: Maat, Cert Store,Tango Cache are initiated in bussiness plugin.
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
g_tfe_instance=ALLOC(struct tfe_instance,1);
|
||||||
|
proxy=tfe_proxy_new(g_tfe_cfg);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
tfe_proxy_run(proxy);
|
||||||
|
proxy_free(proxy);
|
||||||
|
}
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
|
|
||||||
struct sess_cache
|
|
||||||
{
|
|
||||||
};
|
|
||||||
struct sess_cache* session_cache_init()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void session_cache_set(struct sess_cache* cache, struct sockaddr *addr, socklen_t addrlen, const char* sni,SSL_SESSION* session)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
/*-
|
|
||||||
* Tango Frontend Engine (TFE) 3a
|
|
||||||
* Part of Tango Security Gateway
|
|
||||||
*
|
|
||||||
* Copyright (c) 2018-2023, MESA Lab, https://www.mesalab.cn
|
|
||||||
* All rights reserved.
|
|
||||||
*/
|
|
||||||
#include "proxy.h"
|
|
||||||
#include "tfe_util.h"
|
|
||||||
#include "MESA_handle_logger.h"
|
|
||||||
#include "MESA_prof_load.h"
|
|
||||||
#include "wired_cfg.h"
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
struct tfe_instance* g_tfe_instance=NULL;
|
|
||||||
struct tfe_config * g_tfe_cfg=NULL;
|
|
||||||
const char* module_name="TFE";
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
const char* main_profile="./conf/tfe_main.conf";
|
|
||||||
|
|
||||||
tfe_proxy *proxy=NULL;
|
|
||||||
void* wcfg_handle=NULL;
|
|
||||||
|
|
||||||
wcfg_handle=wired_cfg_create(module_name, main_profile);
|
|
||||||
wired_cfg_init(wcfg_handle);
|
|
||||||
wired_cfg_destroy(wcfg_handle);
|
|
||||||
g_tfe_cfg=ALLOC(struct tfe_config, 1);
|
|
||||||
MESA_load_profile_uint_def(main_profile, "SYSTEM", "thread_num",&(g_tfe_cfg->thread_num),1);
|
|
||||||
MESA_load_profile_uint_def(main_profile, "SYSTEM", "use_cert_store",&(g_tfe_cfg->use_cert_store),0);
|
|
||||||
//TODO: Initiate Local Cert Cache, Decryption Mirror, Field Stat, Logger and etc.
|
|
||||||
//NOTICE: Maat, Cert Store,Tango Cache are initiated in bussiness plugin.
|
|
||||||
g_tfe_instance=ALLOC(struct tfe_instance,1);
|
|
||||||
proxy=tfe_proxy_new(g_tfe_cfg);
|
|
||||||
|
|
||||||
//TODO: Drop privs, chroot
|
|
||||||
tfe_proxy_run(proxy);
|
|
||||||
proxy_free(proxy);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,407 +0,0 @@
|
|||||||
|
|
||||||
#include "proxy.h"
|
|
||||||
#include "opts.h"
|
|
||||||
#include "attrib.h"
|
|
||||||
#include "tfe_util.h"
|
|
||||||
#include "tfe_stream.h"
|
|
||||||
#include "tfe_stream_internal.h"
|
|
||||||
#include "MESA_handle_logger.h"
|
|
||||||
#include "io_module_kni.h"
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#include <event2/event.h>
|
|
||||||
#include <event2/listener.h>
|
|
||||||
#include <event2/bufferevent.h>
|
|
||||||
#include <event2/bufferevent_ssl.h>
|
|
||||||
#include <event2/buffer.h>
|
|
||||||
#include <event2/thread.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Proxy engine, built around libevent 2.x.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define TFE_BACKLOG_DEFAULT 20
|
|
||||||
const char* module_name_pxy="TFE_PXY";
|
|
||||||
extern struct tfe_instance* g_tfe_instance;
|
|
||||||
|
|
||||||
__thread int __currect_thread_id;
|
|
||||||
|
|
||||||
|
|
||||||
void free_thread_manager(struct tfe_thread_manager_ctx* ctx)
|
|
||||||
{
|
|
||||||
free(ctx->thr_ctx);
|
|
||||||
ctx->thr_ctx=NULL;
|
|
||||||
free(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __dummy_event_handler(
|
|
||||||
UNUSED evutil_socket_t fd, UNUSED short what,
|
|
||||||
UNUSED void *arg)
|
|
||||||
{
|
|
||||||
/* do nothing */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Thread entry point; runs the event loop of the event base.
|
|
||||||
* Does not exit until the libevent loop is broken explicitly.
|
|
||||||
*/
|
|
||||||
static void *__tfe_thrmgr_thread_entry(void *arg)
|
|
||||||
{
|
|
||||||
struct tfe_thread_ctx *ctx = (struct tfe_thread_ctx *) arg;
|
|
||||||
struct timeval timer_delay = {60, 0};
|
|
||||||
|
|
||||||
struct event *ev;
|
|
||||||
ev = event_new(ctx->evbase, -1, EV_PERSIST, __dummy_event_handler, NULL);
|
|
||||||
|
|
||||||
if (!ev) return NULL;
|
|
||||||
|
|
||||||
evtimer_add(ev, &timer_delay);
|
|
||||||
ctx->running = 1;
|
|
||||||
|
|
||||||
__currect_thread_id = ctx->thread_id;
|
|
||||||
MESA_handle_runtime_log(g_tfe_instance->main_logger, RLOG_LV_FATAL, module_name_pxy,"EventThread %d is running...", __currect_thread_id);
|
|
||||||
|
|
||||||
event_base_dispatch(ctx->evbase);
|
|
||||||
event_free(ev);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int tfe_thread_manager_run(struct tfe_thread_manager_ctx *ctx)
|
|
||||||
{
|
|
||||||
unsigned int thread_id;
|
|
||||||
|
|
||||||
for (thread_id = 0; thread_id < ctx->nr_thread; thread_id++)
|
|
||||||
{
|
|
||||||
if (pthread_create(&(ctx->thr_ctx[thread_id].thr), NULL,
|
|
||||||
__tfe_thrmgr_thread_entry, &(ctx->thr_ctx[thread_id])))
|
|
||||||
{
|
|
||||||
MESA_handle_runtime_log(g_tfe_instance->main_logger, RLOG_LV_FATAL, module_name_pxy, "pthread_create failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!ctx->thr_ctx[thread_id].running)
|
|
||||||
{
|
|
||||||
sched_yield();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MESA_handle_runtime_log(g_tfe_instance->main_logger, RLOG_LV_INFO, module_name_pxy,"Started %d connection handling threads\n", ctx->nr_thread);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int signals[] = {SIGTERM, SIGQUIT, SIGHUP, SIGINT, SIGPIPE, SIGUSR1};
|
|
||||||
|
|
||||||
struct tfe_proxy
|
|
||||||
{
|
|
||||||
char name[32];
|
|
||||||
struct event_base * evbase;
|
|
||||||
struct event * sev[sizeof(signals) / sizeof(int)];
|
|
||||||
struct event * gcev;
|
|
||||||
struct proxy_listener_ctx * lctx;
|
|
||||||
struct tfe_config * opts;
|
|
||||||
void* main_logger;
|
|
||||||
unsigned int thread_num;
|
|
||||||
struct tfe_thread_ctx* work_threads;
|
|
||||||
void* io_mod;
|
|
||||||
cert_mgr* cert_mgr;
|
|
||||||
struct sess_cache* dsess_cache;
|
|
||||||
struct sess_cache* ssess_cache;
|
|
||||||
int module_num;
|
|
||||||
struct tfe_plugin* modules;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Signal handler for SIGTERM, SIGQUIT, SIGINT, SIGHUP, SIGPIPE and SIGUSR1.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
proxy_signal_cb(evutil_socket_t fd, UNUSED short what, void * arg)
|
|
||||||
{
|
|
||||||
tfe_proxy * ctx = (tfe_proxy *) arg;
|
|
||||||
if (OPTS_DEBUG(ctx->opts))
|
|
||||||
{
|
|
||||||
log_dbg_printf("Received signal %i\n", fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (fd)
|
|
||||||
{
|
|
||||||
case SIGTERM:
|
|
||||||
case SIGQUIT:
|
|
||||||
case SIGINT:
|
|
||||||
case SIGHUP: proxy_loopbreak(ctx);
|
|
||||||
break;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
case SIGUSR1:
|
|
||||||
if (log_reopen() == -1) {
|
|
||||||
log_err_printf("Warning: Failed to reopen logs\n");
|
|
||||||
} else {
|
|
||||||
log_dbg_printf("Reopened log files\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
case SIGPIPE: log_err_printf("Warning: Received SIGPIPE; ignoring.\n");
|
|
||||||
break;
|
|
||||||
default: log_err_printf("Warning: Received unexpected signal %i\n", fd);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Garbage collection handler.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
proxy_gc_cb(UNUSED evutil_socket_t fd, UNUSED short what, void * arg)
|
|
||||||
{
|
|
||||||
tfe_proxy * ctx = (tfe_proxy *) arg;
|
|
||||||
|
|
||||||
if (OPTS_DEBUG(ctx->opts))
|
|
||||||
log_dbg_printf("Garbage collecting caches started.\n");
|
|
||||||
|
|
||||||
// cachemgr_gc();
|
|
||||||
|
|
||||||
if (OPTS_DEBUG(ctx->opts))
|
|
||||||
log_dbg_printf("Garbage collecting caches done.\n");
|
|
||||||
}
|
|
||||||
int select_work_thread(struct tfe_proxy *pxy)
|
|
||||||
{
|
|
||||||
|
|
||||||
int min_thread_id = 0;
|
|
||||||
size_t min_load = pxy->work_threads[min_thread_id]->load;
|
|
||||||
|
|
||||||
for (unsigned thread_id = 1; thread_id < pxy->thread_num; thread_id++)
|
|
||||||
{
|
|
||||||
if (min_load > pxy->work_threads[thread_id]->load)
|
|
||||||
{
|
|
||||||
min_load = pxy->work_threads[thread_id]->load;
|
|
||||||
min_thread_id = thread_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pxy->work_threads[min_thread_id]->load++;
|
|
||||||
return min_thread_id;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Callback for accept events on the socket listener bufferevent.
|
|
||||||
*/
|
|
||||||
static void io_mod_accept_cb( evutil_socket_t upstream_fd, evutil_socket_t downstream_fd, enum tfe_session_proto session_type,
|
|
||||||
struct sockaddr * peeraddr, int peeraddrlen, void * arg)
|
|
||||||
{
|
|
||||||
struct tfe_proxy* pxy=(struct tfe_proxy* )arg;
|
|
||||||
struct tfe_stream_private* stream=NULL;
|
|
||||||
int tid=-1;
|
|
||||||
tid=select_work_thread(pxy);
|
|
||||||
stream=tfe_stream_create(upstream_fd, downstream_fd, session_type,peeraddr, peeraddrlen, pxy->work_threads+tid);
|
|
||||||
tfe_stream_setup(stream);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set up the core event loop.
|
|
||||||
* Socket clisock is the privsep client socket used for binding to ports.
|
|
||||||
* Returns ctx on success, or NULL on error.
|
|
||||||
*/
|
|
||||||
struct tfe_proxy * tfe_proxy_new(tfe_config * opts)
|
|
||||||
{
|
|
||||||
struct tfe_proxy * proxy=NULL;
|
|
||||||
size_t i = 0;
|
|
||||||
int ret=0;
|
|
||||||
|
|
||||||
struct timeval gc_delay = {60, 0};
|
|
||||||
|
|
||||||
/* adds locking, only required if accessed from separate threads */
|
|
||||||
evthread_use_pthreads();
|
|
||||||
|
|
||||||
if (OPTS_DEBUG(opts))
|
|
||||||
{
|
|
||||||
event_enable_debug_mode();
|
|
||||||
}
|
|
||||||
|
|
||||||
proxy = ALLOC(struct tfe_proxy,1);
|
|
||||||
proxy->opts = opts;
|
|
||||||
proxy->evbase = event_base_new();
|
|
||||||
if (!proxy->evbase)
|
|
||||||
{
|
|
||||||
log_err_printf("Error getting event base\n");
|
|
||||||
goto error_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OPTS_DEBUG(opts))
|
|
||||||
{
|
|
||||||
proxy_debug_base(proxy->evbase);
|
|
||||||
}
|
|
||||||
switch(opts->input_io_module)
|
|
||||||
{
|
|
||||||
case IO_MOD_KNI:
|
|
||||||
strcpy(proxy->name,"KNI_PXY");
|
|
||||||
proxy->io_mod=io_kni_init(opts->kni_path,proxy->evbase);
|
|
||||||
assert(ret>=0);
|
|
||||||
break;
|
|
||||||
case IO_MOD_TPROXY:
|
|
||||||
default:
|
|
||||||
assert(0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
proxy->thread_num=opts->thread_num;
|
|
||||||
proxy->cert_mgr=cert_manager_init();
|
|
||||||
proxy->dsess_cache=session_cache_init();
|
|
||||||
proxy->ssess_cache=session_cache_init();
|
|
||||||
|
|
||||||
proxy->module_num=2;
|
|
||||||
proxy->modules=ALLOC(struct tfe_plugin,proxy->module_num);
|
|
||||||
proxy->modules[0].proto=APP_PROTO_HTTP1;
|
|
||||||
//todo: setup each protocol module.
|
|
||||||
//proxy->modules[0].on_read=xxx;
|
|
||||||
proxy->modules[1].proto=APP_PROTO_HTTP2;
|
|
||||||
|
|
||||||
proxy->work_threads=ALLOC(struct tfe_thread_ctx, proxy->thread_num);
|
|
||||||
for(i=0;i<proxy->thread_num;i++)
|
|
||||||
{
|
|
||||||
proxy->work_threads[i].thread_id=i;
|
|
||||||
proxy->work_threads[i].evbase = event_base_new();
|
|
||||||
proxy->work_threads[i].opts=opts;
|
|
||||||
proxy->work_threads[i].cert_mgr=proxy->cert_mgr;//reference
|
|
||||||
proxy->work_threads[i].dsess_cache=proxy->dsess_cache;
|
|
||||||
proxy->work_threads[i].ssess_cache=proxy->ssess_cache;
|
|
||||||
proxy->work_threads[i].module_num=proxy->module_num;
|
|
||||||
proxy->work_threads[i].modules=proxy->modules
|
|
||||||
}
|
|
||||||
//Todo: Not handle signal if have mutliple proxy instance.
|
|
||||||
for (i = 0; i < (sizeof(signals) / sizeof(int)); i++)
|
|
||||||
{
|
|
||||||
proxy->sev[i] = evsignal_new(proxy->evbase, signals[i], proxy_signal_cb, proxy);
|
|
||||||
if (!proxy->sev[i])
|
|
||||||
goto error_out;
|
|
||||||
evsignal_add(proxy->sev[i], NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
proxy->gcev = event_new(proxy->evbase, -1, EV_PERSIST, proxy_gc_cb, proxy);
|
|
||||||
if (!proxy->gcev)
|
|
||||||
goto error_out;
|
|
||||||
|
|
||||||
evtimer_add(proxy->gcev, &gc_delay);
|
|
||||||
return proxy;
|
|
||||||
error_out:
|
|
||||||
if (proxy->gcev)
|
|
||||||
{
|
|
||||||
event_free(proxy->gcev);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < (sizeof(proxy->sev) / sizeof(proxy->sev[0])); i++)
|
|
||||||
{
|
|
||||||
if (proxy->sev[i])
|
|
||||||
{
|
|
||||||
event_free(proxy->sev[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (proxy->lctx)
|
|
||||||
{
|
|
||||||
proxy_listener_ctx_free(proxy->lctx);
|
|
||||||
}
|
|
||||||
for(i=0;i<proxy->thread_num;i++)
|
|
||||||
{
|
|
||||||
proxy->work_threads[i].thread_id=i;
|
|
||||||
event_base_free(proxy->work_threads[i].evbase);
|
|
||||||
}
|
|
||||||
|
|
||||||
event_base_free(proxy->evbase);
|
|
||||||
|
|
||||||
free(proxy);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Run the event loop. Returns when the event loop is cancelled by a signal
|
|
||||||
* or on failure.
|
|
||||||
*/
|
|
||||||
void tfe_proxy_run(struct tfe_proxy * proxy)
|
|
||||||
{
|
|
||||||
if (proxy->opts->detach)
|
|
||||||
{
|
|
||||||
event_reinit(proxy->evbase);
|
|
||||||
}
|
|
||||||
#ifndef PURIFY
|
|
||||||
if (OPTS_DEBUG(proxy->opts))
|
|
||||||
{
|
|
||||||
event_base_dump_events(proxy->evbase, stderr);
|
|
||||||
}
|
|
||||||
#endif /* PURIFY */
|
|
||||||
unsigned int thread_id;
|
|
||||||
|
|
||||||
for (thread_id = 0; thread_id < proxy->thread_num; thread_id++)
|
|
||||||
{
|
|
||||||
if (pthread_create(&(proxy->work_threads[thread_id].thr), NULL,
|
|
||||||
__tfe_thrmgr_thread_entry, &(proxy->work_threads[thread_id])))
|
|
||||||
{
|
|
||||||
MESA_handle_runtime_log(proxy->main_logger, RLOG_LV_FATAL, proxy->name, "pthread_create failed.");
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!proxy->work_threads[thread_id].running)
|
|
||||||
{
|
|
||||||
sched_yield();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MESA_handle_runtime_log(proxy->main_logger, RLOG_LV_INFO, proxy->name,"Started %d connection handling threads\n", proxy->nr_thread);
|
|
||||||
if (OPTS_DEBUG(proxy->opts))
|
|
||||||
{
|
|
||||||
log_dbg_printf("Starting main event loop.\n");
|
|
||||||
}
|
|
||||||
event_base_dispatch(proxy->evbase);
|
|
||||||
if (OPTS_DEBUG(proxy->opts))
|
|
||||||
{
|
|
||||||
log_dbg_printf("Main event loop stopped.\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Break the loop of the proxy, causing the tfe_proxy_run to return.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
proxy_loopbreak(tfe_proxy * ctx)
|
|
||||||
{
|
|
||||||
event_base_loopbreak(ctx->evbase);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Free the proxy data structures.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
proxy_free(tfe_proxy * ctx)
|
|
||||||
{
|
|
||||||
if (ctx->gcev)
|
|
||||||
{
|
|
||||||
event_free(ctx->gcev);
|
|
||||||
}
|
|
||||||
if (ctx->lctx)
|
|
||||||
{
|
|
||||||
proxy_listener_ctx_free(ctx->lctx);
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < (sizeof(ctx->sev) / sizeof(ctx->sev[0])); i++)
|
|
||||||
{
|
|
||||||
if (ctx->sev[i])
|
|
||||||
{
|
|
||||||
event_free(ctx->sev[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ctx->thrmgr)
|
|
||||||
{
|
|
||||||
free_thread_manager(ctx->thrmgr);
|
|
||||||
}
|
|
||||||
if (ctx->evbase)
|
|
||||||
{
|
|
||||||
event_base_free(ctx->evbase);
|
|
||||||
}
|
|
||||||
free(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* vim: set noet ft=c: */
|
|
||||||
@@ -1,15 +1,10 @@
|
|||||||
|
|
||||||
#include "tfe_stream.h"
|
|
||||||
#include "tfe_util.h"
|
|
||||||
#include "opts.h"
|
|
||||||
#include "attrib.h"
|
|
||||||
|
|
||||||
|
|
||||||
#include <netinet/in.h>
|
#include <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,6 +20,12 @@
|
|||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
#include <openssl/x509v3.h>
|
#include <openssl/x509v3.h>
|
||||||
|
|
||||||
|
#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)
|
#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
|
||||||
@@ -44,13 +45,33 @@
|
|||||||
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)
|
||||||
|
{
|
||||||
|
struct tfe_thread_ctx * thread = stream->thrmgr_ref;
|
||||||
|
thread->load--;
|
||||||
|
|
||||||
|
switch (stream->session_type)
|
||||||
|
{
|
||||||
|
case SESSION_PROTO_SSL:
|
||||||
|
#if 0
|
||||||
|
ssl_upstream_free(stream->ssl_upstream);
|
||||||
|
ssl_downstream_free(stream->ssl_downstream);
|
||||||
|
#endif
|
||||||
|
thread->stat.value[SSL_NUM]--;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(stream);
|
||||||
|
thread->stat.value[STREAM_NUM]--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
void tfe_stream_detach(const struct tfe_stream * stream)
|
void tfe_stream_detach(const struct tfe_stream * stream)
|
||||||
{
|
{
|
||||||
@@ -59,6 +80,7 @@ void tfe_stream_detach(const struct tfe_stream* stream)
|
|||||||
_stream->plug_ctx[plug_id].state = PLUG_STATE_DETACHED;
|
_stream->plug_ctx[plug_id].state = PLUG_STATE_DETACHED;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tfe_stream_preempt(const struct tfe_stream * stream)
|
int tfe_stream_preempt(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;
|
||||||
@@ -75,18 +97,20 @@ int tfe_stream_preempt(const struct tfe_stream* stream)
|
|||||||
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;
|
||||||
@@ -217,39 +241,44 @@ static void tfe_stream_readcb(struct bufferevent * bev, void * arg)
|
|||||||
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;
|
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;
|
int plug_num = _stream->thrmgr_ref->nr_modules;
|
||||||
|
|
||||||
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;
|
size_t contigous_len = evbuffer_get_length(inbuf), drain_size = 0;
|
||||||
const char* contiguous_data=evbuffer_pullup(inbuf,contigous_len);
|
const unsigned char * contiguous_data = (const unsigned char *)evbuffer_pullup(inbuf, contigous_len);
|
||||||
|
|
||||||
_stream->defere_bytes = 0;
|
_stream->defere_bytes = 0;
|
||||||
_stream->drop_bytes = 0;
|
_stream->drop_bytes = 0;
|
||||||
_stream->forward_bytes = 0;
|
_stream->forward_bytes = 0;
|
||||||
|
|
||||||
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;
|
||||||
|
|
||||||
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,
|
||||||
|
dir, contiguous_data, contigous_len, &(plug_ctx->pme));
|
||||||
_stream->is_plugin_opened = 1;
|
_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)
|
||||||
@@ -281,6 +310,7 @@ 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);
|
||||||
@@ -333,7 +363,7 @@ static void tfe_stream_eventcb(struct bufferevent * bev, short events, void * ar
|
|||||||
|
|
||||||
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)
|
||||||
@@ -355,44 +385,27 @@ static void tfe_stream_eventcb(struct bufferevent * bev, short events, void * ar
|
|||||||
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);
|
||||||
@@ -400,14 +413,13 @@ void ssl_get_cert_on_succ(void * result, void * user)
|
|||||||
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,47 +432,55 @@ void ssl_conn_origin_on_succ(void * result, void * user)
|
|||||||
_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);
|
||||||
|
|
||||||
|
#if 0
|
||||||
cert_mgr_async_get(_stream->ssl_downstream->future_get_cert,
|
cert_mgr_async_get(_stream->ssl_downstream->future_get_cert,
|
||||||
_stream->thrmgr_ref->cert_mgr,
|
_stream->thrmgr_ref->cert_mgr,
|
||||||
_stream->ssl_downstream->sni,
|
_stream->ssl_downstream->sni,
|
||||||
_stream->ssl_downstream->keyring_id,
|
_stream->ssl_downstream->keyring_id,
|
||||||
_stream->ssl_upstream->orig_cert);
|
_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)
|
|
||||||
{
|
|
||||||
//todo
|
|
||||||
assert(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ssl_conn_origin_on_fail(enum e_future_error err, const char * what, void * user)
|
||||||
|
{
|
||||||
|
//TODO:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
void peek_sni_on_succ(void * result, void * user)
|
void peek_sni_on_succ(void * result, void * user)
|
||||||
{
|
{
|
||||||
struct tfe_stream_private * _stream = (struct tfe_stream_private *) user;
|
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 = ALLOC(struct ssl_upstream, 1);
|
||||||
_stream->ssl_upstream->conn_ssl_srv = future_create(ssl_conn_origin_on_succ, ssl_conn_origin_on_fail, _stream);
|
_stream->ssl_upstream->conn_ssl_srv = future_create(ssl_conn_origin_on_succ, ssl_conn_origin_on_fail, _stream);
|
||||||
ssl_async_connect_origin(_stream->ssl_upstream->conn_ssl_srv, _stream->fd_upstream, _stream->ssl_downstream->sni, _stream->thrmgr_ref->evbase, _stream->thrmgr_ref->opts);
|
ssl_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.
|
||||||
@@ -482,19 +502,20 @@ void tfe_stream_setup(struct tfe_stream_private* _stream)
|
|||||||
// 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;
|
||||||
@@ -506,8 +527,6 @@ struct tfe_stream_private* tfe_stream_create(evutil_socket_t fd_downstream, evut
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,98 +0,0 @@
|
|||||||
#include "tfe_stream.h"
|
|
||||||
#include "ssl_stream.h"
|
|
||||||
#include "tfe_stat.h"
|
|
||||||
struct tfe_thread_ctx
|
|
||||||
{
|
|
||||||
pthread_t thr;
|
|
||||||
unsigned int thread_id;
|
|
||||||
size_t load;
|
|
||||||
struct event_base *evbase;
|
|
||||||
unsigned char running;
|
|
||||||
struct tfe_stats stat;
|
|
||||||
tfe_config* opts;
|
|
||||||
cert_mgr cert_mgr;
|
|
||||||
struct sess_cache* dsess_cache;
|
|
||||||
struct sess_cache* ssess_cache;
|
|
||||||
const int module_num;
|
|
||||||
const struct tfe_plugin* modules;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//Downstream: comunication form client to proxy
|
|
||||||
//Upstream: communication form proxy to server
|
|
||||||
struct ssl_downstream
|
|
||||||
{
|
|
||||||
/* server name indicated by client in SNI TLS extension */
|
|
||||||
char *sni;
|
|
||||||
SSL *ssl;
|
|
||||||
X509* fake_cert_ref;//?
|
|
||||||
int keyring_id;
|
|
||||||
struct future* future_sni_peek;
|
|
||||||
struct future* future_get_cert;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ssl_upstream
|
|
||||||
{
|
|
||||||
X509 *orig_cert;
|
|
||||||
SSL *ssl;
|
|
||||||
struct future* conn_ssl_srv;
|
|
||||||
};
|
|
||||||
enum tfe_plugin_state
|
|
||||||
{
|
|
||||||
PLUG_STATE_READONLY,
|
|
||||||
PLUG_STATE_PREEPTION,
|
|
||||||
PLUG_STATE_DETACHED
|
|
||||||
};
|
|
||||||
struct plugin_ctx
|
|
||||||
{
|
|
||||||
|
|
||||||
enum tfe_plugin_state state;
|
|
||||||
void *pme;
|
|
||||||
};
|
|
||||||
struct tfe_stream_write_ctx
|
|
||||||
{
|
|
||||||
struct tfe_stream_private* _stream;
|
|
||||||
enum tfe_conn_dir dir;
|
|
||||||
};
|
|
||||||
struct tfe_conn_private
|
|
||||||
{
|
|
||||||
evutil_socket_t fd;
|
|
||||||
struct bufferevent *bev;
|
|
||||||
uint8_t on_writing;
|
|
||||||
uint8_t closed;
|
|
||||||
uint8_t need_shutdown;
|
|
||||||
struct tfe_stream_write_ctx w_ctx;
|
|
||||||
};
|
|
||||||
struct tfe_stream_private
|
|
||||||
{
|
|
||||||
struct tfe_stream head;
|
|
||||||
enum tfe_session_proto session_type;
|
|
||||||
struct tfe_conn_private conn_upstream;
|
|
||||||
struct tfe_conn_private conn_downstream;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct ssl_downstream* ssl_downstream;
|
|
||||||
void* raw_downstream;
|
|
||||||
};
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct ssl_upstream* ssl_upstream;
|
|
||||||
void* raw_upstream;
|
|
||||||
};
|
|
||||||
uint8_t is_plugin_opened;
|
|
||||||
int calling_idx;
|
|
||||||
size_t forward_bytes;
|
|
||||||
size_t defere_bytes;
|
|
||||||
size_t drop_bytes;
|
|
||||||
enum tfe_app_proto app_proto;
|
|
||||||
int plugin_num;
|
|
||||||
struct plugin_ctx* plug_ctx;
|
|
||||||
unsigned char passthrough; /* 1 if SSL passthrough is active */
|
|
||||||
|
|
||||||
evutil_socket_t fd_downstream, fd_upstream;
|
|
||||||
|
|
||||||
struct tfe_thread_ctx* thrmgr_ref;
|
|
||||||
future* async_future;
|
|
||||||
};
|
|
||||||
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
#include "tfe_util.h"
|
|
||||||
int addr_sock2layer(struct sockaddr * sock_addr, int sockaddrlen, struct layer_addr* layer_addr)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int addr_layer2sock(struct layer_addr* layer_addr,struct sockaddr * sock_addr)
|
|
||||||
{
|
|
||||||
int sockaddrlen=-1;
|
|
||||||
return sockaddrlen;
|
|
||||||
}
|
|
||||||
//functioned as strdup, for dictator compatible.
|
|
||||||
char* tfe_strdup(const char* s)
|
|
||||||
{
|
|
||||||
char*d=NULL;
|
|
||||||
if(s==NULL)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
d=(char*)malloc(strlen(s)+1);
|
|
||||||
memcpy(d,s,strlen(s)+1);
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user