#include "tsg_proxy_logger.h" #include "edit_element.h" #include "pattern_replace.h" #include "http_lua.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_EDIT_ZONE_NUM 64 #define MAX_SCAN_DATA_SIZE ((1 << 16) - 1) enum proxy_action { PX_ACTION_NONE = 0, PX_ACTION_ALLOW = 1, PX_ACTION_DENY = 2, PX_ACTION_MONITOR = 3, PX_ACTION_REDIRECT = 4, PX_ACTION_EXECUTE = 5, PX_ACTION_MANIPULATE = 6, __PX_ACTION_MAX }; enum manipulate_action { MA_ACTION_REPLACE_TEXT, MA_ACTION_REPLACE_FILE, MA_ACTION_EDIT_ELEMENT, MA_ACTION_INJECT_JAVESCRIPT, MA_ACTION_INJECT_CSS, __MA_ACTION_MAX }; enum scan_table { PXY_CTRL_HTTP_URL, PXY_CTRL_HTTP_FQDN, PXY_CTRL_HTTP_REQ_HDR, PXY_CTRL_HTTP_REQ_BODY, PXY_CTRL_HTTP_RES_HDR, PXY_CTRL_HTTP_RES_BODY, PXY_CTRL_APP_ID, __SCAN_TABLE_MAX }; enum proxy_http_stat { STAT_SESSION, STAT_LOG_NUM, STAT_ACTION_MONIT, STAT_ACTION_REJECT, STAT_ACTION_REDIRECT, STAT_ACTION_REPLACE, STAT_ACTION_HIJACK, STAT_ACTION_HIJACK_SZ, STAT_ACTION_INSERT, STAT_ACTION_INSERT_SZ, STAT_ACTION_EDIT_ELEMENT, STAT_ACTION_RUN_SCRIPT, STAT_ACTION_WHITELSIT, STAT_SUSPENDING, __PX_STAT_MAX }; enum manipulate_profile_table { POLICY_PROFLIE_TABLE_REJECT, POLICY_PROFILE_TABLE_JS, POLICY_PROFILE_TABLE_CSS, POLICY_PROFILE_TABLE_HIJACK, POLICY_PROFILE_TABLE_LUA, POLICY_PROFILE_TABLE_MAX }; struct manipulate_profile { char *profile_uuid; int ref_cnt; size_t msg_len; char *profile_name; char *profile_msg; char *profile_type; char *profile_position; struct elua_script **escript_ctx; int timeout; ctemplate::Template * tpl; pthread_mutex_t lock; }; struct maat_rule_t { int vsys_id; uuid_t config_uuid; char *config_uuid_string; int service_id; unsigned char do_log; unsigned char do_blacklist; unsigned char action; char *action_parameter; }; struct policy_action_param { int ref_cnt; enum manipulate_action action; char *message; char *position; float enforcement_ratio; char *profile_uuid_str; int status_code; size_t n_rule; struct replace_rule *repl_rule; size_t e_rule; struct edit_element_rule *elem_rule; struct maat_rule_t hit_rule; pthread_mutex_t lock; }; struct tsg_proxy_rt { struct maat *feather; struct proxy_logger * send_logger; void * local_logger; int thread_num; int scan_table_id[__SCAN_TABLE_MAX]; int plolicy_table_id[POLICY_PROFILE_TABLE_MAX]; ctemplate::Template * tpl_403, * tpl_404, * tpl_451; struct fieldstat_easy *fs_handle; long long stat_val[__PX_STAT_MAX]; int fs_id[__PX_STAT_MAX]; struct event_base* gc_evbase; struct event* gcev; struct tsg_lua_script lua_script; int enable_rate; int ctrl_plugin_idx; int ca_store_reseting; int enable_plugin; }; struct tsg_proxy_rt * g_proxy_rt; static void proxy_http_gc_cb(evutil_socket_t fd, short what, void *arg) { for (int i = 0; i < __PX_STAT_MAX; i++) { long long delta = ATOMIC_EXCHANGE(&(g_proxy_rt->stat_val[i]), 0); fieldstat_easy_counter_incrby(g_proxy_rt->fs_handle, 0, g_proxy_rt->fs_id[i], NULL, 0, delta); } } static void proxy_http_stat_init(struct tsg_proxy_rt * pangu_runtime) { int i=0; struct timeval gc_delay = {0, 500*1000}; //Microseconds, we set 500 miliseconds here. const char* spec[__PX_STAT_MAX]={0}; spec[STAT_SESSION]="http_sess"; spec[STAT_LOG_NUM]="log_num"; spec[STAT_ACTION_MONIT]="intcp_mon_num"; spec[STAT_ACTION_REJECT]="intcp_deny_num"; spec[STAT_ACTION_REDIRECT]="intcp_rdirt_num"; spec[STAT_ACTION_REPLACE]="intcp_repl_num"; spec[STAT_ACTION_HIJACK]="intcp_hijk_num"; spec[STAT_ACTION_HIJACK_SZ]="hijk_bytes"; spec[STAT_ACTION_INSERT]="intcp_ins_num"; spec[STAT_ACTION_INSERT_SZ]="ins_bytes"; spec[STAT_ACTION_EDIT_ELEMENT]="intcp_edit_elem_num"; spec[STAT_ACTION_RUN_SCRIPT]="intcp_rus_num"; spec[STAT_ACTION_WHITELSIT]="intcp_allow_num"; spec[STAT_SUSPENDING]="suspending"; for(i=0;i<__PX_STAT_MAX;i++) { if (spec[i] != NULL) { pangu_runtime->fs_id[i] = fieldstat_easy_register_counter(pangu_runtime->fs_handle, spec[i]); } } g_proxy_rt->gcev = event_new(pangu_runtime->gc_evbase, -1, EV_PERSIST, proxy_http_gc_cb, NULL); evtimer_add(g_proxy_rt->gcev, &gc_delay); return; } void increase_redirect_policy_hit_num(void) { ATOMIC_INC(&(g_proxy_rt->stat_val[STAT_ACTION_REDIRECT])); } void trusted_CA_update_start_cb(int update_type, void* u_para) { if(update_type==MAAT_UPDATE_TYPE_FULL) { if(g_proxy_rt->ca_store_reseting==0) { tfe_proxy_ssl_reset_trust_ca(); TFE_LOG_INFO(g_proxy_rt->local_logger, "Trusted CA Store Reset Start."); } g_proxy_rt->ca_store_reseting++; } } void trusted_CA_update_cert_cb(const char *table_name, const char *table_line, enum maat_operation op, void *u_para) { int ret = 0; cJSON* trust_ca_cert = cJSON_Parse(table_line); if(trust_ca_cert == NULL) { TFE_LOG_ERROR(g_proxy_rt->local_logger, "TRUSTED_CERTIFICATE_AUTHORITY parse table_line failed. table_line:%s", table_line); return; } char *uuid_sring=NULL; char cert_name[128]={0}, cert_file[1024]={0}; cJSON *uuid = cJSON_GetObjectItem(trust_ca_cert, "uuid"); if(uuid && uuid->type==cJSON_String) { uuid_sring = uuid->valuestring; } cJSON *item = cJSON_GetObjectItem(trust_ca_cert, "cert_name"); if(item && item->type==cJSON_String) { memcpy(cert_name, item->valuestring, strlen(item->valuestring)); } item = cJSON_GetObjectItem(trust_ca_cert, "cert_file"); if(item && item->type==cJSON_String) { memcpy(cert_file, item->valuestring, strlen(item->valuestring)); } if(op==MAAT_OP_ADD) { ret=tfe_proxy_ssl_add_trust_ca(cert_file); if(ret<0) { TFE_LOG_ERROR(g_proxy_rt->local_logger, "Trusted CA Store add cert failed %s:%s:%s", uuid_sring, cert_name, cert_file); } else { TFE_LOG_INFO(g_proxy_rt->local_logger, "Trusted CA Store add cert success %s:%s:%s", uuid_sring, cert_name, cert_file); } } else { ret=tfe_proxy_ssl_del_trust_ca(cert_file); if(ret<0) { TFE_LOG_ERROR(g_proxy_rt->local_logger, "Trusted CA Store del cert failed %s:%s:%s", uuid_sring, cert_name, cert_file); } else { TFE_LOG_INFO(g_proxy_rt->local_logger, "Trusted CA Store del cert success %s:%s:%s", uuid_sring, cert_name, cert_file); } } cJSON_Delete(trust_ca_cert); trust_ca_cert=NULL; return; } void trusted_CA_update_crl_cb(int table_id,const char* table_line,void* u_para) { int ret=0, crl_id=0, cert_id=0, is_valid=0; char crl_file[1024]={0}; ret=sscanf(table_line, "%d\t%d\t%s\t%d", &crl_id, &cert_id, crl_file, &is_valid); if(ret!=4) { TFE_LOG_ERROR(g_proxy_rt->local_logger, "Trusted CA Store parse crl config failed: %s", table_line); return; } if(is_valid==1) { ret=tfe_proxy_ssl_add_crl(crl_file); if(ret<0) { TFE_LOG_ERROR(g_proxy_rt->local_logger, "Trusted CA Store add crl failed %d:%d:%s", crl_id, cert_id, crl_file); } else { TFE_LOG_INFO(g_proxy_rt->local_logger, "Trusted CA Store add crl success %d:%d:%s", crl_id, cert_id, crl_file); } } else { ret=tfe_proxy_ssl_del_crl(crl_file); if(ret<0) { TFE_LOG_ERROR(g_proxy_rt->local_logger, "Trusted CA Store del crl failed %d:%d:%s", crl_id, cert_id, crl_file); } else { TFE_LOG_INFO(g_proxy_rt->local_logger, "Trusted CA Store del crl success %d:%d:%s", crl_id, cert_id, crl_file); } } return; } void trusted_CA_update_finish_cb(void* u_para) { if(g_proxy_rt->ca_store_reseting>0) { g_proxy_rt->ca_store_reseting--; if(g_proxy_rt->ca_store_reseting==0) { tfe_proxy_ssl_reset_trust_ca_finish(); TFE_LOG_INFO(g_proxy_rt->local_logger, "Trusted CA Store Reset Finish."); } } } static enum manipulate_action manipulate_action_str2idx(const char *action_str) { const char *clue_action_map[__MA_ACTION_MAX]; clue_action_map[MA_ACTION_REPLACE_TEXT]= "replace_text"; clue_action_map[MA_ACTION_REPLACE_FILE]= "replace_file"; clue_action_map[MA_ACTION_EDIT_ELEMENT]= "edit_element"; clue_action_map[MA_ACTION_INJECT_JAVESCRIPT]= "inject_javascript"; clue_action_map[MA_ACTION_INJECT_CSS]= "inject_css"; size_t i = 0; for (i = 0; i < sizeof(clue_action_map) / sizeof(const char *); i++) { if (0 == strcasecmp(action_str, clue_action_map[i])) break; } return (enum manipulate_action)i; } void octal_utf8_escapes(char *input) { #define AFMTSIZE (67+2+1+2) char afmt [AFMTSIZE]; int num,NConsumed,last,lbuf_sz=0; const char *fmt ="\\%3lo"; snprintf(afmt,AFMTSIZE,"%s%%n",fmt); char lbuf[1024]={0}; snprintf(lbuf, sizeof(lbuf), "%s", input); lbuf_sz = strlen(lbuf); last = lbuf_sz - 1; if(lbuf[last] == '\n') { lbuf[last] = '\0'; last--; } char *iptr = input; while (*iptr) { if((last = sscanf(iptr,afmt,&num, &NConsumed)) > 0) { putchar(num); iptr+=NConsumed; } else { iptr+=1; } } return; } char* str_unescape(char* s) { int i=0,j=0; int len=strlen(s); for(i=0,j=0;ihit_rule.action) { case PX_ACTION_REDIRECT: item=cJSON_GetObjectItem(action_parameter,"vsys_id"); if(item && item->type==cJSON_Number) { param->hit_rule.vsys_id=item->valueint; } item=cJSON_GetObjectItem(action_parameter,"code"); if(item && item->type==cJSON_Number) { param->status_code = item->valueint; } item=cJSON_GetObjectItem(action_parameter,"to"); if(item && item->type==cJSON_String) { param->message = tfe_strdup(item->valuestring); } item=cJSON_GetObjectItem(action_parameter,"enforcement_ratio"); if(item && item->type==cJSON_Number) { param->enforcement_ratio = item->valuedouble; } else { param->enforcement_ratio = 1; } break; case PX_ACTION_DENY: item=cJSON_GetObjectItem(action_parameter,"vsys_id"); if(item && item->type==cJSON_Number) { param->hit_rule.vsys_id=item->valueint; } item=cJSON_GetObjectItem(action_parameter,"code"); if(item && item->type==cJSON_Number) { param->status_code = item->valueint; } item=cJSON_GetObjectItem(action_parameter,"message"); if(item && item->type==cJSON_String) { param->message = tfe_strdup(item->valuestring); } item=cJSON_GetObjectItem(action_parameter,"html_profile"); if(item && item->type==cJSON_String) { param->profile_uuid_str = tfe_strdup(item->valuestring); } break; case PX_ACTION_EXECUTE: item=cJSON_GetObjectItem(action_parameter,"vsys_id"); if(item && item->type==cJSON_Number) { param->hit_rule.vsys_id=item->valueint; } item=cJSON_GetObjectItem(action_parameter,"lua_script"); if(item && item->type==cJSON_String) { param->profile_uuid_str =tfe_strdup(item->valuestring); } item=cJSON_GetObjectItem(action_parameter,"enforcement_ratio"); if(item && item->type==cJSON_Number) { param->enforcement_ratio = item->valuedouble; } else { param->enforcement_ratio = 1; } break; default: break; } return; } void policy_set_param_by_sub_action(struct policy_action_param* param, cJSON *action_parameter) { int rule_id=0; cJSON *rules=NULL, *item=NULL, *sub_item=NULL; switch(param->action) { case MA_ACTION_REPLACE_TEXT: item=cJSON_GetObjectItem(action_parameter,"vsys_id"); if(item && item->type==cJSON_Number) { param->hit_rule.vsys_id=item->valueint; } item=cJSON_GetObjectItem(action_parameter,"enforcement_ratio"); if(item && item->type==cJSON_Number) { param->enforcement_ratio = item->valuedouble; } else { param->enforcement_ratio = 1; } rules = cJSON_GetObjectItem(action_parameter, "rules"); if(rules == NULL) { break; } rule_id = 0; param->repl_rule = ALLOC(struct replace_rule, MAX_EDIT_ZONE_NUM); for (item = rules->child; item != NULL; item = item->next) { char * search = cJSON_GetObjectItem(item , "search_in")->valuestring; if (search == NULL) break; param->repl_rule[rule_id].zone = zone_name_to_id(search); if (param->repl_rule[rule_id].zone == kZoneMax) { break; } param->repl_rule[rule_id].find = tfe_strdup(cJSON_GetObjectItem(item , "find")->valuestring); octal_utf8_escapes(param->repl_rule[rule_id].find); param->repl_rule[rule_id].replace_with = tfe_strdup(cJSON_GetObjectItem(item , "replace_with")->valuestring); octal_utf8_escapes(param->repl_rule[rule_id].replace_with); rule_id++; } param->n_rule = rule_id; break; case MA_ACTION_REPLACE_FILE: item=cJSON_GetObjectItem(action_parameter,"vsys_id"); if(item && item->type==cJSON_Number) { param->hit_rule.vsys_id=item->valueint; } item=cJSON_GetObjectItem(action_parameter,"replacement_file"); if(item && item->type==cJSON_String) { param->profile_uuid_str =tfe_strdup(item->valuestring); } item=cJSON_GetObjectItem(action_parameter,"enforcement_ratio"); if(item && item->type==cJSON_Number) { param->enforcement_ratio = item->valuedouble; } else { param->enforcement_ratio = 1; } break; case MA_ACTION_INJECT_JAVESCRIPT: item=cJSON_GetObjectItem(action_parameter,"vsys_id"); if(item && item->type==cJSON_Number) { param->hit_rule.vsys_id=item->valueint; } item=cJSON_GetObjectItem(action_parameter,"js_file"); if(item && item->type==cJSON_String) { param->profile_uuid_str =tfe_strdup(item->valuestring); } item=cJSON_GetObjectItem(action_parameter,"injection_section"); if(item && item->type==cJSON_String){ param->position = tfe_strdup(item->valuestring); } item=cJSON_GetObjectItem(action_parameter,"enforcement_ratio"); if(item && item->type==cJSON_Number) { param->enforcement_ratio = item->valuedouble; } else { param->enforcement_ratio = 1; } break; case MA_ACTION_INJECT_CSS: item=cJSON_GetObjectItem(action_parameter,"vsys_id"); if(item && item->type==cJSON_Number) { param->hit_rule.vsys_id=item->valueint; } item=cJSON_GetObjectItem(action_parameter,"css_file"); if(item && item->type==cJSON_String) { param->profile_uuid_str =tfe_strdup(item->valuestring); } item=cJSON_GetObjectItem(action_parameter,"enforcement_ratio"); if(item && item->type==cJSON_Number) { param->enforcement_ratio = item->valuedouble; } else { param->enforcement_ratio = 1; } break; case MA_ACTION_EDIT_ELEMENT: item=cJSON_GetObjectItem(action_parameter,"vsys_id"); if(item && item->type==cJSON_Number) { param->hit_rule.vsys_id=item->valueint; } rules = cJSON_GetObjectItem(action_parameter, "rules"); if(rules == NULL) { break; } rule_id = 0; param->elem_rule = ALLOC(struct edit_element_rule, MAX_EDIT_ZONE_NUM); for (item = rules->child; item != NULL; item = item->next) { sub_item=cJSON_GetObjectItem(item,"anchor_element"); if(sub_item != NULL && sub_item->type ==cJSON_Object) { char * search_scope = cJSON_GetObjectItem(sub_item , "search_scope")->valuestring; if (search_scope == NULL) break; param->elem_rule[rule_id].scope = scope_name_to_id(search_scope); if (param->elem_rule[rule_id].scope == KScopeMax) { break; } if(param->elem_rule[rule_id].scope == kScopeInside) { param->elem_rule[rule_id].start_indicator = tfe_strdup(cJSON_GetObjectItem(sub_item , "start_indicator")->valuestring); } param->elem_rule[rule_id].contained_keyword = tfe_strdup(cJSON_GetObjectItem(sub_item,"contained_keyword")->valuestring); } sub_item=cJSON_GetObjectItem(item,"target_element"); if(sub_item != NULL && sub_item->type ==cJSON_Object) { param->elem_rule[rule_id].distane_from_matching = cJSON_GetObjectItem(sub_item , "target_distance_from_matching")->valueint; param->elem_rule[rule_id].element_treatment = tfe_strdup(cJSON_GetObjectItem(sub_item,"element_treatment")->valuestring); } rule_id++; } param->e_rule = rule_id; break; default: break; } return; } void policy_action_param_new(const char *table_name, const char* key, const char* table_line, void **ad, long argl, void* argp) { cJSON* pxy_ctrl_rule = cJSON_Parse(table_line); if(pxy_ctrl_rule == NULL) { TFE_LOG_ERROR(g_proxy_rt->local_logger, "PXY_CTRL_RULE parse table_line failed. table_line:%s", table_line); return; } struct policy_action_param* param=ALLOC(struct policy_action_param, 1); cJSON *uuid = cJSON_GetObjectItem(pxy_ctrl_rule, "uuid"); if(uuid && uuid->type==cJSON_String) { param->hit_rule.config_uuid_string = strdup(uuid->valuestring); uuid_parse(uuid->valuestring, param->hit_rule.config_uuid); } cJSON *action = cJSON_GetObjectItem(pxy_ctrl_rule, "action"); if(action && action->type==cJSON_String) { param->hit_rule.action=action_type_str2idx(action->valuestring); } cJSON *blacklist_option = cJSON_GetObjectItem(pxy_ctrl_rule, "blacklist_option"); if(blacklist_option && blacklist_option->type==cJSON_Number) { param->hit_rule.do_blacklist=blacklist_option->valueint; } cJSON *log_option = cJSON_GetObjectItem(pxy_ctrl_rule, "log_option"); if(log_option && log_option->type==cJSON_String) { param->hit_rule.do_log=log_option_type_str2idx(log_option->valuestring); } cJSON *action_parameter = cJSON_GetObjectItem(pxy_ctrl_rule, "action_parameter"); if(action_parameter == NULL || action_parameter->type!=cJSON_Object) { FREE(¶m); TFE_LOG_ERROR(g_proxy_rt->local_logger, "invalid policy parameter: id = %s", param->hit_rule.config_uuid_string); return; } param->ref_cnt=1; pthread_mutex_init(&(param->lock), NULL); param->hit_rule.action_parameter = cJSON_PrintUnformatted(action_parameter); policy_set_param_by_action(param, action_parameter); cJSON *method=cJSON_GetObjectItem(action_parameter, "sub_action"); if(method && method->type==cJSON_String) { param->action=manipulate_action_str2idx(method->valuestring); } policy_set_param_by_sub_action(param, action_parameter); *ad=param; TFE_LOG_INFO(g_proxy_rt->local_logger, "Add ctrl policy: %s", param->hit_rule.config_uuid_string); cJSON_Delete(pxy_ctrl_rule); return; } void policy_action_param_free_cb(const char *table_name, void **ad, long argl, void *argp) { unsigned int i=0; if(*ad==NULL) { return; } struct policy_action_param* param=(struct policy_action_param*)*ad; pthread_mutex_lock(&(param->lock)); param->ref_cnt--; if(param->ref_cnt>0) { pthread_mutex_unlock(&(param->lock)); return; } pthread_mutex_unlock(&(param->lock)); pthread_mutex_destroy(&(param->lock)); for(i=0; ie_rule; i++) { if(param->elem_rule[i].start_indicator!=NULL) { FREE(&(param->elem_rule[i].start_indicator)); } FREE(&(param->elem_rule[i].element_treatment)); FREE(&(param->elem_rule[i].contained_keyword)); } for(i=0; in_rule; i++) { FREE(&(param->repl_rule[i].find)); FREE(&(param->repl_rule[i].replace_with)); } if (param->elem_rule) FREE(&(param->elem_rule)); if (param->repl_rule) FREE(&(param->repl_rule)); if (param->message) FREE(&(param->message)); if (param->position) FREE(&(param->position)); if(param->profile_uuid_str) FREE(&(param->profile_uuid_str)); if(param->hit_rule.config_uuid_string) FREE(&(param->hit_rule.config_uuid_string)); if(param->hit_rule.action_parameter) FREE(¶m->hit_rule.action_parameter); FREE(&(param)); return; } void policy_action_param_free(struct policy_action_param* param) { policy_action_param_free_cb("PXY_CTRL_RULE_PLUGIN", (void**)¶m, 0, NULL); return; } void policy_action_param_dup(const char *table_name, void **to, void **from, long argl, void *argp) { struct policy_action_param* from_param=*((struct policy_action_param**)from); if(from_param==NULL) { *to=NULL; return; } pthread_mutex_lock(&(from_param->lock)); from_param->ref_cnt++; pthread_mutex_unlock(&(from_param->lock)); *((struct policy_action_param**)to)=from_param; return; } void ma_profile_table_new_cb(const char *table_name, const char* key, const char* table_line, void **ad, long argl, void* argp) { cJSON* response_pages = cJSON_Parse(table_line); if(response_pages == NULL) { TFE_LOG_ERROR(g_proxy_rt->local_logger, "RESPONSE_PAGE parse table_line failed. table_line:%s", table_line); return; } char *profile_path=NULL; struct manipulate_profile* ply_profile=ALLOC(struct manipulate_profile, 1); cJSON *uuid = cJSON_GetObjectItem(response_pages, "uuid"); if(uuid && uuid->type==cJSON_String) { ply_profile->profile_uuid = tfe_strdup(uuid->valuestring); } cJSON *profile_name = cJSON_GetObjectItem(response_pages, "profile_name"); if(profile_name && profile_name->type==cJSON_String) { ply_profile->profile_name=tfe_strdup(profile_name->valuestring); } cJSON *format = cJSON_GetObjectItem(response_pages, "format"); if(format && format->type==cJSON_String) { ply_profile->profile_type=tfe_strdup(format->valuestring); } cJSON *item = cJSON_GetObjectItem(response_pages, "path"); if(item && item->type==cJSON_String) { profile_path=item->valuestring; } ply_profile->ref_cnt=1; pthread_mutex_init(&(ply_profile->lock), NULL); if(strcasecmp(ply_profile->profile_type, "template") == 0) { ply_profile->tpl = ctemplate::Template::GetTemplate(profile_path, ctemplate::DO_NOT_STRIP); }else { ply_profile->profile_msg = tfe_read_file(profile_path, &ply_profile->msg_len); if (ply_profile->profile_msg == NULL) { TFE_LOG_ERROR(g_proxy_rt->local_logger, "Read file failed %s:%s:%s", ply_profile->profile_uuid, ply_profile->profile_name, profile_path); } } cJSON_Delete(response_pages); response_pages=NULL; TFE_LOG_INFO(g_proxy_rt->local_logger, "Policy table add success %s", ply_profile->profile_uuid); *ad = ply_profile; return; } void ma_insert_profile_table_new_cb(const char *table_name, const char* key, const char* table_line, void **ad, long argl, void* argp) { cJSON* insert_script = cJSON_Parse(table_line); if(insert_script == NULL) { TFE_LOG_ERROR(g_proxy_rt->local_logger, "PROXY_INJECT_SCRIPT parse table_line failed. table_line:%s", table_line); return; } char *profile_path=NULL; struct manipulate_profile* ply_profile=ALLOC(struct manipulate_profile, 1); cJSON *uuid = cJSON_GetObjectItem(insert_script, "uuid"); if(uuid && uuid->type==cJSON_String) { ply_profile->profile_uuid = tfe_strdup(uuid->valuestring); } cJSON *profile_name = cJSON_GetObjectItem(insert_script, "profile_name"); if(profile_name && profile_name->type==cJSON_String) { ply_profile->profile_name=tfe_strdup(profile_name->valuestring); } cJSON *item = cJSON_GetObjectItem(insert_script, "path"); if(item && item->type==cJSON_String) { profile_path=item->valuestring; } ply_profile->ref_cnt=1; pthread_mutex_init(&(ply_profile->lock), NULL); if(profile_path != NULL) { ply_profile->profile_msg = tfe_read_file(profile_path, &ply_profile->msg_len); if (ply_profile->profile_msg == NULL) { TFE_LOG_ERROR(g_proxy_rt->local_logger, "Read file failed %s:%s:%s", ply_profile->profile_uuid, ply_profile->profile_name, profile_path); } } cJSON_Delete(insert_script); insert_script=NULL; TFE_LOG_INFO(g_proxy_rt->local_logger, "Policy table add success %s", ply_profile->profile_uuid); *ad = ply_profile; return; } void ma_hijack_profile_table_new_cb(const char *table_name, const char* key, const char* table_line, void **ad, long argl, void* argp) { cJSON* hihijack_files = cJSON_Parse(table_line); if(hihijack_files == NULL) { TFE_LOG_ERROR(g_proxy_rt->local_logger, "PROXY_REPLACEMENT_FILE parse table_line failed. table_line:%s", table_line); return; } struct manipulate_profile* ply_profile=ALLOC(struct manipulate_profile, 1); cJSON *uuid = cJSON_GetObjectItem(hihijack_files, "uuid"); if(uuid && uuid->type==cJSON_String) { ply_profile->profile_uuid = tfe_strdup(uuid->valuestring); } cJSON *profile_name = cJSON_GetObjectItem(hihijack_files, "content_name"); if(profile_name && profile_name->type==cJSON_String) { ply_profile->profile_name=tfe_strdup(profile_name->valuestring); } cJSON *content_type = cJSON_GetObjectItem(hihijack_files, "content_type"); if(content_type && content_type->type==cJSON_String) { ply_profile->profile_type=tfe_strdup(content_type->valuestring); } cJSON *path = cJSON_GetObjectItem(hihijack_files, "path"); if(path && path->type==cJSON_String) { ply_profile->profile_msg=tfe_strdup(path->valuestring); } ply_profile->ref_cnt=1; pthread_mutex_init(&(ply_profile->lock), NULL); cJSON_Delete(hihijack_files); hihijack_files=NULL; TFE_LOG_INFO(g_proxy_rt->local_logger, "Policy table add success %s", ply_profile->profile_uuid); *ad = ply_profile; return; } void ma_lua_profile_table_new_cb(const char *table_name, const char* key, const char* table_line, void **ad, long argl, void* argp) { cJSON* run_scripts = cJSON_Parse(table_line); if(run_scripts == NULL) { TFE_LOG_ERROR(g_proxy_rt->local_logger, "PROXY_LUA_SCRIPT parse table_line failed. table_line:%s", table_line); return; } char *profile_path=NULL; struct manipulate_profile* ply_profile=ALLOC(struct manipulate_profile, 1); cJSON *uuid = cJSON_GetObjectItem(run_scripts, "uuid"); if(uuid && uuid->type==cJSON_String) { ply_profile->profile_uuid = tfe_strdup(uuid->valuestring); } cJSON *max_exec_time = cJSON_GetObjectItem(run_scripts, "max_exec_time"); if(max_exec_time && max_exec_time->type==cJSON_Number) { ply_profile->timeout=max_exec_time->valueint; } cJSON *path = cJSON_GetObjectItem(run_scripts, "path"); if(path && path->type==cJSON_String) { profile_path=path->valuestring; } ply_profile->ref_cnt=1; pthread_mutex_init(&(ply_profile->lock), NULL); ply_profile->profile_name=tfe_strdup(profile_path); ply_profile->profile_msg = tfe_read_file(profile_path, &ply_profile->msg_len); if (ply_profile->profile_msg == NULL) { cJSON_Delete(run_scripts); run_scripts=NULL; TFE_LOG_ERROR(g_proxy_rt->local_logger, "Read file failed %s:%s:%s", ply_profile->profile_uuid, ply_profile->profile_name, profile_path); *ad = ply_profile; return; } int thread_num = g_proxy_rt->thread_num; ply_profile->escript_ctx = ALLOC(struct elua_script *, thread_num); TFE_LOG_INFO(g_proxy_rt->local_logger, "Policy table add success %s", ply_profile->profile_uuid); cJSON_Delete(run_scripts); run_scripts=NULL; *ad = ply_profile; return; } void ma_profile_table_free_cb(const char *table_name, void **ad, long argl, void *argp) { if(*ad==NULL) { return; } struct manipulate_profile* ply_obj=(struct manipulate_profile*)(*ad); pthread_mutex_lock(&(ply_obj->lock)); ply_obj->ref_cnt--; if(ply_obj->ref_cnt>0) { pthread_mutex_unlock(&(ply_obj->lock)); return; } pthread_mutex_unlock(&(ply_obj->lock)); pthread_mutex_destroy(&(ply_obj->lock)); if(ply_obj->profile_uuid) FREE(&ply_obj->profile_uuid); if(ply_obj->profile_type) FREE(&ply_obj->profile_type); if(ply_obj->profile_msg) FREE(&ply_obj->profile_msg); if(ply_obj->escript_ctx) { int i=0; for(i=0; ithread_num; i++) { if(ply_obj->escript_ctx[i]) { elua_cleanup_script(ply_obj->escript_ctx[i]); FREE(&ply_obj->escript_ctx[i]); ply_obj->escript_ctx[i]=NULL; } } free(ply_obj->escript_ctx); ply_obj->escript_ctx=NULL; } FREE(&ply_obj->profile_name); if (ply_obj->profile_position) FREE(&ply_obj->profile_position); FREE(&ply_obj); *ad=NULL; return; } void ma_profile_table_free(struct manipulate_profile* ply_obj) { ma_profile_table_free_cb(0, (void **)&ply_obj, 0, NULL); } void ma_profile_table_dup_cb(const char *table_name, void **to, void **from, long argl, void *argp) { struct manipulate_profile* ply_obj=(struct manipulate_profile*)(*from); pthread_mutex_lock(&(ply_obj->lock)); ply_obj->ref_cnt++; pthread_mutex_unlock(&(ply_obj->lock)); *to=ply_obj; } const char* table_name_idx2str(int profile_idx) { const char *table_name_map[] = {"RESPONSE_PAGE", "PROXY_JS_FILE", "PROXY_CSS_FILE", "PROXY_REPLACEMENT_FILE", "PROXY_LUA_SCRIPT"}; return table_name_map[profile_idx]; } int maat_table_ex_init(int profile_idx, maat_ex_free_func_t* free_func, maat_ex_dup_func_t* dup_func) { int ret = 0; const char *table_name = table_name_idx2str(profile_idx); maat_ex_new_func_t *new_func[] = { [POLICY_PROFLIE_TABLE_REJECT] = ma_profile_table_new_cb, [POLICY_PROFILE_TABLE_JS] = ma_insert_profile_table_new_cb, [POLICY_PROFILE_TABLE_CSS] = ma_insert_profile_table_new_cb, [POLICY_PROFILE_TABLE_HIJACK] = ma_hijack_profile_table_new_cb, [POLICY_PROFILE_TABLE_LUA] = ma_lua_profile_table_new_cb, }; ret=maat_plugin_table_ex_schema_register(g_proxy_rt->feather, table_name, new_func[profile_idx], free_func, dup_func, 0, NULL); if(ret < 0) { TFE_LOG_INFO(NULL, "Pangu HTTP register table %s failed.", table_name); return -1; } return ret; } int proxy_policy_init(const char* profile_path, const char* static_section, const char* dynamic_section) { int ret = 0; g_proxy_rt->feather = tfe_get_maat_handle(); ret = maat_plugin_table_ex_schema_register(g_proxy_rt->feather, "PXY_CTRL_RULE_PLUGIN", policy_action_param_new, policy_action_param_free_cb, policy_action_param_dup, 0, NULL); if(ret<0) { TFE_LOG_INFO(NULL, "Pangu HTTP register table PXY_CTRL_RULE_PLUGIN failed."); goto error_out; } ret = maat_table_callback_register(g_proxy_rt->feather, "TRUSTED_CERTIFICATE_AUTHORITY", trusted_CA_update_start_cb, trusted_CA_update_cert_cb, trusted_CA_update_finish_cb, g_proxy_rt); if(ret<0) { TFE_LOG_INFO(NULL, "Pangu HTTP register table PXY_OBJ_TRUSTED_CA_CERT failed."); goto error_out; } for(int i = 0; i <= POLICY_PROFILE_TABLE_LUA; i++) { ret = maat_table_ex_init(i, ma_profile_table_free_cb, ma_profile_table_dup_cb); if(ret<0) { goto error_out; } } error_out: return ret; } int proxy_http_init(struct tfe_proxy * proxy) { const char * profile_path = "./conf/tfe/tfe.conf";; g_proxy_rt = ALLOC(struct tsg_proxy_rt, 1); MESA_load_profile_int_def(profile_path, "tsg_http", "enable_plugin", &(g_proxy_rt->enable_plugin), 1); if (!g_proxy_rt->enable_plugin) { return 0; } g_proxy_rt->thread_num = tfe_proxy_get_work_thread_count(); g_proxy_rt->gc_evbase=tfe_proxy_get_gc_evbase(); g_proxy_rt->local_logger = (void *)MESA_create_runtime_log_handle("tsg_http", RLOG_LV_DEBUG); g_proxy_rt->send_logger = proxy_log_handle_create(profile_path, "tsg_http", g_proxy_rt->local_logger); if (!g_proxy_rt->send_logger) { goto error_out; } g_proxy_rt->fs_handle = tfe_proxy_get_fs_handle(); proxy_http_stat_init(g_proxy_rt); if(http_lua_handle_create(&g_proxy_rt->lua_script, g_proxy_rt->thread_num, "tfe") <0) { goto error_out; } if(proxy_policy_init(profile_path, "MAAT", "DYNAMIC_MAAT")<0) { goto error_out; } char page_path[256]; memset(page_path, 0, sizeof(page_path)); MESA_load_profile_string_def(profile_path, "TEMPLATE", "PAGE_403", page_path, sizeof(page_path), "./resource/pangu/HTTP403.html"); g_proxy_rt->tpl_403 = ctemplate::Template::GetTemplate(page_path, ctemplate::DO_NOT_STRIP); memset(page_path, 0, sizeof(page_path)); MESA_load_profile_string_def(profile_path, "TEMPLATE", "PAGE_404", page_path, sizeof(page_path), "./resource/pangu/HTTP404.html"); g_proxy_rt->tpl_404 = ctemplate::Template::GetTemplate(page_path, ctemplate::DO_NOT_STRIP); memset(page_path, 0, sizeof(page_path)); MESA_load_profile_string_def(profile_path, "TEMPLATE", "PAGE_451", page_path, sizeof(page_path), "./resource/pangu/HTTP451.html"); g_proxy_rt->tpl_451 = ctemplate::Template::GetTemplate(page_path, ctemplate::DO_NOT_STRIP); g_proxy_rt->enable_rate=0; TFE_LOG_INFO(NULL, "Tsg_pxy HTTP init success."); return 0; error_out: TFE_LOG_ERROR(NULL, "Tsg_pxy HTTP init failed."); return -1; } struct replace_ctx { struct replace_rule * rule; size_t n_rule; struct tfe_http_half * replacing; struct evbuffer * http_body; int actually_replaced; }; struct insert_ctx { struct insert_rule *rule; struct tfe_http_half * replacing; struct evbuffer *http_body; int actually_inserted; }; struct edit_element_ctx { struct edit_element_rule *item; size_t n_item; struct tfe_http_half * editing; struct evbuffer *http_body; int actually_edited; }; struct proxy_http_ctx { int magic_num; enum proxy_action action; char * action_para; int hit_cnt; uuid_t result[MAX_SCAN_RESULT]; struct maat_state *scan_mid; struct maat_stream *sp; struct maat_rule_t * enforce_rules; size_t n_enforce; struct policy_action_param *param; struct evbuffer* log_req_body, *log_resp_body; size_t inject_sz; int manipulate_replaced; struct replace_ctx * rep_ctx; struct insert_ctx * ins_ctx; struct edit_element_ctx * edit_ctx; struct tsg_script_ctx *tsg_ctx; int (* resumed_cb)(const struct tfe_stream * stream, const struct tfe_http_session * session, enum tfe_http_event event, const unsigned char * data, size_t datalen, unsigned int thread_id, struct proxy_http_ctx* ctx); struct tfe_http_session * ref_session; size_t c2s_byte_num; size_t s2c_byte_num; int thread_id; }; static inline int ctx_actually_replaced(struct proxy_http_ctx * ctx) { if(ctx->action == PX_ACTION_MANIPULATE && ctx->param->action == MA_ACTION_REPLACE_TEXT && ctx->rep_ctx->actually_replaced==1) { return 1; } else { return 0; } } static inline int ctx_actually_ran_script(struct proxy_http_ctx * ctx) { if(ctx->action == PX_ACTION_EXECUTE && ctx->tsg_ctx->actually_executed==1) { return 1; } else { return 0; } } static inline int ctx_actually_inserted(struct proxy_http_ctx * ctx) { if((ctx->action == PX_ACTION_MANIPULATE && ctx->param->action == MA_ACTION_INJECT_JAVESCRIPT && ctx->ins_ctx->actually_inserted==1) || (ctx->action == PX_ACTION_MANIPULATE && ctx->param->action == MA_ACTION_INJECT_CSS && ctx->ins_ctx->actually_inserted==1)) { return 1; } else { return 0; } } static inline int ctx_actually_edited(struct proxy_http_ctx * ctx) { if(ctx->action == PX_ACTION_MANIPULATE && ctx->param->action == MA_ACTION_EDIT_ELEMENT && ctx->edit_ctx != NULL && ctx->edit_ctx->actually_edited==1) { return 1; } else { return 0; } } static inline int ctx_actually_manipulate(struct proxy_http_ctx * ctx) { if((ctx->action == PX_ACTION_REDIRECT && ctx->manipulate_replaced==1) || (ctx->action == PX_ACTION_MANIPULATE && ctx->param->action == MA_ACTION_REPLACE_FILE && ctx->manipulate_replaced==1)) { return 1; } else { return 0; } } void http_repl_ctx_free(struct replace_ctx* rep_ctx) { if (rep_ctx->http_body) { evbuffer_free(rep_ctx->http_body); rep_ctx->http_body = NULL; } FREE(&rep_ctx); return; } void http_ins_ctx_free(struct insert_ctx* ins_ctx) { if (ins_ctx->rule->script) FREE(&ins_ctx->rule->script); FREE(&ins_ctx->rule->type); if (ins_ctx->rule->position) FREE(&ins_ctx->rule->position); FREE(&(ins_ctx->rule)); if (ins_ctx->http_body) { evbuffer_free(ins_ctx->http_body); ins_ctx->http_body = NULL; } FREE(&ins_ctx); return; } void http_element_ctx_free(struct edit_element_ctx *edit_ctx) { if (edit_ctx->http_body) { evbuffer_free(edit_ctx->http_body); edit_ctx->http_body = NULL; } FREE(&edit_ctx); return; } void http_tsg_ctx_free(struct tsg_script_ctx *tsg_ctx, int thread_id) { if(tsg_ctx->config_uuid_str) { FREE(&tsg_ctx->config_uuid_str) } if(tsg_ctx->profile_uuid_str) { FREE(&tsg_ctx->profile_uuid_str) } if (tsg_ctx->http_body) { evbuffer_free(tsg_ctx->http_body); tsg_ctx->http_body = NULL; } if (tsg_ctx->http_lua_body) { evbuffer_free(tsg_ctx->http_lua_body); tsg_ctx->http_lua_body = NULL; } http_lua_ctx_free(&g_proxy_rt->lua_script, thread_id, tsg_ctx->elua_ctx); FREE(&tsg_ctx); return; } #define HTTP_CTX_MAGIC_NUM 20181021 static struct proxy_http_ctx * proxy_http_ctx_new(unsigned int thread_id) { struct proxy_http_ctx * ctx = ALLOC(struct proxy_http_ctx, 1); ctx->magic_num=HTTP_CTX_MAGIC_NUM; ctx->scan_mid = maat_state_new(g_proxy_rt->feather, thread_id); ctx->thread_id = (int) thread_id; return ctx; } static void proxy_http_ctx_free(struct proxy_http_ctx * ctx) { assert(ctx->magic_num==HTTP_CTX_MAGIC_NUM); if(ctx->rep_ctx) { http_repl_ctx_free(ctx->rep_ctx); ctx->rep_ctx = NULL; } if(ctx->ins_ctx) { http_ins_ctx_free(ctx->ins_ctx); ctx->ins_ctx = NULL; } if(ctx->edit_ctx) { http_element_ctx_free(ctx->edit_ctx); ctx->edit_ctx = NULL; } if(ctx->tsg_ctx) { http_tsg_ctx_free(ctx->tsg_ctx, ctx->thread_id); ctx->tsg_ctx = NULL; } ctx->manipulate_replaced=0; FREE(&ctx->enforce_rules); policy_action_param_free(ctx->param); ctx->param=NULL; maat_state_free(ctx->scan_mid); ctx->scan_mid = NULL; if(ctx->sp) { maat_stream_free(ctx->sp); ctx->sp=NULL; } if(ctx->log_req_body) { evbuffer_free(ctx->log_req_body); ctx->log_req_body=NULL; } if(ctx->log_resp_body) { evbuffer_free(ctx->log_resp_body); ctx->log_resp_body=NULL; } ctx->magic_num=0; FREE(&ctx); } static inline void addr_tfe2sapp(const struct tfe_stream_addr * tfe_addr, struct ipaddr * sapp_addr) { if(tfe_addr->addrtype==TFE_ADDR_STREAM_TUPLE4_V4||tfe_addr->addrtype==TFE_ADDR_IPV4) { sapp_addr->addrtype = ADDR_TYPE_IPV4; } else { sapp_addr->addrtype=ADDR_TYPE_IPV6; } sapp_addr->paddr = (char *) tfe_addr->paddr; return; } static struct manipulate_profile* get_profile_by_id(const char *table_name, char *cfg_id_str) { struct manipulate_profile* result=NULL; result = (struct manipulate_profile*)maat_plugin_table_get_ex_data(g_proxy_rt->feather, table_name, (const char*)cfg_id_str, strlen(cfg_id_str)); return result; } void proxy_send_metric_log(const struct tfe_stream * stream, struct proxy_http_ctx * ctx, unsigned int thread_id, int state) { size_t i=0; int hit_cnt=0; const char *manipulate_action_map[]= {"replace_text","replace_file","edit_element","inject_javascript","inject_css"}; const char *proxy_action_map[] = {"none", "allow", "deny", "monitor", "redirect", "execute", "modify"}; struct filedstat_easy_manipulation *fieldstat = tfe_get_fieldstat_handle()->manipulation; if(fieldstat == NULL) { return; } for(i=0; i< ctx->n_enforce; i++) { char uuid_string[UUID_STRING_SIZE] = {0}; uuid_unparse(ctx->enforce_rules[i].config_uuid, uuid_string); fieldstat->tags[thread_id][TAG_VSYS_ID].value_longlong = ctx->enforce_rules[i].vsys_id; fieldstat->tags[thread_id][TAG_RULE_ID].value_str = uuid_string; fieldstat->tags[thread_id][TAG_ACTION].value_str = "manipulate"; if(ctx->enforce_rules[i].action == PX_ACTION_MANIPULATE) { fieldstat->tags[thread_id][TAG_SUB_ACTION].value_str = manipulate_action_map[ctx->param->action]; } else { fieldstat->tags[thread_id][TAG_SUB_ACTION].value_str = proxy_action_map[ctx->enforce_rules[i].action]; } size_t c2s_byte_num = 0, s2c_byte_num =0; tfe_stream_info_get(stream, INFO_FROM_DOWNSTREAM_RX_OFFSET, &c2s_byte_num, sizeof(c2s_byte_num)); tfe_stream_info_get(stream, INFO_FROM_UPSTREAM_RX_OFFSET, &s2c_byte_num, sizeof(s2c_byte_num)); uint16_t out_size; unsigned int route_dir; int ret=0; int in_bytes = 0, out_bytes = 0; struct tfe_cmsg *cmsg = tfe_stream_get0_cmsg(stream); if (cmsg != NULL) { ret = tfe_cmsg_get_value(cmsg, TFE_CMSG_COMMON_DIRECTION, (unsigned char *)&route_dir, sizeof(route_dir), &out_size); if (ret != 0) { TFE_LOG_ERROR(g_proxy_rt->local_logger, "failed at fetch route_dir from cmsg: %s", strerror(-ret)); return; } } int dir_is_e2i=(route_dir==69) ? 0 : 1; if (dir_is_e2i == 1) { in_bytes = c2s_byte_num - ctx->c2s_byte_num; out_bytes = s2c_byte_num - ctx->s2c_byte_num; ctx->c2s_byte_num = c2s_byte_num; ctx->s2c_byte_num = s2c_byte_num; } else { in_bytes = s2c_byte_num - ctx->c2s_byte_num; out_bytes = c2s_byte_num - ctx->s2c_byte_num; ctx->c2s_byte_num = s2c_byte_num; ctx->s2c_byte_num = c2s_byte_num; } if(state == 1) { hit_cnt=0; } else { hit_cnt=1; in_bytes=0; out_bytes=0; } if(hit_cnt == 0 && in_bytes == 0 && out_bytes == 0) { continue; } tfe_fieldstat_manipulation_incrby(fieldstat, fieldstat->counter_array[COLUMN_HIT_COUNT], hit_cnt, fieldstat->tags[thread_id], TAG_MAX - 1, thread_id); tfe_fieldstat_manipulation_incrby(fieldstat, fieldstat->counter_array[COLUMN_IN_BYTES], in_bytes, fieldstat->tags[thread_id], TAG_MAX - 1, thread_id); tfe_fieldstat_manipulation_incrby(fieldstat, fieldstat->counter_array[COLUMN_OUT_BYTES], out_bytes, fieldstat->tags[thread_id], TAG_MAX - 1, thread_id); } return; } static unsigned long long try_send_by_token(int inject_sz) { if (g_proxy_rt->enable_rate != 1) { return 1; } return inject_sz; } static int pangu_action_weight[__PX_ACTION_MAX] = {0}; void __pangu_action_weight_init() __attribute__((constructor, used)); void __pangu_action_weight_init() { pangu_action_weight[PX_ACTION_NONE] = 0; pangu_action_weight[PX_ACTION_MONITOR] = 1; pangu_action_weight[PX_ACTION_REDIRECT] = 2; pangu_action_weight[PX_ACTION_EXECUTE] = 2; pangu_action_weight[PX_ACTION_MANIPULATE] = 2; pangu_action_weight[PX_ACTION_DENY] = 3; pangu_action_weight[PX_ACTION_ALLOW] = 4; } static inline int action_cmp(enum proxy_action a1, enum proxy_action a2) { return pangu_action_weight[a1] - pangu_action_weight[a2]; } //enforce_rules[0] contains execute action. static enum proxy_action decide_ctrl_action(uuid_t *result, size_t n_hit, struct maat_rule_t** enforce_rules, size_t * n_enforce, struct policy_action_param **param) { void *ex_data=NULL; char result_uuid_string[UUID_STRING_SIZE]={0}; size_t n_monit = 0, exist_enforce_num = 0, i = 0; struct policy_action_param *get_ex_param=NULL; struct maat_rule_t *hit_rules=NULL; hit_rules=ALLOC(struct maat_rule_t, n_hit); for (i = 0; i < n_hit && ifeather, "PXY_CTRL_RULE_PLUGIN", result_uuid_string, strlen(result_uuid_string)); if(get_ex_param==NULL) { continue; } memcpy(hit_rules+i, &get_ex_param->hit_rule, sizeof(struct maat_rule_t)); policy_action_param_free(get_ex_param); } const struct maat_rule_t * prior_rule = hit_rules; struct maat_rule_t monit_rule[n_hit]; enum proxy_action prior_action = PX_ACTION_NONE; for (i = 0; i < n_hit && i 0) { prior_rule = hit_rules + i; prior_action = __action; } else if (action_cmp(__action, prior_action) == 0) { if(uuid_compare(hit_rules[i].config_uuid, prior_rule->config_uuid) > 0) { prior_rule = hit_rules + i; } } else { continue; } } if (prior_action == PX_ACTION_ALLOW) { if(*n_enforce==0) { *enforce_rules=ALLOC(struct maat_rule_t, 1); } *enforce_rules[0]=*prior_rule; *n_enforce=1; ex_data=maat_plugin_table_get_ex_data(g_proxy_rt->feather, "PXY_CTRL_RULE_PLUGIN", prior_rule->config_uuid_string, strlen(prior_rule->config_uuid_string)); if(ex_data!=NULL) { *param=(struct policy_action_param*)ex_data; } if(hit_rules) { FREE(&hit_rules); } return PX_ACTION_ALLOW; } exist_enforce_num = *n_enforce; if (prior_action == PX_ACTION_MONITOR) { *n_enforce += n_monit; } else { *n_enforce += n_monit + 1; } *enforce_rules = (struct maat_rule_t *) realloc(*enforce_rules, sizeof(struct maat_rule_t) * (*n_enforce)); if (prior_action == PX_ACTION_MONITOR) { memcpy(*enforce_rules + exist_enforce_num, monit_rule, n_monit * sizeof(struct maat_rule_t)); } else { memmove(*enforce_rules+1, *enforce_rules, exist_enforce_num*sizeof(struct maat_rule_t)); memcpy(*enforce_rules, prior_rule, sizeof(struct maat_rule_t)); memcpy(*enforce_rules + exist_enforce_num + 1, monit_rule, n_monit * sizeof(struct maat_rule_t)); } ex_data=maat_plugin_table_get_ex_data(g_proxy_rt->feather, "PXY_CTRL_RULE_PLUGIN", prior_rule->config_uuid_string, strlen(prior_rule->config_uuid_string)); if(ex_data!=NULL) { *param=(struct policy_action_param*)ex_data; } if(hit_rules) { FREE(&hit_rules); } return prior_action; } //HTML template is downloaded from https://github.com/AndiDittrich/HttpErrorPages static void template_generate(int status_code, const char* msg, char ** page_buff, size_t * page_size) { ctemplate::TemplateDictionary dict("pg_page_dict"); //dict is automatically finalized after function returned. if (NULL == msg) { dict.SetValue("msg", "NULL"); } else { dict.SetValue("msg", msg); } std::string output; ctemplate::Template * tpl = NULL; switch (status_code) { case 403: tpl = g_proxy_rt->tpl_403; break; case 404: tpl = g_proxy_rt->tpl_404; break; case 451: tpl = g_proxy_rt->tpl_451; break; default: return; } tpl->Expand(&output, &dict); *page_size = output.length() + 1; *page_buff = tfe_strdup(output.c_str()); } void manipulate_profile_free(struct manipulate_profile* ma_profile) { FREE(&ma_profile->profile_type); FREE(&ma_profile->profile_msg); FREE(&ma_profile->profile_name); FREE(&ma_profile); } static int html_generate(char *profile_uuid, const char* msg, char ** page_buff, size_t * page_size) { int ret = 0; if(profile_uuid==NULL) { ret=-1; return ret; } struct manipulate_profile* block_profile=get_profile_by_id("RESPONSE_PAGE", profile_uuid); if(block_profile==NULL) { ret=-1; return ret; } if(!strncmp(block_profile->profile_type, "template", strlen(block_profile->profile_type))) { ctemplate::TemplateDictionary dict("pg_page_dict"); //dict is automatically finalized after function returned. dict.SetValue("msg", msg); std::string output; block_profile->tpl->Expand(&output, &dict); *page_size = output.length() + 1; *page_buff = tfe_strdup(output.c_str()); } else { *page_size = block_profile->msg_len; *page_buff = tfe_strdup(block_profile->profile_msg); } ma_profile_table_free(block_profile); block_profile=NULL; return ret; } static void html_free(char ** page_buff) { FREE(page_buff); return; } static int http_enforcement_ratio(float enforcement_ratio) { int enforcement_ratio_temp = 0; enforcement_ratio_temp = enforcement_ratio * 10000; srand(time(NULL)); int random = rand() % (10000-1); if (random >=0 && random <= enforcement_ratio_temp) { return 1; } return 0; } int http_lua_profile(char *profile_uuid_str, struct elua_script ***elua_ctx, char **profile_msg, size_t *msg_len, int *timeout) { int ret = 0; struct manipulate_profile* lua_profile=get_profile_by_id("PROXY_LUA_SCRIPT", profile_uuid_str); if(lua_profile==NULL) { ret=-1; return ret; } *elua_ctx=lua_profile->escript_ctx; *profile_msg=tfe_strdup(lua_profile->profile_msg); *msg_len=lua_profile->msg_len; *timeout=lua_profile->timeout; ma_profile_table_free(lua_profile); lua_profile = NULL; return ret; } void http_lua(const struct tfe_stream * stream, const struct tfe_http_session * session, enum tfe_http_event events, const unsigned char * body_frag, size_t frag_size, struct proxy_http_ctx * ctx) { int ret = 0; struct tfe_http_session * to_write_sess = NULL; struct tsg_lua_script *lua_script=&g_proxy_rt->lua_script; lua_script->http_lua_profile=http_lua_profile; to_write_sess = tfe_http_session_allow_write(session); if (to_write_sess == NULL) //fail to wirte, abandon. { TFE_STREAM_LOG_INFO(stream, "tfe_http_session_allow_write() %s failed.", session->req->req_spec.uri); ctx->action = PX_ACTION_NONE; tfe_http_session_detach(session); return; } struct tsg_script_ctx *tsg_ctx = ctx->tsg_ctx; if (ctx->tsg_ctx == NULL) { if ((events & EV_HTTP_REQ_HDR) || (events & EV_HTTP_RESP_HDR)) { struct policy_action_param *param = ctx->param; ctx->tsg_ctx = tsg_ctx = ALLOC(struct tsg_script_ctx, 1); tsg_ctx->profile_uuid_str = tfe_strdup(param->profile_uuid_str); tsg_ctx->addr = stream->addr; tsg_ctx->elua_ctx = http_lua_ctx_new(lua_script, ctx->thread_id); } else { TFE_STREAM_LOG_INFO(stream, "Can only setup replace on REQ/RESP headers, detached."); ctx->action = PX_ACTION_NONE; tfe_http_session_detach(session); return; } } tsg_ctx->events = events; tsg_ctx->session = session; tsg_ctx->local_logger = g_proxy_rt->local_logger; tsg_ctx->config_uuid_str = tfe_strdup(ctx->enforce_rules[0].config_uuid_string); struct tfe_http_half * in_req_half = session->req; struct tfe_http_half * in_resp_half = session->resp; struct tfe_http_req_spec * in_req_spec = &in_req_half->req_spec; struct tfe_http_resp_spec * in_resp_spec = &in_resp_half->resp_spec; if ((events & EV_HTTP_REQ_HDR) || (events & EV_HTTP_RESP_HDR)) { tsg_ctx->http_req_uri=1; tsg_ctx->execut_lua_sucess=0; ret=execute_lua_script_rule(lua_script, tsg_ctx->profile_uuid_str, tsg_ctx->elua_ctx, ctx->thread_id, (void *)tsg_ctx); if(ret==0 && tsg_ctx->execut_lua_sucess==1) { tsg_ctx->actually_executed =1; } tsg_ctx->http_req_uri=0; tsg_ctx->execut_lua_sucess=0; if (tfe_http_in_request(events)) { tsg_ctx->replacing = tfe_http_session_request_create(to_write_sess, in_req_spec->method, tsg_ctx->rewrite_uri !=NULL ? tsg_ctx->rewrite_uri : in_req_spec->uri); tfe_http_session_request_set(to_write_sess, tsg_ctx->replacing); } else { tsg_ctx->replacing = tfe_http_session_response_create(to_write_sess, in_resp_spec->resp_code); tfe_http_session_response_set(to_write_sess, tsg_ctx->replacing); } if (tsg_ctx->rewrite_uri != NULL) { FREE(&tsg_ctx->rewrite_uri); } ret=execute_lua_script_rule(lua_script, tsg_ctx->profile_uuid_str, tsg_ctx->elua_ctx, ctx->thread_id, (void *)tsg_ctx); if(ret==0 && tsg_ctx->execut_lua_sucess==1) { tsg_ctx->actually_executed =1; } struct tfe_http_half * in_half = tfe_http_in_request(events) ? in_req_half : in_resp_half; struct http_field_name in_header_field{}; const char * in_header_value = NULL; void * iterator = NULL; while (true && tsg_ctx->rewrite_header!=1) { if ((in_header_value = tfe_http_field_iterate(in_half, &iterator, &in_header_field)) == NULL) { break; } tfe_http_field_write(tsg_ctx->replacing, &in_header_field, in_header_value); } tsg_ctx->rewrite_header=0; } if ((events & EV_HTTP_REQ_BODY_BEGIN) || (events & EV_HTTP_RESP_BODY_BEGIN)) { assert(tsg_ctx->http_body == NULL); tsg_ctx->http_body = evbuffer_new(); } if ((events & EV_HTTP_REQ_BODY_CONT) || (events & EV_HTTP_RESP_BODY_CONT)) { evbuffer_add(tsg_ctx->http_body, body_frag, frag_size); } if ((events & EV_HTTP_REQ_BODY_END) || (events & EV_HTTP_RESP_BODY_END)) { char * __http_body = (char *) evbuffer_pullup(tsg_ctx->http_body, -1); size_t __http_body_len = evbuffer_get_length(tsg_ctx->http_body); ret=execute_lua_script_rule(lua_script, tsg_ctx->profile_uuid_str, tsg_ctx->elua_ctx, ctx->thread_id, (void *)tsg_ctx); char * __http_lua_body = NULL; size_t __http_body_lua_len = 0; if(ret == 0 && tsg_ctx->http_lua_body != NULL) { tsg_ctx->actually_executed =1; __http_lua_body = (char *) evbuffer_pullup(tsg_ctx->http_lua_body, -1); __http_body_lua_len = evbuffer_get_length(tsg_ctx->http_lua_body); } if (__http_body_lua_len >0) { tfe_http_half_append_body(tsg_ctx->replacing, __http_lua_body, __http_body_lua_len, 0); tsg_ctx->actually_executed=1; } else { tfe_http_half_append_body(tsg_ctx->replacing, __http_body, __http_body_len, 0); } if (tsg_ctx->http_lua_body != NULL) { evbuffer_free(tsg_ctx->http_lua_body); tsg_ctx->http_lua_body = NULL; } if (tsg_ctx->http_body != NULL) { evbuffer_free(tsg_ctx->http_body); tsg_ctx->http_body = NULL; } } if ((events & EV_HTTP_REQ_END) || (events & EV_HTTP_RESP_END)) { tfe_http_half_append_body(tsg_ctx->replacing, NULL, 0, 0); tsg_ctx->replacing = NULL; } return; } void http_replace(const struct tfe_stream * stream, const struct tfe_http_session * session, enum tfe_http_event events, const unsigned char * body_frag, size_t frag_size, struct proxy_http_ctx * ctx) { struct tfe_http_session * to_write_sess = NULL; char * rewrite_buff = NULL; size_t rewrite_sz = 0; struct policy_action_param *param = ctx->param; int ratio = http_enforcement_ratio(param->enforcement_ratio); if (ratio != 1) { TFE_LOG_DEBUG(g_proxy_rt->local_logger, "enforcement ratio:%f", param->enforcement_ratio); ctx->action = PX_ACTION_NONE; return; } to_write_sess = tfe_http_session_allow_write(session); if (to_write_sess == NULL) //fail to wirte, abandon. { TFE_STREAM_LOG_INFO(stream, "tfe_http_session_allow_write() %s failed.", session->req->req_spec.uri); ctx->action = PX_ACTION_NONE; tfe_http_session_detach(session); return; } struct replace_ctx * rep_ctx = ctx->rep_ctx; if (ctx->rep_ctx == NULL) { /* we must determinate the replace action on HTTP header, otherwise, * the header has been forwarded, only replace the body but not modify header will raise exception */ if ((events & EV_HTTP_REQ_HDR) || (events & EV_HTTP_RESP_HDR)) { struct policy_action_param *param = ctx->param; ctx->rep_ctx = rep_ctx = ALLOC(struct replace_ctx, 1); rep_ctx->rule = param->repl_rule; rep_ctx->n_rule = param->n_rule; } else { TFE_STREAM_LOG_INFO(stream, "Can only setup replace on REQ/RESP headers, detached."); ctx->action = PX_ACTION_NONE; tfe_http_session_detach(session); return; } } struct tfe_http_half * in_req_half = session->req; struct tfe_http_half * in_resp_half = session->resp; struct tfe_http_req_spec * in_req_spec = &in_req_half->req_spec; struct tfe_http_resp_spec * in_resp_spec = &in_resp_half->resp_spec; if ((events & EV_HTTP_REQ_HDR) || (events & EV_HTTP_RESP_HDR)) { char * rewrite_uri = NULL; size_t rewrite_uri_sz=0; if (tfe_http_in_request(events)) { if(in_req_spec->uri != NULL) { rewrite_uri_sz = execute_replace_rule(in_req_spec->uri, strlen(in_req_spec->uri), kZoneRequestUri, rep_ctx->rule, rep_ctx->n_rule, &rewrite_uri, 1); } if(rewrite_uri_sz>0) rep_ctx->actually_replaced=1; rep_ctx->replacing = tfe_http_session_request_create(to_write_sess, in_req_spec->method, rewrite_uri_sz >0 ? rewrite_uri : in_req_spec->uri); tfe_http_session_request_set(to_write_sess, rep_ctx->replacing); } else { rep_ctx->replacing = tfe_http_session_response_create(to_write_sess, in_resp_spec->resp_code); tfe_http_session_response_set(to_write_sess, rep_ctx->replacing); } if (rewrite_uri != NULL) { FREE(&rewrite_uri); } enum replace_zone zone = tfe_http_in_request(events) ? kZoneRequestHeaders : kZoneResponseHeader; struct tfe_http_half * in_half = tfe_http_in_request(events) ? in_req_half : in_resp_half; struct http_field_name in_header_field{}; const char * in_header_value = NULL; void * iterator = NULL; while (true) { if ((in_header_value = tfe_http_field_iterate(in_half, &iterator, &in_header_field)) == NULL) { break; } rewrite_buff = NULL; rewrite_sz = 0; rewrite_sz=execute_replace_rule(in_header_value, strlen(in_header_value), zone, rep_ctx->rule, rep_ctx->n_rule, &rewrite_buff, 1); if(rewrite_sz>0) rep_ctx->actually_replaced=1; tfe_http_field_write(rep_ctx->replacing, &in_header_field, rewrite_sz>0? rewrite_buff : in_header_value); if(rewrite_buff != NULL) { FREE(&rewrite_buff); } } } if ((events & EV_HTTP_REQ_BODY_BEGIN) || (events & EV_HTTP_RESP_BODY_BEGIN)) { assert(rep_ctx->http_body == NULL); rep_ctx->http_body = evbuffer_new(); } if ((events & EV_HTTP_REQ_BODY_CONT) || (events & EV_HTTP_RESP_BODY_CONT)) { evbuffer_add(rep_ctx->http_body, body_frag, frag_size); } if ((events & EV_HTTP_REQ_BODY_END) || (events & EV_HTTP_RESP_BODY_END)) { int options = 0; char * __http_body = (char *) evbuffer_pullup(rep_ctx->http_body, -1); size_t __http_body_len = evbuffer_get_length(rep_ctx->http_body); enum replace_zone r_zone = tfe_http_in_request(events) ? kZoneRequestBody : kZoneResponseBody; rewrite_buff = NULL; rewrite_sz = 0; if ((tfe_http_in_response(events) && in_resp_spec->content_type != NULL && strcasestr(in_resp_spec->content_type, "utf-8")) || tfe_http_in_request(events)) { options = 1; } rewrite_sz = execute_replace_rule(__http_body, __http_body_len, r_zone, rep_ctx->rule, rep_ctx->n_rule, &rewrite_buff, options); if (rewrite_sz >0 ) { tfe_http_half_append_body(rep_ctx->replacing, rewrite_buff, rewrite_sz, 0); rep_ctx->actually_replaced=1; } else { tfe_http_half_append_body(rep_ctx->replacing, __http_body, __http_body_len, 0); } if (rewrite_buff != NULL) { FREE(&rewrite_buff); } if (rep_ctx->http_body != NULL) { evbuffer_free(rep_ctx->http_body); rep_ctx->http_body = NULL; } } if ((events & EV_HTTP_REQ_END) || (events & EV_HTTP_RESP_END)) { tfe_http_half_append_body(rep_ctx->replacing, NULL, 0, 0); rep_ctx->replacing = NULL; } } static void http_get_client_id(const struct tfe_stream * stream, char *replace_regex) { const char *sip,*dip,*sport,*dport; tfe_stream_addr_str_split((char *)stream->str_stream_info, &sip, &sport, &dip, &dport); snprintf(replace_regex, TFE_SYMBOL_MAX, "%s", sip); } static void http_get_subscriber_id(const struct tfe_stream * stream, char *replace_regex) { int ret = 0; uint16_t opt_out_size; char source_subscribe_id[TFE_SYMBOL_MAX] = {0}; struct tfe_cmsg *cmsg = tfe_stream_get0_cmsg(stream); if (cmsg != NULL) { ret = tfe_cmsg_get_value(cmsg, TFE_CMSG_SRC_SUB_ID, (unsigned char *)source_subscribe_id, sizeof(source_subscribe_id), &opt_out_size); if (ret != 0) { TFE_LOG_ERROR(g_proxy_rt->local_logger, "fetch src sub id from cmsg failed, ret: %d addr: %s", ret, stream->str_stream_info); } } if(strlen(source_subscribe_id) > 0) { snprintf(replace_regex, TFE_SYMBOL_MAX, "%s", source_subscribe_id); } else { snprintf(replace_regex, TFE_SYMBOL_MAX, "%s", " "); } } static int http_regex_replace(const struct tfe_stream * stream, char *message, char *profile_id_str, char **rewrite_message) { int i=0, n_rule=0; char replace_with[TFE_SYMBOL_MAX]={0}; struct replace_rule rule[3]; memset(rule, 0, sizeof(struct replace_rule)); if(message == NULL) { return 0; } if(strcasestr(message,"{{tsg_policy_uuid}}") != NULL) { rule[n_rule].zone = kZoneRequestUri; rule[n_rule].find = tfe_strdup("{{tsg_policy_uuid}}"); snprintf(replace_with, TFE_SYMBOL_MAX, "%s", profile_id_str); rule[n_rule].replace_with = tfe_strdup(replace_with); n_rule++; } if(strcasestr(message,"tsg_subscriber_id") != NULL) { memset(replace_with, 0, TFE_SYMBOL_MAX); rule[n_rule].zone = kZoneRequestUri; rule[n_rule].find = tfe_strdup("{{tsg_subscriber_id}}"); http_get_subscriber_id(stream, replace_with); rule[n_rule].replace_with = tfe_strdup(replace_with); n_rule++; } if(strcasestr(message,"tsg_client_ip") != NULL) { memset(replace_with, 0, TFE_SYMBOL_MAX); rule[n_rule].zone = kZoneRequestUri; rule[n_rule].find = tfe_strdup("{{tsg_client_ip}}"); http_get_client_id(stream, replace_with); rule[n_rule].replace_with = tfe_strdup(replace_with); n_rule++; } size_t rewrite_uri_sz = execute_replace_rule(message, strlen(message), kZoneRequestUri, rule, n_rule, rewrite_message, 1); for(i=0; iparam; int resp_code = param->status_code; char *rd_url = param->message; int ratio = http_enforcement_ratio(param->enforcement_ratio); if (ratio != 1) { TFE_LOG_DEBUG(g_proxy_rt->local_logger, "enforcement ratio:%f", param->enforcement_ratio); ctx->action = PX_ACTION_NONE; return; } ctx->manipulate_replaced = 1; if (resp_code <= 0 || rd_url == NULL){ TFE_LOG_ERROR(g_proxy_rt->local_logger, "Invalid redirect rule %s paramter", ctx->enforce_rules[0].config_uuid_string); goto error_out; } if ((events & EV_HTTP_RESP_BODY_BEGIN) || (events & EV_HTTP_RESP_BODY_CONT) || (events & EV_HTTP_RESP_BODY_END) || (events & EV_HTTP_RESP_END)) { ctx->action = PX_ACTION_NONE; return; } to_write = tfe_http_session_allow_write(session); if (to_write == NULL) { assert(0); } ATOMIC_INC(&(g_proxy_rt->stat_val[STAT_ACTION_REDIRECT])); response = tfe_http_session_response_create(to_write, resp_code); rewrite_uri_sz = http_regex_replace(stream, rd_url, ctx->enforce_rules[0].config_uuid_string, &rewrite_uri); if(rewrite_uri_sz>0 && rewrite_uri!= NULL) { tfe_http_std_field_write(response, TFE_HTTP_LOCATION, rewrite_uri); FREE(&rewrite_uri); } else { tfe_http_std_field_write(response, TFE_HTTP_LOCATION, rd_url); } tfe_http_std_field_write(response, TFE_HTTP_CONT_LENGTH, "0"); tfe_http_half_append_body(response, NULL, 0, 0); tfe_http_session_response_set(to_write, response); tfe_http_session_detach(session); error_out: return; } static void http_block(const struct tfe_stream * stream, const struct tfe_http_session * session, enum tfe_http_event events, struct proxy_http_ctx * ctx) { int ret = -1; struct tfe_http_half * response = NULL; char * page_buff = NULL; size_t page_size = 0; size_t rewrite_message_sz=0; char *rewrite_message=NULL; char cont_len_str[16]; struct policy_action_param *param = ctx->param; int resp_code = param->status_code; char *message = param->message; struct tfe_http_session * to_write_sess = NULL; if (events & EV_HTTP_RESP_HDR || tfe_http_in_hdr(events)) { to_write_sess = tfe_http_session_allow_write(session); response = tfe_http_session_response_create(to_write_sess, resp_code); ret = html_generate(param->profile_uuid_str, message, &page_buff, &page_size); if (ret != 0) { rewrite_message_sz = http_regex_replace(stream, message, ctx->enforce_rules[0].config_uuid_string, &rewrite_message); if(rewrite_message_sz>0 && rewrite_message!= NULL) { message = rewrite_message; } /*read local configuration**/ template_generate(resp_code, message, &page_buff, &page_size); if(rewrite_message_sz>0 && rewrite_message!= NULL) { FREE(&rewrite_message); } } tfe_http_std_field_write(response, TFE_HTTP_CONT_TYPE, "text/html; charset=utf-8"); snprintf(cont_len_str, sizeof(cont_len_str), "%lu", page_size); tfe_http_std_field_write(response, TFE_HTTP_CONT_LENGTH, cont_len_str); ATOMIC_INC(&(g_proxy_rt->stat_val[STAT_ACTION_REJECT])); tfe_http_half_append_body(response, page_buff, page_size, 0); tfe_http_half_append_body(response, NULL, 0, 0); tfe_http_session_response_set(to_write_sess, response); tfe_http_session_detach(session); html_free(&page_buff); } else { ATOMIC_INC(&(g_proxy_rt->stat_val[STAT_ACTION_REJECT])); to_write_sess = tfe_http_session_allow_write(session); tfe_http_session_kill(to_write_sess); } return; } static void http_hijack(const struct tfe_http_session * session, enum tfe_http_event events, struct proxy_http_ctx * ctx) { struct policy_action_param *param = ctx->param; struct tfe_http_half * response = NULL; struct tfe_http_session * to_write_sess = NULL; if (param->profile_uuid_str == NULL) { TFE_LOG_ERROR(g_proxy_rt->local_logger, "Invalid hijack rule %s", ctx->enforce_rules[0].config_uuid_string); ctx->action = PX_ACTION_NONE; return; } if (http_enforcement_ratio(param->enforcement_ratio) != 1) { TFE_LOG_DEBUG(g_proxy_rt->local_logger, "enforcement ratio:%f", param->enforcement_ratio); ctx->action = PX_ACTION_NONE; return; } ctx->manipulate_replaced = 1; if (tfe_http_in_request(events)) { return; } if(events & EV_HTTP_RESP_HDR) { struct manipulate_profile* hijack_profile=get_profile_by_id("PROXY_REPLACEMENT_FILE", param->profile_uuid_str); if (NULL == hijack_profile) { TFE_LOG_ERROR(g_proxy_rt->local_logger, "get table obj faild, profile_id = %s", param->profile_uuid_str); ctx->action = PX_ACTION_NONE; return; } char * hijack_buff=NULL; size_t hijack_size=0; hijack_buff = tfe_read_file(hijack_profile->profile_msg, &hijack_size); if (NULL == hijack_buff){ TFE_LOG_ERROR(g_proxy_rt->local_logger, "read hijack file faild, path = %s", hijack_profile->profile_msg); ctx->action = PX_ACTION_NONE; return; } if (try_send_by_token(hijack_size) <= 0) { FREE(&hijack_buff); TFE_LOG_ERROR(g_proxy_rt->local_logger, "No token is available to send data, profile_id = %s", param->profile_uuid_str); ctx->action = PX_ACTION_NONE; return; } ctx->inject_sz = hijack_size; ATOMIC_ADD(&(g_proxy_rt->stat_val[STAT_ACTION_HIJACK_SZ]), hijack_size); ATOMIC_INC(&(g_proxy_rt->stat_val[STAT_ACTION_HIJACK])); char cont_len_str[16]; to_write_sess = tfe_http_session_allow_write(session); response = tfe_http_session_response_create(to_write_sess, 200); if (0!=strcasecmp(hijack_profile->profile_name, "null")) { int hijack_file_len = strlen(hijack_profile->profile_name)+strlen("filename=\"\"")+1; char *hijack_file_name = ALLOC(char, hijack_file_len); snprintf(hijack_file_name, hijack_file_len, "filename=\"%s\"", hijack_profile->profile_name); tfe_http_nonstd_field_write(response, "Content-Disposition", hijack_file_name); FREE(&hijack_file_name); } const char* cont_disposition_val=tfe_http_std_field_read(to_write_sess->resp, TFE_HTTP_CONT_DISPOSITION); if (cont_disposition_val != NULL) { tfe_http_std_field_write(response, TFE_HTTP_CONT_DISPOSITION, cont_disposition_val); } tfe_http_std_field_write(response, TFE_HTTP_CONT_TYPE, hijack_profile->profile_type); snprintf(cont_len_str, sizeof(cont_len_str), "%lu", hijack_size); tfe_http_std_field_write(response, TFE_HTTP_CONT_LENGTH, cont_len_str); tfe_http_half_append_body(response, hijack_buff, hijack_size, 0); tfe_http_half_append_body(response, NULL, 0, 0); tfe_http_session_response_set(to_write_sess, response); tfe_http_session_detach(session); ma_profile_table_free(hijack_profile); FREE(&hijack_buff); hijack_profile = NULL; } else { to_write_sess = tfe_http_session_allow_write(session); tfe_http_session_kill(to_write_sess); } return; } static int format_insert_rule(char *profile_uuid, char *position, enum manipulate_action action, struct insert_rule *rule) { int ret = 0; if(profile_uuid == NULL) { ret=-1; return ret; } const char *profile_type = (action==MA_ACTION_INJECT_JAVESCRIPT)? "js" : "css"; const char *proflie_table_name = (action==MA_ACTION_INJECT_JAVESCRIPT)? "PROXY_JS_FILE" : "PROXY_CSS_FILE"; struct manipulate_profile* insert_profile=get_profile_by_id(proflie_table_name, profile_uuid); if(insert_profile==NULL) { ret=-1; return ret; } rule->script = tfe_strdup(insert_profile->profile_msg); rule->type = tfe_strdup(profile_type); if(position) { rule->position = tfe_strdup(position); } rule->inject_sz = insert_profile->msg_len; ma_profile_table_free(insert_profile); insert_profile = NULL; return ret; } static void http_insert(const struct tfe_stream * stream, const struct tfe_http_session * session, enum tfe_http_event events, const unsigned char * body_frag, size_t frag_size, enum manipulate_action action, struct proxy_http_ctx * ctx) { struct tfe_http_session * to_write_sess = NULL; char * rewrite_buff = NULL; size_t rewrite_sz = 0; struct policy_action_param *param = ctx->param; int ratio = http_enforcement_ratio(param->enforcement_ratio); if (ratio != 1) { TFE_LOG_DEBUG(g_proxy_rt->local_logger, "enforcement ratio:%f", param->enforcement_ratio); ctx->action = PX_ACTION_NONE; return; } to_write_sess = tfe_http_session_allow_write(session); if (to_write_sess == NULL) //fail to wirte, abandon. { TFE_STREAM_LOG_INFO(stream, "tfe_http_session_allow_write() %s failed.", session->req->req_spec.uri); ctx->action = PX_ACTION_NONE; tfe_http_session_detach(session); return; } struct insert_ctx *ins_ctx = ctx->ins_ctx; if (ctx->ins_ctx == NULL) { /* we must determinate the replace action on HTTP header, otherwise, * the header has been forwarded, only replace the body but not modify header will raise exception */ if ((events & EV_HTTP_REQ_HDR) || (events & EV_HTTP_RESP_HDR)) { ctx->ins_ctx = ins_ctx = ALLOC(struct insert_ctx, 1); ins_ctx->rule = ALLOC(struct insert_rule, 1); int ret=format_insert_rule(param->profile_uuid_str, param->position, action, ins_ctx->rule); if (ret<0) { TFE_LOG_ERROR(g_proxy_rt->local_logger, "Failed to get policy table, profile_id = %s", param->profile_uuid_str); ctx->action = PX_ACTION_NONE; return; } if (try_send_by_token(ins_ctx->rule->inject_sz) <= 0) { TFE_LOG_ERROR(g_proxy_rt->local_logger, "No token is available to send data, profile_id = %s", param->profile_uuid_str); ctx->action = PX_ACTION_NONE; return; } ctx->inject_sz = ins_ctx->rule->inject_sz; } else { TFE_STREAM_LOG_INFO(stream, "Can only setup insert on REQ/RESP headers, detached."); ctx->action = PX_ACTION_NONE; tfe_http_session_detach(session); return; } } struct tfe_http_half * in_req_half = session->req; struct tfe_http_half * in_resp_half = session->resp; struct tfe_http_req_spec * in_req_spec = &in_req_half->req_spec; struct tfe_http_resp_spec * in_resp_spec = &in_resp_half->resp_spec; if ((events & EV_HTTP_REQ_HDR) || (events & EV_HTTP_RESP_HDR)) { if (tfe_http_in_request(events)) { ins_ctx->replacing = tfe_http_session_request_create(to_write_sess, in_req_spec->method, in_req_spec->uri); tfe_http_session_request_set(to_write_sess, ins_ctx->replacing); } else { ins_ctx->replacing = tfe_http_session_response_create(to_write_sess, in_resp_spec->resp_code); tfe_http_session_response_set(to_write_sess, ins_ctx->replacing); } struct tfe_http_half * in_half = tfe_http_in_request(events) ? in_req_half : in_resp_half; struct http_field_name in_header_field{}; const char * in_header_value = NULL; void * iterator = NULL; while (true) { if ((in_header_value = tfe_http_field_iterate(in_half, &iterator, &in_header_field)) == NULL) { break; } tfe_http_field_write(ins_ctx->replacing, &in_header_field, in_header_value); } } if ((events & EV_HTTP_REQ_BODY_BEGIN) || (events & EV_HTTP_RESP_BODY_BEGIN)) { assert(ins_ctx->http_body == NULL); ins_ctx->http_body = evbuffer_new(); } if ((events & EV_HTTP_REQ_BODY_CONT) || (events & EV_HTTP_RESP_BODY_CONT)) { evbuffer_add(ins_ctx->http_body, body_frag, frag_size); } if ((events & EV_HTTP_REQ_BODY_END) || (events & EV_HTTP_RESP_BODY_END)) { char * http_body = (char *) evbuffer_pullup(ins_ctx->http_body, -1); size_t http_body_len = evbuffer_get_length(ins_ctx->http_body); const char* cont_type_val=tfe_http_std_field_read(ins_ctx->replacing, TFE_HTTP_CONT_TYPE); rewrite_buff = NULL; rewrite_sz = 0; if (cont_type_val != NULL && strstr(cont_type_val, "text/html") != NULL) { rewrite_sz = execute_insert_rule(http_body, http_body_len, ins_ctx->rule, &rewrite_buff); } if (rewrite_sz >0) { tfe_http_half_append_body(ins_ctx->replacing, rewrite_buff, rewrite_sz, 0); ATOMIC_INC(&(g_proxy_rt->stat_val[STAT_ACTION_INSERT])); ATOMIC_ADD(&(g_proxy_rt->stat_val[STAT_ACTION_INSERT_SZ]), ctx->inject_sz); ins_ctx->actually_inserted=1; } else { tfe_http_half_append_body(ins_ctx->replacing, http_body, http_body_len, 0); } if (rewrite_buff != NULL) { FREE(&rewrite_buff); } if (ins_ctx->http_body != NULL) { evbuffer_free(ins_ctx->http_body); ins_ctx->http_body = NULL; } } if ((events & EV_HTTP_REQ_END) || (events & EV_HTTP_RESP_END)) { tfe_http_half_append_body(ins_ctx->replacing, NULL, 0, 0); ins_ctx->replacing = NULL; } return; } void http_element(const struct tfe_stream * stream, const struct tfe_http_session * session, enum tfe_http_event events, const unsigned char * body_frag, size_t frag_size, struct proxy_http_ctx * ctx) { struct tfe_http_session * to_write_sess = NULL; char * rewrite_buff = NULL; size_t rewrite_sz = 0; if (tfe_http_in_request(events)) { return; } to_write_sess = tfe_http_session_allow_write(session); if (to_write_sess == NULL) { TFE_STREAM_LOG_INFO(stream, "tfe_http_session_allow_write() %s failed.", session->req->req_spec.uri); ctx->action = PX_ACTION_NONE; tfe_http_session_detach(session); return; } struct edit_element_ctx * edit_ctx = ctx->edit_ctx; if (ctx->edit_ctx == NULL) { if (events & EV_HTTP_RESP_HDR) { struct policy_action_param *param = ctx->param; ctx->edit_ctx = edit_ctx = ALLOC(struct edit_element_ctx, 1); edit_ctx->item = param->elem_rule; edit_ctx->n_item = param->e_rule; } else { TFE_STREAM_LOG_INFO(stream, "Can only setup editing on RESP headers, detached."); ctx->action = PX_ACTION_NONE; tfe_http_session_detach(session); return; } } struct tfe_http_half * in_resp_half = session->resp; struct tfe_http_resp_spec * in_resp_spec = &in_resp_half->resp_spec; if (events & EV_HTTP_RESP_HDR) { edit_ctx->editing= tfe_http_session_response_create(to_write_sess, in_resp_spec->resp_code); tfe_http_session_response_set(to_write_sess, edit_ctx->editing); struct tfe_http_half * in_half = in_resp_half; struct http_field_name in_header_field{}; const char * in_header_value = NULL; void * iterator = NULL; while (true) { if ((in_header_value = tfe_http_field_iterate(in_half, &iterator, &in_header_field)) == NULL) { break; } tfe_http_field_write(edit_ctx->editing, &in_header_field, in_header_value); } } if (events & EV_HTTP_RESP_BODY_BEGIN) { assert(edit_ctx->http_body == NULL); edit_ctx->http_body = evbuffer_new(); } if (events & EV_HTTP_RESP_BODY_CONT) { evbuffer_add(edit_ctx->http_body, body_frag, frag_size); } if (events & EV_HTTP_RESP_BODY_END) { char * __http_body = (char *) evbuffer_pullup(edit_ctx->http_body, -1); size_t __http_body_len = evbuffer_get_length(edit_ctx->http_body); rewrite_buff = NULL; rewrite_sz = 0; if(in_resp_spec->content_type != NULL && strcasestr(in_resp_spec->content_type, "text/html")) { rewrite_sz = execute_edit_element_rule(__http_body, __http_body_len, edit_ctx->item, edit_ctx->n_item, &rewrite_buff, 0); } if(in_resp_spec->content_type != NULL && (strcasestr(in_resp_spec->content_type, "json") || strcasestr(in_resp_spec->content_type, "text/javascript"))) { rewrite_sz = execute_edit_element_rule(__http_body, __http_body_len, edit_ctx->item, edit_ctx->n_item, &rewrite_buff, 1); } if (rewrite_sz >0 ) { tfe_http_half_append_body(edit_ctx->editing, rewrite_buff, rewrite_sz, 0); ATOMIC_INC(&(g_proxy_rt->stat_val[STAT_ACTION_EDIT_ELEMENT])); edit_ctx->actually_edited=1; } else { tfe_http_half_append_body(edit_ctx->editing, __http_body, __http_body_len, 0); } if (rewrite_buff != NULL) { FREE(&rewrite_buff); } if (edit_ctx->http_body != NULL) { evbuffer_free(edit_ctx->http_body); edit_ctx->http_body = NULL; } } if (events & EV_HTTP_RESP_END) { tfe_http_half_append_body(edit_ctx->editing, NULL, 0, 0); edit_ctx->editing = NULL; } } static void http_manipulate(const struct tfe_stream * stream, const struct tfe_http_session * session, enum tfe_http_event events, const unsigned char * body_frag, size_t frag_size, struct proxy_http_ctx * ctx) { struct policy_action_param *param = ctx->param; if (param == NULL) { TFE_LOG_ERROR(g_proxy_rt->local_logger, "Failed to get the json format parsed. config_id = %s",ctx->enforce_rules[0].config_uuid_string); ctx->action = PX_ACTION_NONE; return; } switch(param->action) { case MA_ACTION_REPLACE_TEXT: http_replace(stream, session, events, body_frag, frag_size, ctx); break; case MA_ACTION_REPLACE_FILE: http_hijack(session, events, ctx); break; case MA_ACTION_INJECT_JAVESCRIPT: case MA_ACTION_INJECT_CSS: http_insert(stream, session, events, body_frag, frag_size, param->action, ctx); break; case MA_ACTION_EDIT_ELEMENT: http_element(stream, session, events, body_frag, frag_size, ctx); break; default: assert(0); break; } return; } static int get_fqdn_len(char *str_host) { char *p=NULL; int fqdn_len=0; if(str_host == NULL) { goto finish; } p=index(str_host, ':'); if(p==NULL) { fqdn_len=strlen(str_host); } else { fqdn_len=p-str_host; } finish: return fqdn_len; } enum proxy_action http_scan(const struct tfe_http_session * session, enum tfe_http_event events, const unsigned char * body_frag, size_t frag_size, struct proxy_http_ctx * ctx, const struct tfe_stream * stream) { void * iterator = NULL; const char *filed_name=NULL; const char * field_val = NULL; struct http_field_name field_name; struct tfe_http_half * http_half; uuid_t *result = ctx->result; char buff[TFE_STRING_MAX], * p = NULL; int scan_ret = 0; size_t n_hit_result=0; size_t hit_cnt = ctx->hit_cnt, i = 0; if (events & EV_HTTP_REQ_HDR) { char *str_host = (char *)session->req->req_spec.host; int str_host_length = get_fqdn_len(str_host); if (str_host != NULL && str_host_length != 0) { scan_ret = maat_scan_string(g_proxy_rt->feather, "TSG_OBJ_FQDN", "SERVER_FQDN", str_host, str_host_length, result + hit_cnt, MAX_SCAN_RESULT - hit_cnt, &n_hit_result, ctx->scan_mid); if (scan_ret == MAAT_SCAN_HIT) { hit_cnt += n_hit_result; } scan_ret = maat_scan_not_logic(g_proxy_rt->feather, "TSG_OBJ_FQDN", "SERVER_FQDN", result + hit_cnt, MAX_SCAN_RESULT - hit_cnt, &n_hit_result, ctx->scan_mid); if (scan_ret == MAAT_SCAN_HIT) { hit_cnt += n_hit_result; } scan_ret = tfe_scan_fqdn_tags(stream, result, ctx->scan_mid, hit_cnt, g_proxy_rt->local_logger); if (scan_ret > 0) { hit_cnt += scan_ret; } } const char * str_url = session->req->req_spec.url; int str_url_length = (int) (strlen(session->req->req_spec.url)); scan_ret = maat_scan_string(g_proxy_rt->feather, "TSG_OBJ_URL", "HTTP_URL", str_url, str_url_length, result + hit_cnt, MAX_SCAN_RESULT - hit_cnt, &n_hit_result, ctx->scan_mid); if (scan_ret == MAAT_SCAN_HIT) { hit_cnt += n_hit_result; } scan_ret = maat_scan_not_logic(g_proxy_rt->feather, "TSG_OBJ_URL", "HTTP_URL", result + hit_cnt, MAX_SCAN_RESULT - hit_cnt, &n_hit_result, ctx->scan_mid); if (scan_ret == MAAT_SCAN_HIT) { hit_cnt += n_hit_result; } } if ((events & EV_HTTP_REQ_HDR) || (events & EV_HTTP_RESP_HDR)) { filed_name = events & EV_HTTP_REQ_HDR ? "HTTP_REQ_HDR" : "HTTP_RES_HDR"; struct maat_stream *sp = maat_stream_new(g_proxy_rt->feather, "TSG_OBJ_KEYWORD", filed_name, ctx->scan_mid); http_half = events & EV_HTTP_REQ_HDR ? session->req : session->resp; while (hit_cnt < MAX_SCAN_RESULT) { field_val = tfe_http_field_iterate(http_half, &iterator, &field_name); if (field_val == NULL) { break; } scan_ret = maat_stream_scan(sp, field_val, strlen(field_val), result + hit_cnt, MAX_SCAN_RESULT - hit_cnt, &n_hit_result, ctx->scan_mid); if (scan_ret == MAAT_SCAN_HIT) { hit_cnt += n_hit_result; } const char * str_field_name = http_field_name_to_string(&field_name); if(str_field_name == NULL) { break; } scan_ret = maat_stream_scan(sp, str_field_name, strlen(str_field_name), result + hit_cnt, MAX_SCAN_RESULT - hit_cnt, &n_hit_result, ctx->scan_mid); if (scan_ret == MAAT_SCAN_HIT) { hit_cnt += n_hit_result; } } scan_ret = maat_scan_not_logic(g_proxy_rt->feather, "TSG_OBJ_KEYWORD", filed_name, result + hit_cnt, MAX_SCAN_RESULT - hit_cnt, &n_hit_result, ctx->scan_mid); if (scan_ret == MAAT_SCAN_HIT) { hit_cnt += n_hit_result; } maat_stream_free(sp); } if ((events & EV_HTTP_REQ_BODY_BEGIN) | (events & EV_HTTP_RESP_BODY_BEGIN)) { assert(ctx->sp == NULL); filed_name = events & EV_HTTP_REQ_BODY_BEGIN ? "HTTP_REQ_BODY" : "HTTP_RES_BODY"; ctx->sp = maat_stream_new(g_proxy_rt->feather, "TSG_OBJ_KEYWORD", filed_name, ctx->scan_mid); } const unsigned char *scan_body_frag=NULL; size_t scan_len=0; if (body_frag != NULL) { scan_body_frag = body_frag; while (scan_body_frag < body_frag + frag_size) { scan_len = (scan_body_frag + MAX_SCAN_DATA_SIZE < body_frag + frag_size) ? MAX_SCAN_DATA_SIZE : (body_frag + frag_size - scan_body_frag); scan_ret = maat_stream_scan(ctx->sp, (const char *)scan_body_frag, scan_len, result + hit_cnt, MAX_SCAN_RESULT - hit_cnt, &n_hit_result, ctx->scan_mid); if (scan_ret == MAAT_SCAN_HIT) { hit_cnt += n_hit_result; } scan_body_frag += MAX_SCAN_DATA_SIZE; } } if ((events & EV_HTTP_REQ_BODY_END) | (events & EV_HTTP_RESP_BODY_END)) { filed_name = events & EV_HTTP_REQ_BODY_END ? "HTTP_REQ_BODY" : "HTTP_RES_BODY"; scan_ret = maat_scan_not_logic(g_proxy_rt->feather, "TSG_OBJ_KEYWORD", filed_name, result + hit_cnt, MAX_SCAN_RESULT - hit_cnt, &n_hit_result, ctx->scan_mid); if (scan_ret == MAAT_SCAN_HIT) { hit_cnt += n_hit_result; } maat_stream_free(ctx->sp); ctx->sp = NULL; } if (hit_cnt > 0) { ctx->action = decide_ctrl_action(result, hit_cnt, &ctx->enforce_rules, &ctx->n_enforce, &ctx->param); if (ctx->action == PX_ACTION_ALLOW) { TFE_LOG_INFO(g_proxy_rt->local_logger, "Bypass rules matched: url=%s policy id=%s.", session->req->req_spec.url, ctx->enforce_rules[0].config_uuid_string); goto __out; } if (hit_cnt > 1) { p = buff; for (i = 0; i < hit_cnt && ilocal_logger, "Multiple rules matched: url=%s num=%lu ids=%s execute=%s.", session->req->req_spec.url, hit_cnt, buff, ctx->enforce_rules[0].config_uuid_string); } ctx->hit_cnt=0; } __out: return ctx->action; } void enforce_control_policy(const struct tfe_stream * stream, const struct tfe_http_session * session, enum tfe_http_event events, const unsigned char * body_frag, size_t frag_size, unsigned int thread_id, struct proxy_http_ctx * ctx) { if(ctx->action==PX_ACTION_NONE||ctx->action==PX_ACTION_MONITOR) { //ctx->action changed in http_scan. http_scan(session, events, body_frag, frag_size, ctx, stream); } switch (ctx->action) { case PX_ACTION_NONE: break; case PX_ACTION_MONITOR: //send log on close. break; case PX_ACTION_DENY: http_block(stream, session, events, ctx); break; case PX_ACTION_MANIPULATE: http_manipulate(stream, session, events, body_frag, frag_size, ctx); break; case PX_ACTION_ALLOW: tfe_http_session_detach(session); ATOMIC_INC(&(g_proxy_rt->stat_val[STAT_ACTION_WHITELSIT])); break; case PX_ACTION_REDIRECT: http_redirect(stream, session, events, ctx); break; case PX_ACTION_EXECUTE: http_lua(stream, session, events, body_frag, frag_size, ctx); break; default: assert(0); break; } /* Don't store reqeust/response body when NOT hit or hit whitelist */ if(ctx->action == PX_ACTION_NONE || ctx->action == PX_ACTION_ALLOW) { return; } /* Otherwise, store body */ if(events & EV_HTTP_REQ_BODY_CONT) { if(ctx->log_req_body == NULL) ctx->log_req_body = evbuffer_new(); evbuffer_add(ctx->log_req_body, body_frag, frag_size); } if(events & EV_HTTP_RESP_BODY_CONT) { if(ctx->log_resp_body == NULL) ctx->log_resp_body = evbuffer_new(); evbuffer_add(ctx->log_resp_body, body_frag, frag_size); } if((((ctx_actually_replaced(ctx)) || (ctx_actually_inserted(ctx)) || (ctx_actually_edited(ctx)) || (ctx_actually_manipulate(ctx)) || ctx_actually_ran_script(ctx)) || ctx->action == PX_ACTION_DENY || (ctx->action == PX_ACTION_MONITOR))) { proxy_send_metric_log(stream, ctx, thread_id, 1); } return; } #define RESUMED_CB_NO_MORE_CALLS 0 void proxy_on_http_begin(const struct tfe_stream *stream, const struct tfe_http_session *session, unsigned int thread_id, void **pme) { if (!g_proxy_rt->enable_plugin) { return; } struct proxy_http_ctx * ctx = *(struct proxy_http_ctx **) pme; struct ipaddr sapp_addr; int hit_cnt = 0, scan_ret=0; assert(ctx == NULL); ATOMIC_INC(&(g_proxy_rt->stat_val[STAT_SESSION])); ctx = proxy_http_ctx_new(thread_id); scan_ret = tfe_scan_subscribe_id(stream, ctx->result, ctx->scan_mid, hit_cnt, g_proxy_rt->local_logger); if(scan_ret>0) { hit_cnt += scan_ret; } scan_ret = tfe_scan_ip_tags(stream, ctx->result, ctx->scan_mid, hit_cnt, g_proxy_rt->local_logger); if(scan_ret>0) { hit_cnt += scan_ret; } long long app_id=67; scan_ret = tfe_scan_app_id(ctx->result, ctx->scan_mid, hit_cnt, app_id); if(scan_ret > 0) { hit_cnt += scan_ret; } scan_ret = tfe_scan_device(stream, ctx->result, ctx->scan_mid, hit_cnt, g_proxy_rt->local_logger); if(scan_ret > 0) { hit_cnt += scan_ret; } scan_ret = tfe_scan_zone(stream, ctx->result, ctx->scan_mid, hit_cnt); if(scan_ret > 0) { hit_cnt += scan_ret; } addr_tfe2sapp(stream->addr, &sapp_addr); if (sapp_addr.addrtype == ADDR_TYPE_IPV4) { scan_ret = tfe_scan_ipv4_addr(stream, ctx->result, ctx->scan_mid, hit_cnt, sapp_addr); if (scan_ret > 0) { hit_cnt += scan_ret; } scan_ret = tfe_scan_port(stream, ctx->result, ctx->scan_mid, hit_cnt, sapp_addr.v4->source, sapp_addr.v4->dest); if(scan_ret > 0) { hit_cnt += scan_ret; } } if (sapp_addr.addrtype == ADDR_TYPE_IPV6) { scan_ret = tfe_scan_ipv6_addr(stream, ctx->result, ctx->scan_mid, hit_cnt, sapp_addr); if (scan_ret > 0) { hit_cnt += scan_ret; } scan_ret = tfe_scan_port(stream, ctx->result, ctx->scan_mid, hit_cnt, sapp_addr.v6->source, sapp_addr.v6->dest); if(scan_ret > 0) { hit_cnt += scan_ret; } } if(hit_cnt > 0) { ctx->hit_cnt = hit_cnt; } *pme = ctx; return; } void proxy_on_http_end(const struct tfe_stream * stream, const struct tfe_http_session * session, unsigned int thread_id, void ** pme) { if (!g_proxy_rt->enable_plugin) { return; } struct proxy_http_ctx * ctx = *(struct proxy_http_ctx **) pme; size_t i=0, j=0; int ret=0; if(ctx->action == PX_ACTION_MANIPULATE && ctx->param->action == MA_ACTION_REPLACE_TEXT && ctx->rep_ctx->actually_replaced==0) { for(i=0; i< ctx->n_enforce; i++) { if((unsigned char)ctx->enforce_rules[i].action == PX_ACTION_MANIPULATE) { if(i+1 > ctx->n_enforce) { memmove(ctx->enforce_rules+i, ctx->enforce_rules+i+1, sizeof(struct maat_rule_t)); } j++; } } ctx->n_enforce-=j; if(ctx->n_enforce==0) { ctx->action = PX_ACTION_NONE; FREE(&(ctx->enforce_rules)); } } struct proxy_log log_msg = {.stream=stream, .http=session, .result=(struct log_rule_t *)ctx->enforce_rules, .result_num=ctx->n_enforce, .req_body=ctx->log_req_body, .resp_body=ctx->log_resp_body, .action=0, .inject_sz=ctx->inject_sz, .c2s_byte_num=ctx->c2s_byte_num, .s2c_byte_num=ctx->s2c_byte_num}; if(ctx->action == PX_ACTION_MANIPULATE) { log_msg.action = ctx->param->action; } if(ctx->action != PX_ACTION_NONE && (((ctx_actually_replaced(ctx)) || (ctx_actually_inserted(ctx)) || (ctx_actually_edited(ctx)) || (ctx_actually_manipulate(ctx)) || ctx_actually_ran_script(ctx)) || (ctx->action == PX_ACTION_MONITOR || ctx->action == PX_ACTION_DENY || ctx->action == PX_ACTION_ALLOW))) { ret=proxy_send_log(g_proxy_rt->send_logger, &log_msg); ATOMIC_ADD(&(g_proxy_rt->stat_val[STAT_LOG_NUM]), ret); for(i=0; i< ctx->n_enforce; i++) { if(ctx->enforce_rules[i].action == PX_ACTION_MONITOR) { ATOMIC_INC(&(g_proxy_rt->stat_val[STAT_ACTION_MONIT])); } } proxy_send_metric_log(stream, ctx, thread_id, 0); } if(ctx->rep_ctx && ctx->rep_ctx->actually_replaced==1) { ATOMIC_INC(&(g_proxy_rt->stat_val[STAT_ACTION_REPLACE])); } if(ctx->tsg_ctx && ctx->tsg_ctx->actually_executed==1) { ATOMIC_INC(&(g_proxy_rt->stat_val[STAT_ACTION_RUN_SCRIPT])); } proxy_http_ctx_free(ctx); *pme = NULL; return; } int proxy_on_http_data(const struct tfe_stream * stream, const struct tfe_http_session * session, enum tfe_http_event events, const unsigned char * body_frag, size_t frag_size, unsigned int thread_id, void ** pme) { if (!g_proxy_rt->enable_plugin) { return CALL_NEXT_PLUGIN; } struct proxy_http_ctx * ctx = *(struct proxy_http_ctx **) pme; int ret=0; if(ctx->resumed_cb) { ret=ctx->resumed_cb(stream, session, events, body_frag, frag_size,thread_id, ctx); if(ret==RESUMED_CB_NO_MORE_CALLS) { ctx->resumed_cb=NULL; } return NO_CALL_NEXT_PLUGIN; } enforce_control_policy(stream, session, events, body_frag, frag_size,thread_id, ctx); return NO_CALL_NEXT_PLUGIN; } struct tfe_plugin proxy_http_spec = { .symbol=NULL, .type = TFE_PLUGIN_TYPE_BUSINESS, .on_init = proxy_http_init, .on_deinit = NULL, .on_open = NULL, .on_data = NULL, .on_close = NULL, .on_session_begin=proxy_on_http_begin, .on_session_data=proxy_on_http_data, .on_session_end=proxy_on_http_end }; TFE_PLUGIN_REGISTER(proxy_http, proxy_http_spec)