From 0db794c48ecc68921539d14ca040934d25d3c462 Mon Sep 17 00:00:00 2001 From: fengweihao Date: Thu, 18 Jun 2020 19:36:10 +0800 Subject: [PATCH] =?UTF-8?q?TSG-2071=20=E7=AE=A1=E6=8E=A7=E7=AD=96=E7=95=A5?= =?UTF-8?q?=E5=BC=95=E7=94=A8subid=E6=97=A0=E6=B3=95=E5=91=BD=E4=B8=AD=20*?= =?UTF-8?q?=E9=99=90=E6=B5=81=E9=9D=99=E6=80=81=E5=BA=93=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=20*Ip=E5=BD=92=E5=B1=9E=E5=9C=B0=E6=97=A5=E5=BF=97=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E4=BF=AE=E6=94=B9=20*Maat=E5=A2=9E=E5=8A=A0Deffered?= =?UTF-8?q?=E5=BC=80=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugin/business/pangu-http/src/pangu_http.cpp | 68 +++++++++++++++--- plugin/business/traffic-mirror/src/entry.cpp | 4 +- vendor/CMakeLists.txt | 2 +- vendor/ratelimiter-1.1.0-x86_64.tar.gz | Bin 5061 -> 5604 bytes 4 files changed, 64 insertions(+), 10 deletions(-) diff --git a/plugin/business/pangu-http/src/pangu_http.cpp b/plugin/business/pangu-http/src/pangu_http.cpp index 4951ca8..7a9d567 100644 --- a/plugin/business/pangu-http/src/pangu_http.cpp +++ b/plugin/business/pangu-http/src/pangu_http.cpp @@ -199,7 +199,7 @@ static Maat_feather_t create_maat_feather(const char * instance_name, const char char redis_port_range[TFE_STRING_MAX] = {0}; char accept_tags[TFE_STRING_MAX] = {0}; int redis_port_begin=0, redis_port_end=0; - int redis_port_select=0; + int redis_port_select=0, deferred_load_on=0; int redis_db_idx = 0; char json_cfg_file[TFE_STRING_MAX] = {0}, maat_stat_file[TFE_STRING_MAX] = {0}; MESA_load_profile_int_def(profile, section, "maat_input_mode", &(input_mode), 0); @@ -234,6 +234,7 @@ static Maat_feather_t create_maat_feather(const char * instance_name, const char MESA_load_profile_string_def(profile, section, "stat_file", maat_stat_file, sizeof(maat_stat_file), ""); MESA_load_profile_int_def(profile, section, "effect_interval_s", &(effect_interval), 60); + MESA_load_profile_int_def(profile, section, "deferred_load_on", &(deferred_load_on), 0); effect_interval *= 1000;//convert s to ms assert(strlen(inc_cfg_dir) != 0 || strlen(ful_cfg_dir) != 0 || strlen(redis_server)!=0 || strlen(json_cfg_file)!=0); @@ -269,6 +270,7 @@ static Maat_feather_t create_maat_feather(const char * instance_name, const char Maat_set_feather_opt(target, MAAT_OPT_PERF_ON, NULL, 0); } } + Maat_set_feather_opt(target, MAAT_OPT_DEFERRED_LOAD, &deferred_load_on, sizeof(deferred_load_on)); Maat_set_feather_opt(target, MAAT_OPT_EFFECT_INVERVAL_MS, &effect_interval, sizeof(effect_interval)); Maat_set_feather_opt(target, MAAT_OPT_SCAN_DETAIL, &scan_detail, sizeof(scan_detail)); @@ -876,6 +878,43 @@ int maat_table_init(const char* table_name, return table_id; } +static char* tfe_unescape(char* s) +{ + int i=0,j=0; + int len=strlen(s); + for(i=0,j=0;ilocal_logger, "Policy table parse ip ASN failed, ret:%d, %s", ret, table_line); return; } + tfe_unescape(organization); struct ip_data_table* ip_asn=ALLOC(struct ip_data_table, 1); memset(ip_asn, 0, sizeof(struct ip_data_table)); @@ -923,6 +963,10 @@ void ip_location_table_new_cb(int table_id, const char* key, const char* table_l TFE_LOG_ERROR(g_pangu_rt->local_logger, "Policy table parse ip location failed, ret:%d, %s", ret, table_line); return; } + tfe_unescape(continent_full); + tfe_unescape(country_full); + tfe_unescape(province_full); + tfe_unescape(city_full); struct ip_data_table* ip_asn=ALLOC(struct ip_data_table, 1); memset(ip_asn, 0, sizeof(struct ip_data_table)); @@ -1118,7 +1162,6 @@ int pangu_policy_init(const char* profile_path, const char* static_section, cons goto error_out; } } - for(int i = POLICY_ASN_USER_DEFINED; i < POLICY_PROFILE_TABLE_MAX; i++) { ret = maat_ip_table_init(i, ip_table_free_cb, ip_table_dup_cb); @@ -1127,7 +1170,6 @@ int pangu_policy_init(const char* profile_path, const char* static_section, cons goto error_out; } } - g_pangu_rt->dyn_maat = create_maat_feather("dyn", profile_path, dynamic_section, g_pangu_rt->thread_num, g_pangu_rt->local_logger); if (!g_pangu_rt->maat) { @@ -2758,6 +2800,8 @@ int http_ip_location_scan(struct Maat_rule_t *result, struct ip_address *sip, st { hit_cnt+=scan_ret; } + memset(buff,0,sizeof(buff)); + snprintf(buff, sizeof(buff), "%s,%s,%s", ip_location_server->city_full, ip_location_server->province_full, ip_location_server->country_full); ctx->ip_ctx.location_server=tfe_strdup(buff); } if(ip_location_client!=NULL) @@ -2771,6 +2815,8 @@ int http_ip_location_scan(struct Maat_rule_t *result, struct ip_address *sip, st { hit_cnt+=scan_ret; } + memset(buff,0,sizeof(buff)); + snprintf(buff, sizeof(buff), "%s,%s,%s", ip_location_client->city_full, ip_location_client->province_full, ip_location_client->country_full); ctx->ip_ctx.location_client=tfe_strdup(buff); } @@ -2784,6 +2830,7 @@ int http_ip_location_scan(struct Maat_rule_t *result, struct ip_address *sip, st int http_ip_asn_scan(struct Maat_rule_t *result, struct ip_address* sip, struct ip_address* dip, int hit_cnt, unsigned int thread_id, struct pangu_http_ctx * ctx) { int scan_ret=0; + char buff[TFE_STRING_MAX]={0}; struct ip_data_table* ip_asn_client=NULL, *ip_asn_server=NULL; Maat_ip_plugin_get_EX_data(g_pangu_rt->maat, g_pangu_rt->plolicy_table_id[POLICY_ASN_USER_DEFINED], sip, (void **)&ip_asn_client, 1); @@ -2809,7 +2856,8 @@ int http_ip_asn_scan(struct Maat_rule_t *result, struct ip_address* sip, struct { hit_cnt+=scan_ret; } - ctx->ip_ctx.asn_server=tfe_strdup(ip_asn_server->asn); + snprintf(buff, sizeof(buff), "%s(%s)", ip_asn_server->asn, ip_asn_server->organization); + ctx->ip_ctx.asn_server=tfe_strdup(buff); } if(ip_asn_client!=NULL) { @@ -2821,7 +2869,8 @@ int http_ip_asn_scan(struct Maat_rule_t *result, struct ip_address* sip, struct { hit_cnt+=scan_ret; } - ctx->ip_ctx.asn_client=tfe_strdup(ip_asn_client->asn); + snprintf(buff, sizeof(buff), "%s(%s)", ip_asn_client->asn, ip_asn_client->organization); + ctx->ip_ctx.asn_client=tfe_strdup(buff); } if(ip_asn_server) ip_table_free(ip_asn_server); @@ -2901,9 +2950,12 @@ void pangu_on_http_begin(const struct tfe_stream * stream, } addr_tfe2sapp(stream->addr, &sapp_addr); - hit_cnt += Maat_scan_proto_addr(g_pangu_rt->maat, g_pangu_rt->scan_table_id[PXY_CTRL_IP], &sapp_addr, 0, - result+hit_cnt, MAX_SCAN_RESULT-hit_cnt, &(ctx->scan_mid), (int) thread_id); - + scan_ret = Maat_scan_proto_addr(g_pangu_rt->maat, g_pangu_rt->scan_table_id[PXY_CTRL_IP], &sapp_addr, 0, + result+hit_cnt, MAX_SCAN_RESULT-hit_cnt, &(ctx->scan_mid), (int) thread_id); + if(scan_ret>0) + { + hit_cnt+=scan_ret; + } if (hit_cnt > 0) { ctx->action = decide_ctrl_action(result, hit_cnt, &ctx->enforce_rules, &ctx->n_enforce, &ctx->param); diff --git a/plugin/business/traffic-mirror/src/entry.cpp b/plugin/business/traffic-mirror/src/entry.cpp index c338698..ff68ea7 100644 --- a/plugin/business/traffic-mirror/src/entry.cpp +++ b/plugin/business/traffic-mirror/src/entry.cpp @@ -339,7 +339,7 @@ static Maat_feather_t maat_feather_create_with_override(const char * instance_na char redis_port_range[TFE_STRING_MAX] = {0}; char accept_tags[TFE_STRING_MAX] = {0}; int redis_port_begin = 0, redis_port_end = 0; - int redis_port_select = 0; + int redis_port_select = 0, deferred_load_on=0; int redis_db_idx = 0; char json_cfg_file[TFE_STRING_MAX] = {0}; @@ -354,6 +354,7 @@ static Maat_feather_t maat_feather_create_with_override(const char * instance_na MESA_load_profile_string_def(profile, section, "maat_redis_server", redis_server, sizeof(redis_server), ""); MESA_load_profile_string_def(profile, section, "maat_redis_port_range", redis_port_range, sizeof(redis_server), "6379"); + MESA_load_profile_int_def(profile, section, "deferred_load_on", &(deferred_load_on), 0); ret = sscanf(redis_port_range, "%d-%d", &redis_port_begin, &redis_port_end); if (ret == 1) @@ -414,6 +415,7 @@ static Maat_feather_t maat_feather_create_with_override(const char * instance_na } } + Maat_set_feather_opt(target, MAAT_OPT_DEFERRED_LOAD, &deferred_load_on, sizeof(deferred_load_on)); Maat_set_feather_opt(target, MAAT_OPT_EFFECT_INVERVAL_MS, &effect_interval, sizeof(effect_interval)); Maat_set_feather_opt(target, MAAT_OPT_SCAN_DETAIL, &scan_detail, sizeof(scan_detail)); if (strlen(accept_tags) > 0) diff --git a/vendor/CMakeLists.txt b/vendor/CMakeLists.txt index b897f49..70d764b 100644 --- a/vendor/CMakeLists.txt +++ b/vendor/CMakeLists.txt @@ -97,7 +97,7 @@ set_property(TARGET nghttp2-static APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ### ratelimiter ExternalProject_Add(ratelimiter PREFIX ratelimiter URL ${CMAKE_CURRENT_SOURCE_DIR}/ratelimiter-1.1.0-x86_64.tar.gz - URL_MD5 4e5d01586fef4165c4dfd1f1a3595e61 + URL_MD5 6e4b9b31c70b9e84e2a6434fab6268f9 CONFIGURE_COMMAND "" BUILD_COMMAND make BUILD_IN_SOURCE 1) diff --git a/vendor/ratelimiter-1.1.0-x86_64.tar.gz b/vendor/ratelimiter-1.1.0-x86_64.tar.gz index d127dccf27c358c054ae3a237162c25e4aea5f83..2a304ad439fe0559f4496fe9fc6efa783c03acea 100644 GIT binary patch literal 5604 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 literal 5061 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