summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore6
-rw-r--r--qq_file_send.c486
-rw-r--r--qq_file_send.inf44
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