#include #include #include #include #include #include #include #include #include extern "C" { #include #include #include #include } #include "pkt_seq_matcher.h" #define UNUSED(x) (void)(x) const char *CFG_FILE_PATH="stellar_plugin/pkt_seq_matcher.conf"; static int g_log_level=30; void * g_logger_handle = NULL; thread_local hs_scratch_t *hs_scratch = NULL; thread_local char unicode_charactor[5] = {0}; // 函数用于将单个Unicode码点转换为UTF-8编码并存储到buffer中 static void encode_utf8(int codepoint, char *buffer) { int index = 0; if (codepoint <= 0x7F) { // 1字节UTF-8字符 buffer[(index)++] = codepoint; } else if (codepoint <= 0x7FF) { // 2字节UTF-8字符 buffer[(index)++] = 0xC0 | (codepoint >> 6); buffer[(index)++] = 0x80 | (codepoint & 0x3F); } else if (codepoint <= 0xFFFF) { // 3字节UTF-8字符 buffer[(index)++] = 0xE0 | (codepoint >> 12); buffer[(index)++] = 0x80 | ((codepoint >> 6) & 0x3F); buffer[(index)++] = 0x80 | (codepoint & 0x3F); } else if (codepoint <= 0x10FFFF) { // 4字节UTF-8字符 buffer[(index)++] = 0xF0 | (codepoint >> 18); buffer[(index)++] = 0x80 | ((codepoint >> 12) & 0x3F); buffer[(index)++] = 0x80 | ((codepoint >> 6) & 0x3F); buffer[(index)++] = 0x80 | (codepoint & 0x3F); } } // 定义匹配事件的回调函数 static int eventHandler(unsigned int id, unsigned long long from, unsigned long long to, unsigned int flags, void *context) { struct pkt_seq_matcher_ctx *ctx = (struct pkt_seq_matcher_ctx *)context; ctx->match_flag = 1; return 0; // 继续搜索 } static int pkt_seq_matcher_hyperscan_init(struct pkt_seq_matcher_plugin_info *psm_plugin_info) { hs_error_t err; hs_compile_error_t *compile_err; const char *expression[6] = {"[\u00C9-\u03E8][\u099C-\u0B68]{3}[\u05B5-\u067C][\u0001-\u05B4]{0,3}[\u0001-\u0258][\u067D-\u080C][\u0001-\u05B4]", "[\u00C9-\u03E8][\u099C-\u0B68]{3}[\u0001-\u05B4]{0,3}[\u0001-\u00C8][\u05B5-\u067C][\u0001-\u05B4]", "[\u00C9-\u03E8][\u099C-\u0B68]{2}[\u067D-\u099C][\u0001-\u0258][\u067D-\u080C][\u0001-\u05B4]", "[\u00C9-\u03E8][\u099C-\u0B68]{2}[\u067D-\u099C][\u0001-\u00C8][\u05B5-\u067C][\u0001-\u05B4]", "[\u0259-\u03E8][\u05B5-\u067C][\u0001-\u05B4]", "[\u0259-\u03E8][\u067D-\u080C][\u0001-\u05B4]"}; unsigned int flags[6] = {HS_FLAG_DOTALL | HS_FLAG_UTF8, HS_FLAG_DOTALL | HS_FLAG_UTF8, HS_FLAG_DOTALL | HS_FLAG_UTF8, HS_FLAG_DOTALL | HS_FLAG_UTF8, HS_FLAG_DOTALL | HS_FLAG_UTF8, HS_FLAG_DOTALL | HS_FLAG_UTF8}; unsigned int ids[6] = {0, 1, 2, 3, 4, 5}; hs_database_t *db = NULL; err = hs_compile_multi(expression, flags, ids, 6, HS_MODE_STREAM, NULL, &db, &compile_err); if (err != HS_SUCCESS) { MESA_handle_runtime_log(g_logger_handle, RLOG_LV_FATAL, "PKT_SEQ_MATCHER", "compile failed: %d:%s, pattern:%s", compile_err->expression, compile_err->message, expression[compile_err->expression]); hs_free_compile_error(compile_err); return -1; } psm_plugin_info->hs_database = db; MESA_handle_runtime_log(g_logger_handle, RLOG_LV_DEBUG, "PKT_SEQ_MATCHER", "hyperscan compile success"); return 0; } static void pkt_seq_matcher_exdata_free_cb(struct session *sess, int idx, void *ex_ptr, void *arg) { UNUSED(sess); UNUSED(idx); UNUSED(arg); if (ex_ptr == NULL) { return; } struct pkt_seq_matcher_ctx *ctx = (struct pkt_seq_matcher_ctx *)ex_ptr; hs_close_stream(ctx->hs_stream, hs_scratch, NULL, NULL); free(ex_ptr); } int pkt_seq_matcher_entry(struct session *session, int events, const struct packet *pkt, void *cb_arg) { if (pkt == NULL) { return 0; } struct pkt_seq_matcher_plugin_info *psm_plugin_info = (struct pkt_seq_matcher_plugin_info *)cb_arg; struct pkt_seq_matcher_ctx *ctx = (struct pkt_seq_matcher_ctx *)session_get_ex_data(session, psm_plugin_info->sess_ctx_exdata_idx); size_t payload_len = 0; int pkt_direction; if (ctx == NULL) { ctx = (struct pkt_seq_matcher_ctx *)calloc(1, sizeof(struct pkt_seq_matcher_ctx)); session_set_ex_data(session, psm_plugin_info->sess_ctx_exdata_idx, ctx); if (hs_scratch == NULL) { hs_error_t err = hs_alloc_scratch(psm_plugin_info->hs_database, &hs_scratch); if (err != HS_SUCCESS) { MESA_handle_runtime_log(g_logger_handle, RLOG_LV_FATAL, "PKT_SEQ_MATCHER", "alloc for scratch failed"); goto DETACH_SESSION; } } hs_error_t err = hs_open_stream(psm_plugin_info->hs_database, 0, &ctx->hs_stream); if (err != HS_SUCCESS) { MESA_handle_runtime_log(g_logger_handle, RLOG_LV_FATAL, "PKT_SEQ_MATCHER", "%s: open stream failed", session_get0_readable_addr(session)); goto DETACH_SESSION; } } session_get0_current_payload(session, &payload_len); if (payload_len == 0) { return 0; } pkt_direction = packet_get_direction(pkt); MESA_handle_runtime_log(g_logger_handle, RLOG_LV_DEBUG, "PKT_SEQ_MATCHER", "%s: payload_len: %d", pkt_direction == PACKET_DIRECTION_C2S ? "C2S" : "S2C", payload_len); if (pkt_direction == PACKET_DIRECTION_S2C) { payload_len += 1460; } memset(unicode_charactor, 0, sizeof(unicode_charactor)); encode_utf8(payload_len, unicode_charactor); if (hs_scan_stream(ctx->hs_stream, (const char *)unicode_charactor, strlen(unicode_charactor), 0, hs_scratch, eventHandler, ctx) != HS_SUCCESS) { MESA_handle_runtime_log(g_logger_handle, RLOG_LV_FATAL, "PKT_SEQ_MATCHER", "%s: scan failed, pkt_len: %d", session_get0_readable_addr(session), payload_len); } if (ctx->match_flag == 1) { MESA_handle_runtime_log(g_logger_handle, RLOG_LV_DEBUG, "PKT_SEQ_MATCHER", "%s: match success", session_get0_readable_addr(session)); goto DETACH_SESSION; } return 0; DETACH_SESSION: struct session_event *i_ev = session_get_intrinsic_event(session, psm_plugin_info->plugin_id); session_event_assign(i_ev, psm_plugin_info->st, session, 0, pkt_seq_matcher_entry, psm_plugin_info); return 0; } extern "C" void *pkt_seq_matcher_plugin_init(struct stellar *st) { char log_path[128]={0}; struct pkt_seq_matcher_plugin_info *psm_plugin_info = (struct pkt_seq_matcher_plugin_info *)calloc(1, sizeof(struct pkt_seq_matcher_plugin_info)); psm_plugin_info->st = st; psm_plugin_info->sess_ctx_exdata_idx = stellar_session_get_ex_new_index(st, "PKT_SEQ_matcher_SESS_CTX", pkt_seq_matcher_exdata_free_cb, NULL); MESA_load_profile_int_def(CFG_FILE_PATH, "PKT_SEQ_matcher","LOG_LEVEL", &g_log_level, 30); MESA_load_profile_string_def(CFG_FILE_PATH, "PKT_SEQ_matcher","LOG_PATH", log_path, sizeof(log_path), "log/pkt_seq_matcher"); g_logger_handle = MESA_create_runtime_log_handle(log_path, g_log_level); if(g_logger_handle == NULL) { printf("MESA_create_runtime_log object failed ...\n"); goto ERROR; } if (pkt_seq_matcher_hyperscan_init(psm_plugin_info) != 0) { goto ERROR; } psm_plugin_info->plugin_id = stellar_plugin_register(st, (SESS_EV_TCP|SESS_EV_UDP|SESS_EV_OPENING|SESS_EV_PACKET|SESS_EV_CLOSING), pkt_seq_matcher_entry, psm_plugin_info); return psm_plugin_info; ERROR: if (psm_plugin_info != NULL) { free(psm_plugin_info); } return NULL; } extern "C" void pkt_seq_matcher_plugin_exit(void *plugin_ctx) { if (plugin_ctx == NULL) { return; } struct pkt_seq_matcher_plugin_info *psm_plugin_info = (struct pkt_seq_matcher_plugin_info *)plugin_ctx; MESA_destroy_runtime_log_handle(g_logger_handle); hs_free_database(psm_plugin_info->hs_database); free(plugin_ctx); return; }