/* * author:yangwei * create time:2021-8-21 * */ #pragma GCC diagnostic ignored "-Wunused-parameter" #include #include #include #include #include "app_l7_protocol.h" #include "cjson/cJSON.h" //#include "MESA_prof_load.h" #include "stellar/stellar.h" #include "stellar/session.h" #include "stellar/stellar_exdata.h" #include "stellar/stellar_mq.h" struct app_test_para { cJSON *test_result_root; cJSON *load_result_root; int result_count; }; struct app_test_para g_test_para={}; static int commit_test_result_json(struct app_test_para *para, cJSON *node, const char *name); struct app_test_plugin_env { int test_exdata_idx; int l7_exdata_idx; int test_app_plugin_id; struct stellar *st; }; #define MAX_PROTO_ID_NUM 10000 static char *g_proto_id2name[MAX_PROTO_ID_NUM]; static int load_l7_protocol_mapper(const char *filename) { memset(g_proto_id2name, 0, sizeof(g_proto_id2name)); int ret=0, proto_id=0;; FILE *fp=NULL; char line[1024]={0}; char type_name[32]={0}; char proto_name[32]={0}; fp=fopen(filename, "r"); if(fp==NULL) { printf("Open %s failed ...", filename); return -1; } memset(line, 0, sizeof(line)); while((fgets(line, sizeof(line), fp))!=NULL) { if(line[0]=='#' || line[0]=='\n' || line[0]=='\r' ||line[0]=='\0') { continue; } ret=sscanf(line, "%31s %31s %d", type_name, proto_name, &proto_id); assert(ret==3 && proto_id < MAX_PROTO_ID_NUM); g_proto_id2name[proto_id] = (char*)calloc(strlen(proto_name)+1, 1); strcpy(g_proto_id2name[proto_id], proto_name); memset(line, 0, sizeof(line)); } fclose(fp); fp=NULL; return ret; } static void commit_test_result(struct app_test_plugin_env *env, cJSON *ctx, struct session *sess) { assert(env->l7_exdata_idx >= 0 && ctx != NULL); struct l7_protocol_label *label = (struct l7_protocol_label *)session_exdata_get(sess, env->l7_exdata_idx);; if(label != NULL) { int proto_ids[8]; const char* proto_names[8]; for(int i = 0; i < label->protocol_id_num; i++) { proto_ids[i] = (int)(label->protocol_id[i]); proto_names[i] = g_proto_id2name[proto_ids[i]]; } cJSON *label_ids = cJSON_CreateIntArray(proto_ids, label->protocol_id_num); cJSON_AddItemToObject(ctx, "l7_label_id", label_ids); cJSON *label_names = cJSON_CreateStringArray(proto_names, label->protocol_id_num); cJSON_AddItemToObject(ctx, "l7_label_name", label_names); } else { cJSON_AddStringToObject(ctx, "l7_label_id", "UNKNOWN"); } unsigned char dir_flag; int is_symmetric=session_is_symmetric(sess, &dir_flag); if(is_symmetric) { cJSON_AddStringToObject(ctx, "STREAM_DIR", "DOUBLE"); } else if(dir_flag == SESSION_SEEN_C2S_FLOW) { cJSON_AddStringToObject(ctx, "STREAM_DIR", "C2S"); } else if(dir_flag == SESSION_SEEN_S2C_FLOW) { cJSON_AddStringToObject(ctx, "STREAM_DIR", "S2C"); } else { assert(0); } if (ctx) { char result_name[128] = ""; sprintf(result_name, "APP_PROTO_IDENTIFY_RESULT_%d", g_test_para.result_count); commit_test_result_json(&g_test_para, ctx, result_name); g_test_para.result_count += 1; } return; } void *APP_TEST_CTX_NEW(struct session *sess, void *plugin_env) { cJSON *ctx =cJSON_CreateObject(); cJSON_AddStringToObject(ctx, "Tuple4", session_get0_readable_addr(sess)); enum session_type type= session_get_type(sess); if (type == SESSION_TYPE_TCP) { cJSON_AddStringToObject(ctx, "STREAM_TYPE", "TCP"); } if (type == SESSION_TYPE_UDP) { cJSON_AddStringToObject(ctx, "STREAM_TYPE", "UDP"); } return ctx; } void APP_TEST_CTX_FREE(struct session *sess, void *session_ctx, void *plugin_env) { cJSON *ctx = (cJSON *)session_ctx; commit_test_result((struct app_test_plugin_env*)plugin_env, ctx, sess); return; } static void APP_TEST_ON_SESSION_MSG(struct session *sess, int topic_id, const void *msg, void *per_session_ctx, void *plugin_env) { return; } extern "C" void *APP_TEST_PLUG_INIT(struct stellar *st) { struct app_test_plugin_env *env = (struct app_test_plugin_env *)calloc(1, sizeof(struct app_test_plugin_env)); env->st=st; //const char *l7_label_name=(const char*)"L7_PROTOCOL_LABEL"; //const char *l7_bridge_name=(const char*)"APP_BRIDGE"; const char *l7_proto_name=(const char*)"./tsgconf/tsg_l7_protocol.conf"; //MESA_load_profile_string_def("./tsgconf/main.conf", "SYSTEM", "L7_LABEL_NAME", l7_label_name, sizeof(l7_label_name), "L7_PROTOCOL_LABEL"); //MESA_load_profile_string_def("./tsgconf/main.conf", "SYSTEM", "APP_BRIDGE_NAME", l7_bridge_name, sizeof(l7_bridge_name), "APP_BRIDGE"); //MESA_load_profile_string_def("./tsgconf/main.conf", "SYSTEM", "L7_PROTOCOL_FILE", l7_proto_name, sizeof(l7_proto_name), "./tsgconf/tsg_l7_protocol.conf"); env->l7_exdata_idx= stellar_exdata_new_index(st, "L7_PROTOCOL", stellar_exdata_free_default, NULL); env->test_exdata_idx= stellar_exdata_new_index(st, "APP_PROTO_TEST", stellar_exdata_free_default, NULL); if(env->l7_exdata_idx<0 || env->test_exdata_idx<0) { printf("APP_PROTO_IDENTIFY_TEST_PLUG_INIT:stellar_session_get_ex_new_index faild!!!\n"); exit(-1); } int ret = load_l7_protocol_mapper(l7_proto_name); if(ret<0) { printf("APP_PROTO_IDENTIFY_TEST_PLUG_INIT:l7_protocol_mapper failed !!!\n"); exit(-1); } env->test_app_plugin_id=stellar_session_plugin_register(st, APP_TEST_CTX_NEW, APP_TEST_CTX_FREE, env); if(env->test_app_plugin_id < 0) { printf("APP_PROTO_IDENTIFY_TEST_PLUG_INIT:stellar_plugin_register failed !!!\n"); exit(-1); } int tcp_topic_id=stellar_mq_get_topic_id(st, TOPIC_TCP); int udp_topic_id=stellar_mq_get_topic_id(st, TOPIC_UDP); if(tcp_topic_id < 0 || udp_topic_id < 0) { perror("get tcp or udp topic id failed\n"); exit(-1); } stellar_session_mq_subscribe(st, tcp_topic_id, APP_TEST_ON_SESSION_MSG, env->test_app_plugin_id); stellar_session_mq_subscribe(st, udp_topic_id, APP_TEST_ON_SESSION_MSG, env->test_app_plugin_id); printf("APP_PROTO_IDENTIFY_TEST_PLUG_INIT OK!\n"); return env; } extern "C" void APP_TEST_PLUG_DESTROY(void *ctx) { struct app_test_plugin_env *env = (struct app_test_plugin_env *)ctx; free(env); printf("APP_PROTO_IDENTIFY_TEST_PLUG_DESTROY OK!\n"); return ; } #include #include "stellar/stellar.h" static int commit_test_result_json(struct app_test_para *para, cJSON *node, const char *name) { assert(node != NULL || name != NULL || para != NULL); if(para->test_result_root) { //cJSON_AddItemToObject(g_test_result_root, name, node); cJSON_AddStringToObject(node, "name", name); cJSON_AddItemToArray(para->test_result_root, node); return 0; } return -1; } static cJSON *load_result_from_jsonfile(const char *json_path) { if(json_path == NULL)return NULL; long file_len = 0; char *file_content = NULL; FILE *fp = NULL; fp = fopen(json_path, "r+"); if (NULL == fp) { return NULL; } fseek(fp, 0, SEEK_END); file_len = ftell(fp); fseek(fp, 0, SEEK_SET); if (file_len == 0) { fclose(fp); return NULL; } file_content = (char *) malloc(file_len + 1); fread(file_content, file_len, 1, fp); file_content[file_len] = '\0'; cJSON *load = cJSON_Parse(file_content); free(file_content); fclose(fp); return load; } static int app_test_para_start(struct app_test_para *para, const char *load_json_path) { para->test_result_root = cJSON_CreateArray(); para->load_result_root = load_result_from_jsonfile(load_json_path); para->result_count=1;//count start from 1 return 0; } static int app_test_para_finish(struct app_test_para *para) { if(para==NULL)return -1; if(para->test_result_root==NULL || para->load_result_root==NULL)return -1; int ret=-1; if(cJSON_GetArraySize(para->test_result_root)!=cJSON_GetArraySize(para->load_result_root)) { char *load_json_str = cJSON_Print(para->load_result_root); printf("LOAD Raw:\n%s\n", load_json_str); free(load_json_str); char *result_json_str = cJSON_Print(para->test_result_root); printf("TEST Raw:\n%s\n", result_json_str); free(result_json_str); ret=-1; goto error_out; } ret = cJSON_Compare(para->load_result_root, para->test_result_root, 0); if (ret != 1) { char *load_json_str = cJSON_Print(para->load_result_root); printf("LOAD Raw:\n%s\n", load_json_str); free(load_json_str); char *result_json_str = cJSON_Print(para->test_result_root); printf("TEST Raw:\n%s\n", result_json_str); free(result_json_str); cJSON *t_load = para->load_result_root->child, *t_test = para->test_result_root->child; while (t_load != NULL) { // print first diff item, then return; if(1 != cJSON_Compare(t_load, t_test, 0)) { load_json_str = cJSON_Print(t_load); printf("LOAD Diff:\n%s\n", load_json_str); free(load_json_str); result_json_str = cJSON_Print(t_test); printf("TEST Diff:\n%s\n", result_json_str); free(result_json_str); goto error_out; } t_load = t_load->next; t_test = t_test->next; } } error_out: if(para->test_result_root)cJSON_Delete(para->test_result_root); if(para->load_result_root)cJSON_Delete(para->load_result_root); return ret; } /********************************************** * GTEST MAIN * **********************************************/ #define RESULT_JSON_DIR_NAME "test_result_json" #define TEST_ENV_DIR_NAME "test_env" const char *g_test_dir=NULL; #include char g_cwd[PATH_MAX]; #include static inline void system_cmd(const char *cmd, ...) { char buf[4096] = {0}; va_list args; va_start(args, cmd); vsnprintf(buf, sizeof(buf), cmd, args); va_end(args); system(buf); } class gtest_glimpse_detector : public ::testing::Test { protected: char result_json_path[4096] = {0}; char pcap_path[4096] = {0}; // Constructor should be default; static members should be set externally gtest_glimpse_detector() = default; void SetUp() override { chdir(g_cwd); std::cout << "SetUpTestCase called for work_dir: " << g_test_dir<< std::endl; system_cmd("mkdir -p ./conf/"); system_cmd("mkdir -p ./log/ "); system_cmd("mkdir -p ./plugin"); system_cmd("mkdir -p ./tsgconf/"); system_cmd("cp %s/%s/tsg_l7_protocol.conf ./tsgconf/tsg_l7_protocol.conf", g_test_dir, TEST_ENV_DIR_NAME); system_cmd("cp %s/%s/stellar.toml ./conf/stellar.toml", g_test_dir, TEST_ENV_DIR_NAME); system_cmd("cp %s/%s/log.toml ./conf/log.toml", g_test_dir, TEST_ENV_DIR_NAME); system_cmd("cp %s/%s/spec.toml ./plugin/spec.toml", g_test_dir, TEST_ENV_DIR_NAME); // Retrieve current test info const ::testing::TestInfo* test_info = ::testing::UnitTest::GetInstance()->current_test_info(); std::cout << "Setting up test environment for test case: " << test_info->test_case_name() << " in work_dir: " << g_test_dir << std::endl; // Initialize paths based on test case name and arguments memset(&g_test_para, 0, sizeof(struct app_test_para)); snprintf(result_json_path, sizeof(result_json_path), "%s/%s/%s.json", g_test_dir, RESULT_JSON_DIR_NAME, test_info->name()); snprintf(pcap_path, sizeof(pcap_path), "%s/%s", g_test_dir, test_info->name()); std::cout << "result_json_path: " << result_json_path << std::endl; std::cout << "pcap_path: " << pcap_path << std::endl; system_cmd("tomlq -t -i '.packet_io.dumpfile_dir = \"%s\" ' ./conf/stellar.toml", pcap_path); system_cmd("pwd"); system_cmd("cat ./conf/stellar.toml"); } }; TEST_F(gtest_glimpse_detector, app_pcap) { app_test_para_start(&g_test_para, result_json_path); stellar_run(0, NULL); EXPECT_EQ(app_test_para_finish(&g_test_para), 1); } TEST_F(gtest_glimpse_detector, dns_pcap) { app_test_para_start(&g_test_para, result_json_path); stellar_run(0, NULL); EXPECT_EQ(app_test_para_finish(&g_test_para), 1); } TEST_F(gtest_glimpse_detector, mixed_pcap) { app_test_para_start(&g_test_para, result_json_path); stellar_run(0, NULL); EXPECT_EQ(app_test_para_finish(&g_test_para), 1); } TEST_F(gtest_glimpse_detector, openvpn_pcap) { app_test_para_start(&g_test_para, result_json_path); stellar_run(0, NULL); EXPECT_EQ(app_test_para_finish(&g_test_para), 1); } TEST_F(gtest_glimpse_detector, ppp_pcap) { app_test_para_start(&g_test_para, result_json_path); stellar_run(0, NULL); EXPECT_EQ(app_test_para_finish(&g_test_para), 1); } TEST_F(gtest_glimpse_detector, socks_pcap) { app_test_para_start(&g_test_para, result_json_path); stellar_run(0, NULL); EXPECT_EQ(app_test_para_finish(&g_test_para), 1); } int main(int argc, char ** argv) { if(argc != 2) { printf("Invalid Argument!!!\n Usage: ./[gtest_main] [/path/to/glimpse_detector_test_dir] \n"); return -1; } getcwd(g_cwd, sizeof(g_cwd)); ::testing::InitGoogleTest(&argc, argv); g_test_dir=argv[1]; return RUN_ALL_TESTS(); }