diff --git a/plugin/business/pangu-http/src/pangu_http.cpp b/plugin/business/pangu-http/src/pangu_http.cpp index 58c0c40..75dd1ca 100644 --- a/plugin/business/pangu-http/src/pangu_http.cpp +++ b/plugin/business/pangu-http/src/pangu_http.cpp @@ -16,6 +16,8 @@ #include #include +#include + #include #include #include @@ -27,21 +29,30 @@ #define MAX_SCAN_RESULT 16 #define MAX_EDIT_ZONE_NUM 64 -enum pangu_action//Bigger action number is prior. +enum pangu_action //Bigger action number is prior. { PG_ACTION_NONE = 0x00, PG_ACTION_MONIT = 0x01, PG_ACTION_FORWARD = 0x02, /* N/A */ PG_ACTION_REJECT = 0x10, PG_ACTION_DROP = 0x20, /* N/A */ - PG_ACTION_REDIRECT = 0x30, + PG_ACTION_MANIPULATE = 0x30, PG_ACTION_RATELIMIT = 0x40, /* N/A */ - PG_ACTION_REPLACE = 0x50, PG_ACTION_LOOP = 0x60, /* N/A */ PG_ACTION_WHITELIST = 0x80, __PG_ACTION_MAX }; +enum manipulate_actin +{ + MA_ACTION_REDIRECT = 0, + MA_ACTION_BLOCK, + MA_ACTION_REPLACE, + MA_ACTION_HIJACK, + MA_ACTION_INSERT, + __MA_ACTION_MAX +}; + enum scan_table { PXY_CTRL_IP, @@ -63,10 +74,47 @@ enum pangu_http_stat STAT_ACTION_REDIRECT, STAT_ACTION_PRE_REPLACE, STAT_ACTION_REPLACE, + STAT_ACTION_HIJACK, + STAT_ACTION_INSERT, STAT_ACTION_WHITELSIT, STAT_SUSPENDING, __PG_STAT_MAX }; + +enum policy_table +{ + POLICY_TABLE_REJECT, + POLICY_TABLE_HIJACK, + POLICY_TABLE_INSERT, + POLICY_TABLE_MAX +}; + +struct policy_object +{ + int cfg_id; + size_t msg_len; + char *profile_name; + char *profile_msg; + char *profile_type; + ctemplate::Template * tpl; +}; + +struct plolicy_param +{ + int ref_cnt; + int action; + + char *message; + char *position; + + int profile_id; + int status_code; + + size_t n_rule; + struct replace_rule *rule; + pthread_mutex_t lock; +}; + struct pangu_rt { Maat_feather_t maat; @@ -77,6 +125,7 @@ struct pangu_rt int log_level; int thread_num; int scan_table_id[__SCAN_TABLE_MAX]; + int plolicy_table_id[POLICY_TABLE_MAX]; ctemplate::Template * tpl_403, * tpl_404, * tpl_451; char * reject_page; int page_size; @@ -90,9 +139,10 @@ struct pangu_rt int fs_id[__PG_STAT_MAX]; struct event_base* gc_evbase; struct event* gcev; - + + int plolicy_param_idx; int ca_store_reseting; - + }; struct pangu_rt * g_pangu_rt; @@ -169,7 +219,7 @@ static Maat_feather_t create_maat_feather(const char * instance_name, const char break; } - + Maat_set_feather_opt(target, MAAT_OPT_FOREIGN_CONT_DIR, "./pangu_files", strlen("./pangu_files")+1); if (maat_stat_on) { @@ -200,6 +250,7 @@ error_out: Maat_burn_feather(target); return NULL; } + static void pangu_http_gc_cb(evutil_socket_t fd, short what, void * arg) { int i=0; @@ -223,6 +274,8 @@ static void pangu_http_stat_init(struct pangu_rt * pangu_runtime) spec[STAT_ACTION_REDIRECT]="redirect"; spec[STAT_ACTION_PRE_REPLACE]="pre_replace"; spec[STAT_ACTION_REPLACE]="replace"; + spec[STAT_ACTION_HIJACK]="hijack"; + spec[STAT_ACTION_INSERT]="insert"; spec[STAT_ACTION_WHITELSIT]="whitelist"; spec[STAT_SUSPENDING]="suspending"; @@ -250,7 +303,7 @@ void trusted_CA_update_start_cb(int update_type, void* u_para) } g_pangu_rt->ca_store_reseting++; } - + } void trusted_CA_update_cert_cb(int table_id, const char* table_line, void* u_para) { @@ -335,6 +388,7 @@ void trusted_CA_update_finish_cb(void* u_para) } } } + static int get_column_pos(const char* line, int column_seq, size_t *offset, size_t *len) { const char* seps=" \t"; @@ -370,12 +424,12 @@ void subscribe_id_new_cb(int table_id, const char* key, const char* table_line, size_t subscribe_id_offset, len; ret=get_column_pos(table_line, 7, &subscribe_id_offset, &len); if(ret<0) - { + { TFE_LOG_ERROR(g_pangu_rt->local_logger, "Add subscribe ID faild: %s", table_line); return; - } + } *ad=ALLOC(char, len+1); - memcpy(*ad, table_line+subscribe_id_offset, len); + memcpy(*ad, table_line+subscribe_id_offset, len); TFE_LOG_INFO(g_pangu_rt->local_logger, "Add subscribe ID: %s", (char*)*ad); return; } @@ -386,12 +440,304 @@ void subscribe_id_free_cb(int table_id, MAAT_PLUGIN_EX_DATA* ad, long argl, void *ad=NULL; } +static +int to_val_idx(const char *key) +{ + const char *clue_action_map[] = {"redirect", + "block", + "replace", + "hijack", + "insert" + }; + size_t i = 0; + + for (i = 0; i < sizeof(clue_action_map) / sizeof(const char *); i++) + { + if (0 == strcasecmp(key, clue_action_map[i])) + break; + } + return i; +} + +void policy_param_new(int idx, const struct Maat_rule_t* rule, const char* srv_def_large, + MAAT_RULE_EX_DATA* ad, long argl, void *argp) +{ + *ad=NULL; + if((unsigned int)rule->serv_def_lenlocal_logger, "invalid policy parameter: id = %d", rule->config_id); + return; + } + + struct plolicy_param* param=ALLOC(struct plolicy_param, 1); + + param->ref_cnt=1; + pthread_mutex_init(&(param->lock), NULL); + + item=cJSON_GetObjectItem(json,"method"); + if(item && item->type==cJSON_String){ + param->action =to_val_idx(item->valuestring); + } + + switch(param->action) + { + case MA_ACTION_REDIRECT: + item=cJSON_GetObjectItem(json,"code"); + if(item && item->type==cJSON_Number){ + param->status_code = item->valueint; + } + item=cJSON_GetObjectItem(json,"to"); + if(item && item->type==cJSON_String){ + param->message = tfe_strdup(item->valuestring); + } + break; + case MA_ACTION_BLOCK: + item=cJSON_GetObjectItem(json,"code"); + if(item && item->type==cJSON_Number){ + param->status_code = item->valueint; + } + item=cJSON_GetObjectItem(json,"message"); + if(item && item->type==cJSON_String){ + param->message = tfe_strdup(item->valuestring); + } + item=cJSON_GetObjectItem(json,"html_profile"); + if(item && item->type==cJSON_Number){ + param->profile_id = item->valueint; + } + break; + case MA_ACTION_REPLACE: + rules = cJSON_GetObjectItem(json, "rules"); + if(rules) + { + size_t idx = 0; + param->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->rule[idx].zone = zone_name_to_id(search); + if (param->rule[idx].zone == kZoneMax) + { + break; + } + param->rule[idx].find = tfe_strdup(cJSON_GetObjectItem(item , "find")->valuestring); + param->rule[idx].replace_with = tfe_strdup(cJSON_GetObjectItem(item , "replace_with")->valuestring); + idx++; + } + param->n_rule = idx; + } + break; + case MA_ACTION_HIJACK: + item=cJSON_GetObjectItem(json,"hijack_profile"); + if(item && item->type==cJSON_Number){ + param->profile_id = item->valueint; + } + break; + case MA_ACTION_INSERT: + item=cJSON_GetObjectItem(json,"insert_profile"); + if(item && item->type==cJSON_Number){ + param->profile_id = item->valueint; + } + item=cJSON_GetObjectItem(json,"position"); + if(item && item->type==cJSON_String){ + param->position = tfe_strdup(item->valuestring); + } + break; + default: assert(0); + break; + } + cJSON_Delete(json); + *ad=param; + return; +} + +void policy_param_free(int idx, const struct Maat_rule_t* rule, const char* srv_def_large, MAAT_RULE_EX_DATA* ad, long argl, void *argp) +{ + unsigned int i=0; + if(*ad==NULL) + { + return; + } + struct plolicy_param* param=(struct plolicy_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; in_rule; i++) + { + FREE(&(param->rule[i].find)); + FREE(&(param->rule[i].replace_with)); + } + + if (param->message) + FREE(&(param->message)); + if (param->position) + FREE(&(param->position)); + FREE(&(param)); + return; +} + +void policy_param_dup(int idx, MAAT_RULE_EX_DATA *to, MAAT_RULE_EX_DATA *from, long argl, void *argp) +{ + struct plolicy_param* from_param=*((struct plolicy_param**)from); + pthread_mutex_lock(&(from_param->lock)); + from_param->ref_cnt++; + pthread_mutex_unlock(&(from_param->lock)); + *((struct plolicy_param**)to)=from_param; + return; +} + +void policy_table_new_cb(int table_id, const char* key, const char* table_line, MAAT_PLUGIN_EX_DATA* ad, long argl, void* argp) +{ + int ret=0, cfg_id=0, is_valid=0; + char profile_name[128]={0}, formate[128]={0}; + char profile_path[TFE_PATH_MAX]={0}; + + ret=sscanf(table_line, "%d\t%s\t%s\t%s\t%d", &cfg_id, profile_name, formate, profile_path, &is_valid); + if(ret!=5) + { + TFE_LOG_ERROR(g_pangu_rt->local_logger, "Policy table parse config failed: %s", table_line); + return; + } + struct policy_object* ply_obj=ALLOC(struct policy_object, 1); + + ply_obj->cfg_id=cfg_id; + if(strcasecmp(formate, "template") == 0) + { + ply_obj->tpl = ctemplate::Template::GetTemplate(profile_path, ctemplate::DO_NOT_STRIP); + }else + { + ply_obj->profile_msg = rt_read_file(profile_path, &ply_obj->msg_len); + if (ply_obj->profile_msg == NULL || ply_obj->msg_len == 0) + { + TFE_LOG_ERROR(g_pangu_rt->local_logger, "Read file failed %d:%s:%s", cfg_id, profile_name, profile_path); + } + } + ply_obj->profile_name=tfe_strdup(profile_name); + ply_obj->profile_type=tfe_strdup(formate); + + *ad = ply_obj; + return; +} + +void policy_table_free_cb(int table_id, MAAT_PLUGIN_EX_DATA* ad, long argl, void *argp) +{ + struct policy_object* ply_obj=(struct policy_object*)(*ad); + FREE(&ply_obj->profile_type); + FREE(&ply_obj->profile_msg); + FREE(&ply_obj->profile_name); + FREE(&ply_obj); + *ad=NULL; +} + +void policy_table_dup_cb(int table_id, MAAT_PLUGIN_EX_DATA *to, MAAT_PLUGIN_EX_DATA *from, long argl, void *argp) +{ + struct policy_object* ply_obj=(struct policy_object*)(*from); + *to=ply_obj; +} + +int maat_table_init(const char* table_name, + Maat_start_callback_t *start, Maat_update_callback_t *update,Maat_finish_callback_t *finish, + void *u_para) +{ + int table_id=0; + + table_id=Maat_table_register(g_pangu_rt->maat, table_name); + if(table_id<0) + { + goto finish; + } + Maat_table_callback_register(g_pangu_rt->maat, table_id, + start, update, finish, u_para); +finish: + return table_id; +} + +int maat_table_ex_init(const char* table_name, int policy_id, + Maat_plugin_EX_new_func_t* new_func, + Maat_plugin_EX_free_func_t* free_func, + Maat_plugin_EX_dup_func_t* dup_func) +{ + int table_id = 0; + + table_id=g_pangu_rt->plolicy_table_id[policy_id]=Maat_table_register(g_pangu_rt->maat, table_name); + if(table_id<0) + { + goto finish; + } + table_id=Maat_plugin_EX_register(g_pangu_rt->maat, + table_id, + new_func,free_func, + dup_func,NULL,0,NULL); +finish: + return table_id; +} + +int panggu_policy_init() +{ + int table_id=0, policy_id = 0; + + const char *table_name_map[] = {"PXY_PROFILE_RESPONSE_PAGES", + "PXY_PROFILE_HIJACK_FILES", + "PXY_PROFILE_INSERT_SCRIPTS", + }; + + table_id = maat_table_init("PXY_OBJ_TRUSTED_CA_CERT", + trusted_CA_update_start_cb, + trusted_CA_update_cert_cb, + trusted_CA_update_finish_cb, + g_pangu_rt); + if(table_id<0) + { + TFE_LOG_INFO(NULL, "Pangu HTTP register table PXY_OBJ_TRUSTED_CA_CERT failed."); + goto finish; + } + + table_id = maat_table_init("PXY_OBJ_TRUSTED_CA_CRL", + trusted_CA_update_start_cb, + trusted_CA_update_crl_cb, + trusted_CA_update_finish_cb, + g_pangu_rt); + if(table_id<0) + { + TFE_LOG_INFO(NULL, "Pangu HTTP register table PXY_OBJ_TRUSTED_CA_CRL failed."); + goto finish; + } + + for (policy_id = 0; policy_id thread_num = tfe_proxy_get_work_thread_count(); g_pangu_rt->gc_evbase=tfe_proxy_get_gc_evbase(); @@ -404,9 +750,7 @@ int pangu_http_init(struct tfe_proxy * proxy) } g_pangu_rt->fs_handle = tfe_proxy_get_fs_handle(); pangu_http_stat_init(g_pangu_rt); - - g_pangu_rt->maat = create_maat_feather("static", profile, "MAAT", g_pangu_rt->thread_num, g_pangu_rt->local_logger); if (!g_pangu_rt->maat) { @@ -430,37 +774,24 @@ int pangu_http_init(struct tfe_proxy * proxy) goto error_out; } } - table_id=Maat_table_register(g_pangu_rt->maat, "PXY_OBJ_TRUSTED_CA_CERT"); - if(table_id<0) - { - TFE_LOG_INFO(NULL, "Pangu HTTP register table PXY_OBJ_TRUSTED_CA_CERT failed."); - goto error_out; - } - Maat_table_callback_register(g_pangu_rt->maat, table_id, - trusted_CA_update_start_cb, - trusted_CA_update_cert_cb, - trusted_CA_update_finish_cb, - g_pangu_rt); - table_id=Maat_table_register(g_pangu_rt->maat, "PXY_OBJ_TRUSTED_CA_CRL"); + g_pangu_rt->plolicy_param_idx=Maat_rule_get_ex_new_index(g_pangu_rt->maat, "PXY_CTRL_COMPILE", + policy_param_new, policy_param_free, policy_param_dup, + 0, NULL); + + table_id = panggu_policy_init(); if(table_id<0) { - TFE_LOG_INFO(NULL, "Pangu HTTP register table PXY_OBJ_TRUSTED_CA_CRL failed."); goto error_out; } - Maat_table_callback_register(g_pangu_rt->maat, table_id, - trusted_CA_update_start_cb, - trusted_CA_update_crl_cb, - trusted_CA_update_finish_cb, - g_pangu_rt); - + g_pangu_rt->dyn_maat = create_maat_feather("dyn", profile, "DYNAMIC_MAAT", g_pangu_rt->thread_num, g_pangu_rt->local_logger); if (!g_pangu_rt->maat) { goto error_out; } g_pangu_rt->subscribe_id_table_id=Maat_table_register(g_pangu_rt->dyn_maat, "IPD_DYN_SUBSCRIBE_IP"); - temp=Maat_plugin_EX_register(g_pangu_rt->dyn_maat, + temp=Maat_plugin_EX_register(g_pangu_rt->dyn_maat, g_pangu_rt->subscribe_id_table_id, subscribe_id_new_cb, subscribe_id_free_cb, @@ -487,7 +818,7 @@ int pangu_http_init(struct tfe_proxy * proxy) MESA_load_profile_string_def(profile, "TEMPLATE", "PAGE_451", page_path, sizeof(page_path), "./resource/pangu/HTTP451.html"); g_pangu_rt->tpl_451 = ctemplate::Template::GetTemplate(page_path, ctemplate::DO_NOT_STRIP); - + MESA_load_profile_int_def(profile, "TANGO_CACHE", "suspend_max", &(temp), 1024*1024); g_pangu_rt->suspend_max=temp; @@ -511,7 +842,6 @@ error_out: return -1; } - struct replace_ctx { struct replace_rule * rule; @@ -521,6 +851,14 @@ struct replace_ctx int actually_replaced; }; +struct insert_ctx +{ + struct insert_rule *rule; + struct tfe_http_half * replacing; + struct evbuffer *http_body; + int actually_replaced; +}; + struct pangu_http_ctx { int magic_num; @@ -532,14 +870,16 @@ struct pangu_http_ctx struct Maat_rule_t * enforce_rules; size_t n_enforce; char * enforce_para; + struct plolicy_param *param; struct evbuffer* log_req_body, *log_resp_body; struct replace_ctx * rep_ctx; - + struct insert_ctx * ins_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 pangu_http_ctx* ctx); - + enum cache_pending_result pending_result; struct future *f_cache_pending, *f_cache_query; struct tfe_http_session * ref_session; @@ -548,28 +888,35 @@ struct pangu_http_ctx size_t cache_result_declared_sz, cache_result_actual_sz; struct cache_write_context* cache_write_ctx; int cache_wirte_result; - + int thread_id; }; void http_repl_ctx_free(struct replace_ctx* rep_ctx) { - for (size_t i = 0; i < rep_ctx->n_rule; i++) - { - FREE(&(rep_ctx->rule[i].find)); - FREE(&(rep_ctx->rule[i].replace_with)); - } - FREE(&(rep_ctx->rule)); 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) +{ + FREE(&(ins_ctx->rule)); + if (ins_ctx->http_body) + { + evbuffer_free(ins_ctx->http_body); + ins_ctx->http_body = NULL; + } + FREE(&ins_ctx); + return; +} + + #define HTTP_CTX_MAGIC_NUM 20181021 static struct pangu_http_ctx * pangu_http_ctx_new(unsigned int thread_id) { @@ -588,9 +935,14 @@ static void pangu_http_ctx_free(struct pangu_http_ctx * 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; + } FREE(&ctx->enforce_rules); FREE(&ctx->enforce_para); - Maat_clean_status(&(ctx->scan_mid)); + Maat_clean_status(&(ctx->scan_mid)); ctx->scan_mid = NULL; if(ctx->sp) @@ -614,7 +966,7 @@ static void pangu_http_ctx_free(struct pangu_http_ctx * ctx) //Dirty close ctx->cached_response=NULL; } - + if(ctx->f_cache_query) { future_destroy(ctx->f_cache_query); @@ -659,10 +1011,9 @@ void __pangu_action_weight_init() { pangu_action_weight[PG_ACTION_NONE] = 0; pangu_action_weight[PG_ACTION_MONIT] = 1; - pangu_action_weight[PG_ACTION_REPLACE] = 2; - pangu_action_weight[PG_ACTION_REDIRECT] = 3; - pangu_action_weight[PG_ACTION_REJECT] = 4; - pangu_action_weight[PG_ACTION_WHITELIST] = 5; + pangu_action_weight[PG_ACTION_MANIPULATE] = 2; + pangu_action_weight[PG_ACTION_REJECT] = 3; + pangu_action_weight[PG_ACTION_WHITELIST] = 4; } static inline int action_cmp(enum pangu_action a1, enum pangu_action a2) @@ -672,7 +1023,7 @@ static inline int action_cmp(enum pangu_action a1, enum pangu_action a2) //enforce_rules[0] contains execute action. static enum pangu_action decide_ctrl_action(const struct Maat_rule_t * hit_rules, size_t n_hit, - struct Maat_rule_t ** enforce_rules, size_t * n_enforce, char** enforce_para) + struct Maat_rule_t ** enforce_rules, size_t * n_enforce, struct plolicy_param **param) { size_t n_monit = 0, exist_enforce_num = 0, i = 0; const struct Maat_rule_t * prior_rule = hit_rules; @@ -733,26 +1084,17 @@ static enum pangu_action decide_ctrl_action(const struct Maat_rule_t * hit_rules 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)); } - if(*enforce_para!=NULL) + + void *ex_data=Maat_rule_get_ex_data(g_pangu_rt->maat, prior_rule, g_pangu_rt->plolicy_param_idx); + if(ex_data!=NULL) { - free(*enforce_para); - } - size_t __serv_def_len = (size_t)prior_rule->serv_def_len; - *enforce_para = ALLOC(char, __serv_def_len); - - if (__serv_def_len > MAX_SERVICE_DEFINE_LEN) - { - Maat_read_rule(g_pangu_rt->maat,prior_rule, MAAT_RULE_SERV_DEFINE, *enforce_para, __serv_def_len); - } - else - { - strcpy(*enforce_para, prior_rule->service_defined); + *param=(struct plolicy_param*)ex_data; } return prior_action; } //HTML template is downloaded from https://github.com/AndiDittrich/HttpErrorPages -static void html_generate(int status_code, int cfg_id, const char* msg, char ** page_buff, size_t * page_size) +static void template_generate(int status_code, int cfg_id, const char* msg, char ** page_buff, size_t * page_size) { ctemplate::TemplateDictionary dict("pg_page_dict"); //dict is automatically finalized after function returned. dict.SetIntValue("cfg_id", cfg_id); @@ -776,14 +1118,69 @@ static void html_generate(int status_code, int cfg_id, const char* msg, char ** *page_buff = tfe_strdup(output.c_str()); } +static int html_generate(int cfg_id, const char* msg, char ** page_buff, size_t * page_size) +{ +#define KEY_LEN 16 + int ret = 0; + struct policy_object* ply_obj=NULL; + + int tables_id = g_pangu_rt->plolicy_table_id[POLICY_TABLE_REJECT]; + + char cfg_id_str[KEY_LEN] = {0}; + snprintf(cfg_id_str, KEY_LEN, "%d", cfg_id); + + ply_obj = (struct policy_object*)Maat_plugin_get_EX_data(g_pangu_rt->maat, tables_id, (const char*)cfg_id_str); + if(ply_obj==NULL) + { + ret=-1; + return ret; + } + if(!strncmp(ply_obj->profile_type, "template", strlen(ply_obj->profile_type))) + { + ctemplate::TemplateDictionary dict("pg_page_dict"); //dict is automatically finalized after function returned. + dict.SetIntValue("cfg_id", cfg_id); + dict.SetValue("msg", msg); + std::string output; + + ply_obj->tpl->Expand(&output, &dict); + *page_size = output.length() + 1; + *page_buff = tfe_strdup(output.c_str()); + } + else + { + *page_size = ply_obj->msg_len; + *page_buff = tfe_strdup(ply_obj->profile_msg); + } + return ret; +} + static void html_free(char ** page_buff) { FREE(page_buff); 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 pangu_http_ctx * ctx) +static struct policy_object* get_obj_for_id(int cfg_id) +{ +#define KEY_LEN 16 + struct policy_object* ply_obj=NULL; + + char cfg_id_str[KEY_LEN] = {0}; + + snprintf(cfg_id_str, KEY_LEN, "%d", cfg_id); + + int tables_id = g_pangu_rt->plolicy_table_id[POLICY_TABLE_HIJACK]; + ply_obj = (struct policy_object*)Maat_plugin_get_EX_data(g_pangu_rt->maat, tables_id, (const char*)cfg_id_str); + if(ply_obj==NULL) + { + goto finish; + } +finish: + return ply_obj; +} + +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 pangu_http_ctx * ctx) { struct tfe_http_session * to_write_sess = NULL; char * rewrite_buff = NULL; @@ -804,9 +1201,10 @@ void http_replace(const struct tfe_stream * stream, const struct tfe_http_sessio * 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 plolicy_param *param = ctx->param; ctx->rep_ctx = rep_ctx = ALLOC(struct replace_ctx, 1); - rep_ctx->rule = ALLOC(struct replace_rule, MAX_EDIT_ZONE_NUM); - rep_ctx->n_rule = format_replace_rule(ctx->enforce_para, rep_ctx->rule, MAX_EDIT_ZONE_NUM); + rep_ctx->rule = param->rule; + rep_ctx->n_rule = param->n_rule; } else { @@ -865,7 +1263,7 @@ void http_replace(const struct tfe_stream * stream, const struct tfe_http_sessio rewrite_sz=execute_replace_rule(in_header_value, strlen(in_header_value), zone, rep_ctx->rule, rep_ctx->n_rule, &rewrite_buff); - if(rewrite_sz>0) rep_ctx->actually_replaced=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) { @@ -891,13 +1289,13 @@ void http_replace(const struct tfe_stream * stream, const struct tfe_http_sessio 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; - + rewrite_sz = execute_replace_rule(__http_body, __http_body_len, r_zone, rep_ctx->rule, rep_ctx->n_rule, &rewrite_buff); - + if (rewrite_sz >0 ) { @@ -956,7 +1354,7 @@ static void http_reject(const struct tfe_http_session * session, enum tfe_http_e to_write_sess = tfe_http_session_allow_write(session); response = tfe_http_session_response_create(to_write_sess, resp_code); - html_generate(resp_code, ctx->enforce_rules[0].config_id, msg, &page_buff, &page_size); + template_generate(resp_code, ctx->enforce_rules[0].config_id, msg, &page_buff, &page_size); 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); @@ -976,24 +1374,21 @@ static void http_reject(const struct tfe_http_session * session, enum tfe_http_e } static void http_redirect(const struct tfe_http_session * session, enum tfe_http_event events, - struct pangu_http_ctx * ctx) + struct pangu_http_ctx * ctx) { - int resp_code = 0, ret = 0; - char * url = NULL; - struct tfe_http_half * response = NULL; struct tfe_http_session * to_write = NULL; - url = ALLOC(char, ctx->enforce_rules[0].serv_def_len); - ret = sscanf(ctx->enforce_para, "code=%d;url=%[^;]", &resp_code, url); + struct plolicy_param *param = ctx->param; - if (ret != 2) - { - TFE_LOG_ERROR(g_pangu_rt->local_logger, "Invalid redirect rule %d paramter %s", - ctx->enforce_rules[0].config_id, ctx->enforce_para); + int resp_code = param->status_code; + char *rd_url = param->message; + + if (resp_code <= 0 || rd_url == NULL){ + TFE_LOG_ERROR(g_pangu_rt->local_logger, "Invalid redirect rule %d paramter", + ctx->enforce_rules[0].config_id); goto error_out; } - to_write = tfe_http_session_allow_write(session); if (to_write == NULL) { @@ -1001,7 +1396,7 @@ static void http_redirect(const struct tfe_http_session * session, enum tfe_http } response = tfe_http_session_response_create(to_write, resp_code); - tfe_http_std_field_write(response, TFE_HTTP_LOCATION, url); + 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); @@ -1009,13 +1404,322 @@ static void http_redirect(const struct tfe_http_session * session, enum tfe_http tfe_http_session_detach(session); error_out: - free(url); + return; +} + +static void http_block(const struct tfe_http_session * session, enum tfe_http_event events, + struct pangu_http_ctx * ctx) +{ + int ret = -1; + struct tfe_http_half * response = NULL; + char * page_buff = NULL; + size_t page_size = 0; + + char cont_len_str[16]; + + struct plolicy_param *param = ctx->param; + + int resp_code = param->status_code; + int cfg_id = param->profile_id; + char *message = param->message; + + if (resp_code <= 0 || cfg_id <= 0){ + TFE_LOG_ERROR(g_pangu_rt->local_logger, "Invalid block rule %d", ctx->enforce_rules[0].config_id); + ctx->action = PG_ACTION_NONE; + return; + } + + struct tfe_http_session * to_write_sess = NULL; + + if(events & EV_HTTP_RESP_HDR || tfe_http_in_request(events)) + { + to_write_sess = tfe_http_session_allow_write(session); + response = tfe_http_session_response_create(to_write_sess, resp_code); + + ret = html_generate(cfg_id, message, &page_buff, &page_size); + if (ret != 0) + { + TFE_LOG_ERROR(g_pangu_rt->local_logger, "Failed to get policy table, table_id = %d", cfg_id); + ctx->action = PG_ACTION_NONE; + } + 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); + + 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 + { + 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 pangu_http_ctx * ctx) +{ + struct plolicy_param *param = ctx->param; + + int cfg_id = param->profile_id; + + if (cfg_id <= 0){ + TFE_LOG_ERROR(g_pangu_rt->local_logger, "Invalid hijack rule %d", + ctx->enforce_rules[0].config_id); + ctx->action = PG_ACTION_NONE; + return; + } + + struct tfe_http_half * response = NULL; + char cont_len_str[16]; + + struct tfe_http_session * to_write_sess = NULL; + if(events & EV_HTTP_RESP_HDR || tfe_http_in_request(events)) + { + to_write_sess = tfe_http_session_allow_write(session); + response = tfe_http_session_response_create(to_write_sess, 200); + + struct policy_object* ply_obj=get_obj_for_id(cfg_id); + if (NULL == ply_obj){ + TFE_LOG_ERROR(g_pangu_rt->local_logger, "get table obj faild, table_id = %d", cfg_id); + ctx->action = PG_ACTION_NONE; + return; + } + int hijack_len = strlen(ply_obj->profile_name)+strlen("filename=\"\"")+1; + char *hijack_name = ALLOC(char, hijack_len); + snprintf(hijack_name, hijack_len, "filename=\"%s\"", ply_obj->profile_name); + tfe_http_nonstd_field_write(response, "Content-Disposition", hijack_name); + FREE(&hijack_name); + tfe_http_std_field_write(response, TFE_HTTP_CONT_TYPE, ply_obj->profile_type); + snprintf(cont_len_str, sizeof(cont_len_str), "%lu", ply_obj->msg_len); + tfe_http_std_field_write(response, TFE_HTTP_CONT_LENGTH, cont_len_str); + + char * page_buff = ply_obj->profile_msg; + size_t page_size = ply_obj->msg_len; + + size_t frag_size=8192; size_t sendlen=0; + unsigned char body_frag[frag_size]; + + tfe_http_session_response_set(to_write_sess, response); + tfe_http_half_write_body_begin(response, 1); + for (sendlen= 0; sendlen < page_size; sendlen+=frag_size) + { + memcpy(body_frag, page_buff+sendlen, frag_size); + tfe_http_half_write_body_data(response, body_frag, frag_size); + memset(body_frag, 0, frag_size); + } + tfe_http_half_write_body_end(response); + tfe_http_session_detach(session); + } + else + { + to_write_sess = tfe_http_session_allow_write(session); + tfe_http_session_kill(to_write_sess); + } + return; +} + +static int format_insert_rule(struct plolicy_param *param, int cfg_id, struct insert_rule *rule) +{ +#define KEY_LEN 16 + int ret = 0; + struct policy_object* ply_obj=NULL; + + int tables_id = g_pangu_rt->plolicy_table_id[POLICY_TABLE_INSERT]; + + char cfg_id_str[KEY_LEN] = {0}; + snprintf(cfg_id_str, KEY_LEN, "%d", cfg_id); + + ply_obj = (struct policy_object*)Maat_plugin_get_EX_data(g_pangu_rt->maat, tables_id, (const char*)cfg_id_str); + if(ply_obj==NULL) + { + ret=-1; + return ret; + } + rule->stype = ply_obj->profile_msg; + rule->type = ply_obj->profile_type; + + if (param->position == NULL){ + rule->position = NULL; + }else{ + rule->position = param->position; + } + 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, struct pangu_http_ctx * ctx) +{ + struct tfe_http_session * to_write_sess = NULL; + char * rewrite_buff = NULL; + size_t rewrite_sz = 0; + + struct plolicy_param *param = ctx->param; + + 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 = PG_ACTION_NONE; + tfe_http_session_detach(session); return; + } + + struct insert_ctx *ins_ctx = ctx->ins_ctx; + if (ctx->ins_ctx == NULL) + { + if ((events & EV_HTTP_REQ_HDR) || (events & EV_HTTP_RESP_HDR)) + { + int cfg_id = param->profile_id; + ctx->ins_ctx = ins_ctx = ALLOC(struct insert_ctx, 1); + ins_ctx->rule = ALLOC(struct insert_rule, 1); + int ret=format_insert_rule(param, cfg_id, ins_ctx->rule); + if (ret<0) + { + TFE_LOG_ERROR(g_pangu_rt->local_logger, "Failed to get policy table, table_id = %d", cfg_id); + ctx->action = PG_ACTION_NONE; + return; + } + } + else + { + TFE_STREAM_LOG_INFO(stream, "Can only setup replace on REQ/RESP headers, detached."); + ctx->action = PG_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); + + rewrite_buff = NULL; + rewrite_sz = 0; + + 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); + ins_ctx->actually_replaced=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; +} + +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 pangu_http_ctx * ctx) +{ + struct plolicy_param *param = ctx->param; + if (param == NULL) + { + TFE_LOG_ERROR(g_pangu_rt->local_logger, "Failed to get the json format parsed. config_id = %d", + ctx->enforce_rules[0].config_id); + ctx->action = PG_ACTION_NONE; + return; + } + + switch(param->action) + { + case MA_ACTION_REDIRECT: + http_redirect(session, events, ctx); + ATOMIC_INC(&(g_pangu_rt->stat_val[STAT_ACTION_REDIRECT])); + break; + case MA_ACTION_BLOCK: + http_block(session, events, ctx); + ATOMIC_INC(&(g_pangu_rt->stat_val[STAT_ACTION_REJECT])); + break; + case MA_ACTION_REPLACE: + http_replace(stream, session, events, body_frag, frag_size, ctx); + ATOMIC_INC(&(g_pangu_rt->stat_val[STAT_ACTION_PRE_REPLACE])); + break; + case MA_ACTION_HIJACK: + http_hijack(session, events, ctx); + ATOMIC_INC(&(g_pangu_rt->stat_val[STAT_ACTION_HIJACK])); + break; + case MA_ACTION_INSERT: + http_insert(stream, session, events, body_frag, frag_size, ctx); + ATOMIC_INC(&(g_pangu_rt->stat_val[STAT_ACTION_INSERT])); + break; + default: assert(0); + break; + } + return; } enum pangu_action http_scan(const struct tfe_http_session * session, enum tfe_http_event events, const unsigned char * body_frag, size_t frag_size, struct pangu_http_ctx * ctx) { - void * interator = NULL; + void * iterator = NULL; const char * field_val = NULL; struct http_field_name field_name; struct Maat_rule_t result[MAX_SCAN_RESULT]; @@ -1043,7 +1747,7 @@ enum pangu_action http_scan(const struct tfe_http_session * session, enum tfe_ht ->scan_table_id[PXY_CTRL_HTTP_RES_HDR]; while (hit_cnt < MAX_SCAN_RESULT) { - field_val = tfe_http_field_iterate(session->req, &interator, &field_name); + field_val = tfe_http_field_iterate(session->req, &iterator, &field_name); if (field_val == NULL) { break; @@ -1090,7 +1794,7 @@ enum pangu_action http_scan(const struct tfe_http_session * session, enum tfe_ht if (hit_cnt > 0) { - ctx->action = decide_ctrl_action(result, hit_cnt, &ctx->enforce_rules, &ctx->n_enforce, &ctx->enforce_para); + ctx->action = decide_ctrl_action(result, hit_cnt, &ctx->enforce_rules, &ctx->n_enforce, &ctx->param); if (ctx->action == PG_ACTION_WHITELIST) goto __out; if (hit_cnt > 1) @@ -1112,6 +1816,7 @@ enum pangu_action http_scan(const struct tfe_http_session * session, enum tfe_ht __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 pangu_http_ctx * ctx) @@ -1129,19 +1834,14 @@ void enforce_control_policy(const struct tfe_stream * stream, const struct tfe_h ATOMIC_INC(&(g_pangu_rt->stat_val[STAT_ACTION_MONIT])); //send log on close. break; - case PG_ACTION_REJECT: + case PG_ACTION_REJECT: http_reject(session, events, ctx); ATOMIC_INC(&(g_pangu_rt->stat_val[STAT_ACTION_REJECT])); break; - case PG_ACTION_REDIRECT: - http_redirect(session, events, ctx); - ATOMIC_INC(&(g_pangu_rt->stat_val[STAT_ACTION_REDIRECT])); + case PG_ACTION_MANIPULATE: + http_manipulate(stream, session, events, body_frag, frag_size, ctx); break; - case PG_ACTION_REPLACE: - http_replace(stream, session, events, body_frag, frag_size, ctx); - ATOMIC_INC(&(g_pangu_rt->stat_val[STAT_ACTION_PRE_REPLACE])); - break; - case PG_ACTION_WHITELIST: + case PG_ACTION_WHITELIST: tfe_http_session_detach(session); ATOMIC_INC(&(g_pangu_rt->stat_val[STAT_ACTION_WHITELSIT])); break; @@ -1220,8 +1920,8 @@ static void cache_read_on_succ(future_result_t * result, void * user) ctx->resumed_cb=dummy_resume; tfe_http_session_resume(ctx->ref_session); ATOMIC_DEC(&(g_pangu_rt->stat_val[STAT_SUSPENDING])); - - ctx->cached_response=tfe_http_session_response_create(ctx->ref_session, 200); + + ctx->cached_response=tfe_http_session_response_create(ctx->ref_session, 200); tfe_http_std_field_write(ctx->cached_response, TFE_HTTP_CONT_TYPE, meta->content_type); tfe_http_std_field_write(ctx->cached_response, TFE_HTTP_LAST_MODIFIED, meta->last_modified); tfe_http_std_field_write(ctx->cached_response, TFE_HTTP_ETAG, meta->etag); @@ -1230,12 +1930,12 @@ static void cache_read_on_succ(future_result_t * result, void * user) snprintf(temp, sizeof(temp), "%lu", meta->content_length); tfe_http_std_field_write(ctx->cached_response, TFE_HTTP_CONT_LENGTH, temp); - //Dirty code here. + //Dirty code here. tfe_http_session_response_set(ctx->ref_session, ctx->cached_response); - //From now, ownership of cached_response has been transfered to http session, + //From now, ownership of cached_response has been transfered to http session, //bussines plugin only hold this pointer as an reference for writing response body. tfe_http_half_write_body_begin(ctx->cached_response, 1); - + meta=NULL; break; case CACHE_QUERY_RESULT_DATA: @@ -1246,7 +1946,7 @@ static void cache_read_on_succ(future_result_t * result, void * user) case CACHE_QUERY_RESULT_END: assert(ctx->cached_response!=NULL); tfe_http_half_write_body_end(ctx->cached_response); - //ownership has been transferred to http session, set to NULL. + //ownership has been transferred to http session, set to NULL. ctx->pending_result=PENDING_RESULT_HIT; ctx->cached_response=NULL; assert(ctx->cache_result_actual_sz==ctx->cache_result_declared_sz); @@ -1291,7 +1991,7 @@ static void cache_pend_on_succ(future_result_t * result, void * user) const struct cached_meta* meta=NULL; meta=cache_pending_result_read_meta(result, ctx->cmid); ctx->resumed_cb=dummy_resume; - tfe_http_session_resume(ctx->ref_session); + tfe_http_session_resume(ctx->ref_session); ATOMIC_DEC(&(g_pangu_rt->stat_val[STAT_SUSPENDING])); future_destroy(ctx->f_cache_pending); ctx->f_cache_pending=NULL; @@ -1309,7 +2009,7 @@ static void cache_pend_on_succ(future_result_t * result, void * user) struct http_field_name in_field_name; const char * in_header_value = NULL; void * iterator = NULL; - ctx->cache_revalidate_req=tfe_http_session_request_create(ctx->ref_session, + ctx->cache_revalidate_req=tfe_http_session_request_create(ctx->ref_session, ctx->ref_session->req->req_spec.method, ctx->ref_session->req->req_spec.uri); while (true) { @@ -1342,7 +2042,7 @@ static void cache_pend_on_fail(enum e_future_error err, const char * what, void ctx->resumed_cb=dummy_resume; future_destroy(ctx->f_cache_pending); ctx->f_cache_pending=NULL; - + return; } @@ -1353,7 +2053,7 @@ void cache_pend(const struct tfe_http_session * session, unsigned int thread_id, ctx->pending_result=PENDING_RESULT_FOBIDDEN; return; } - ctx->f_cache_pending=future_create("cache_pend", cache_pend_on_succ, cache_pend_on_fail, ctx); + ctx->f_cache_pending=future_create("cache_pend", cache_pend_on_succ, cache_pend_on_fail, ctx); ctx->ref_session=tfe_http_session_allow_write(session); ctx->pending_result=web_cache_async_pending(g_pangu_rt->cache, thread_id, session->req, &(ctx->cmid), ctx->f_cache_pending); switch(ctx->pending_result) @@ -1362,11 +2062,11 @@ void cache_pend(const struct tfe_http_session * session, unsigned int thread_id, tfe_http_session_suspend(ctx->ref_session); ATOMIC_INC(&(g_pangu_rt->stat_val[STAT_SUSPENDING])); break; - case PENDING_RESULT_ALLOWED: + case PENDING_RESULT_ALLOWED: case PENDING_RESULT_FOBIDDEN: case PENDING_RESULT_MISS: future_destroy(ctx->f_cache_pending); - ctx->f_cache_pending=NULL; + ctx->f_cache_pending=NULL; break; default: break; @@ -1394,7 +2094,7 @@ void cache_read(const struct tfe_http_session * session, unsigned int thread_id, } } -void cache_write(const struct tfe_http_session * session, enum tfe_http_event events, +void cache_write(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 pangu_http_ctx * ctx) { @@ -1410,11 +2110,11 @@ void cache_write(const struct tfe_http_session * session, enum tfe_http_event ev if(events & EV_HTTP_RESP_BODY_END && ctx->cache_write_ctx!=NULL) { ctx->cache_wirte_result=web_cache_write_end(ctx->cache_write_ctx); - ctx->cache_write_ctx=NULL; + ctx->cache_write_ctx=NULL; //printf("cache update success: %s\n", ctx->ref_session->req->req_spec.url); } -} +} void pangu_on_http_begin(const struct tfe_stream * stream, const struct tfe_http_session * session, unsigned int thread_id, void ** pme) @@ -1440,7 +2140,7 @@ void pangu_on_http_begin(const struct tfe_stream * stream, { scan_ret = Maat_full_scan_string(g_pangu_rt->maat, g_pangu_rt->scan_table_id[PXY_CTRL_SUBSCRIBE_ID], CHARSET_UTF8, sip, strlen(sip), - result+hit_cnt, NULL, MAX_SCAN_RESULT-hit_cnt, + result+hit_cnt, NULL, MAX_SCAN_RESULT-hit_cnt, &(ctx->scan_mid), (int) thread_id); if(scan_ret>0) { @@ -1462,11 +2162,11 @@ 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); - + if (hit_cnt > 0) { - ctx->action = decide_ctrl_action(result, hit_cnt, &ctx->enforce_rules, &ctx->n_enforce, &ctx->enforce_para); + ctx->action = decide_ctrl_action(result, hit_cnt, &ctx->enforce_rules, &ctx->n_enforce, &ctx->param); } if (ctx->action == PG_ACTION_WHITELIST) { @@ -1486,11 +2186,12 @@ void pangu_on_http_end(const struct tfe_stream * stream, struct pangu_http_ctx * ctx = *(struct pangu_http_ctx **) pme; size_t i=0, j=0; int ret=0; - if(ctx->action == PG_ACTION_REPLACE && ctx->rep_ctx->actually_replaced==0) + + if(ctx->action == PG_ACTION_MANIPULATE && ctx->param->action == MA_ACTION_REPLACE && ctx->rep_ctx->actually_replaced==0) { for(i=0; i< ctx->n_enforce; i++) { - if((unsigned char)ctx->enforce_rules[i].action == PG_ACTION_REPLACE) + if((unsigned char)ctx->enforce_rules[i].action == PG_ACTION_MANIPULATE) { if(i+1 > ctx->n_enforce) { @@ -1508,10 +2209,13 @@ void pangu_on_http_end(const struct tfe_stream * stream, } struct pangu_log log_msg = {.stream=stream, .http=session, .result=ctx->enforce_rules, .result_num=ctx->n_enforce, .req_body= ctx->log_req_body, .resp_body=ctx->log_resp_body}; - if (ctx->action != PG_ACTION_NONE&& !(ctx->action == PG_ACTION_REPLACE && ctx->n_enforce==1 && ctx->rep_ctx->actually_replaced==0)) + if (ctx->action != PG_ACTION_NONE&& + !(ctx->action == PG_ACTION_MANIPULATE && + ctx->param->action == MA_ACTION_REPLACE && + ctx->n_enforce==1 && ctx->rep_ctx->actually_replaced==0)) { ret=pangu_send_log(g_pangu_rt->send_logger, &log_msg); - ATOMIC_ADD(&(g_pangu_rt->stat_val[STAT_LOG_NUM]), ret); + ATOMIC_ADD(&(g_pangu_rt->stat_val[STAT_LOG_NUM]), ret); } if(ctx->rep_ctx && ctx->rep_ctx->actually_replaced==0) { @@ -1541,7 +2245,7 @@ void pangu_on_http_data(const struct tfe_stream * stream, const struct tfe_http_ } return; } - + enforce_control_policy(stream, session, events, body_frag, frag_size,thread_id, ctx); if(g_pangu_rt->cache_enabled && ctx->action == PG_ACTION_NONE) @@ -1570,8 +2274,6 @@ void pangu_on_http_data(const struct tfe_stream * stream, const struct tfe_http_ return; } - - struct tfe_plugin pangu_http_spec = { .symbol=NULL, .type = TFE_PLUGIN_TYPE_BUSINESS, diff --git a/plugin/business/pangu-http/src/pattern_replace.cpp b/plugin/business/pangu-http/src/pattern_replace.cpp index e015803..b81da0b 100644 --- a/plugin/business/pangu-http/src/pattern_replace.cpp +++ b/plugin/business/pangu-http/src/pattern_replace.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -30,7 +31,8 @@ enum replace_zone zone_name_to_id(const char * name) } return (enum replace_zone) i; } -static char * strchr_esc(char * s, const char delim) +static char *__attribute__((__unused__)) +strchr_esc(char * s, const char delim) { char * token; if (s == NULL) @@ -54,7 +56,8 @@ static char * strchr_esc(char * s, const char delim) return token; } } -static char * strtok_r_esc(char * s, const char delim, char ** save_ptr) +static char *__attribute__((__unused__)) +strtok_r_esc(char * s, const char delim, char ** save_ptr) { char * token; @@ -75,8 +78,26 @@ static char * strtok_r_esc(char * s, const char delim, char ** save_ptr) return s; } +char *rt_read_file(const char* filename, size_t *input_sz) +{ + FILE* fp=NULL; + struct stat file_info; + stat(filename, &file_info); + *input_sz=file_info.st_size; -size_t format_replace_rule(const char * exec_para, struct replace_rule * replace, size_t n_replace) + fp=fopen(filename,"r"); + if(fp==NULL) + { + return NULL; + } + char* data=(char*)malloc((*input_sz)); + fread(data,1,*input_sz,fp); + fclose(fp); + + return data; +} +size_t __attribute__((__unused__)) +format_replace_rule(const char * exec_para, struct replace_rule * replace, size_t n_replace) { char * tmp = ALLOC(char, strlen(exec_para) + 1); char * token = NULL, * sub_token = NULL, * saveptr = NULL, * saveptr2 = NULL; @@ -225,15 +246,81 @@ size_t execute_replace_rule(const char * in, size_t in_sz, return 0; } } + +size_t insert_string(char * in, size_t in_sz, const char *insert_on, const char *stype, const char *type, char** out) +{ + char *target=NULL; + size_t outlen=0, target_size=0; + char position[]=""; + + /* ""*/ + int js_type_len = 58; + /*""*/ + int css_type_len = 49; + + char* head_string=NULL; + + if (0==strcasecmp(type, "css")) + { + target_size = in_sz+strlen(stype)+css_type_len; + target = ALLOC(char, target_size); + } + + if (0==strcasecmp(type, "js")) + { + target_size = in_sz+strlen(stype)+js_type_len; + target = ALLOC(char, target_size); + } + + if (insert_on != NULL && 0==strcasecmp(insert_on, "after-page-load")) + { + memcpy(position, "", sizeof(position)); + } + head_string=strstr(in, position); + if (head_string != NULL) + { + strncat(target, in, MIN((unsigned int)(head_string-in), target_size)); + size_t style_len = 0; char *style_msg = NULL; + if (0==strcasecmp(type, "js")) + { + style_len = strlen(stype)+js_type_len+1; + style_msg = ALLOC(char, style_len); + snprintf(style_msg, style_len, "", stype); + } + if (0==strcasecmp(type, "css")) + { + style_len = strlen(stype)+css_type_len+1; + style_msg = ALLOC(char, style_len); + snprintf(style_msg, style_len, "\n", stype); + } + strncat(target, style_msg, target_size); + free(style_msg); + style_msg = NULL; + strncat(target, head_string, target_size); + *out = target; + outlen = strlen(target) + 1; + }else + { + free(target); + target = NULL; + outlen = 0; + } + return outlen; +} + +size_t execute_insert_rule(char * in, size_t in_sz, const struct insert_rule * rules, char** out) +{ + return insert_string(in, in_sz, rules->position, rules->stype, rules->type, out); +} + void simple_replace(const char* find, const char* replacement, const char* input, size_t in_sz, char** output, size_t *output_sz) { - char* exec_para=NULL; - asprintf(&exec_para,"zone=http_resp_body;substitute=/%s/%s", find, replacement); - size_t n_got_rule=0; + size_t n_got_rule=1; struct replace_rule rules[16]; - n_got_rule=format_replace_rule(exec_para, rules, sizeof(rules)/sizeof(rules[0])); + rules[0].zone = kZoneResponseBody; + rules[0].find = tfe_strdup(find); + rules[0].replace_with = tfe_strdup(replacement); *output_sz=execute_replace_rule(input, strlen(input), kZoneResponseBody, rules, n_got_rule, output); - free(exec_para); return; } diff --git a/plugin/business/pangu-http/src/pattern_replace.h b/plugin/business/pangu-http/src/pattern_replace.h index 3786999..6c89dd7 100644 --- a/plugin/business/pangu-http/src/pattern_replace.h +++ b/plugin/business/pangu-http/src/pattern_replace.h @@ -9,6 +9,11 @@ enum replace_zone kZoneResponseBody, kZoneMax }; + +/** + rule type: replace + rule type: insert(find: insert on, replace_with: insert content) +*/ struct replace_rule { enum replace_zone zone; @@ -16,11 +21,22 @@ struct replace_rule char * replace_with; }; +struct insert_rule +{ + char * stype; + char * type; + char * position; +}; //@parm exec_para example input: //zone=http_req_body; substitute=/中華民國/中华人民共和国;zone=http_resp_header; substitute=/Content-Type:\btext\/html/Content-Type:\bvideo\/mp4 //@return formated rule number. -size_t format_replace_rule(const char * exec_para, struct replace_rule * replace, size_t n_replace); size_t execute_replace_rule(const char * in, size_t in_sz, enum replace_zone zone, const struct replace_rule * rules, size_t n_rule, char** out); +size_t execute_insert_rule(char * in, size_t in_sz, const struct insert_rule * rules, char** out); +size_t insert_string(char * in, size_t in_sz, const char *insert_on, const char *stype, const char *type, char** out); void simple_replace(const char* find, const char* replacement, const char* input, size_t in_sz, char** output, size_t *output_sz); +enum replace_zone zone_name_to_id(const char * name); +char *rt_read_file(const char* filename, size_t *input_sz); + + diff --git a/plugin/business/pangu-http/src/test_pattern_replace.cpp b/plugin/business/pangu-http/src/test_pattern_replace.cpp index ba1bc51..b5ef209 100644 --- a/plugin/business/pangu-http/src/test_pattern_replace.cpp +++ b/plugin/business/pangu-http/src/test_pattern_replace.cpp @@ -113,6 +113,70 @@ TEST(PatternReplace, UTF8) return; } +TEST(PatternInsert, CSS) +{ + const char* filename="./test_data/index_of__centos.html"; + const char* custom = "h1,h2{color: red;}ul.tabmain a{color: green;}"; + char *input=NULL, *output=NULL; + size_t output_sz=0, input_sz = 0; + + input = rt_read_file(filename, &input_sz); + EXPECT_TRUE(input_sz>0); + + output_sz = insert_string(input, input_sz, NULL, custom, "css", &output); + + //printf("output = %s\n", output); + + EXPECT_TRUE(output_sz>0); + EXPECT_TRUE(NULL!=strstr(output, custom)); + free(output); + free(input); +} + +TEST(PatternInsert, after_body) +{ + const char* filename="./test_data/index_of__centos.html"; + const char* custom = "var now=new Date();var year=now.getYear()+1900;var month=now.getMonth()+1;var date=now.getDate();var day=now.getDay();\ + var time=\"curtime\"+year+\"year\"+month+\"month\"+date+\"date\"+week;alert(time);"; + char *input=NULL, *output=NULL; + size_t output_sz=0, input_sz = 0; + + input = rt_read_file(filename, &input_sz); + EXPECT_TRUE(input_sz>0); + + output_sz = insert_string(input, input_sz, "after-page-load", custom, "js", &output); + + //printf("%s\n", output); + + EXPECT_TRUE(output_sz>0); + EXPECT_TRUE(NULL!=strstr(output, custom)); + + free(input); + free(output); + output = NULL; +} + +TEST(PatternInsert, before_body) +{ + const char* filename="./test_data/index_of__centos.html"; + const char* custom = "var now=new Date();var year=now.getYear()+1900;var month=now.getMonth()+1;var date=now.getDate();var day=now.getDay();\ + var time=\"curtime\"+year+\"year\"+month+\"month\"+date+\"date\"+week;alert(time);"; + char *input=NULL, *output=NULL; + size_t output_sz=0, input_sz = 0; + + input = rt_read_file(filename, &input_sz); + EXPECT_TRUE(input_sz>0); + + output_sz = insert_string(input, input_sz, "before-page-load", custom, "js", &output); + //printf("%s\n", output); + + EXPECT_TRUE(output_sz>0); + EXPECT_TRUE(NULL!=strstr(output, custom)); + + free(input); + free(output); + output = NULL; +} int main(int argc, char ** argv) { diff --git a/plugin/business/pangu-http/test_data/index_of__centos.html b/plugin/business/pangu-http/test_data/index_of__centos.html new file mode 100644 index 0000000..25cdabb --- /dev/null +++ b/plugin/business/pangu-http/test_data/index_of__centos.html @@ -0,0 +1,85 @@ + + +Index of /centos/ + + +

Index of /centos/


../
+2/                                                 09-Sep-2009 05:18                   -
+2.1/                                               09-Sep-2009 05:18                   -
+3/                                                 02-Mar-2011 23:44                   -
+3.1/                                               02-Mar-2011 23:44                   -
+3.3/                                               02-Mar-2011 23:44                   -
+3.4/                                               02-Mar-2011 23:44                   -
+3.5/                                               02-Mar-2011 23:44                   -
+3.6/                                               02-Mar-2011 23:44                   -
+3.7/                                               02-Mar-2011 23:44                   -
+3.8/                                               02-Mar-2011 23:44                   -
+3.9/                                               02-Mar-2011 23:44                   -
+4/                                                 03-Apr-2017 11:34                   -
+4.0/                                               18-Jul-2005 21:11                   -
+4.1/                                               21-Oct-2005 17:54                   -
+4.2/                                               04-Nov-2006 12:43                   -
+4.3/                                               10-Nov-2006 22:15                   -
+4.4/                                               07-Jul-2007 18:21                   -
+4.5/                                               10-Jan-2008 16:12                   -
+4.6/                                               31-Mar-2009 11:55                   -
+4.7/                                               08-Mar-2010 10:56                   -
+4.8/                                               13-Mar-2012 00:14                   -
+4.9/                                               03-Apr-2017 11:34                   -
+5/                                                 03-Apr-2017 11:34                   -
+5.0/                                               16-Oct-2014 13:37                   -
+5.1/                                               16-Oct-2014 13:37                   -
+5.10/                                              03-Apr-2017 11:30                   -
+5.11/                                              03-Apr-2017 11:34                   -
+5.2/                                               16-Oct-2014 13:37                   -
+5.3/                                               16-Oct-2014 13:37                   -
+5.4/                                               16-Oct-2014 13:37                   -
+5.5/                                               16-Oct-2014 13:37                   -
+5.6/                                               16-Oct-2014 13:37                   -
+5.7/                                               16-Oct-2014 13:37                   -
+5.8/                                               16-Oct-2014 13:37                   -
+5.9/                                               16-Oct-2014 13:38                   -
+6/                                                 02-Jul-2018 15:32                   -
+6.0/                                               16-Oct-2014 13:42                   -
+6.1/                                               16-Oct-2014 13:42                   -
+6.10/                                              02-Jul-2018 15:32                   -
+6.2/                                               16-Oct-2014 13:42                   -
+6.3/                                               16-Oct-2014 13:42                   -
+6.4/                                               16-Oct-2014 13:42                   -
+6.5/                                               05-Jan-2015 14:33                   -
+6.6/                                               12-Aug-2015 12:23                   -
+6.7/                                               01-Jun-2016 16:09                   -
+6.8/                                               12-Jun-2017 12:38                   -
+6.9/                                               25-Jul-2018 15:42                   -
+7/                                                 02-Dec-2018 14:34                   -
+7.0.1406/                                          07-Apr-2015 14:24                   -
+7.1.1503/                                          08-Jan-2016 15:25                   -
+7.2.1511/                                          28-Jan-2017 14:29                   -
+7.3.1611/                                          25-Oct-2017 14:57                   -
+7.4.1708/                                          24-May-2018 13:25                   -
+7.5.1804/                                          04-Jan-2019 16:00                   -
+7.6.1810/                                          02-Dec-2018 14:34                   -
+HEADER.images/                                     07-Nov-2013 15:21                   -
+build/                                             12-Jun-2005 12:56                   -
+dostools/                                          04-Apr-2007 09:45                   -
+graphics/                                          12-Jun-2014 11:59                   -
+HEADER.html                                        29-Sep-2014 19:27                1234
+RPM-GPG-KEY-CentOS-3                               15-Mar-2004 23:16                1795
+RPM-GPG-KEY-CentOS-4                               26-Feb-2005 17:51                1795
+RPM-GPG-KEY-CentOS-5                               19-Feb-2007 17:57                1504
+RPM-GPG-KEY-CentOS-6                               10-Jul-2011 14:28                1706
+RPM-GPG-KEY-CentOS-7                               04-Jul-2014 16:01                1690
+RPM-GPG-KEY-CentOS-Debug-6                         10-Jul-2011 14:28                1730
+RPM-GPG-KEY-CentOS-Debug-7                         09-Dec-2015 09:59                1004
+RPM-GPG-KEY-CentOS-Security-6                      10-Jul-2011 14:28                1730
+RPM-GPG-KEY-CentOS-Testing-6                       10-Jul-2011 14:28                1734
+RPM-GPG-KEY-CentOS-Testing-7                       09-Dec-2015 09:59                1690
+RPM-GPG-KEY-beta                                   19-Feb-2007 17:56                1512
+RPM-GPG-KEY-centos4                                26-Feb-2005 17:51                1795
+TIME                                               17-May-2019 05:35                  11
+dir_sizes                                          17-May-2019 05:10                 963
+filelist.gz                                        17-May-2019 05:10             5612272
+timestamp.txt                                      17-May-2019 05:35                  29
+

+ + \ No newline at end of file