diff options
| author | 姜鹏辉 <[email protected]> | 2020-11-05 11:05:27 +0800 |
|---|---|---|
| committer | 姜鹏辉 <[email protected]> | 2020-11-05 11:05:27 +0800 |
| commit | 2599d55acf0637ea2184b68c845dcac880e4b957 (patch) | |
| tree | 893da7fb3a31d3dcaaee17e31224c865902c08e0 | |
Initial committcp
| -rw-r--r-- | .gitignore | 6 | ||||
| -rw-r--r-- | qq_file_send.c | 486 | ||||
| -rw-r--r-- | qq_file_send.inf | 44 |
3 files changed, 536 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..34f71f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*.so +*.txt +*.cmake +Makefile +*.sh + diff --git a/qq_file_send.c b/qq_file_send.c new file mode 100644 index 0000000..e0ee87e --- /dev/null +++ b/qq_file_send.c @@ -0,0 +1,486 @@ +#include <time.h> +#include <arpa/inet.h> +#include <stdio.h> +#include <ctype.h> +#include <MESA/MESA_prof_load.h> +#include <MESA/MESA_handle_logger.h> +#include <MESA/MESA_htable.h> +#include <MESA/stream.h> +#include <nirvana_client.h> +#define LOG_PATH "./log/qq_file/" +#define ONLINE_PUBLIC_SEND 0 +#define OFFLINE_SEND 1 +#define NAME_SIZE 80 +#define NIRVANA + +//#define ONLINE_LOCAL_SEND_SMALL 2 +//#define ONLINE_LOCAL_SEND_BIG 3 + +typedef struct +{ + int separator_flag; + int send_type; // OFFLINE_SEND + char uuid[36]; + int content_len; + char filename[NAME_SIZE]; + UCHAR dir; + struct nirvana_streaming_asyctx *ctx; +}qq_pme_info,*qq_pme_info_p; + +typedef struct +{ + int feature_type; + char *separator_header; + int header_len; + int uuid_deviation; + char *uuid_suffix; + int uuid_suffix_len; + int content_deviation; +}struct_separator_feature; + + +typedef struct +{ + char *filename; + struct nirvana_streaming_asyctx *ctx; +}file_info; + +int file_cnt = 0; + +struct_separator_feature online_feature,offline_feature; +MESA_htable_handle file_htable; +char post_header[NAME_SIZE],save_directory[NAME_SIZE]; +int locally_save; // save file to local machine +void *runtime_log; +struct event_base *ev_base; +struct nirvana_asyn_instance *instance_asyn; + +void get_next_of_pat(const char *pat, int *next) +{ + next[0] = -1; + int i = 0, j = -1, size_of_pat = strlen(pat); + + while (i < size_of_pat) + { + if (j == -1 || pat[i] == pat[j]) + { + ++i; + ++j; + next[i] = j; + } + else + { + j = next[j]; + } + } +} + + +int kmp(char *str, char *pat, int size_of_str) +{ + int i = 0, j = 0, size_of_pat = strlen(pat); + int next[256]; + get_next_of_pat(pat, next); + + while (i < size_of_str && j < size_of_pat) + { + if (j == -1 || str[i] == pat[j]) + { + ++i; + ++j; + } + else + { + j = next[j]; + } + } + if (j == size_of_pat) + { + return i - j; + } + else + { + return -1; + } +} + + +/* + * @Description: Processing payload and extracting separator + * @param: payload + * @param: payload_len + * @param: Characteristics of separators + * @param: pme + * @return: =0 : success + <0 : fail +*/ +int parse_separator(char **payload,int payload_len,struct_separator_feature separator_feature,qq_pme_info **pme) +{ + int uuid_len = 35; + //match by header + if(strncmp(*payload,separator_feature.separator_header,separator_feature.header_len) != 0) + { + return -1; + } + // match by the suffix which is after uuid + if( strncmp( (*payload)+separator_feature.uuid_deviation + uuid_len+1,separator_feature.uuid_suffix,separator_feature.uuid_suffix_len) != 0) + { + return -2; + } + qq_pme_info_p qq_pme = *pme; + strncpy(qq_pme->uuid,(*payload) + separator_feature.uuid_deviation,uuid_len); + //printf("this uuid:%s\n",qq_pme->uuid); + + (*payload)+=separator_feature.content_deviation; + + qq_pme->content_len = payload_len-separator_feature.content_deviation; + qq_pme->send_type = separator_feature.feature_type; + return 0; +} + + +/* + * @Description: Converts a string in hex to decimal(int) + * @param: char + * @return: int +*/ +int hexch_to_int(char ch) +{ + int res; + if ((ch >= 'A') && (ch <='F')) + { + res = 10+ch-'A'; + } + else if ((ch >= 'a') && (ch <='f')) + { + res = 10+ch-'a'; + } + else{ + res = ch-'0'; + } + return res; +} + +/* + * @Description: 'abcd00' -> {0xab,0xcd,0x00} + * @param: in_str + * @param: the len of out_str + * @param: out_str + * @return: None +*/ +void str_to_ascii(char *in_str,int str_len,char* out_str) +{ + int i; + for (i=0;i<str_len;i++) + { + out_str[i] = hexch_to_int(in_str[i*2])*16 + hexch_to_int(in_str[i*2+1]); + } +} + + +/* + * @Description: read the feature of the separator in the profile + * @param: [IN] profile name + * @param: [OUT] p_separator_feature + * @param: [IN] section name + * @param: [IN] feature type eg.ONLINE_PUBLIC_SEND/OFFLINE_SEND + * @return: + 0 : success + -1: fail +*/ +int read_profile_of_separator(const char *inf_file,struct_separator_feature *p_separator_feature,char *section,int feature_type) +{ + + char *separator_header_array,*uuid_suffix_array; + int read_res = 0; + + p_separator_feature->feature_type = feature_type; + + //header_len + read_res += MESA_load_profile_int_nodef(inf_file,section,"header_len",&(p_separator_feature->header_len)); + + //header + p_separator_feature->separator_header = (char *)malloc(p_separator_feature->header_len); + separator_header_array = (char *)malloc(p_separator_feature->uuid_suffix_len<<2); + read_res += MESA_load_profile_string_nodef(inf_file,section,"separator_header",separator_header_array,p_separator_feature->header_len<<2); + str_to_ascii(separator_header_array,p_separator_feature->header_len,p_separator_feature->separator_header); + + //uuid_deviation + read_res += MESA_load_profile_int_nodef(inf_file,section,"uuid_deviation",&(p_separator_feature->uuid_deviation)); + + //uuid_suffix_len + read_res += MESA_load_profile_int_nodef(inf_file,section,"uuid_suffix_len",&(p_separator_feature->uuid_suffix_len)); + + //uuid_suffix + p_separator_feature->uuid_suffix = (char *)malloc(p_separator_feature->uuid_suffix_len); + uuid_suffix_array = (char *)malloc(p_separator_feature->uuid_suffix_len<<2); + read_res += MESA_load_profile_string_nodef(inf_file,section,"uuid_suffix",uuid_suffix_array,p_separator_feature->uuid_suffix_len<<2); + str_to_ascii(uuid_suffix_array,p_separator_feature->uuid_suffix_len,p_separator_feature->uuid_suffix); + + //content_deviation + read_res += MESA_load_profile_int_nodef(inf_file,section,"content_deviation",&(p_separator_feature->content_deviation)); + + if (!read_res) + return -1; + return 0; +} + + +/* + * @Description: different files have different uuids. + modify the filename in pme according to the current uuid + * @param: pme + * @return: None +*/ +void match_uuid(qq_pme_info **pme) +{ + qq_pme_info_p qq_pme = *pme; + file_info* thisfile = (file_info *) MESA_htable_search(file_htable,(u_char *)qq_pme->uuid,strlen(qq_pme->uuid)); + if (thisfile == NULL) + { + // new file + file_info *newfile; + newfile = (file_info *)malloc(sizeof(file_info)); + newfile->filename = (char *)malloc(sizeof(qq_pme->filename)); + strncpy(newfile->filename,qq_pme->filename,strlen(qq_pme->filename)); +#ifdef NIRVANA + newfile->ctx = qq_pme->ctx; +#endif + MESA_htable_add(file_htable,(u_char *) qq_pme->uuid,strlen(qq_pme->uuid),(void *)newfile); + } + else + { + // there is a file point in htable + // so change the pme + strncpy(qq_pme->filename,thisfile->filename,strlen(thisfile->filename)); +#ifdef NIRVANA + qq_pme->ctx = thisfile->ctx; +#endif + } + +} + +/* + * @Description: Used to delete value from hash table + * @param: file_info * + * @return: Null +*/ +void free_fileinfo(void *thisfile) +{ + //thisfile = thisfile; + file_info *p = (file_info *)thisfile; + free(p->filename); + free(p); +} + +/* + * @Description: + * @param: + * @return: +*/ +void free_pme(qq_pme_info **pme) +{ + qq_pme_info_p qq_pme = *pme; + free(qq_pme->ctx); + free(qq_pme); +} + +char qq_file_send_entry(struct streaminfo *a_tcp,void **pme,int thread_seq,void *a_packet) +{ + + int payload_len; + //char *post_header = "POST /ftn_handler?bmd5="; + struct tcpdetail* tcp_detail = a_tcp->ptcpdetail; + payload_len = tcp_detail->datalen; + char *payload =(char *)tcp_detail->pdata; + qq_pme_info_p qq_pme = (qq_pme_info_p) *pme; + switch(a_tcp->opstate) + { + case OP_STATE_PENDING: + + if(!strncmp(post_header,payload,strlen(post_header))) + { + if (*pme == NULL) + { + *pme =(qq_pme_info_p)malloc(sizeof(qq_pme_info)); + qq_pme = *pme; + } + //1aa23fc86a9ea7dbea7c987dcb4bea1f 32Byte + UINT32 createtime = tcp_detail->createtime; + char filename[100]; + + printf("ip:%u\n",a_tcp->addr.ipv4->saddr); + //printf("ip:%s\n",ip_str); + + // the filename is determined by createtime and md5 + sprintf(filename,"%s/qqfile_%d_%u",save_directory,file_cnt,createtime); + file_cnt ++; + strncpy(qq_pme->filename,filename,strlen(filename)); + // separator_flag is 1 means that the next TCP packet contains a separator + qq_pme->separator_flag = 1; + qq_pme->dir = a_tcp->curdir; + printf("start\n"); +#ifdef NIRVANA + // nirvana section + struct nirvana_streaming_asyctx *ctx; + union nirvana_progid progid; + struct streaming_meta streammeta; + struct nvn_opt_unit opt[1]; + int opt_num = 1; + + opt[0].opt_type = NVN_OPT_TYPE_KEY_SINGLE; + opt[0].opt_len = strlen(filename)+1; + opt[0].opt_value = filename; + + streammeta.msg_type = NVN_MSG_TYPE_AV_FRAGMENT; + streammeta.msg_subtype = 0; + streammeta.cont_code = 0; + streammeta.protocol = NVN_PROTOCOL_HTTP; + streammeta.live_streaming = 0; + streammeta.cap_IP = 0; + streammeta.dir = DIR_C2S; + streammeta.request_single_flow = 1; + + calculate_md5_for_progid(filename, strlen(filename), &progid); + streammeta.balance_seed = caculate_seed_using_sdbm_hash((char*)&progid, sizeof(progid)); + ctx = nirvana_streaming_asyn_update_start(instance_asyn, &progid, &streammeta); + if(ctx == NULL) + { + return APP_STATE_DROPME; + } + nirvana_streaming_asyn_update_meta(ctx, opt, opt_num); + qq_pme->ctx = ctx; +#endif + } + else + { + return APP_STATE_DROPME; + } + break; + case OP_STATE_DATA: + //printf("dir %d %d %d %d\n",a_tcp->curdir,qq_pme->dir,DIR_C2S,DIR_S2C); + if(a_tcp->curdir != qq_pme->dir) + { + return APP_STATE_GIVEME; + } + if(!strncmp(post_header,payload,strlen(post_header))) + { + qq_pme->separator_flag = 1; + return APP_STATE_GIVEME; + } + // The next payload contains the separator, which needs to be processed + if(qq_pme->separator_flag == 1) + { + char **ppayload = &payload; + int parse_res; + parse_res = parse_separator(ppayload,payload_len,offline_feature,&qq_pme); + if(parse_res < 0) + { + // If offline matching fails, the online rule will be matched again + parse_res = parse_separator(ppayload,payload_len,online_feature,&qq_pme); + if(parse_res < 0) + { + // If both matches fail, the rule is wrong or the traffic is wrong +#ifdef NIRVANA + nirvana_streaming_asyn_update_end(qq_pme->ctx); + nirvana_streaming_asyn_update_cancel(qq_pme->ctx); +#endif + return APP_STATE_DROPME; + } + } + qq_pme->separator_flag = 0; + match_uuid(&qq_pme); + + printf("%d separa:%s %s\n",thread_seq,qq_pme->filename,qq_pme->uuid); + if(locally_save == 1) + { + FILE *fp = fopen(qq_pme->filename,"ab"); + fwrite(payload,qq_pme->content_len,1,fp); + fclose(fp); + } +#ifdef NIRVANA + nirvana_streaming_asyn_update_data(qq_pme->ctx,payload ,qq_pme->content_len); +#endif + } + else + { + //printf("%d file:%s %s\n",thread_seq,qq_pme->filename,qq_pme->uuid); + if(locally_save == 1) + { + FILE *fp = fopen(qq_pme->filename,"ab"); + fwrite(payload,payload_len,1,fp); + fclose(fp); + } +#ifdef NIRVANA + nirvana_streaming_asyn_update_data(qq_pme->ctx,payload ,qq_pme->content_len); +#endif + } + + break; + case OP_STATE_CLOSE: +#ifdef NIRVANA + nirvana_streaming_asyn_update_end(qq_pme->ctx); + nirvana_streaming_asyn_update_cancel(qq_pme->ctx); +#endif + + MESA_htable_del(file_htable,(u_char *)qq_pme->uuid,strlen(qq_pme->uuid),free_fileinfo); + break; + } + + return APP_STATE_GIVEME; +} +int suggestion_inform_callback(struct suggest_receive_info *info, struct nirvana_message_survey *detail, const char *snap_URL, struct nvn_opt_unit *opts, void *privdata) +{ + char fromip_str[64]; + + inet_ntop(AF_INET, &info->from_ip, fromip_str, 64); + + printf("Receive suggest from: %s, progid=0x%lu_%lu\n", fromip_str, detail->progid.progid_long.progidH, detail->progid.progid_long.progidL); + return 0; +} + + +void nirvana_client_init() +{ + struct nirvana_parameter *parameter; + ev_base = event_base_new(); + parameter = nirvana_client_parameter_new("./plug/protocol/qq_file_send/qq_file_send.inf", "NIRVANA", runtime_log); + instance_asyn = nirvana_client_instance_new(parameter, ev_base, runtime_log, suggestion_inform_callback, NULL); + event_base_dispatch(ev_base); +} + +void qq_file_send_init() +{ + printf("qq_file_end init\n"); + const char *inf_file = "./plug/protocol/qq_file_send/qq_file_send.inf"; + read_profile_of_separator(inf_file,&online_feature,"ONLINE_FEATURE",ONLINE_PUBLIC_SEND); + read_profile_of_separator(inf_file,&offline_feature,"OFFLINE_FEATURE",OFFLINE_SEND); + + MESA_load_profile_string_nodef(inf_file,"CAPTURE","post_header",post_header,NAME_SIZE); + MESA_load_profile_string_nodef(inf_file,"CAPTURE","save_directory",save_directory,NAME_SIZE); + MESA_load_profile_int_def(inf_file,"CAPTURE","locally_save",&locally_save,0); + + runtime_log = MESA_create_runtime_log_handle("./runtime.log", 10); +#ifdef NIRVANA + nirvana_client_init(); +#endif + // init a hashtable,key is uuid,value is pme + file_htable = MESA_htable_born(); + int *psafe = (int *)malloc(sizeof(int)); + *psafe = 1; + MESA_htable_set_opt(file_htable,MHO_THREAD_SAFE,psafe,sizeof(int)); + MESA_htable_mature(file_htable); + MESA_htable_print_crtl(file_htable,0); +} +void GET_PLUGID(unsigned short plugid) +{ + ; +} +long long FLAG_CHANGE(char *flag_str) +{ + return 1; +} +void PROT_FUNSTAT(long long protflag) +{ + ; +}
\ No newline at end of file diff --git a/qq_file_send.inf b/qq_file_send.inf new file mode 100644 index 0000000..292d155 --- /dev/null +++ b/qq_file_send.inf @@ -0,0 +1,44 @@ +[PLUGINFO] +PLUGNAME=QQ_FILE_SEND +SO_PATH=./plug/protocol/qq_file_send/qq_file_send.so +INIT_FUNC=qq_file_send_init +DESTROY_FUNC=QQ_FILE_SEND_DESTROY +GETPLUGID_FUNC=GET_PLUGID +FLAGCHANGE_FUNC=FLAG_CHANGE +FLAGSTATE_FUNC=PROT_FUNSTAT + +[TCP] +FUNC_FLAG=ALL +FUNC_NAME=qq_file_send_entry + + +[CAPTURE] +post_header = POST /ftn_handler?bmd5= +locally_save = 1 +save_directory = /home/jiangph + + +[ONLINE_FEATURE] +separator_header = abcd9876000003ef0000 +#separator_header = [171,205,152,118,0,0,3,239,0,0] +header_len = 10 +uuid_deviation = 83 +uuid_suffix = 0014 +#uuid_suffix = [0,20] +uuid_suffix_len = 2 +content_deviation = 161 + + +[OFFLINE_FEATURE] +separator_header = abcd9876000003ef0000 +#separator_header = [171,205,152,118,0,0,3,239,0,0] +header_len = 10 +uuid_deviation = 83 +uuid_suffix = 3f3f +#uuid_suffix = [63,63] +uuid_suffix_len = 2 +content_deviation = 364 + +[NIRVANA] +dest_addr_ip_list=[tcp:192.168.10.90] +dest_addr_port=6230
\ No newline at end of file |
