#include "pangu_logger.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_SCAN_RESULT 16 #define MAX_EDIT_ZONE_NUM 64 #define MAX_EDIT_MATCHES 16 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_RATELIMIT = 0x40, /* N/A */ PG_ACTION_REPLACE = 0x50, PG_ACTION_LOOP = 0x60, /* N/A */ PG_ACTION_WHITELIST = 0x80 }; enum scan_table { PXY_CTRL_IP, PXY_CTRL_HTTP_URL, PXY_CTRL_HTTP_REQ_HDR, PXY_CTRL_HTTP_REQ_BODY, PXY_CTRL_HTTP_RES_HDR, PXY_CTRL_HTTP_RES_BODY, __SCAN_TABLE_MAX }; struct pangu_rt { Maat_feather_t maat; struct pangu_logger* send_logger; void* local_logger; int log_level; int thread_num; int scan_table_id[__SCAN_TABLE_MAX]; char* reject_page; int page_size; }; struct pangu_rt *g_pangu_rt; static Maat_feather_t create_maat_feather(const char* profile, const char* section,int max_thread, void* logger) { Maat_feather_t target; int maat_json_switch=0,maat_stat_on=0,maat_perf_on=0; int ret=0,scan_detail=0,effect_interval=60; char table_info[TFE_STRING_MAX]={0},inc_cfg_dir[TFE_STRING_MAX]={0},ful_cfg_dir[TFE_STRING_MAX]={0}; char json_cfg_file[TFE_STRING_MAX]={0},maat_stat_file[TFE_STRING_MAX]={0}; const char* instance_name="pangu"; MESA_load_profile_int_def(profile, section,"MAAT_JSON_SWITCH", &(maat_json_switch),0); MESA_load_profile_int_def(profile, section,"STAT_SWITCH", &(maat_stat_on),1); MESA_load_profile_int_def(profile, section,"PERF_SWITCH", &(maat_perf_on),1); MESA_load_profile_string_def(profile,section,"TABLE_INFO",table_info, sizeof(table_info),""); MESA_load_profile_string_def(profile,section,"INC_CFG_DIR",inc_cfg_dir, sizeof(inc_cfg_dir),""); MESA_load_profile_string_def(profile,section,"FULL_CFG_DIR",ful_cfg_dir, sizeof(ful_cfg_dir),""); MESA_load_profile_string_def(profile,section,"JSON_CFG_FILE",json_cfg_file, sizeof(json_cfg_file),""); MESA_load_profile_string_def(profile,section,"STAT_FILE",maat_stat_file, sizeof(maat_stat_file),""); MESA_load_profile_int_def(profile,section,"EFFECT_INTERVAL_S", &(effect_interval),60); effect_interval*=1000;//convert s to ms assert(strlen(inc_cfg_dir)!=0&&strlen(ful_cfg_dir)!=0); target=Maat_feather(max_thread,table_info, logger); Maat_set_feather_opt(target,MAAT_OPT_INSTANCE_NAME,instance_name, strlen(instance_name)+1); if(maat_json_switch==1) { Maat_set_feather_opt(target, MAAT_OPT_JSON_FILE_PATH, json_cfg_file, strlen(json_cfg_file)+1); } else { Maat_set_feather_opt(target, MAAT_OPT_FULL_CFG_DIR, ful_cfg_dir, strlen(ful_cfg_dir)+1); Maat_set_feather_opt(target, MAAT_OPT_INC_CFG_DIR, inc_cfg_dir, strlen(inc_cfg_dir)+1); } if(maat_stat_on) { Maat_set_feather_opt(target, MAAT_OPT_STAT_FILE_PATH, maat_stat_file, strlen(maat_stat_file)+1); Maat_set_feather_opt(target, MAAT_OPT_STAT_ON, NULL, 0); if(maat_perf_on) { Maat_set_feather_opt(target, MAAT_OPT_PERF_ON, NULL, 0); } } Maat_set_feather_opt(target, MAAT_OPT_EFFECT_INVERVAL_MS, &effect_interval, sizeof(effect_interval)); Maat_set_feather_opt(target, MAAT_OPT_SCAN_DETAIL, &scan_detail, sizeof(scan_detail)); ret=Maat_initiate_feather(target); if(ret<0) { TFE_LOG_ERROR(logger, "%s MAAT init failed.", __FUNCTION__); return NULL; } return target; } void pangu_http_init(struct tfe_proxy * proxy) { const char* profile="./pangu/pangu_pxy.conf"; const char* logfile="./log/pangu_pxy.log"; g_pangu_rt=ALLOC(struct pangu_rt,1); MESA_load_profile_int_def(profile, "DEBUG", "LOG_LEVEL", &(g_pangu_rt->log_level),0); g_pangu_rt->local_logger=MESA_create_runtime_log_handle(logfile, g_pangu_rt->log_level); g_pangu_rt->send_logger=pangu_log_handle_create(profile, "LOG", g_pangu_rt->local_logger); if(!g_pangu_rt->send_logger) { goto error_out; } g_pangu_rt->maat=create_maat_feather(profile, "MAAT", g_pangu_rt->thread_num, g_pangu_rt->local_logger); if(!g_pangu_rt->maat) { goto error_out; } const char* table_name[__SCAN_TABLE_MAX]; table_name[PXY_CTRL_IP]="PXY_CTRL_IP"; table_name[PXY_CTRL_HTTP_URL]="PXY_CTRL_HTTP_URL"; table_name[PXY_CTRL_HTTP_REQ_HDR]="PXY_CTRL_HTTP_REQ_HDR"; table_name[PXY_CTRL_HTTP_REQ_BODY]="PXY_CTRL_HTTP_REQ_BODY"; table_name[PXY_CTRL_HTTP_RES_HDR]="PXY_CTRL_HTTP_RES_HDR"; table_name[PXY_CTRL_HTTP_RES_BODY]="PXY_CTRL_HTTP_RES_BODY"; for(int i=0;i<__SCAN_TABLE_MAX;i++) { g_pangu_rt->scan_table_id[i]=Maat_table_register(g_pangu_rt->maat, table_name[i]); if(g_pangu_rt->scan_table_id[i]<0) { TFE_LOG_ERROR(NULL, "Pangu HTTP Maat table %s register failed.", table_name[i]); goto error_out; } } TFE_LOG_INFO(NULL, "Pangu HTTP init success."); return; error_out: TFE_LOG_ERROR(NULL, "Pangu HTTP init failed."); return; } static void _wrap_std_field_write(struct tfe_http_half * half, enum tfe_http_std_field field_id, const char * value) { struct http_field_name tmp_name; tmp_name.field_id=field_id; tmp_name.field_name=NULL; tfe_http_field_write(half, &tmp_name, value); return; } #if 0 static void _wrap_non_std_field_write(struct tfe_http_half * half, const char* field_name, const char * value) { struct http_field_name tmp_name; tmp_name.field_id=TFE_HTTP_UNKNOWN_FIELD; //todo remove force convert after tfe_http.h improved. tmp_name.field_name=(char*)field_name; tfe_http_field_write(half, &tmp_name, value); return; } #endif enum replace_zone { kZoneRequestUri=0, kZoneRequestHeaders, kZoneRequestBody, kZoneResponseHeader, kZoneResponseBody, kZoneMax }; struct replace_rule { enum replace_zone zone; char* find; char* replace_with; }; struct replace_ctx { struct replace_rule* rule; size_t n_rule; struct tfe_http_half * replacing; struct evbuffer* http_body; size_t body_size; }; struct pangu_http_ctx { enum pangu_action action; char* action_para; scan_status_t mid; stream_para_t sp; struct Maat_rule_t* exec_rule; struct Maat_rule_t* monit_rule; int monit_num; char* exec_para; struct replace_ctx *rep_ctx; int thread_id; }; static struct pangu_http_ctx* pangu_http_ctx_new(unsigned int thread_id) { struct pangu_http_ctx* ctx=ALLOC(struct pangu_http_ctx,1); ctx->mid=NULL; ctx->thread_id=(int)thread_id; return ctx; } static void pangu_http_ctx_free(struct pangu_http_ctx* ctx) { if(ctx->rep_ctx!=NULL) { for(size_t i=0;irep_ctx->n_rule;i++) { FREE(&(ctx->rep_ctx->rule[i].find)); FREE(&(ctx->rep_ctx->rule[i].replace_with)); } evbuffer_free(ctx->rep_ctx->http_body); ctx->rep_ctx->http_body=NULL; //todo destroy http_half; assert(ctx->rep_ctx->replacing==NULL); FREE(&(ctx->rep_ctx)); } Maat_clean_status(&(ctx->mid)); ctx->mid=NULL; free(ctx); } inline void addr_tfe2sapp(const struct tfe_stream_addr* tfe_addr, struct ipaddr* sapp_addr) { sapp_addr->addrtype=tfe_addr->addrtype; sapp_addr->paddr=(char*)tfe_addr->paddr; return; } /* 20180909记录 1)const char * tfe_http_field_iterate(const struct tfe_http_half * half, void * interator, struct http_field_name * name); void**? 2)http入口函数返回值增加 enum tfe_bussiness_action 3)struct http_field_name中的field_name内存是如何分配到? 4)http对上层要暴露evbuffer吗? 5) uint64_t cont_len; uint64_t cont_range_from; uint64_t cont_range_to; 需要保留吗?accept_encoding? 6)entry函数中缺少thread id; 7) plugin init and deinit cb; 8) add http session open and close cb; 9)enum tfe_bussiness_action pangu_http_entry(const struct tfe_stream * stream, const struct tfe_http_session * session, uint64_t event, const char* body_frag, size_t frag_size, unsigned int thread_id void ** pme) */ static enum pangu_action decide_ctrl_action(const Maat_rule_t* hit_result,int cnt,const Maat_rule_t**enforce_rule) { int i=0; const Maat_rule_t* tmp_rule=hit_result; enum pangu_action tmp_action=PG_ACTION_NONE; for(i=0;itmp_action) { tmp_rule=hit_result+i; tmp_action=(enum pangu_action)hit_result[i].action; } else if((enum pangu_action)hit_result[i].action==tmp_action) { if(hit_result[i].config_idconfig_id) { tmp_rule=hit_result+i; } } else { continue; } } *enforce_rule=tmp_rule; return tmp_action; } //https://github.com/AndiDittrich/HttpErrorPages static void html_generate(const char* enforce_para, char** page_buff,size_t *page_size) { *page_buff=g_pangu_rt->reject_page; *page_size=g_pangu_rt->page_size; } static void html_free(char** page_buff) { return; } static int is_http_request(uint64_t events) { if((events&EV_HTTP_REQ_HDR)|(events&EV_HTTP_REQ_BODY_BEGIN)|(events&EV_HTTP_REQ_BODY_END)|(events&EV_HTTP_REQ_BODY_CONT)) { return 1; } else { return 0; } } enum replace_zone zone_name_to_id(const char* name) { const char* std_name[]={"http_req_uri", "http_req_header", "http_req_body", "http_resp_header", "http_resp_body", "http_resp_body"}; size_t i=0; for(i=0;i< sizeof(std_name)/sizeof(const char*);i++) { if(0==strcasecmp(name,std_name[i])) { break; } } return (enum replace_zone)i; } static char* strchr_esc(char* s,const char delim) { char *token; if(s==NULL) return NULL; for(token=s;*token!='\0';token++) { if(*token=='\\') { token++; continue; } if(*token==delim) break; } if (*token == '\0') { return NULL; } else { return token; } } static char *strtok_r_esc(char *s, const char delim, char **save_ptr) { char *token; if (s == NULL) s = *save_ptr; /* Scan leading delimiters. */ token=strchr_esc(s,delim); if(token==NULL) { *save_ptr=token; return s; } /* Find the end of the token. */ *token='\0'; token++; *save_ptr=token; return s; } size_t 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; size_t idx=0; const char* str_zone="replace="; const char* str_subs="substitute="; memcpy(tmp,exec_para,strlen(exec_para)); for (token = tmp; ; token= NULL) { sub_token= strtok_r(token,";", &saveptr); if (sub_token == NULL) break; if(0==strncasecmp(sub_token,str_zone,strlen(str_zone))) { replace[idx].zone=zone_name_to_id(sub_token+strlen(str_zone)); if(replace[idx].zone==kZoneMax) { break; } } if(0==strncasecmp(sub_token,str_subs,strlen(str_subs))) { sub_token+=strlen(str_subs); replace[idx].find=tfe_strdup(strtok_r_esc(sub_token,'/', &saveptr2)); replace[idx].replace_with=tfe_strdup(strtok_r_esc(NULL, '/', &saveptr2)); idx++; if(idx==n_replace) { break; } } } free(tmp); tmp=NULL; return idx; } size_t select_replace_rule(enum replace_zone zone, const struct replace_rule* replace, size_t n_replace, const struct replace_rule** selected, size_t n_selected) { size_t i=0,j=0; for(i=0;ireplace_with); status=regcomp(®, zone->find, REG_EXTENDED|REG_NEWLINE); if(status!=0) { char error_message[TFE_STRING_MAX]; regerror (status, ®, error_message, sizeof(error_message)); TFE_LOG_ERROR(g_pangu_rt->local_logger,"Regex error compiling '%s': %s\n", zone->find, error_message); regfree(®); return NULL; } /* "p" is a pointer into the string which points to the end of the previous match. */ const char *p = in; /* "pre_sub_expr_end" is a pointer into the string which points to the end of the previous sub expression match. */ const char *pre_sub_expr_end=NULL; /* "N_matches" is the maximum number of matches allowed. */ const int n_matches = MAX_EDIT_MATCHES; /* "M" contains the matches found. */ regmatch_t m[n_matches]; int i = 0; while (1) { int nomatch = regexec (®, p, n_matches, m, 0); if (nomatch) { break; } if(is_replaced==0) { out=evbuffer_new(); is_replaced=1; } assert(m[0].rm_so!=-1); pre_sub_expr_end=p; if(m[1].rm_so == -1)//no sub expr, replace the entire expr. { evbuffer_add(out, pre_sub_expr_end, m[0].rm_so-(pre_sub_expr_end-p)); evbuffer_add(out, zone->replace_with, replace_len); pre_sub_expr_end=p + m[0].rm_eo; } else //have sub expr, replace the sub expr. { for (i = 1, pre_sub_expr_end=p; i < n_matches; i++) { if (m[i].rm_so == -1) { break; } evbuffer_add(out, pre_sub_expr_end, m[i].rm_so-(pre_sub_expr_end-p)); evbuffer_add(out, zone->replace_with, replace_len); pre_sub_expr_end = p + m[i].rm_eo; } } p += m[0].rm_eo; } if(is_replaced) { evbuffer_add(out, pre_sub_expr_end, in_sz-(pre_sub_expr_end-p)); } regfree(®); return out; } struct evbuffer* execute_replace_rule(const char* in, size_t in_sz, enum replace_zone zone, const struct replace_rule* rules, size_t n_rule) { const struct replace_rule* todo[MAX_EDIT_ZONE_NUM]; size_t n_todo=0, i=0; struct evbuffer* out=NULL; const char* interator=NULL; struct evbuffer* new_out=NULL, *pre_out=NULL; if(in==0) { return NULL; } //Do not process buffer that contains '\0'. if(0!=memchr(in, '\0', in_sz)) { return NULL; } n_todo=select_replace_rule(zone, rules, n_rule, todo, MAX_EDIT_ZONE_NUM); interator=in; for(i=0; ireq->req_spec.uri); tfe_http_session_detach(session); return; } if(ctx->rep_ctx==NULL) { 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->exec_para, rep_ctx->rule, MAX_EDIT_ZONE_NUM); } if(events&EV_HTTP_REQ_HDR) { rewrite_url=execute_replace_rule(session->req->req_spec.uri, strlen(session->req->req_spec.uri), kZoneRequestUri, rep_ctx->rule, rep_ctx->n_rule); } if((events&EV_HTTP_REQ_HDR)|(events&EV_HTTP_RESP_HDR)) { if(events&EV_HTTP_REQ_HDR) { rep_ctx->replacing=tfe_http_session_request_create(to_write_sess, session->req->req_spec.method, rewrite_url!=NULL ? (char*)evbuffer_pullup(rewrite_url,-1) : session->req->req_spec.uri); evbuffer_free(rewrite_url); rewrite_url=NULL; } else { rep_ctx->replacing=tfe_http_session_response_create(to_write_sess, session->resp->resp_spec.resp_code); } while(1) { buff_in=tfe_http_field_iterate(session->req, &interator, &tmp_name); if(tmp_name.field_id==TFE_HTTP_CONT_LENGTH) { continue; } if(buff_in!=NULL) { rewrite_buff=execute_replace_rule(buff_in, strlen(buff_in), events&EV_HTTP_REQ_HDR?kZoneRequestHeaders:kZoneResponseHeader, rep_ctx->rule, rep_ctx->n_rule); tfe_http_field_write(rep_ctx->replacing, &tmp_name, rewrite_buff!=NULL ? (char*)evbuffer_pullup(rewrite_buff, -1) : buff_in); evbuffer_free(rewrite_buff); rewrite_buff=NULL; } else { break; } } } if((events&EV_HTTP_REQ_BODY_BEGIN)|(events&EV_HTTP_RESP_BODY_BEGIN)) { assert(rep_ctx->http_body==NULL); assert(rep_ctx->body_size=0); rep_ctx->http_body=evbuffer_new(); } if(body_frag!=NULL) { evbuffer_add(rep_ctx->http_body, body_frag, frag_size); rep_ctx->body_size++; } if((events&EV_HTTP_REQ_BODY_END)|(events&EV_HTTP_RESP_BODY_END)) { assert(rep_ctx->body_size==evbuffer_get_length(rep_ctx->http_body)); buff_in=(char*)evbuffer_pullup(rep_ctx->http_body, -1); rewrite_buff=execute_replace_rule(buff_in, rep_ctx->body_size, events&EV_HTTP_REQ_HDR?kZoneRequestHeaders:kZoneResponseHeader, rep_ctx->rule, rep_ctx->n_rule); char cont_len_str[TFE_SYMBOL_MAX]; snprintf(cont_len_str, sizeof(cont_len_str), "%lu", evbuffer_get_length(rewrite_buff)); _wrap_std_field_write(rep_ctx->replacing, TFE_HTTP_CONT_LENGTH, cont_len_str); tfe_http_half_append_body(rep_ctx->replacing, (char*)evbuffer_pullup(rewrite_buff, -1), evbuffer_get_length(rewrite_buff),0); evbuffer_free(rewrite_buff); rewrite_buff=NULL; if(is_http_request(events)) { tfe_http_session_request_set(to_write_sess, rep_ctx->replacing); } else { tfe_http_session_response_set(to_write_sess, rep_ctx->replacing); } rep_ctx->replacing=NULL;//http half's ownership has been transfered to session. evbuffer_free(rep_ctx->http_body); rep_ctx->http_body=NULL; rep_ctx->body_size=0; } return; } static void http_reject(const struct tfe_http_session * session, uint64_t events, struct pangu_http_ctx* ctx) { int resp_code=0,ret=0; struct tfe_http_half* response=NULL; char* page_buff=NULL; size_t page_size=0; char cont_len_str[TFE_STRING_MAX]; struct tfe_http_session* to_write_sess=NULL; ret=sscanf(ctx->exec_para,"code=%d;",&resp_code); if(ret!=1) { TFE_LOG_ERROR(g_pangu_rt->local_logger, "Invalid reject rule %d paramter %s", ctx->exec_rule->config_id, ctx->exec_para); goto error_out; } to_write_sess=tfe_http_session_allow_write(session); response=tfe_http_session_response_create(to_write_sess, resp_code); html_generate(ctx->exec_para, &page_buff, &page_size); _wrap_std_field_write(response, TFE_HTTP_CONT_TYPE, "text/html; charset=utf-8"); snprintf(cont_len_str,sizeof(cont_len_str), "%lu", page_size); _wrap_std_field_write(response, TFE_HTTP_CONT_LENGTH, cont_len_str); tfe_http_half_append_body(response, page_buff, page_size, 0); tfe_http_session_response_set(to_write_sess, response); response=NULL; error_out: html_free(&page_buff); return; } static void http_redirect(const struct tfe_http_session * session, uint64_t events, 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->exec_rule->serv_def_len); ret=sscanf(ctx->exec_para,"code=%d%[^;];url=%*[^;];",&resp_code,url); if(ret!=2) { TFE_LOG_ERROR(g_pangu_rt->local_logger, "Invalid redirect rule %d paramter %s", ctx->exec_rule->config_id, ctx->exec_para); goto error_out; } to_write=tfe_http_session_allow_write(session); response=tfe_http_session_response_create(to_write, resp_code); _wrap_std_field_write(response, TFE_HTTP_LOCATION, url); tfe_http_session_response_set(to_write, response); response=NULL; error_out: free(url); return; } enum pangu_action http_scan(const struct tfe_http_session * session, uint64_t events, const char* body_frag, size_t frag_size, struct pangu_http_ctx* ctx) { void * interator=NULL; const char* field_val=NULL; struct http_field_name field_name; struct Maat_rule_t result[MAX_SCAN_RESULT]; const struct Maat_rule_t* choosen=NULL; char buff[TFE_STRING_MAX], *p=NULL; int scan_ret=0, hit_cnt=0, table_id=0, read_rule_ret=0; unsigned int i=0; if(events&EV_HTTP_REQ_HDR) { scan_ret=Maat_full_scan_string(g_pangu_rt->maat, g_pangu_rt->scan_table_id[PXY_CTRL_HTTP_URL], CHARSET_UTF8, session->req->req_spec.url, strlen(session->req->req_spec.url), result, NULL, MAX_SCAN_RESULT, &(ctx->mid), ctx->thread_id); if(scan_ret>0) { hit_cnt+=scan_ret; } } if((events&EV_HTTP_REQ_HDR)|(events&EV_HTTP_RESP_HDR)) { table_id=events&EV_HTTP_REQ_HDR?g_pangu_rt->scan_table_id[PXY_CTRL_HTTP_REQ_HDR]:g_pangu_rt->scan_table_id[PXY_CTRL_HTTP_RES_HDR]; while(hit_cntreq, &interator, &field_name); if(field_val==NULL) { break; } scan_ret=Maat_set_scan_status(g_pangu_rt->maat, &(ctx->mid), MAAT_SET_SCAN_DISTRICT, field_name.field_name,strlen(field_name.field_name)); assert(scan_ret==0); scan_ret=Maat_full_scan_string(g_pangu_rt->maat, table_id, CHARSET_UTF8, field_val, strlen(field_val), result+hit_cnt, NULL, MAX_SCAN_RESULT-hit_cnt, &(ctx->mid), ctx->thread_id); if(scan_ret>0) { hit_cnt+=scan_ret; } } } if((events&EV_HTTP_REQ_BODY_BEGIN)|(events&EV_HTTP_RESP_BODY_BEGIN)) { assert(ctx->sp==NULL); table_id=events&EV_HTTP_REQ_BODY_BEGIN?g_pangu_rt->scan_table_id[PXY_CTRL_HTTP_REQ_BODY]:g_pangu_rt->scan_table_id[PXY_CTRL_HTTP_RES_BODY]; ctx->sp=Maat_stream_scan_string_start(g_pangu_rt->maat, table_id, ctx->thread_id); } if(body_frag!=NULL) { scan_ret=Maat_stream_scan_string(&(ctx->sp),CHARSET_UTF8, body_frag, (int)frag_size ,result+hit_cnt, NULL, MAX_SCAN_RESULT-hit_cnt, &(ctx->mid)); if(scan_ret>0) { hit_cnt+=scan_ret; } } if((events&EV_HTTP_REQ_BODY_END)|(events&EV_HTTP_RESP_BODY_END)) { Maat_stream_scan_string_end(&(ctx->sp)); ctx->sp=NULL; } if(hit_cnt>0) { ctx->action=decide_ctrl_action(result, hit_cnt, &choosen); ctx->exec_rule=ALLOC(struct Maat_rule_t, 1); memcpy(ctx->exec_rule, choosen, sizeof(struct Maat_rule_t)); if(ctx->exec_rule->serv_def_len>MAX_SERVICE_DEFINE_LEN) { ctx->exec_para=ALLOC(char, ctx->exec_rule->serv_def_len); read_rule_ret=Maat_read_rule(g_pangu_rt->maat, ctx->exec_rule, MAAT_RULE_SERV_DEFINE, ctx->exec_para, ctx->exec_rule->serv_def_len); assert(read_rule_ret== ctx->exec_rule->serv_def_len); } if(hit_cnt>1) { p=buff; for(i=0;i<(unsigned int)hit_cnt;i++) { p+=snprintf(p, sizeof(buff)-(p-buff), "%d:", result[i].config_id); } *p='\0'; TFE_LOG_INFO(g_pangu_rt->local_logger, "Multiple rules matched: url=%s num=%d ids=%s execute=%d.", session->req->req_spec.url, hit_cnt, buff, ctx->exec_rule->config_id); } } return ctx->action; } void pangu_on_http_begin(const struct tfe_stream * stream, const struct tfe_http_session * session, unsigned int thread_id, void ** pme) { struct pangu_http_ctx* ctx=*(struct pangu_http_ctx**)pme; struct Maat_rule_t result[MAX_SCAN_RESULT]; const struct Maat_rule_t* choosen=NULL; struct ipaddr sapp_addr; int hit_cnt=0; assert(ctx==NULL); ctx=pangu_http_ctx_new(thread_id); 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, MAX_SCAN_RESULT, &(ctx->mid), (int)thread_id); if(hit_cnt>0) { ctx->action=decide_ctrl_action(result, hit_cnt, &choosen); } if(ctx->action==PG_ACTION_WHITELIST) { tfe_http_session_detach(session); } } void pangu_on_http_end(const struct tfe_stream * stream, const struct tfe_http_session * session, unsigned int thread_id, void ** pme) { struct pangu_http_ctx* ctx=*(struct pangu_http_ctx**)pme; struct pangu_log log_msg={.stream=stream, .http=session, .result=ctx->exec_rule, .result_num=1}; if(ctx->action!=PG_ACTION_NONE) { pangu_log_send(g_pangu_rt->send_logger, &log_msg, NULL, 0); } pangu_http_ctx_free(ctx); *pme=NULL; return; } void pangu_on_http_data(const struct tfe_stream * stream, const struct tfe_http_session * session, uint64_t events, const char* body_frag, size_t frag_size, unsigned int thread_id, void ** pme) { struct pangu_http_ctx* ctx=*(struct pangu_http_ctx**)pme; enum pangu_action hit_action=PG_ACTION_NONE; Re_Enter: switch(ctx->action) { case PG_ACTION_NONE: hit_action=http_scan(session, events, body_frag, frag_size, ctx); if(hit_action!=PG_ACTION_NONE) { //ctx->action changed in http_scan. goto Re_Enter; } break; case PG_ACTION_MONIT: //send log on close. break; case PG_ACTION_REJECT: http_reject(session, events, ctx); break; case PG_ACTION_REDIRECT: http_redirect(session, events, ctx); case PG_ACTION_REPLACE: http_replace(stream, session, events, body_frag, frag_size,ctx); break; case PG_ACTION_WHITELIST: tfe_http_session_detach(session); break; default: assert(0); break; } return; }