diff --git a/common/include/tfe_utils.h b/common/include/tfe_utils.h index a8b37a3..d33f685 100644 --- a/common/include/tfe_utils.h +++ b/common/include/tfe_utils.h @@ -9,6 +9,7 @@ #include #include //scan_dir #include +#include #include "kafka.h" #define LOG_TAG_CTRLPKT "CTRL_PACKET" @@ -22,6 +23,8 @@ #define TFE_FAKE_C_DEFAULT_TTL 60 #define TFE_FAKE_S_DEFAULT_TTL 65 +#define UUID_STRING_SIZE 37 + #ifndef TFE_CONFIG_BACKLOG_DEFAULT #define TFE_CONFIG_BACKLOG_DEFAULT 20 #endif diff --git a/conf/tfe/tfe.conf b/conf/tfe/tfe.conf index c316b69..1a61296 100644 --- a/conf/tfe/tfe.conf +++ b/conf/tfe/tfe.conf @@ -61,7 +61,6 @@ timeout_debug=0 [ssl] ssl_debug=0 -ssl_ja3_table=PXY_SSL_FINGERPRINT # ssl version Not available, configured via TSG website # ssl_max_version=tls13 # ssl_min_version=ssl3 diff --git a/platform/include/internal/ssl_service_cache.h b/platform/include/internal/ssl_service_cache.h index d569fce..be74d27 100644 --- a/platform/include/internal/ssl_service_cache.h +++ b/platform/include/internal/ssl_service_cache.h @@ -39,7 +39,7 @@ struct ssl_service_cache unsigned int fail_as_proto_err_count; unsigned int fail_time_window; }; -struct ssl_service_cache* ssl_service_cache_create(unsigned int slot_size, unsigned int expire_seconds, int fail_as_pinning_cnt, int fail_as_proto_err_cnt, int fail_time_win, char *ja3_table_name); +struct ssl_service_cache* ssl_service_cache_create(unsigned int slot_size, unsigned int expire_seconds, int fail_as_pinning_cnt, int fail_as_proto_err_cnt, int fail_time_win); void ssl_service_cache_destroy(struct ssl_service_cache* cache); int ssl_service_cache_read(struct ssl_service_cache *svc_cache, const struct ssl_chello *chello, const struct tfe_stream *tcp_stream, struct ssl_service_status *result); diff --git a/platform/src/ssl_service_cache.cpp b/platform/src/ssl_service_cache.cpp index 13c7adc..7313965 100644 --- a/platform/src/ssl_service_cache.cpp +++ b/platform/src/ssl_service_cache.cpp @@ -5,11 +5,10 @@ struct ssl_svc_ja3 { - char ja3_hash[33]; - int fingerprint_id; + uuid_t uuid; + char ja3_hash[33]; int pinning_state; - int is_valid; - int ref_cnt; + int ref_cnt; }; struct ssl_svc_addr @@ -20,135 +19,168 @@ struct ssl_svc_addr const char *dport; }; -static int table_id = 0; - -static void ssl_svc_ja3_param_dup_cb(int table_id, void **to, void **from, long argl, void *argp) +static void ssl_svc_ja3_param_dup_cb(const char *table_name, void **to, void **from, long argl, void *argp) { - struct ssl_svc_ja3 *param = (struct ssl_svc_ja3 *)*from; - if (param) - { - __sync_add_and_fetch(&(param->ref_cnt), 1); - *to = param; - } - else - { - *to = NULL; - } - return; + struct ssl_svc_ja3 *param = (struct ssl_svc_ja3 *)*from; + if (param) + { + __sync_add_and_fetch(&(param->ref_cnt), 1); + *to = param; + } + else + { + *to = NULL; + } + return; } -static void ssl_svc_ja3_param_new_cb(const char *table_name, int table_id, const char *key, const char *table_line, void **ad, long argl, void *argp) +// NOTE: key is ja3_hash +static void ssl_svc_ja3_param_new_cb(const char *table_name, const char *key, const char *table_line, void **ad, long argl, void *argp) { - int is_valid = 0; - int pinning_state = 0; - int fingerprint_id = 0; - char ja3_hash[33] = {0}; + cJSON *json = NULL; + cJSON *item = NULL; + struct ssl_svc_ja3 *param = NULL; - if (sscanf(table_line, "%d\t%s\t%d\t%d", &fingerprint_id, ja3_hash, &pinning_state, &is_valid) != 4) - { - TFE_LOG_ERROR(g_default_logger, "Invalid JA3 policy: %s", table_line); - return; - } + char *json_str = strdup(table_line); + json = cJSON_Parse(json_str); + if (json == NULL) + { + TFE_LOG_ERROR(g_default_logger, "Invalid JA3 policy: (invalid json format) %s", table_line); + goto error_out; + } - struct ssl_svc_ja3 *param = ALLOC(struct ssl_svc_ja3, 1); - param->fingerprint_id = fingerprint_id; - memcpy(param->ja3_hash, ja3_hash, 32); - param->pinning_state = pinning_state; - param->is_valid = is_valid; - param->ref_cnt = 1; + param = ALLOC(struct ssl_svc_ja3, 1); + param->ref_cnt = 1; - *ad = param; - TFE_LOG_INFO(g_default_logger, "Add JA3 policy: id:%d, ja3_hash:%s, pinning_state:%d, is_valid:%d, ref_cnt:%d", - param->fingerprint_id, param->ja3_hash, param->pinning_state, param->is_valid, param->ref_cnt); + // uuid + item = cJSON_GetObjectItem(json, "uuid"); + if (!item || !cJSON_IsString(item)) + { + TFE_LOG_ERROR(g_default_logger, "Invalid JA3 policy: (invalid uuid param) %s", table_line); + goto error_out; + } + uuid_parse(item->valuestring, param->uuid); + + // ja3_hash + item = cJSON_GetObjectItem(json, "ja3_hash"); + if (!item || !cJSON_IsString(item)) + { + TFE_LOG_ERROR(g_default_logger, "Invalid JA3 policy: (invalid ja3_hash param) %s", table_line); + goto error_out; + } + strncpy(param->ja3_hash, item->valuestring, 32); + + // pinning_state + item = cJSON_GetObjectItem(json, "pinning_state"); + if (!item || !cJSON_IsNumber(item)) + { + TFE_LOG_ERROR(g_default_logger, "Invalid JA3 policy: (invalid pinning_state param) %s", table_line); + goto error_out; + } + param->pinning_state = item->valueint; + + *ad = param; + TFE_LOG_INFO(g_default_logger, "Add JA3 policy: uuid:%s, ja3_hash:%s, pinning_state:%d", + key, param->ja3_hash, param->pinning_state); + + cJSON_Delete(json); + free(json_str); + return; + +error_out: + if (json) + { + cJSON_Delete(json); + } + if (json_str) + { + free(json_str); + } + if (param) + { + free(param); + } + *ad = NULL; + return; } -static void ssl_svc_ja3_param_free_cb(int table_id, void **ad, long argl, void *argp) +static void ssl_svc_ja3_param_free_cb(const char *table_name, void **ad, long argl, void *argp) { - struct ssl_svc_ja3 *param = (struct ssl_svc_ja3 *)*ad; - if (param == NULL) - { - return; - } + struct ssl_svc_ja3 *param = (struct ssl_svc_ja3 *)*ad; + if (param == NULL) + { + return; + } - if ((__sync_sub_and_fetch(¶m->ref_cnt, 1) == 0)) - { - TFE_LOG_INFO(g_default_logger, "Del JA3 policy: id:%d, ja3_hash:%s, pinning_state:%d, is_valid:%d, ref_cnt:%d", - param->fingerprint_id, param->ja3_hash, param->pinning_state, param->is_valid, param->ref_cnt); - free(param); - *ad = NULL; - } + if ((__sync_sub_and_fetch(¶m->ref_cnt, 1) == 0)) + { + char uuid_str[UUID_STRING_SIZE] = {0}; + uuid_unparse(param->uuid, uuid_str); + TFE_LOG_INFO(g_default_logger, "Del JA3 policy: id:%s", uuid_str); + free(param); + *ad = NULL; + } } static void ssl_svc_ja3_param_free(struct ssl_svc_ja3 *param) { - ssl_svc_ja3_param_free_cb(0, (void **)¶m, 0, NULL); - return; + ssl_svc_ja3_param_free_cb(NULL, (void **)¶m, 0, NULL); } -static int ssl_svc_ja3_init(const char *table_name) +static int ssl_svc_ja3_init() { - table_id = maat_get_table_id(tfe_get_maat_handle(), table_name); - if (table_id < 0) - { - TFE_LOG_ERROR(g_default_logger, "Maat table %s register failed.", table_name); - return 0; - } - int ret = maat_plugin_table_ex_schema_register(tfe_get_maat_handle(), - table_name, - ssl_svc_ja3_param_new_cb, - ssl_svc_ja3_param_free_cb, - ssl_svc_ja3_param_dup_cb, - 0, - NULL); - if (ret < 0) - { - TFE_LOG_ERROR(g_default_logger, "failed at Maat_plugin_EX_register(%s), table_id = %d, ret = %d", - table_name, table_id, ret); - return 0; - } - - return 1; + if (maat_plugin_table_ex_schema_register(tfe_get_maat_handle(), + "PXY_SSL_FINGERPRINT", + ssl_svc_ja3_param_new_cb, + ssl_svc_ja3_param_free_cb, + ssl_svc_ja3_param_dup_cb, + 0, + NULL) != 0) + { + TFE_LOG_ERROR(g_default_logger, "failed at Maat_plugin_EX_register(PXY_SSL_FINGERPRINT)"); + return -1 + } + else + { + return 0; + } } enum ssl_ja3_pinning_status ssl_svc_ja3_scan(char *ja3_hash, const char *addr_str) { - enum ssl_ja3_pinning_status ret = JA3_PINNING_STATUS_UNKNOWN; - struct ssl_svc_ja3 *param = NULL; + enum ssl_ja3_pinning_status ret = JA3_PINNING_STATUS_UNKNOWN; + struct ssl_svc_ja3 *param = NULL; + char uuid_str[UUID_STRING_SIZE] = {0}; - param = (struct ssl_svc_ja3 *)maat_plugin_table_get_ex_data(tfe_get_maat_handle(), table_id, ja3_hash, strlen(ja3_hash)); - if (param == NULL) - { - ret = JA3_PINNING_STATUS_UNKNOWN; - goto end; - } - TFE_LOG_INFO(g_default_logger, "Hit JA3 policy: id:%d, ja3_hash:%s, pinning_state:%d, is_valid:%d, ref_cnt:%d, addr:%s", - param->fingerprint_id, param->ja3_hash, param->pinning_state, param->is_valid, param->ref_cnt, addr_str); - - if (!param->is_valid) - { - ret = JA3_PINNING_STATUS_UNKNOWN; - goto end; - } + param = (struct ssl_svc_ja3 *)maat_plugin_table_get_ex_data(tfe_get_maat_handle(), "PXY_SSL_FINGERPRINT", ja3_hash, strlen(ja3_hash)); + if (param == NULL) + { + ret = JA3_PINNING_STATUS_UNKNOWN; + goto end; + } + uuid_unparse(param->uuid, uuid_str); + TFE_LOG_INFO(g_default_logger, "Hit JA3 policy: uuid:%s, ja3_hash:%s, pinning_state:%d, addr:%s", + uuid_str, param->ja3_hash, param->pinning_state, addr_str); // 1 - pinning - if (param->pinning_state) - { - ret = JA3_PINNING_STATUS_IS_PINNING; - } - // 0 - not pinning - else + if (param->pinning_state) { - ret = JA3_PINNING_STATUS_NOT_PINNING; - } + ret = JA3_PINNING_STATUS_IS_PINNING; + } + // 0 - not pinning + else + { + ret = JA3_PINNING_STATUS_NOT_PINNING; + } end: - if (param) - { - ssl_svc_ja3_param_free(param); - param = NULL; - } + if (param) + { + ssl_svc_ja3_param_free(param); + param = NULL; + } - return ret; + return ret; } struct ssl_svc_client_st @@ -510,10 +542,9 @@ void ssl_service_cache_write(struct ssl_service_cache *svc_cache, const struct s free(addr_str); } -struct ssl_service_cache *ssl_service_cache_create(unsigned int slot_size, unsigned int expire_seconds, int fail_as_pinning_cnt, int fail_as_proto_err_cnt, int fail_time_win -, char *ja3_table_name) +struct ssl_service_cache *ssl_service_cache_create(unsigned int slot_size, unsigned int expire_seconds, int fail_as_pinning_cnt, int fail_as_proto_err_cnt, int fail_time_win) { - if (ssl_svc_ja3_init(ja3_table_name) == 0) + if (ssl_svc_ja3_init() != 0) { return NULL; } diff --git a/platform/src/ssl_stream.cpp b/platform/src/ssl_stream.cpp index 84e9d51..898c58a 100644 --- a/platform/src/ssl_stream.cpp +++ b/platform/src/ssl_stream.cpp @@ -631,7 +631,6 @@ struct ssl_mgr * ssl_manager_init(const char * ini_profile, const char * section struct ssl_mgr * mgr = ALLOC(struct ssl_mgr, 1); int ret = 0; - char ja3_table_name[TFE_STRING_MAX] = {0}; char version_str[TFE_SYMBOL_MAX] = {}; mgr->logger = logger; mgr->ev_base_gc=ev_base_gc; @@ -711,11 +710,10 @@ struct ssl_mgr * ssl_manager_init(const char * ini_profile, const char * section MESA_load_profile_uint_def(ini_profile, section, "service_cache_fail_time_window", &(mgr->svc_cnt_time_window), 30); - MESA_load_profile_string_def(ini_profile, section, "ssl_ja3_table", ja3_table_name, sizeof(ja3_table_name), "PXY_SSL_FINGERPRINT"); - mgr->svc_cache=ssl_service_cache_create(mgr->svc_cache_slots, mgr->svc_expire_seconds, - mgr->svc_fail_as_pinning_cnt, - mgr->svc_fail_as_proto_err_cnt, - mgr->svc_cnt_time_window, ja3_table_name); + mgr->svc_cache = ssl_service_cache_create(mgr->svc_cache_slots, mgr->svc_expire_seconds, + mgr->svc_fail_as_pinning_cnt, + mgr->svc_fail_as_proto_err_cnt, + mgr->svc_cnt_time_window); if (mgr->svc_cache == NULL) { TFE_LOG_ERROR(logger, "Failed to create service cache"); diff --git a/resource/pangu/pangu_http.json b/resource/pangu/pangu_http.json index 1517855..5d29494 100644 --- a/resource/pangu/pangu_http.json +++ b/resource/pangu/pangu_http.json @@ -275,9 +275,9 @@ { "table_name": "PXY_SSL_FINGERPRINT", "table_content": [ - "1\t599f223c2c9ee5702f5762913889dc21\t0\t1", - "2\teb149984fc9c44d85ed7f12c90d818be\t1\t0", - "3\te6573e91e6eb777c0933c5b8f97f10cd\t1\t1" + "{\"uuid\":\"JA300000-0000-0000-0000-000000000001\",\"ja3_hash\":\"599f223c2c9ee5702f5762913889dc21\",\"pinning_state\":1,\"is_valid\":1}", + "{\"uuid\":\"JA300000-0000-0000-0000-000000000002\",\"ja3_hash\":\"eb149984fc9c44d85ed7f12c90d818be\",\"pinning_state\":1,\"is_valid\":1}", + "{\"uuid\":\"JA300000-0000-0000-0000-000000000003\",\"ja3_hash\":\"e6573e91e6eb777c0933c5b8f97f10cd\",\"pinning_state\":1,\"is_valid\":1}" ] }, { diff --git a/resource/pangu/table_info.conf b/resource/pangu/table_info.conf index 72b6c8f..e80f245 100644 --- a/resource/pangu/table_info.conf +++ b/resource/pangu/table_info.conf @@ -372,10 +372,9 @@ "table_id":34, "table_name":"PXY_SSL_FINGERPRINT", "table_type":"plugin", - "valid_column":4, "custom": { - "key":2, - "key_type":"pointer" + "key_type":"pointer", + "key_name":"ja3_hash" } }, {