您好,登錄后才能下訂單哦!
#include <pcap.h> #include <stdlib.h> #include <malloc.h> #include <stdio.h> #include <string.h> #include <signal.h> #include <time.h> #include <sys/socket.h> #include <unistd.h> #include <sys/types.h> #include <errno.h> #include <sys/syslog.h> #include <fcntl.h> #include <arpa/inet.h> #include <net/ethernet.h> #include <netinet/in.h> #include <netinet/if_ether.h> #include <netinet/ip.h> #include <netinet/udp.h> #include <netinet/tcp.h> #include <netinet/ip_icmp.h> #include <pthread.h> /**/typedef struct value{ u_int32_t sip; /*源IP*/ unsigned long long packets; /* 報數 */ unsigned long long tcp; unsigned long long udp; unsigned long long icmp; unsigned long long other; unsigned long long bytes; /* 流量 */ }value; /* */ typedef struct{ value v; /* 結構體 value*/ unsigned long long fpacket; /* 進包數 */ unsigned long long fbytes; /* 進流量 */ }xvalue; #define HASHSIZE 10000 /* hash表大小 */ #define HASHSIZEIN 1000 /* hash表大小 */ /*自定義結構體 */ typedef struct node{ u_int32_t ip; // ip地址,次結構體記錄Ip對應的以下屬性 unsigned long long bytes; /* 字節數 */ unsigned long long packets; /* 數據包數 */ unsigned long long fbytes; /* 進流量 */ unsigned long long fpacket; /* 進包數 */ unsigned long long tcp; /* 是否為tcp協議 */ unsigned long long udp; /* 是否為udp協議 */ unsigned long long icmp; /* 是否為icmp協議 */ unsigned long long other; /* 其他 */ struct node *next; /* 下一個節點指針 */ }htnode; typedef htnode **hashtable; unsigned long long in_bytes; //進網流量 unsigned long long in_packets; //進網包數 unsigned long long out_bytes; //出網流量 unsigned long long out_packets=0; //出網包數 bpf_u_int32 netp,maskp; /* 網絡地址 , 子網掩碼*/ hashtable ht,ht_out; pthread_mutex_t hash_lock; /*線程鎖*/ pthread_attr_t attr; sigset_t mask_sig; int hash(u_int32_t ip, int size) { return ip % size; } htnode * hashtable_search(hashtable T, int size, u_int32_t ip){ htnode *p=T[hash(ip, size)]; while(p!=NULL && p->ip!=ip) p=p->next; return p; } int hashtable_insert(hashtable T, int size, htnode *s) { int d; htnode *p=hashtable_search(T, size, s->ip); if(p!=NULL){ p->fbytes += s->fbytes; p->fpacket += s->fpacket; p->bytes += s->bytes; p->packets += s->packets; p->tcp += s->tcp; p->udp += s->udp; p->icmp += s->icmp; p->other += s->other; free(s); s=NULL; }else{ d=hash(s->ip, size); s->next = T[d]; T[d]=s; } } //哈希表銷毀void hashtable_descrty(hashtable h, int size, int in_out){ value *v; xvalue vs[400]; int sock,j=1; struct sockaddr_in svraddr; if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0){ exit(1); } svraddr.sin_family = AF_INET; svraddr.sin_port = htons(4200); if(inet_pton(AF_INET, "IP地址", &svraddr.sin_addr) < 0){ exit(1); } //將IP地址由點分十進制 轉為 網絡字節序格式 if(connect(sock, (const struct sockaddr *)&svraddr, sizeof(svraddr)) < 0){ close(sock);return; } //啟動socket,連接服務端,準備推送數據 memset(&vs[0], 0, sizeof(xvalue)); //外網ip記錄的數據 if(in_out==0){ vs[0].v.other = 0; vs[0].fbytes = out_bytes; vs[0].fpacket = out_packets; //內網ip記錄的數據 }else{ vs[0].v.other = 1; vs[0].fbytes = in_bytes; vs[0].fpacket = in_packets; } int i; for (i = 0; i < size; i++) { htnode *p,*t; p = h[i]; if (p ==NULL ) continue; while(p->next != NULL){ vs[j].v.sip = p->ip; vs[j].v.tcp = p->tcp; vs[j].v.udp = p->udp; vs[j].v.icmp = p->icmp; vs[j].v.other = p->other; vs[j].v.bytes = p->bytes; vs[j].v.packets = p->packets; vs[j].fbytes = p->fbytes; vs[j].fpacket = p->fpacket; j++; t = p->next; free(p); p=t; } vs[j].v.sip = p->ip; vs[j].v.tcp = p->tcp; vs[j].v.udp = p->udp; vs[j].v.icmp = p->icmp; vs[j].v.other = p->other; vs[j].v.bytes = p->bytes; vs[j].v.packets = p->packets; vs[j].fbytes = p->fbytes; vs[j].fpacket = p->fpacket; j++; free(p); p=NULL; } free(h); h=NULL; write(sock, vs, sizeof(xvalue) * j); //將數據傳給服務端 close(sock); } int insert_top(hashtable T, htnode *p, int newsize){ struct in_addr addr; htnode *t,*f; int i; for (i = 0; i < newsize; ++i) { if (T[i] != NULL){ if(p->bytes > T[i]->bytes){ t = T[i]; int j=i; while(j<(newsize-1) && t!=NULL){ j++; f=T[j]; T[j]=t; t=f; } if(t!=NULL) free(t); p->next = NULL; T[i] = p; return 0; } }else{ p->next = NULL; T[i] = p; return 0; } } return 1; } hashtable hashtable_top(hashtable h, int size, int newsize){ hashtable topht; if((topht = (struct node **)calloc(newsize, sizeof(struct node*))) == NULL) exit(-1); int i; for (i = 0; i < size; i++) { htnode *p,*t; p = h[i]; if (p ==NULL ) continue; while(p->next != NULL){ t = p->next; if (insert_top(topht,p,newsize)){ free(p); p=NULL; } p=t; } if (insert_top(topht,p,newsize)){ free(p); p=NULL; } } free(h); h=NULL; return topht; } /*數據包處理程序*/ void callPacket(u_char *arg, const struct pcap_pkthdr* pack, const u_char *content) { struct ether_header *ethernet; /* 結構體 以太網包頭 */ struct iphdr *ip; /* 結構體 ip包頭 */ ethernet=(struct ether_header *)content; /*從content中提取以太網包頭信息*/ //ip 檢測數據包是否為IP包 if(ntohs(ethernet->ether_type)==ETHERTYPE_IP) { ip=(struct iphdr*)(content+14); /*content前14byte 為以太網包頭,將指針移動14byte之后為IP包頭開始位置 ,此處 從content中提取IP包頭數據 */ int tot_len=ntohs(ip->tot_len) + 18; /*計算數據包總長度 ip->tot_len代表 ip首部記錄的ip包數據包大小, 18= 14+4 14:代表以太網的(源地址+目標地址+類型) 4代表(CRC)*/ //外網包 htnode *hv_out; if( (hv_out = (struct node*)calloc(1, sizeof(struct node))) ==NULL) exit(-1); /* 分配內存*/ hv_out->bytes = tot_len; hv_out->packets = 1; //內網包 htnode *hv; // 包含所有內網Ip的進流量、進包數、出流量、出包數 if( (hv = (struct node*)calloc(1, sizeof(struct node))) ==NULL) exit(-1); hv->bytes = tot_len; hv->packets = 1; switch(ip->protocol) { case 6: hv_out->tcp = 1; hv->tcp = 1; break; case 17: hv_out->udp = 1; hv->udp = 1; break; case 1: hv_out->icmp = 1; hv->icmp = 1; break; default: hv_out->other = 1; hv->other = 1; break; } //出網包 如果數據包是從服務端流向客戶端 if ( ((ip->saddr & maskp)==netp) && ((ip->daddr & maskp)!=netp) ){ //內網ip 記錄此內網Ip的出流量、出包數 hv->ip = ip->saddr; //數據包中的源IP地址 此處為內網IP地址 pthread_mutex_lock(&hash_lock); hashtable_insert(ht, HASHSIZE, hv); //將hv添加到hash表 pthread_mutex_unlock(&hash_lock); //外網ip 記錄服務端返回給此外網ip的返回流量、返回包數 hv_out->ip = ip->daddr; //數據包中的目標IP地址 此處為外網ip地址 pthread_mutex_lock(&hash_lock); hashtable_insert(ht_out, HASHSIZEIN, hv_out); //將hv_out添加到hash表 out_bytes += tot_len; //出網流量增加 out_packets++; //出網報數增加 pthread_mutex_unlock(&hash_lock); //進網包 如果數據包是從客戶端流向服務端 }else if( ((ip->daddr & maskp)==netp) && ((ip->saddr & maskp)!=netp) ){ //內網ip 記錄此內網ip的進流量、進包數 hv->fbytes = tot_len; hv->fpacket = 1; hv->ip = ip->daddr; //數據包中的目標id 此處為內網IP地址 pthread_mutex_lock(&hash_lock); hashtable_insert(ht, HASHSIZE, hv); //將數據插入ht shah表 pthread_mutex_unlock(&hash_lock); //外網ip 記錄此外網ip的請求流量,請求包數 hv_out->fbytes = tot_len; hv_out->fpacket = 1; hv_out->ip = ip->saddr; //數據包中的源IP, 此處為外網IP pthread_mutex_lock(&hash_lock); hashtable_insert(ht_out, HASHSIZEIN, hv_out); //將數據插入ht_out in_bytes += tot_len; //進網流量增加 in_packets++; //進網包數增加 pthread_mutex_unlock(&hash_lock); //內網廣播包 }else if( ((ip->daddr & maskp)==netp) && ((ip->saddr & maskp)==netp) ){ free(hv); hv=NULL; free(hv_out); hv_out=NULL; in_bytes += tot_len; //將內網廣播包當做進入流量 in_packets++; //將內網數據包當做進入流量 //外網包 }else{ free(hv); hv=NULL; free(hv_out); hv_out=NULL; out_bytes += tot_len; out_packets++; } // ARP包 作為 進網包,大小為60byte else if(ntohs (ethernet->ether_type) == ETHERTYPE_ARP) { in_bytes += 60; in_packets++; } } /*抓包程序*/ void *th_works(void *devname){ char errBuf[PCAP_ERRBUF_SIZE]; /* 定義錯誤信息 */ pcap_t *device = pcap_open_live(devname, 65535, 1, 0, errBuf); /* 準備抓包 */ pcap_loop(device, -1, callPacket, NULL); /* 循環抓包,并將抓取到的數據包作為參數傳給callPacket()函數 */ pcap_close(device); /*結束抓包*/ } void th_sigs(){ for(;;){ int sig; if (sigwait(&mask_sig, &sig) != 0){ printf("wait signal error\n"); exit(1); } hashtable oldht, oldht_out, topht, topht_out; switch (sig){ case SIGTERM: printf("Recv signal term, proc will exit...\n"); exit(0); case SIGINT: printf("Ctrl + C, proc will exit...\n"); exit(0); case SIGALRM: oldht = ht; oldht_out = ht_out; if((ht = (struct node **)calloc(HASHSIZE, sizeof(struct node*))) == NULL) exit(-1); if((ht_out = (struct node **)calloc(HASHSIZEIN, sizeof(struct node*))) == NULL) exit(-1); alarm(300); //printf("in_bytes:%lld in_packets:%lld out_bytes:%lld out_packets:%lld\n", in_bytes, in_packets, out_bytes, out_packets); syslog(LOG_NOTICE, "in_bytes:%llu in_packets:%llu out_bytes:%llu out_packets:%llu", in_bytes, in_packets, out_bytes, out_packets); //內網ip hashtable_descrty(oldht, HASHSIZE, 1); //外網ip排序,取前20 topht_out = hashtable_top(oldht_out, HASHSIZEIN, 20); hashtable_descrty(topht_out, 20, 0); in_bytes=0; in_packets=0; out_bytes=0; out_packets=0; break; default: printf("Recv signum = %i\n", sig); break; } } } /*退出進程*/ void myexit(void){ pthread_mutex_destroy(&hash_lock); pthread_attr_destroy(&attr); } /*將 本進程作為守護進程 */ void Daemon(void){ pid_t mypid1, mypid2; u_short n = 0; openlog("sniffer3",LOG_PID, LOG_LOCAL7); umask(0); if ((mypid1 = fork()) == -1) { syslog(LOG_ERR, "fork: %s", strerror(errno));exit(1); } if (mypid1 > 0) exit(0); setsid(); signal(SIGHUP, SIG_IGN); if ((mypid2 = fork()) == -1) { syslog(LOG_ERR, "fork: %s", strerror(errno)); exit(1); } if (mypid2 > 0) exit(0); chdir("/"); for(; n < 1025; n++) close(n); open("/dev/null", O_RDWR); dup(0); dup(0); } int main(){ /* 將此進程作為守護進程 */ Daemon(); char errBuf[PCAP_ERRBUF_SIZE], *devname; /*定義錯誤信息 ,設備名稱*/ devname = pcap_lookupdev(errBuf); /*自動獲取設備*/ char net[20],mask[20]; /* 定義網路地址 子網掩碼 */ struct in_addr addr; /*結構體 in_addr 用來表示一個32位的IPv4地址*/ int ret,perr; ret = pcap_lookupnet(devname, &netp, &maskp, errBuf); /* 更具網卡 自動查詢網絡地址和子網掩碼*/ addr.s_addr = netp; /*賦值*/ strcpy(net,inet_ntoa(addr)); /*將網絡字節序IP 轉為 點分十進制IP*/ addr.s_addr = maskp; strcpy(mask,inet_ntoa(addr)); /*原理同上,將網絡字節序IP 轉為 點分十進制IP */ pthread_mutex_init(&hash_lock, NULL); pthread_t sigtid,workid,workid2; pthread_attr_init(&attr); pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); atexit(myexit); ht = (struct node **)calloc(HASHSIZE , sizeof(struct node*)); /*動態分配內存,hash表*/ ht_out = (struct node **)calloc(HASHSIZEIN, sizeof(struct node*)); /*動態分配內存,hash表*/ sigfillset(&mask_sig); if ((perr = pthread_sigmask(SIG_BLOCK, &mask_sig, NULL)) != 0 ){ printf("pthread_sigmask error\n"); exit(1); } if ((perr = pthread_create(&sigtid, &attr, (void *)th_sigs, NULL)) != 0){ printf("pthread_th_sigs error\n"); exit(1); } //創建進程 執行th_works(devname)函數 if ((perr = pthread_create(&workid, NULL, th_works, devname)) != 0 ){ printf("pthread_th_works error\n"); exit(1); } alarm(300); int forint=0; for (;;){ forint++; sleep(60); } return 0; }
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。