编写连接业务层的代码。

This commit is contained in:
zhengchao
2019-05-18 18:27:13 +08:00
parent 3f305a9e88
commit 61bc647d1f
8 changed files with 249 additions and 63 deletions

View File

@@ -91,6 +91,7 @@ struct tfe_proxy
struct tfe_plugin * modules;
struct ssl_mgr * ssl_mgr_handler;
struct ssl_policy_enforcer* ssl_ply_enforcer;
struct key_keeper * key_keeper_handler;
struct kni_acceptor * kni_acceptor_handler;

View File

@@ -1,6 +1,9 @@
#pragma once
#include <ssl_stream.h>
#include <MESA/Maat_rule.h>
struct ssl_policy_enforcer;
struct ssl_policy_enforcer* ssl_policy_enforcer_create(void);
void ssl_policy_enforcer_init(struct ssl_policy_enforcer* enforcer, Maat_feather_t maat, void* logger);
enum ssl_stream_action ssl_policy_enforce(struct ssl_stream *upstream, void* u_para);

View File

@@ -122,6 +122,7 @@ void ssl_openssl_version(void);
int ssl_init(void);
int ssl_reinit(void);
void ssl_fini(void);
int sslver_str2num(const char * version_str);
char * ssl_sha1_to_str(unsigned char *, int);

View File

@@ -38,13 +38,14 @@
#include <MESA/MESA_prof_load.h>
#include <MESA/field_stat2.h>
#include <tfe_plugin.h>
#include <ssl_policy.h>
static int signals[] = {SIGHUP, SIGPIPE, SIGUSR1};
/* Global Resource */
void * g_default_logger = NULL;
struct tfe_proxy * g_default_proxy = NULL;
extern Maat_feather_t g_business_maat;
/* Per thread resource */
thread_local unsigned int __currect_thread_id = 0;
thread_local void * __currect_default_logger = NULL;
@@ -335,8 +336,6 @@ int tfe_stat_init(struct tfe_proxy * proxy, const char * profile)
proxy->fs_handle = fs_handle;
return 0;
}
extern struct ssl_policy_enforcer* ssl_policy_enforcer_create(void);
extern enum ssl_stream_action ssl_policy_enforce(struct ssl_stream *upstream, void* u_para);
int main(int argc, char * argv[])
{
@@ -386,8 +385,9 @@ int main(int argc, char * argv[])
/* SSL INIT */
g_default_proxy->ssl_ply_enforcer = ssl_policy_enforcer_create();
g_default_proxy->ssl_mgr_handler = ssl_manager_init(main_profile, "ssl", g_default_proxy->evbase, g_default_logger,
ssl_policy_enforce, ssl_policy_enforcer_create());
ssl_policy_enforce, g_default_proxy->ssl_ply_enforcer);
CHECK_OR_EXIT(g_default_proxy->ssl_mgr_handler, "Failed at init SSL manager. Exit.");
for (size_t i = 0; i < (sizeof(signals) / sizeof(int)); i++)
@@ -417,7 +417,8 @@ int main(int argc, char * argv[])
CHECK_OR_EXIT(ret >= 0, "Plugin %s init failed. Exit. ", plugin_iter->symbol);
TFE_LOG_INFO(g_default_logger, "Plugin %s initialized. ", plugin_iter->symbol);
}
//ugly here. g_business_maat is available after plugin initiate.
ssl_policy_enforcer_init(g_default_proxy->ssl_ply_enforcer, g_business_maat, g_default_logger);
ret = tfe_proxy_work_thread_run(g_default_proxy);
CHECK_OR_EXIT(ret == 0, "Failed at creating thread. Exit.");

View File

@@ -1,13 +1,163 @@
#include <ssl_stream.h>
#include <ssl_utils.h>
#include <tfe_utils.h>
#include <openssl/ssl.h>
#include <MESA/Maat_rule.h>
#include <cjson/cJSON.h>
struct ssl_policy_enforcer
{
Maat_feather_t maat;
int compile_table_id;
void* logger;
};
struct intercept_param
{
int policy_id;
int ref_cnt;
int keyring;
int bypass_ev_cert;
int bypass_ct_cert;
int bypass_mutual_auth;
int bypass_pinning;
int no_verify_cn;
int no_verify_issuer;
int no_verify_self_signed;
int no_verify_expry_date;
int block_fake_cert;
int ssl_min_version;
int ssl_max_version;
int mirror_client;
int decrypt_mirror_enabled;
int mirror_profile_id;
};
struct ssl_policy_enforcer* ssl_policy_enforcer_create(void)
{
return NULL;
struct ssl_policy_enforcer* enforcer=ALLOC(struct ssl_policy_enforcer, 1);
return enforcer;
}
void intercept_policy_dup_cb(int table_id, MAAT_PLUGIN_EX_DATA* to, MAAT_PLUGIN_EX_DATA* from, long argl, void* argp)
{
struct intercept_param* param= (struct intercept_param*) *from;
param->ref_cnt++;
*to = param;
return;
}
void intercept_policy_new_cb(int table_id, const char* key, const char* table_line, MAAT_PLUGIN_EX_DATA* ad, long argl, void* argp)
{
int ret=0;
size_t intercept_user_region_offset=0, len=0;
char* json_str=NULL;
cJSON *json=NULL, *exclusions=NULL, *cert_verify=NULL, *approach=NULL, *ssl_ver=NULL, *item=NULL;
struct intercept_param* param=NULL;
struct ssl_policy_enforcer* enforcer=(struct ssl_policy_enforcer*)argp;
ret=Maat_helper_read_column(table_line, 7, &intercept_user_region_offset, &len);
if(ret<0)
{
TFE_LOG_ERROR(enforcer->logger, "Get intercept user region: %s", table_line);
return;
}
json_str=ALLOC(char, len+1);
memcpy(json_str, table_line+intercept_user_region_offset, len);
json=cJSON_Parse(json_str);
if(json==NULL)
{
TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter: id = %s", key);
goto error_out;
}
param=ALLOC(struct intercept_param, 1);
param->policy_id=atoi(key);
param->ref_cnt=1;
param->bypass_mutual_auth=1;
param->bypass_pinning=1;
item=cJSON_GetObjectItem(json, "keyring");
if(item && item->type==cJSON_Number) param->keyring=item->valueint;
exclusions=cJSON_GetObjectItem(json, "exclusions");
if(exclusions)
{
item=cJSON_GetObjectItem(exclusions, "ev_cert");
if(item && item->type==cJSON_Number) param->bypass_ev_cert=item->valueint;
item=cJSON_GetObjectItem(exclusions, "cert_transparency");
if(item && item->type==cJSON_Number) param->bypass_ct_cert=item->valueint;
item=cJSON_GetObjectItem(exclusions, "client_cert_req");
if(item && item->type==cJSON_Number) param->bypass_mutual_auth=item->valueint;
item=cJSON_GetObjectItem(exclusions, "pinning");
if(item && item->type==cJSON_Number) param->bypass_pinning=item->valueint;
}
cert_verify=cJSON_GetObjectItem(json, "cert_verify");
if(cert_verify)
{
approach=cJSON_GetObjectItem(cert_verify, "approach");
if(approach)
{
item=cJSON_GetObjectItem(approach, "cn");
if(item && item->type==cJSON_Number && item->valueint==0) param->no_verify_cn=1;
item=cJSON_GetObjectItem(approach, "issuer");
if(item && item->type==cJSON_Number && item->valueint==0) param->no_verify_issuer=1;
item=cJSON_GetObjectItem(approach, "self-signed");
if(item && item->type==cJSON_Number && item->valueint==0) param->no_verify_self_signed=1;
item=cJSON_GetObjectItem(approach, "expiration");
if(item && item->type==cJSON_Number && item->valueint==0) param->no_verify_expry_date=1;
}
item=cJSON_GetObjectItem(exclusions, "fail_method");
if(item && item->type==cJSON_String)
{
if(0==strcasecmp(item->string, "Fail-Close"))
{
param->block_fake_cert=1;
}
}
}
ssl_ver=cJSON_GetObjectItem(json, "ssl_ver");
if(ssl_ver)
{
item=cJSON_GetObjectItem(ssl_ver, "mirror_client");
if(item && item->type==cJSON_String) param->mirror_client=item->valueint;
item=cJSON_GetObjectItem(ssl_ver, "min");
if(item && item->type==cJSON_String) param->ssl_min_version=sslver_str2num(item->string);
item=cJSON_GetObjectItem(ssl_ver, "max");
if(item && item->type==cJSON_String) param->ssl_max_version=sslver_str2num(item->string);
}
*ad=param;
TFE_LOG_INFO(enforcer->logger, "Add intercept policy: %d", param->policy_id);
error_out:
cJSON_Delete(json);
free(json_str);
return;
}
void intercept_policy_free_cb(int table_id, MAAT_PLUGIN_EX_DATA* ad, long argl, void* argp)
{
struct ssl_policy_enforcer* enforcer=(struct ssl_policy_enforcer*)argp;
struct intercept_param* param= (struct intercept_param*) *ad;
param->ref_cnt--;
if(param->ref_cnt==0)
{
free(param);
TFE_LOG_INFO(enforcer->logger, "Del intercept policy %d", param->policy_id);
free(*ad);
*ad=NULL;
}
}
void ssl_policy_enforcer_init(struct ssl_policy_enforcer* enforcer, Maat_feather_t maat, void* logger)
{
enforcer->maat=maat;
enforcer->logger=logger;
enforcer->compile_table_id=Maat_table_register(enforcer->maat, "PXY_INTERCEPT_COMPILE");
int ret=Maat_plugin_EX_register(enforcer->maat,
enforcer->compile_table_id,
intercept_policy_new_cb,
intercept_policy_free_cb,
intercept_policy_dup_cb,
NULL,
0,
enforcer);
assert(ret==1);
return;
}
enum ssl_stream_action ssl_policy_enforce(struct ssl_stream *upstream, void* u_para)
{
@@ -20,6 +170,10 @@ enum ssl_stream_action ssl_policy_enforce(struct ssl_stream *upstream, void* u_p
assert(ret==1);
ret=ssl_stream_get_integer_opt(upstream, SSL_STREAM_OPT_IS_MUTUAL_AUTH, &is_mauth);
ret=ssl_stream_set_integer_opt(upstream, SSL_STREAM_OPT_NO_VERIFY_EXPIRY_DATE, 1);
ret=ssl_stream_set_integer_opt(upstream, SSL_STREAM_OPT_PROTOCOL_MIN_VERSION, SSL3_VERSION);
ret=ssl_stream_set_integer_opt(upstream, SSL_STREAM_OPT_PROTOCOL_MIN_VERSION, TLS1_3_VERSION);
assert(ret=1);
if(pinning_staus>0||is_ev||is_mauth)
{
return SSL_ACTION_PASSTHROUGH;

View File

@@ -200,7 +200,7 @@ struct ssl_stream
struct ssl_upstream_parts up_parts;
struct ssl_downstream_parts down_parts;
};
int ssl_min_ver, ssl_max_ver;
int ssl_min_version, ssl_max_version, negotiated_version;
const unsigned char* alpn_selected; //reference to SSL_ALPN_HTTP_2/SSL_ALPN_HTTP_1_1
struct ssl_stream* peer;
struct __ssl_stream_debug _do_not_use;
@@ -393,7 +393,7 @@ void ssl_stat_init(struct ssl_mgr * mgr)
return;
}
static SSL * downstream_ssl_create(struct ssl_mgr * mgr, struct keyring * crt, const unsigned char* selected_alpn);
static SSL * downstream_ssl_create(struct ssl_mgr * mgr, struct keyring * crt, int negotiated_version, const unsigned char* selected_alpn);
static SSL * upstream_ssl_create(struct ssl_mgr * mgr, struct ssl_stream* s_stream, evutil_socket_t fd);
static void sslctx_set_opts(SSL_CTX * sslctx, struct ssl_mgr * mgr);
@@ -407,26 +407,34 @@ struct ssl_chello * ssl_peek_result_release_chello(future_result_t * result)
}
struct ssl_stream * ssl_stream_new(struct ssl_mgr * mgr, evutil_socket_t fd, enum tfe_conn_dir dir,
struct ssl_chello * client_hello, struct keyring * kyr, const unsigned char* selected_alpn)
struct ssl_chello * client_hello, struct keyring * kyr, struct ssl_stream * peer)
{
UNUSED int ret = 0;
const unsigned char* selected_alpn=peer->alpn_selected;
struct ssl_stream * s_stream = ALLOC(struct ssl_stream, 1);
s_stream->dir = dir;
s_stream->mgr = mgr;
s_stream->_do_not_use.fd = fd;
assert(ret == 0);
s_stream->ssl_max_version=mgr->ssl_max_version;
s_stream->ssl_min_version=mgr->ssl_min_version;
s_stream->peer=peer;
switch (dir)
{
case CONN_DIR_DOWNSTREAM:
assert(peer!=NULL);
ATOMIC_INC(&(s_stream->mgr->stat_val[SSL_DOWN_NEW]));
s_stream->down_parts.keyring = kyr;
s_stream->ssl = downstream_ssl_create(mgr, kyr, selected_alpn);
s_stream->ssl = downstream_ssl_create(mgr, kyr, peer->negotiated_version, selected_alpn);
break;
case CONN_DIR_UPSTREAM:
ATOMIC_INC(&(s_stream->mgr->stat_val[SSL_UP_NEW]));
s_stream->up_parts.verify_param.no_verify_expiry_date=1;
s_stream->up_parts.verify_param.no_verify_cn=1;
s_stream->up_parts.client_hello = client_hello;
s_stream->ssl_min_version=client_hello->min_version.ossl_format;
s_stream->ssl_max_version=client_hello->max_version.ossl_format;
s_stream->ssl = upstream_ssl_create(mgr, s_stream, fd);
break;
default: assert(0);
@@ -467,45 +475,7 @@ static void ssl_stream_free(struct ssl_stream * s_stream)
return;
}
static int sslver_str2num(const char * version_str)
{
int sslversion = -1;
assert(OPENSSL_VERSION_NUMBER >= 0x10100000L);
/*
* Support for SSLv2 and the corresponding SSLv2_method(),
* SSLv2_server_method() and SSLv2_client_method() functions were
* removed in OpenSSL 1.1.0.
*/
if (!strcmp(version_str, "ssl3"))
{
sslversion = SSL3_VERSION;
}
else if (!strcmp(version_str, "tls10") || !strcmp(version_str, "tls1"))
{
sslversion = TLS1_VERSION;
}
else if (!strcmp(version_str, "tls11"))
{
sslversion = TLS1_1_VERSION;
}
else if (!strcmp(version_str, "tls12"))
{
sslversion = TLS1_2_VERSION;
}
else if (!strcmp(version_str, "tls13"))
{
sslversion = TLS1_3_VERSION;
}
else
{
sslversion = -1;
}
return sslversion;
}
static void log_ssl_master_key(SSL* ssl, int fd, tfe_conn_dir dir, FILE* fp)
{
char* key_str=NULL;
@@ -829,8 +799,8 @@ static SSL * upstream_ssl_create(struct ssl_mgr * mgr, struct ssl_stream* s_stre
ret=SSL_CTX_set_cipher_list(sslctx, mgr->default_ciphers);
}
if (SSL_CTX_set_min_proto_version(sslctx, mgr->ssl_min_version) == 0 ||
SSL_CTX_set_max_proto_version(sslctx, mgr->ssl_max_version) == 0)
if (SSL_CTX_set_min_proto_version(sslctx, s_stream->ssl_min_version) == 0 ||
SSL_CTX_set_max_proto_version(sslctx, s_stream->ssl_max_version) == 0)
{
SSL_CTX_free(sslctx);
return NULL;
@@ -868,7 +838,7 @@ static SSL * upstream_ssl_create(struct ssl_mgr * mgr, struct ssl_stream* s_stre
{
/* session resuming based on remote endpoint address and port */
sess = up_session_get(mgr->up_sess_cache, (struct sockaddr *) &addr, addrlen, chello->sni,
SSL_get_min_proto_version(ssl), SSL_get_max_proto_version(ssl));
s_stream->ssl_min_version, s_stream->ssl_max_version);
if (sess)
{
SSL_set_session(ssl, sess); /* increments sess refcount */
@@ -1171,6 +1141,7 @@ static void ssl_server_connected_eventcb(struct bufferevent * bev, short events,
s_stream->alpn_selected=NULL;
}
}
s_stream->negotiated_version=SSL_version(s_stream->ssl);
promise_success(p, ctx);
}
wrap_ssl_connect_server_ctx_free(ctx);
@@ -1479,7 +1450,7 @@ static int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
* Create and set up a new SSL_CTX instance for terminating SSL.
* Set up all the necessary callbacks, the keyring, the keyring chain and key.
*/
static SSL * downstream_ssl_create(struct ssl_mgr * mgr, struct keyring * crt, const unsigned char* selected_alpn)
static SSL * downstream_ssl_create(struct ssl_mgr * mgr, struct keyring * crt, int negotiated_version, const unsigned char* selected_alpn)
{
SSL_CTX * sslctx = SSL_CTX_new(mgr->sslmethod());
if (!sslctx) return NULL;
@@ -1490,7 +1461,16 @@ static SSL * downstream_ssl_create(struct ssl_mgr * mgr, struct keyring * crt, c
SSL_CTX_set_cipher_list(sslctx, mgr->default_ciphers);
//TFE's OPENSSL_VERSION_NUMBER >= 0x10100000L
if (mgr->ssl_min_version)
if(negotiated_version)
{
if (SSL_CTX_set_min_proto_version(sslctx, negotiated_version) == 0 ||
SSL_CTX_set_max_proto_version(sslctx, negotiated_version) == 0)
{
SSL_CTX_free(sslctx);
return NULL;
}
}
else if(mgr->ssl_min_version)
{
if (SSL_CTX_set_min_proto_version(sslctx, mgr->ssl_min_version) == 0 ||
SSL_CTX_set_max_proto_version(sslctx, mgr->ssl_max_version) == 0)
@@ -1664,6 +1644,7 @@ static void ssl_client_connected_eventcb(struct bufferevent * bev, short events,
{
log_ssl_master_key(ctx->downstream->ssl, ctx->fd_downstream, CONN_DIR_DOWNSTREAM, mgr->fp_master_key);
}
ctx->downstream->negotiated_version=SSL_version(ctx->downstream->ssl);
promise_success(p, ctx);
}
ssl_connect_client_ctx_free(ctx);
@@ -1682,10 +1663,8 @@ void ask_keyring_on_succ(void * result, void * user)
kyr = key_keeper_release_keyring(result); //kyr will be freed at ssl downstream closing.
clock_gettime(CLOCK_MONOTONIC, &(ctx->start));
ctx->downstream = ssl_stream_new(mgr, ctx->fd_downstream, CONN_DIR_DOWNSTREAM,
ctx->origin_ssl->up_parts.client_hello, kyr,
ctx->origin_ssl?ctx->origin_ssl->alpn_selected:NULL);
ctx->downstream->peer=ctx->origin_ssl;
ctx->downstream = ssl_stream_new(mgr, ctx->fd_downstream, CONN_DIR_DOWNSTREAM, NULL,
kyr, ctx->origin_ssl);
ctx->bev_down = bufferevent_openssl_socket_new(evbase, ctx->fd_downstream, ctx->downstream->ssl,
BUFFEREVENT_SSL_ACCEPTING, BEV_OPT_DEFER_CALLBACKS | BEV_OPT_THREADSAFE);
bufferevent_openssl_set_allow_dirty_shutdown(ctx->bev_down, 1);
@@ -1930,7 +1909,10 @@ int ssl_stream_set_integer_opt(struct ssl_stream *upstream, enum SSL_STREAM_OPT
upstream->up_parts.block_fake_cert=opt_val;
break;
case SSL_STREAM_OPT_PROTOCOL_MIN_VERSION:
upstream->ssl_min_version=opt_val;
break;
case SSL_STREAM_OPT_PROTOCOL_MAX_VERSION:
upstream->ssl_max_version=opt_val;
break;
default:
return 0;

View File

@@ -4,6 +4,7 @@
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <assert.h>
#include <openssl/crypto.h>
#include <openssl/engine.h>
@@ -150,6 +151,45 @@ void ssl_openssl_version(void)
#endif /* !SSL_OP_TLS_ROLLBACK_BUG */
fprintf(stderr, "\n");
}
int sslver_str2num(const char * version_str)
{
int sslversion = -1;
assert(OPENSSL_VERSION_NUMBER >= 0x10100000L);
/*
* Support for SSLv2 and the corresponding SSLv2_method(),
* SSLv2_server_method() and SSLv2_client_method() functions were
* removed in OpenSSL 1.1.0.
*/
if (!strcmp(version_str, "ssl3"))
{
sslversion = SSL3_VERSION;
}
else if (!strcmp(version_str, "tls10") || !strcmp(version_str, "tls1"))
{
sslversion = TLS1_VERSION;
}
else if (!strcmp(version_str, "tls11"))
{
sslversion = TLS1_1_VERSION;
}
else if (!strcmp(version_str, "tls12"))
{
sslversion = TLS1_2_VERSION;
}
else if (!strcmp(version_str, "tls13"))
{
sslversion = TLS1_3_VERSION;
}
else
{
sslversion = -1;
}
return sslversion;
}
/*
* 1 if OpenSSL has been initialized, 0 if not. When calling a _load()

View File

@@ -146,6 +146,9 @@ struct pangu_rt
};
struct pangu_rt * g_pangu_rt;
Maat_feather_t g_business_maat;
#define MAAT_INPUT_JSON 0
#define MAAT_INPUT_REDIS 1
#define MAAT_INPUT_FILE 2
@@ -835,6 +838,7 @@ int pangu_http_init(struct tfe_proxy * proxy)
TFE_LOG_INFO(NULL, "Tango Cache Enabled.");
}
TFE_LOG_INFO(NULL, "Pangu HTTP init success.");
g_business_maat=g_pangu_rt->maat;
return 0;
error_out: