#include #include #include #include "cJSON.h" #include "session_flags_internal.h" #include "tunneling.h" #include "stellar/log.h" #define UNUSED(x) (void)(x) thread_local hs_scratch_t *hs_scratch = NULL; extern struct session_flags_init_conf g_sf_conf; static char tunneling_length_to_character(enum flow_type flow_type, size_t len) { char ret; switch(len) { case 1 ... 200: ret = 'A'; break; case 201 ... 600: ret = 'B'; break; case 601 ... 1000: ret = 'C'; break; case 1001 ... 1460: ret = 'D'; break; default: ret = 'Z'; break; } if (flow_type == FLOW_TYPE_C2S) { return ret; } else { return tolower(ret); } } static int tunneling_match_event_handler(unsigned int id, unsigned long long from, unsigned long long to, unsigned int flags, void *context) { UNUSED(id); UNUSED(from); UNUSED(to); UNUSED(flags); struct session_flags_ctx *ctx = (struct session_flags_ctx *)context; ctx->stat.result.flags |= SESSION_FLAGS_TUNNELING; return 0; } int tunneling_scan_sequence(struct session_flags_plugin_info *sf_plugin_info, struct session *session, struct session_flags_ctx *ctx, size_t payload_len, enum flow_type flow_type, uint64_t pkts_cnt) { if (ctx->stat.result.flags & SESSION_FLAGS_TUNNELING) { return 0; } ctx->stat.tunneling_stat.payload_pkt_num++; if (ctx->stat.result.is_tls && ctx->stat.tunneling_stat.payload_pkt_num <= g_sf_conf.tunneling_tls_ignore_pkts) { return 0; } if((ctx->stat.result.is_tls==0) && (ctx->stat.tunneling_stat.payload_pkt_num > g_sf_conf.tunneling_max_scan_pkts)) { return 0; } if((ctx->stat.result.is_tls) && (ctx->stat.tunneling_stat.payload_pkt_num > g_sf_conf.tunneling_max_scan_pkts+g_sf_conf.tunneling_tls_ignore_pkts)) { return 0; } if (hs_scratch == NULL) { hs_error_t err = hs_alloc_scratch(sf_plugin_info->tunneling_hs_db, &hs_scratch); if (err != HS_SUCCESS) { STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "hs_alloc_scratch failed, err:%d", err); return -1; } } char tunneling_seq_char = tunneling_length_to_character(flow_type, payload_len); STELLAR_LOG_DEBUG(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "session: %s, is tls:%s, total_num: %d, payload_pkt_num: %d, tunneling_seq_char:%c, payload_len:%d", session_get0_readable_addr(session), ctx->stat.result.is_tls == true ? "yes":"no", pkts_cnt, ctx->stat.tunneling_stat.payload_pkt_num, tunneling_seq_char, payload_len); hs_error_t err = hs_scan_stream(ctx->tunneling_hs_stream, &tunneling_seq_char, 1, 0, hs_scratch, tunneling_match_event_handler, ctx); if (err != HS_SUCCESS) { STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "hs_scan_stream failed, err:%d", err); return -1; } if (ctx->stat.result.flags & SESSION_FLAGS_TUNNELING) { ctx->stat.result.identify[session_flags_tunneling_mask] = pkts_cnt; } return 0; } void tunneling_hs_stream_init(struct session_flags_plugin_info *sf_plugin_info, struct session_flags_ctx *ctx) { hs_error_t err = hs_open_stream(sf_plugin_info->tunneling_hs_db, 0, &ctx->tunneling_hs_stream); if (err != HS_SUCCESS) { STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "hs_open_stream failed, err:%d", err); return; } } void tunneling_hs_stream_free(struct session_flags_ctx *ctx) { if (ctx->tunneling_hs_stream == NULL) { return; } hs_close_stream(ctx->tunneling_hs_stream, hs_scratch, NULL, NULL); } int tunneling_hyperscan_engine_init(struct session_flags_plugin_info *sf_plugin_info, struct session_flags_init_conf *g_sf_conf) { cJSON *json = NULL, *item = NULL; int array_num; char **pcre = NULL; hs_compile_error_t *compile_err; hs_error_t err; unsigned int *flags = NULL; unsigned int *ids = NULL; int ret = 0; g_sf_conf->tunneling_enabled = 0; json = cJSON_Parse(g_sf_conf->tunneling_pcre_list); if (json == NULL) { STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "cJSON_Parse failed, tunneling_pcre_list:%s", g_sf_conf->tunneling_pcre_list); goto END; } item = cJSON_GetObjectItem(json, "tunneling_pcre_list"); if (item == NULL) { STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "cJSON_GetObjectItem failed, tunneling_pcre_list:%s", g_sf_conf->tunneling_pcre_list); goto END; } array_num = cJSON_GetArraySize(item); if (array_num < 0) { STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "array size error, array_num:%d", array_num); goto END; } if (array_num == 0) { goto END; } g_sf_conf->tunneling_enabled = 1; pcre = (char **)calloc(array_num, sizeof(char *)); for (int i = 0; i < array_num; i++) { pcre[i] = cJSON_GetArrayItem(item, i)->valuestring; } flags = (unsigned int *)calloc(array_num, sizeof(unsigned int)); ids = (unsigned int *)calloc(array_num, sizeof(unsigned int)); for (int i = 0; i < array_num; i++) { flags[i] = HS_FLAG_DOTALL; ids[i] = i; } err = hs_compile_multi(pcre, flags, ids, array_num, HS_MODE_STREAM, NULL, &sf_plugin_info->tunneling_hs_db, &compile_err); if (err != HS_SUCCESS) { STELLAR_LOG_FATAL(sf_plugin_info->log_handle, SESSION_FLAGS_LOG_MODULE, "hs_compile_multi failed, err:%d, pattern id: %d, err_msg: %s, pattern: %s", err, compile_err->expression, compile_err->message, pcre[compile_err->expression]); cJSON_Delete(json); free(pcre); ret = -1; goto END; } END: if (json != NULL) { cJSON_Delete(json); } if (pcre != NULL) { free(pcre); } if (flags != NULL) { free(flags); } if (ids != NULL) { free(ids); } return ret; } void tunneling_hyperscan_engine_exit(hs_database_t *tunneling_hs_db) { if (tunneling_hs_db != NULL) { hs_free_database(tunneling_hs_db); } }