diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index fd19b04..c513953 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -2,7 +2,7 @@ common src/tfe_utils.cpp src/tfe_types.cpp src/tfe_future.cpp src/tfe_http.cpp src/tfe_plugin.cpp src/tfe_rpc.cpp src/tfe_cmsg.cpp src/tfe_kafka_logger.cpp src/tfe_resource.cpp src/tfe_scan.cpp src/tfe_pkt_util.cpp src/tfe_tcp_restore.cpp src/raw_socket.cpp src/packet_construct.cpp - src/tap.cpp src/io_uring.cpp) + src/tap.cpp src/io_uring.cpp src/intercept_policy.cpp) target_include_directories(common PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include) target_link_libraries(common PUBLIC libevent-static libevent-static-openssl libevent-static-pthreads rdkafka) target_link_libraries(common PUBLIC MESA_handle_logger cjson) diff --git a/common/include/intercept_policy.h b/common/include/intercept_policy.h new file mode 100644 index 0000000..5fab9ff --- /dev/null +++ b/common/include/intercept_policy.h @@ -0,0 +1,9 @@ +#pragma once +#include + +struct intercept_policy_enforcer; +struct intercept_policy_enforcer *intercept_policy_enforcer_create(void *logger); +void intercept_policy_enforce_destory(struct intercept_policy_enforcer *enforcer); +// return 0 : success +// return -1 : error (need passthrough) +int intercept_policy_enforce(struct intercept_policy_enforcer *enforcer, struct tfe_cmsg *cmsg); \ No newline at end of file diff --git a/common/include/ssl_stream.h b/common/include/ssl_stream.h index 1781e20..7c38ec4 100644 --- a/common/include/ssl_stream.h +++ b/common/include/ssl_stream.h @@ -46,7 +46,11 @@ int ssl_stream_get_integer_opt(struct ssl_stream *upstream, enum SSL_STREAM_OPT int ssl_stream_get_string_opt(struct ssl_stream *upstream, enum SSL_STREAM_OPT opt_type, char* in_buff, size_t sz); void ssl_stream_set_cmsg_string(struct ssl_stream *stream, enum tfe_cmsg_tlv_type type, const char *value_str); + uint64_t ssl_stream_get_policy_id(struct ssl_stream *upstream); +int ssl_stream_get_decrypted_profile_id(struct ssl_stream *upstream); +int ssl_stream_get_trusted_keyring_profile_id(struct ssl_stream *upstream); +int ssl_stream_get_untrusted_keyring_profile_id(struct ssl_stream *upstream); unsigned int is_ssl_debug(); diff --git a/common/include/tfe_cmsg.h b/common/include/tfe_cmsg.h index ef226a1..60f7978 100644 --- a/common/include/tfe_cmsg.h +++ b/common/include/tfe_cmsg.h @@ -36,6 +36,10 @@ enum tfe_cmsg_tlv_type TFE_CMSG_POLICY_ID = 0x10, // size uint64_t TFE_CMSG_STREAM_TRACE_ID = 0x11, + TFE_CMSG_TCP_OPTION_PROFILE_ID, // size int + TFE_CMSG_DECRYPTION_PROFILE_ID, // size int + TFE_CMSG_KEYRING_FOR_TRUSTED_ID, // size int + TFE_CMSG_KEYRING_FOR_UNTRUSTED, // size int TFE_CMSG_SSL_INTERCEPT_STATE, //size uint64_t, 0-passthrough, 1-intercept, 2-shutdown, referer from enum ssl_stream_action TFE_CMSG_SSL_SERVER_SIDE_LATENCY, //size uint64_t, milisecond diff --git a/common/src/intercept_policy.cpp b/common/src/intercept_policy.cpp new file mode 100644 index 0000000..1fbaafd --- /dev/null +++ b/common/src/intercept_policy.cpp @@ -0,0 +1,271 @@ +#include +#include +#include +#include +#include + +struct intercept_param +{ + uint64_t rule_id; + int ref_cnt; + int keyring_for_trusted; + int keyring_for_untrusted; + int decryption_profile; + int tcp_option_profile; +}; + +struct intercept_policy_enforcer +{ + struct maat *maat; + int table_id; + void *logger; +}; + +static void intercept_param_new_cb(const char *table_name, int table_id, const char *key, const char *table_line, void **ad, long argl, void *argp) +{ + size_t len = 0; + size_t offset = 0; + char *json_str = NULL; + cJSON *json = NULL; + cJSON *item = NULL; + struct intercept_param *param = NULL; + struct intercept_policy_enforcer *enforcer = (struct intercept_policy_enforcer *)argp; + + if (maat_helper_read_column(table_line, 7, &offset, &len) < 0) + { + TFE_LOG_ERROR(enforcer->logger, "Invalid intercept user region: %s", table_line); + goto error_out; + } + + json_str = ALLOC(char, len + 1); + memcpy(json_str, table_line + offset, len); + json = cJSON_Parse(json_str); + if (json == NULL) + { + TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter: id = %s", key); + goto error_out; + } + + item = cJSON_GetObjectItem(json, "protocol"); + if (unlikely(!item || !cJSON_IsString(item))) + { + TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter: %s invalid protocol format", key); + goto error_out; + } + if (0 != strcasecmp(item->valuestring, "SSL") && 0 != strcasecmp(item->valuestring, "HTTP")) + { + goto error_out; + } + + param = ALLOC(struct intercept_param, 1); + param->rule_id = atoll(key); + param->ref_cnt = 1; + param->keyring_for_trusted = 1; + param->keyring_for_untrusted = 0; + param->decryption_profile = 0; + param->tcp_option_profile = 0; + + item = cJSON_GetObjectItem(json, "keyring_for_trusted"); + if (item) + { + if (item->type == cJSON_Number) + { + param->keyring_for_trusted = item->valueint; + } + else if (item->type == cJSON_String) + { + param->keyring_for_trusted = atoi(item->valuestring); + } + else + { + TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter: %lu invalid keyring_for_trusted format", param->rule_id); + } + } + + item = cJSON_GetObjectItem(json, "keyring_for_untrusted"); + if (item) + { + if (item->type == cJSON_Number) + { + param->keyring_for_untrusted = item->valueint; + } + else if (item->type == cJSON_String) + { + param->keyring_for_untrusted = atoi(item->valuestring); + } + else + { + TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter: %lu invalid keyring_for_untrusted format", param->rule_id); + } + } + + item = cJSON_GetObjectItem(json, "decryption"); + if (item) + { + if (item->type == cJSON_Number) + { + param->decryption_profile = item->valueint; + } + else if (item->type == cJSON_String) + { + param->decryption_profile = atoi(item->valuestring); + } + else + { + TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter: %lu invalid decryption_profile format", param->rule_id); + } + } + + item = cJSON_GetObjectItem(json, "tcp_option_profile"); + if (item) + { + if (item->type == cJSON_Number) + { + param->tcp_option_profile = item->valueint; + } + else if (item->type == cJSON_String) + { + param->tcp_option_profile = atoi(item->valuestring); + } + else + { + TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter: %lu invalid tcp_option_profile format", param->rule_id); + } + } + + *ad = param; + TFE_LOG_INFO(enforcer->logger, "Add intercept policy: %lu", param->rule_id); + +error_out: + if (json) + { + cJSON_Delete(json); + } + if (json_str) + { + free(json_str); + } +} + +static void intercept_param_free_cb(int table_id, void **ad, long argl, void *argp) +{ + struct intercept_policy_enforcer *enforcer = (struct intercept_policy_enforcer *)argp; + struct intercept_param *param = (struct intercept_param *)*ad; + if (param == NULL) + { + return; + } + + if ((__sync_sub_and_fetch(¶m->ref_cnt, 1) == 0)) + { + TFE_LOG_INFO(enforcer->logger, "Del intercept policy %lu", param->rule_id); + free(param); + *ad = NULL; + } +} + +static void intercept_param_dup_cb(int table_id, void **to, void **from, long argl, void *argp) +{ + struct intercept_param *param = (struct intercept_param *)*from; + if (param) + { + __sync_add_and_fetch(&(param->ref_cnt), 1); + *to = param; + } + else + { + *to = NULL; + } +} + +static void intercept_param_free(struct intercept_param *param) +{ + intercept_param_free_cb(0, (void **)¶m, 0, NULL); +} + +struct intercept_policy_enforcer *intercept_policy_enforcer_create(void *logger) +{ + int ret = 0; + struct intercept_policy_enforcer *enforcer = ALLOC(struct intercept_policy_enforcer, 1); + enforcer->maat = (struct maat *)tfe_bussiness_resouce_get(STATIC_MAAT); + enforcer->logger = logger; + enforcer->table_id = maat_get_table_id(enforcer->maat, "TSG_SECURITY_COMPILE"); + + if (enforcer->table_id < 0) + { + TFE_LOG_ERROR(enforcer->logger, "failed at register table of TSG_SECURITY_COMPILE, ret = %d", enforcer->table_id); + goto error_out; + } + + ret = maat_plugin_table_ex_schema_register(enforcer->maat, + "TSG_SECURITY_COMPILE", + intercept_param_new_cb, + intercept_param_free_cb, + intercept_param_dup_cb, + 0, + enforcer); + if (ret != 0) + { + TFE_LOG_ERROR(enforcer->logger, "failed at register callback of TSG_SECURITY_COMPILE, ret = %d", ret); + goto error_out; + } + + return enforcer; + +error_out: + intercept_policy_enforce_destory(enforcer); + return NULL; +} + +void intercept_policy_enforce_destory(struct intercept_policy_enforcer *enforcer) +{ + if (enforcer) + { + free(enforcer); + enforcer = NULL; + } +} + +// return 0 : success +// return -1 : error (need passthrough) +int intercept_policy_enforce(struct intercept_policy_enforcer *enforcer, struct tfe_cmsg *cmsg) +{ + int ret = 0; + uint16_t size = 0; + uint64_t rule_id = 0; + char buff[16] = {0}; + struct intercept_param *param = NULL; + + int passthrough = 1; + char reason[] = "Invalid Intercept Param"; + + ret = tfe_cmsg_get_value(cmsg, TFE_CMSG_POLICY_ID, (unsigned char *)&rule_id, sizeof(rule_id), &size); + if (ret < 0) + { + TFE_LOG_ERROR(g_default_logger, "Failed at fetch intercept rule_id from cmsg: %s", strerror(-ret)); + goto error_passthrough; + } + + snprintf(buff, sizeof(buff), "%lu", rule_id); + param = (struct intercept_param *)maat_plugin_table_get_ex_data(enforcer->maat, enforcer->table_id, buff); + if (param == NULL) + { + TFE_LOG_INFO(enforcer->logger, "Failed to get intercept parameter of policy %lu.", rule_id); + goto error_passthrough; + } + + tfe_cmsg_set(cmsg, TFE_CMSG_TCP_OPTION_PROFILE_ID, (const unsigned char *)&(param->tcp_option_profile), sizeof(param->tcp_option_profile)); + tfe_cmsg_set(cmsg, TFE_CMSG_DECRYPTION_PROFILE_ID, (const unsigned char *)&(param->decryption_profile), sizeof(param->decryption_profile)); + tfe_cmsg_set(cmsg, TFE_CMSG_KEYRING_FOR_TRUSTED_ID, (const unsigned char *)&(param->keyring_for_trusted), sizeof(param->keyring_for_trusted)); + tfe_cmsg_set(cmsg, TFE_CMSG_KEYRING_FOR_UNTRUSTED, (const unsigned char *)&(param->keyring_for_untrusted), sizeof(param->keyring_for_untrusted)); + + intercept_param_free(param); + + return 0; + +error_passthrough: + tfe_cmsg_set(cmsg, TFE_CMSG_TCP_PASSTHROUGH, (const unsigned char *)&passthrough, sizeof(passthrough)); + tfe_cmsg_set(cmsg, TFE_CMSG_SSL_PASSTHROUGH_REASON, (const unsigned char *)&reason, strlen(reason)); + + return -1; +} \ No newline at end of file diff --git a/platform/include/internal/proxy.h b/platform/include/internal/proxy.h index 3e6c442..d402385 100644 --- a/platform/include/internal/proxy.h +++ b/platform/include/internal/proxy.h @@ -5,6 +5,7 @@ #include #include #include +#include struct ssl_mgr; struct key_keeper; @@ -130,6 +131,7 @@ struct tfe_proxy struct tfe_plugin * modules; struct ssl_mgr * ssl_mgr_handler; + struct intercept_policy_enforcer *int_ply_enforcer; struct tcp_policy_enforcer *tcp_ply_enforcer; struct ssl_policy_enforcer *ssl_ply_enforcer; struct chaining_policy_enforcer *chain_ply_enforcer; diff --git a/platform/src/acceptor_kni_v3.cpp b/platform/src/acceptor_kni_v3.cpp index b923f93..8a39bfc 100644 --- a/platform/src/acceptor_kni_v3.cpp +++ b/platform/src/acceptor_kni_v3.cpp @@ -15,10 +15,11 @@ #include #include #include +#include #define TCP_RESTORE_TCPOPT_KIND 88 -extern void tcp_policy_enforce(struct tcp_policy_enforcer *enforcer, struct tfe_cmsg *cmsg, uint64_t rule_id); +extern int tcp_policy_enforce(struct tcp_policy_enforcer *tcp_enforcer, struct tfe_cmsg *cmsg); extern void chaining_policy_enforce(struct chaining_policy_enforcer *enforcer, struct tfe_cmsg *cmsg, uint64_t rule_id); struct acceptor_kni_v3 @@ -604,7 +605,6 @@ static int payload_handler_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, s uint8_t stream_protocol_in_char = 0; uint8_t enalbe_decrypted_traffic_steering = 0; uint16_t size = 0; - uint64_t rule_id = 0; uint64_t chaining_rule_id = 0; // only use for acceptv4 struct acceptor_kni_v3 *__ctx = (struct acceptor_kni_v3 *)data; clock_gettime(CLOCK_MONOTONIC, &(__ctx->start)); @@ -716,14 +716,9 @@ static int payload_handler_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, s goto end; } - ret = tfe_cmsg_get_value(cmsg, TFE_CMSG_POLICY_ID, (unsigned char *)&rule_id, sizeof(rule_id), &size); - if (ret < 0) - { - TFE_LOG_ERROR(g_default_logger, "failed at fetch rule_id from cmsg: %s", strerror(-ret)); - goto end; - } - tcp_policy_enforce(__ctx->proxy->tcp_ply_enforcer, cmsg, rule_id); - chaining_policy_enforce(__ctx->proxy->chain_ply_enforcer, cmsg, chaining_rule_id); + intercept_policy_enforce(__ctx->proxy->int_ply_enforcer, cmsg); + tcp_policy_enforce(__ctx->proxy->tcp_ply_enforcer, cmsg); + chaining_policy_enforce(__ctx->proxy->chain_ply_enforcer, cmsg, chaining_rule_id); if (overwrite_tcp_mss(cmsg, &restore_info)) { diff --git a/platform/src/proxy.cpp b/platform/src/proxy.cpp index 9e9632a..d2fc87b 100644 --- a/platform/src/proxy.cpp +++ b/platform/src/proxy.cpp @@ -698,6 +698,9 @@ int main(int argc, char * argv[]) TFE_LOG_INFO(g_default_logger, "Plugin %s initialized. ", plugin_iter->symbol); } + g_default_proxy->int_ply_enforcer = intercept_policy_enforcer_create(g_default_logger); + CHECK_OR_EXIT(g_default_proxy->int_ply_enforcer != NULL, "Failed at creating intercept policy enforcer. Exit."); + g_default_proxy->tcp_ply_enforcer = tcp_policy_enforcer_create(g_default_logger); CHECK_OR_EXIT(g_default_proxy->tcp_ply_enforcer != NULL, "Failed at creating tcp policy enforcer. Exit."); diff --git a/platform/src/ssl_stream.cpp b/platform/src/ssl_stream.cpp index 52c8e6d..2584b32 100644 --- a/platform/src/ssl_stream.cpp +++ b/platform/src/ssl_stream.cpp @@ -2219,6 +2219,39 @@ uint64_t ssl_stream_get_policy_id(struct ssl_stream *upstream) return policy_id; } +int ssl_stream_get_decrypted_profile_id(struct ssl_stream *upstream) +{ + uint16_t out_size; + int profile_id = 0; + struct tfe_cmsg *cmsg = tfe_stream_get0_cmsg(upstream->tcp_stream); + int ret = tfe_cmsg_get_value(cmsg, TFE_CMSG_DECRYPTION_PROFILE_ID, (unsigned char *)profile_id, sizeof(profile_id), &out_size); + assert(ret == 0); + + return profile_id; +} + +int ssl_stream_get_trusted_keyring_profile_id(struct ssl_stream *upstream) +{ + uint16_t out_size; + int keyring_id = 0; + struct tfe_cmsg *cmsg = tfe_stream_get0_cmsg(upstream->tcp_stream); + int ret = tfe_cmsg_get_value(cmsg, TFE_CMSG_KEYRING_FOR_TRUSTED_ID, (unsigned char *)keyring_id, sizeof(keyring_id), &out_size); + assert(ret == 0); + + return keyring_id; +} + +int ssl_stream_get_untrusted_keyring_profile_id(struct ssl_stream *upstream) +{ + uint16_t out_size; + int keyring_id = 0; + struct tfe_cmsg *cmsg = tfe_stream_get0_cmsg(upstream->tcp_stream); + int ret = tfe_cmsg_get_value(cmsg, TFE_CMSG_KEYRING_FOR_UNTRUSTED, (unsigned char *)keyring_id, sizeof(keyring_id), &out_size); + assert(ret == 0); + + return keyring_id; +} + int ssl_stream_get_string_opt(struct ssl_stream *upstream, enum SSL_STREAM_OPT opt_type, char* in_buff, size_t sz) { const char* sni=upstream->up_parts.client_hello->sni?upstream->up_parts.client_hello->sni:"null"; diff --git a/plugin/business/ssl-policy/src/ssl_policy.cpp b/plugin/business/ssl-policy/src/ssl_policy.cpp index 140eebb..6cb0866 100644 --- a/plugin/business/ssl-policy/src/ssl_policy.cpp +++ b/plugin/business/ssl-policy/src/ssl_policy.cpp @@ -10,18 +10,9 @@ struct ssl_policy_enforcer { struct maat *maat; - int policy_table_id; int profile_table_id; void* logger; }; -struct intercept_param -{ - uint64_t policy_id; - int ref_cnt; - int keyring_for_trusted; - int keyring_for_untrusted; - int decryption_profile_id; -}; struct decryption_param { @@ -43,147 +34,6 @@ struct decryption_param int mirror_client_version; }; -void intercept_param_dup_cb(int table_id, void **to, void **from, long argl, void* argp) -{ - struct intercept_param* param= (struct intercept_param*) *from; - if(param) - { - __sync_add_and_fetch(&(param->ref_cnt), 1); - *to = param; - } - else - { - *to=NULL; - } - return; -} - -void intercept_param_new_cb(const char *table_name, int table_id, const char* key, const char* table_line, void **ad, long argl, void* argp) -{ - int ret=0; - size_t intercept_user_region_offset=0, len=0; - char* json_str=NULL; - cJSON *json=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; - } - - item=cJSON_GetObjectItem(json, "protocol"); - if(unlikely(!item || !cJSON_IsString(item))) - { - TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter: %s invalid protocol format", key); - goto error_out; - } - if(0!=strcasecmp(item->valuestring, "SSL")&& 0!=strcasecmp(item->valuestring, "HTTP")) - { - goto error_out; - } - - param=ALLOC(struct intercept_param, 1); - param->policy_id=atoll(key); - param->ref_cnt=1; - /* - param->bypass_mutual_auth=1; - param->bypass_pinning=1; - param->mirror_client_version=1; - */ - param->keyring_for_trusted=1; - param->keyring_for_untrusted=0; - param->decryption_profile_id=0; - - item=cJSON_GetObjectItem(json, "keyring_for_trusted"); - if(item) - { - if(item->type==cJSON_Number) - { - param->keyring_for_trusted=item->valueint; - } - else if(item->type==cJSON_String) - { - param->keyring_for_trusted=atoi(item->valuestring); - } - else - { - TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter: %lu invalid keyring_for_trusted format", param->policy_id); - } - } - - item=cJSON_GetObjectItem(json, "keyring_for_untrusted"); - if(item) - { - if(item->type==cJSON_Number) - { - param->keyring_for_untrusted=item->valueint; - } - else if(item->type==cJSON_String) - { - param->keyring_for_untrusted=atoi(item->valuestring); - } - else - { - TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter: %lu invalid keyring_for_untrusted format", param->policy_id); - } - } - - item=cJSON_GetObjectItem(json, "decryption"); - if(item) - { - if(item->type==cJSON_Number) - { - param->decryption_profile_id=item->valueint; - } - else if(item->type==cJSON_String) - { - param->decryption_profile_id=atoi(item->valuestring); - } - else - { - TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter: %lu invalid decryption format", param->policy_id); - } - } - *ad=param; - TFE_LOG_INFO(enforcer->logger, "Add intercept policy: %lu", param->policy_id); -error_out: - cJSON_Delete(json); - free(json_str); - return; -} -void intercept_param_free_cb(int table_id, void **ad, long argl, void* argp) -{ - struct ssl_policy_enforcer* enforcer=(struct ssl_policy_enforcer*)argp; - struct intercept_param* param= (struct intercept_param*) *ad; - if(param==NULL) - { - return; - } - - if ((__sync_sub_and_fetch(¶m->ref_cnt, 1) == 0)) - { - TFE_LOG_INFO(enforcer->logger, "Del intercept policy %lu", param->policy_id); - free(param); - *ad=NULL; - } -} -void intercept_param_free(struct intercept_param* param) -{ - intercept_param_free_cb(0, (void**)¶m, 0, NULL); - return; -} - void profile_param_dup_cb(int table_id, void **to, void **from, long argl, void* argp) { struct decryption_param* param= (struct decryption_param*) *from; @@ -319,21 +169,12 @@ error_out: } struct ssl_policy_enforcer* ssl_policy_enforcer_create(void* logger) { + UNUSED int ret=0; struct ssl_policy_enforcer* enforcer=ALLOC(struct ssl_policy_enforcer, 1); enforcer->maat=(struct maat*)tfe_bussiness_resouce_get(STATIC_MAAT);; enforcer->logger=logger; - enforcer->policy_table_id=maat_get_table_id(enforcer->maat, "TSG_SECURITY_COMPILE"); - assert(enforcer->policy_table_id >= 0); enforcer->profile_table_id=maat_get_table_id(enforcer->maat, "PXY_PROFILE_DECRYPTION"); assert(enforcer->profile_table_id >= 0); - UNUSED int ret=maat_plugin_table_ex_schema_register(enforcer->maat, - "TSG_SECURITY_COMPILE", - intercept_param_new_cb, - intercept_param_free_cb, - intercept_param_dup_cb, - 0, - enforcer); - assert(ret==0); ret=maat_plugin_table_ex_schema_register(enforcer->maat, "PXY_PROFILE_DECRYPTION", profile_param_new_cb, @@ -347,32 +188,24 @@ struct ssl_policy_enforcer* ssl_policy_enforcer_create(void* logger) enum ssl_stream_action ssl_policy_enforce(struct ssl_stream *upstream, void* u_para) { UNUSED struct ssl_policy_enforcer* enforcer=(struct ssl_policy_enforcer*)u_para; - struct intercept_param *policy_param=NULL; - struct decryption_param *profile_param=NULL; enum ssl_stream_action action=SSL_ACTION_PASSTHROUGH; UNUSED int ret=0; - uint64_t policy_id=0; - char policy_id_str[16]={0}; + char sni[512]; + char addr_string[512]; char profile_id_str[16]={0}; - char sni[512], addr_string[512]; - policy_id = ssl_stream_get_policy_id(upstream); - snprintf(policy_id_str, sizeof(policy_id_str), "%lu", policy_id); - policy_param=(struct intercept_param *)maat_plugin_table_get_ex_data(enforcer->maat, enforcer->policy_table_id, policy_id_str); - if(policy_param==NULL) - { - TFE_LOG_INFO(enforcer->logger, "Failed to get intercept parameter of policy %lu.", policy_id); - ssl_stream_set_cmsg_string(upstream, TFE_CMSG_SSL_PASSTHROUGH_REASON, "Invalid Intercept Param"); - return SSL_ACTION_PASSTHROUGH; - } - else - { - ssl_stream_get_string_opt(upstream, SSL_STREAM_OPT_SNI, sni, sizeof(sni)); - ssl_stream_get_string_opt(upstream, SSL_STREAM_OPT_ADDR, addr_string, sizeof(addr_string)); - TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy %lu", addr_string, sni, policy_id); - } - snprintf(profile_id_str, sizeof(profile_id_str), "%u", policy_param->decryption_profile_id); - profile_param=(struct decryption_param *)maat_plugin_table_get_ex_data(enforcer->maat, enforcer->profile_table_id, profile_id_str); + uint64_t policy_id = ssl_stream_get_policy_id(upstream); + int decryption_profile_id = ssl_stream_get_decrypted_profile_id(upstream); + int keyring_for_trusted = ssl_stream_get_trusted_keyring_profile_id(upstream); + int keyring_for_untrusted = ssl_stream_get_untrusted_keyring_profile_id(upstream); + + + ssl_stream_get_string_opt(upstream, SSL_STREAM_OPT_SNI, sni, sizeof(sni)); + ssl_stream_get_string_opt(upstream, SSL_STREAM_OPT_ADDR, addr_string, sizeof(addr_string)); + TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy %lu", addr_string, sni, policy_id); + + snprintf(profile_id_str, sizeof(profile_id_str), "%u", decryption_profile_id); + struct decryption_param *profile_param=(struct decryption_param *)maat_plugin_table_get_ex_data(enforcer->maat, enforcer->profile_table_id, profile_id_str); if (profile_param==NULL) { TFE_LOG_INFO(enforcer->logger, "Failed to get decryption parameter of profile %s.", profile_id_str); @@ -397,8 +230,8 @@ enum ssl_stream_action ssl_policy_enforce(struct ssl_stream *upstream, void* u_p { ret=ssl_stream_set_integer_opt(upstream, SSL_STREAM_OPT_BLOCK_FAKE_CERT, 1); } - ret=ssl_stream_set_integer_opt(upstream, SSL_STREAM_OPT_KEYRING_FOR_TRUSTED, policy_param->keyring_for_trusted); - ret=ssl_stream_set_integer_opt(upstream, SSL_STREAM_OPT_KEYRING_FOR_UNTRUSTED, policy_param->keyring_for_untrusted); + ret=ssl_stream_set_integer_opt(upstream, SSL_STREAM_OPT_KEYRING_FOR_TRUSTED, keyring_for_trusted); + ret=ssl_stream_set_integer_opt(upstream, SSL_STREAM_OPT_KEYRING_FOR_UNTRUSTED, keyring_for_untrusted); ret=ssl_stream_get_integer_opt(upstream, SSL_STREAM_OPT_PINNING_STATUS, &pinning_staus); assert(ret==0); @@ -415,46 +248,44 @@ enum ssl_stream_action ssl_policy_enforce(struct ssl_stream *upstream, void* u_p { action = SSL_ACTION_PASSTHROUGH; ssl_stream_set_cmsg_string(upstream, TFE_CMSG_SSL_PASSTHROUGH_REASON, "Certificate Not Installed"); - TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %lu, action PASSTHROUGH due to Certificate Not Installed", addr_string, sni, policy_param->policy_id); + TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %lu, action PASSTHROUGH due to Certificate Not Installed", addr_string, sni, policy_id); } else if ((pinning_staus == 1 || ja3_pinning_status == JA3_PINNING_STATUS_IS_PINNING) && ja3_pinning_status != JA3_PINNING_STATUS_NOT_PINNING && profile_param->bypass_pinning) { action = SSL_ACTION_PASSTHROUGH; ssl_stream_set_cmsg_string(upstream, TFE_CMSG_SSL_PASSTHROUGH_REASON, "Certificate Pinning"); - TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %lu, action PASSTHROUGH due to Certificate Pinning", addr_string, sni, policy_param->policy_id); + TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %lu, action PASSTHROUGH due to Certificate Pinning", addr_string, sni, policy_id); } else if (is_mauth && profile_param->bypass_mutual_auth) { action = SSL_ACTION_PASSTHROUGH; ssl_stream_set_cmsg_string(upstream, TFE_CMSG_SSL_PASSTHROUGH_REASON, "Mutual Authentication"); - TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %lu, action PASSTHROUGH due to Mutual Authentication", addr_string, sni, policy_param->policy_id); + TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %lu, action PASSTHROUGH due to Mutual Authentication", addr_string, sni, policy_id); } else if (is_ev && profile_param->bypass_ev_cert) { action = SSL_ACTION_PASSTHROUGH; ssl_stream_set_cmsg_string(upstream, TFE_CMSG_SSL_PASSTHROUGH_REASON, "EV Certificate"); - TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %lu, action PASSTHROUGH due to EV Certificate", addr_string, sni, policy_param->policy_id); + TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %lu, action PASSTHROUGH due to EV Certificate", addr_string, sni, policy_id); } else if (is_ct && profile_param->bypass_ct_cert) { action = SSL_ACTION_PASSTHROUGH; ssl_stream_set_cmsg_string(upstream, TFE_CMSG_SSL_PASSTHROUGH_REASON, "Certificate Transparency"); - TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %lu, action PASSTHROUGH due to Certificate Transparency", addr_string, sni, policy_param->policy_id); + TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %lu, action PASSTHROUGH due to Certificate Transparency", addr_string, sni, policy_id); } else if (has_error && profile_param->bypass_protocol_errors) { action = SSL_ACTION_PASSTHROUGH; ssl_stream_set_cmsg_string(upstream, TFE_CMSG_SSL_PASSTHROUGH_REASON, "Protocol Errors"); - TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %lu, action PASSTHROUGH due to Protocol Errors", addr_string, sni, policy_param->policy_id); + TFE_LOG_DEBUG(enforcer->logger, "%s %s enforce policy_id %lu, action PASSTHROUGH due to Protocol Errors", addr_string, sni, policy_id); } else { action = SSL_ACTION_INTERCEPT; } - intercept_param_free(policy_param); profile_param_free(profile_param); - policy_param=NULL; profile_param=NULL; return action; } diff --git a/plugin/business/tcp-policy/src/tcp_policy.cpp b/plugin/business/tcp-policy/src/tcp_policy.cpp index 4152d5d..aebc259 100644 --- a/plugin/business/tcp-policy/src/tcp_policy.cpp +++ b/plugin/business/tcp-policy/src/tcp_policy.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -11,8 +10,7 @@ struct tcp_policy_enforcer { struct maat *maat; - int policy_table_id; - int profile_table_id; + int table_id; void *logger; }; @@ -39,100 +37,6 @@ struct tcp_profile_param struct side_conn_param server_side; }; -struct intercept_param -{ - uint64_t rule_id; - int ref_cnt; - int tcp_option_profile; -}; - -static void intercept_param_new_cb(const char *table_name, int table_id, const char *key, const char *table_line, void **ad, long argl, void *argp) -{ - size_t offset = 0; - size_t len = 0; - char *json_str = NULL; - cJSON *json = NULL; - cJSON *item = NULL; - struct intercept_param *policy_param = NULL; - struct tcp_policy_enforcer *enforcer = (struct tcp_policy_enforcer *)argp; - - if (maat_helper_read_column(table_line, 7, &offset, &len) < 0) - { - TFE_LOG_ERROR(enforcer->logger, "Invalid intercept user region: %s", table_line); - goto error_out; - } - - json_str = ALLOC(char, len + 1); - memcpy(json_str, table_line + offset, len); - json = cJSON_Parse(json_str); - if (json == NULL) - { - TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter: id = %s", key); - goto error_out; - } - - item = cJSON_GetObjectItem(json, "tcp_option_profile"); - if (item == NULL || item->type != cJSON_Number) - { - TFE_LOG_ERROR(enforcer->logger, "Invalid intercept parameter: %s invalid tcp_option_profile format", key); - goto error_out; - } - - policy_param = ALLOC(struct intercept_param, 1); - policy_param->rule_id = atoll(key); - policy_param->ref_cnt = 1; - policy_param->tcp_option_profile = item->valueint; - - *ad = policy_param; - TFE_LOG_INFO(enforcer->logger, "Add intercept policy: %lu", policy_param->rule_id); - -error_out: - if (json) - { - cJSON_Delete(json); - } - if (json_str) - { - free(json_str); - } -} - -static void intercept_param_free_cb(int table_id, void **ad, long argl, void *argp) -{ - struct tcp_policy_enforcer *enforcer = (struct tcp_policy_enforcer *)argp; - struct intercept_param *policy_param = (struct intercept_param *)*ad; - if (policy_param == NULL) - { - return; - } - - if ((__sync_sub_and_fetch(&policy_param->ref_cnt, 1) == 0)) - { - TFE_LOG_INFO(enforcer->logger, "Del intercept policy %lu", policy_param->rule_id); - free(policy_param); - *ad = NULL; - } -} - -static void intercept_param_free(struct intercept_param *policy_param) -{ - intercept_param_free_cb(0, (void **)&policy_param, 0, NULL); -} - -static void intercept_param_dup_cb(int table_id, void **to, void **from, long argl, void *argp) -{ - struct intercept_param *policy_param = (struct intercept_param *)*from; - if (policy_param) - { - __sync_add_and_fetch(&(policy_param->ref_cnt), 1); - *to = policy_param; - } - else - { - *to = NULL; - } -} - static int parser_side_conn_param(const char *json_str, struct side_conn_param *out_val, void *logger) { cJSON *json = NULL; @@ -217,7 +121,7 @@ static void profile_param_new_cb(const char *table_name, int table_id, const cha char client_side_conn_param[512] = {0}; char server_side_conn_param[512] = {0}; int is_valid = 0; - struct tcp_profile_param *profile_param = NULL; + struct tcp_profile_param *param = NULL; struct tcp_policy_enforcer *enforcer = (struct tcp_policy_enforcer *)argp; ret = sscanf(table_line, "%d\t%d\t%d\t%s\t%s\t%d", &profile_id, &tcp_passthrough, &bypass_duplicated_packet, client_side_conn_param, server_side_conn_param, &is_valid); @@ -227,60 +131,54 @@ static void profile_param_new_cb(const char *table_name, int table_id, const cha goto error_out; } - profile_param = ALLOC(struct tcp_profile_param, 1); - profile_param->ref_cnt = 1; - profile_param->tcp_passthrough = tcp_passthrough; - profile_param->bypass_duplicated_packet = bypass_duplicated_packet; + param = ALLOC(struct tcp_profile_param, 1); + param->ref_cnt = 1; + param->tcp_passthrough = tcp_passthrough; + param->bypass_duplicated_packet = bypass_duplicated_packet; - if (parser_side_conn_param(client_side_conn_param, &profile_param->client_side, enforcer->logger) == -1) + if (parser_side_conn_param(client_side_conn_param, ¶m->client_side, enforcer->logger) == -1) { goto error_out; } - if (parser_side_conn_param(server_side_conn_param, &profile_param->server_side, enforcer->logger) == -1) + if (parser_side_conn_param(server_side_conn_param, ¶m->server_side, enforcer->logger) == -1) { goto error_out; } - *ad = profile_param; + *ad = param; TFE_LOG_INFO(enforcer->logger, "Add tcp option profile: %s", key); return; error_out: - if (profile_param) + if (param) { - free(profile_param); + free(param); } - return; } static void profile_param_free_cb(int table_id, void **ad, long argl, void *argp) { - struct tcp_profile_param *profile_param = (struct tcp_profile_param *)*ad; - if (profile_param == NULL) + struct tcp_profile_param *param = (struct tcp_profile_param *)*ad; + if (param == NULL) { return; } - if ((__sync_sub_and_fetch(&profile_param->ref_cnt, 1) == 0)) + if ((__sync_sub_and_fetch(¶m->ref_cnt, 1) == 0)) { - free(profile_param); + free(param); *ad = NULL; } } -static void profile_param_free(struct tcp_profile_param *profile_param) -{ - profile_param_free_cb(0, (void **)&profile_param, 0, NULL); -} - static void profile_param_dup_cb(int table_id, void **to, void **from, long argl, void *argp) { - struct tcp_profile_param *profile_param = (struct tcp_profile_param *)*from; - if (profile_param) + struct tcp_profile_param *param = (struct tcp_profile_param *)*from; + if (param) { - __sync_add_and_fetch(&(profile_param->ref_cnt), 1); - *to = profile_param; + __sync_add_and_fetch(&(param->ref_cnt), 1); + *to = param; } else { @@ -288,35 +186,24 @@ static void profile_param_dup_cb(int table_id, void **to, void **from, long argl } } +static void profile_param_free(struct tcp_profile_param *param) +{ + profile_param_free_cb(0, (void **)¶m, 0, NULL); +} + struct tcp_policy_enforcer *tcp_policy_enforcer_create(void *logger) { int ret = 0; struct tcp_policy_enforcer *enforcer = ALLOC(struct tcp_policy_enforcer, 1); enforcer->maat = (struct maat *)tfe_bussiness_resouce_get(STATIC_MAAT); enforcer->logger = logger; - enforcer->policy_table_id = maat_get_table_id(enforcer->maat, "TSG_SECURITY_COMPILE"); - if (enforcer->policy_table_id < 0) + enforcer->table_id = maat_get_table_id(enforcer->maat, "PXY_PROFILE_TCP_OPTION"); + if (enforcer->table_id < 0) { - TFE_LOG_ERROR(enforcer->logger, "failed at register table of TSG_SECURITY_COMPILE, ret = %d", enforcer->policy_table_id); - goto error_out; - } - enforcer->profile_table_id = maat_get_table_id(enforcer->maat, "PXY_PROFILE_TCP_OPTION"); - if (enforcer->profile_table_id < 0) - { - TFE_LOG_ERROR(enforcer->logger, "failed at register table of PXY_PROFILE_TCP_OPTION, ret = %d", enforcer->profile_table_id); + TFE_LOG_ERROR(enforcer->logger, "failed at register table of PXY_PROFILE_TCP_OPTION, ret = %d", enforcer->table_id); goto error_out; } - ret = maat_plugin_table_ex_schema_register(enforcer->maat, "TSG_SECURITY_COMPILE", - intercept_param_new_cb, - intercept_param_free_cb, - intercept_param_dup_cb, - 0, enforcer); - if (ret < 0) - { - TFE_LOG_ERROR(enforcer->logger, "failed at register callback of TSG_SECURITY_COMPILE, ret = %d", ret); - goto error_out; - } ret = maat_plugin_table_ex_schema_register(enforcer->maat, "PXY_PROFILE_TCP_OPTION", profile_param_new_cb, profile_param_free_cb, @@ -343,31 +230,33 @@ void tcp_policy_enforcer_destory(struct tcp_policy_enforcer *enforcer) } } -void tcp_policy_enforce(struct tcp_policy_enforcer *enforcer, struct tfe_cmsg *cmsg, uint64_t rule_id) +// return 0 : success +// return -1 : error (need passthrough) +int tcp_policy_enforce(struct tcp_policy_enforcer *tcp_enforcer, struct tfe_cmsg *cmsg) { - char rule_id_str[16] = {0}; - char profile_id_str[16] = {0}; + int ret = 0; + int profile_id = 0; + uint16_t size = 0; + char buffer[16] = {0}; - snprintf(rule_id_str, sizeof(rule_id_str), "%lu", rule_id); - struct intercept_param *policy_param = (struct intercept_param *)maat_plugin_table_get_ex_data(enforcer->maat, enforcer->policy_table_id, rule_id_str); - if (policy_param == NULL) + ret = tfe_cmsg_get_value(cmsg, TFE_CMSG_TCP_OPTION_PROFILE_ID, (unsigned char *)&profile_id, sizeof(profile_id), &size); + if (ret < 0) { - TFE_LOG_INFO(enforcer->logger, "Failed to get intercept parameter of policy %lu.", rule_id); - return; + TFE_LOG_ERROR(g_default_logger, "Failed at fetch tcp_option_profile from cmsg: %s", strerror(-ret)); + return -1; } - snprintf(profile_id_str, sizeof(profile_id_str), "%d", policy_param->tcp_option_profile); - struct tcp_profile_param *profile_param = (struct tcp_profile_param *)maat_plugin_table_get_ex_data(enforcer->maat, enforcer->profile_table_id, profile_id_str); - if (profile_param == NULL) + snprintf(buffer, sizeof(buffer), "%d", profile_id); + struct tcp_profile_param *param = (struct tcp_profile_param *)maat_plugin_table_get_ex_data(tcp_enforcer->maat, tcp_enforcer->table_id, buffer); + if (param == NULL) { - TFE_LOG_INFO(enforcer->logger, "Failed to get tcp option parameter of profile %lu.", rule_id); - intercept_param_free(policy_param); - return; + TFE_LOG_INFO(tcp_enforcer->logger, "Failed to get tcp option parameter of profile %d.", profile_id); + return -1; } - tfe_cmsg_set(cmsg, TFE_CMSG_TCP_PASSTHROUGH, (unsigned char *)&profile_param->tcp_passthrough, sizeof(profile_param->tcp_passthrough)); + tfe_cmsg_set(cmsg, TFE_CMSG_TCP_PASSTHROUGH, (unsigned char *)¶m->tcp_passthrough, sizeof(param->tcp_passthrough)); - struct side_conn_param *client_side = &profile_param->client_side; + struct side_conn_param *client_side = ¶m->client_side; tfe_cmsg_set(cmsg, TFE_CMSG_DOWNSTREAM_TCP_MSS_ENABLE, (unsigned char *)&client_side->maxseg_enable, sizeof(client_side->maxseg_enable)); tfe_cmsg_set(cmsg, TFE_CMSG_DOWNSTREAM_TCP_MSS_VALUE, (unsigned char *)&client_side->maxseg_vaule, sizeof(client_side->maxseg_vaule)); tfe_cmsg_set(cmsg, TFE_CMSG_DOWNSTREAM_TCP_NODELAY, (unsigned char *)&client_side->nodelay, sizeof(client_side->nodelay)); @@ -378,7 +267,7 @@ void tcp_policy_enforce(struct tcp_policy_enforcer *enforcer, struct tfe_cmsg *c tfe_cmsg_set(cmsg, TFE_CMSG_DOWNSTREAM_TCP_KEEPINTVL, (unsigned char *)&client_side->keepidle, sizeof(client_side->keepintvl)); tfe_cmsg_set(cmsg, TFE_CMSG_DOWNSTREAM_TCP_USER_TIMEOUT, (unsigned char *)&client_side->user_timeout, sizeof(client_side->user_timeout)); - struct side_conn_param *server_side = &profile_param->server_side; + struct side_conn_param *server_side = ¶m->server_side; tfe_cmsg_set(cmsg, TFE_CMSG_UPSTREAM_TCP_MSS_ENABLE, (unsigned char *)&server_side->maxseg_enable, sizeof(server_side->maxseg_enable)); tfe_cmsg_set(cmsg, TFE_CMSG_UPSTREAM_TCP_MSS_VALUE, (unsigned char *)&server_side->maxseg_vaule, sizeof(server_side->maxseg_vaule)); tfe_cmsg_set(cmsg, TFE_CMSG_UPSTREAM_TCP_NODELAY, (unsigned char *)&server_side->nodelay, sizeof(server_side->nodelay)); @@ -389,12 +278,13 @@ void tcp_policy_enforce(struct tcp_policy_enforcer *enforcer, struct tfe_cmsg *c tfe_cmsg_set(cmsg, TFE_CMSG_UPSTREAM_TCP_KEEPINTVL, (unsigned char *)&server_side->keepintvl, sizeof(server_side->keepintvl)); tfe_cmsg_set(cmsg, TFE_CMSG_UPSTREAM_TCP_USER_TIMEOUT, (unsigned char *)&server_side->user_timeout, sizeof(server_side->user_timeout)); - TFE_LOG_INFO(enforcer->logger, "hit rule_id %lu tcp_option_profile %d tcp_passthrough %d " - "client_side={maxseg_enable:%d, maxseg_vaule:%d, nodelay:%d, ttl:%d, keepalive:%d, keepcnt:%d, keepidle:%d, keepintvl:%d, user_timeout:%d} " - "server_side={maxseg_enable:%d, maxseg_vaule:%d, nodelay:%d, ttl:%d, keepalive:%d, keepcnt:%d, keepidle:%d, keepintvl:%d, user_timeout:%d} ", - rule_id, policy_param->tcp_option_profile, profile_param->tcp_passthrough, + TFE_LOG_INFO(tcp_enforcer->logger, "hit tcp_option_profile %d tcp_passthrough %d " + "client_side={maxseg_enable:%d, maxseg_vaule:%d, nodelay:%d, ttl:%d, keepalive:%d, keepcnt:%d, keepidle:%d, keepintvl:%d, user_timeout:%d} " + "server_side={maxseg_enable:%d, maxseg_vaule:%d, nodelay:%d, ttl:%d, keepalive:%d, keepcnt:%d, keepidle:%d, keepintvl:%d, user_timeout:%d} ", + profile_id, param->tcp_passthrough, client_side->maxseg_enable, client_side->maxseg_vaule, client_side->nodelay, client_side->ttl, client_side->keepalive, client_side->keepcnt, client_side->keepidle, client_side->keepidle, client_side->user_timeout, server_side->maxseg_enable, server_side->maxseg_vaule, server_side->nodelay, server_side->ttl, server_side->keepalive, server_side->keepcnt, server_side->keepidle, server_side->keepidle, server_side->user_timeout); - profile_param_free(profile_param); - intercept_param_free(policy_param); + profile_param_free(param); + + return 0; } \ No newline at end of file diff --git a/plugin/business/tcp-policy/src/tcp_policy.h b/plugin/business/tcp-policy/src/tcp_policy.h index 5b34a5f..616bfe4 100644 --- a/plugin/business/tcp-policy/src/tcp_policy.h +++ b/plugin/business/tcp-policy/src/tcp_policy.h @@ -1,8 +1,9 @@ #pragma once #include -#include struct tcp_policy_enforcer; struct tcp_policy_enforcer *tcp_policy_enforcer_create(void *logger); void tcp_policy_enforcer_destory(struct tcp_policy_enforcer *enforcer); -void tcp_policy_enforce(struct tcp_policy_enforcer *enforcer, struct tfe_cmsg *cmsg, uint64_t rule_id); \ No newline at end of file +// return 0 : success +// return -1 : error (need passthrough) +int tcp_policy_enforce(struct tcp_policy_enforcer *tcp_enforcer, struct tfe_cmsg *cmsg); \ No newline at end of file