#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; /* 報數(shù) */
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; /* 進包數(shù) */
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; /* 字節(jié)數(shù) */
unsigned long long packets; /* 數(shù)據包數(shù) */
unsigned long long fbytes; /* 進流量 */
unsigned long long fpacket; /* 進包數(shù) */
unsigned long long tcp; /* 是否為tcp協(xié)議 */
unsigned long long udp; /* 是否為udp協(xié)議 */
unsigned long long icmp; /* 是否為icmp協(xié)議 */
unsigned long long other; /* 其他 */
struct node *next; /* 下一個節(jié)點指針 */
}htnode;
typedef htnode **hashtable;
unsigned long long in_bytes; //進網流量
unsigned long long in_packets; //進網包數(shù)
unsigned long long out_bytes; //出網流量
unsigned long long out_packets=0; //出網包數(shù)
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地址由點分十進制 轉為 網絡字節(jié)序格式
if(connect(sock, (const struct sockaddr *)&svraddr, sizeof(svraddr)) < 0){ close(sock);return; } //啟動socket,連接服務端,準備推送數(shù)據
memset(&vs[0], 0, sizeof(xvalue));
//外網ip記錄的數(shù)據
if(in_out==0){
vs[0].v.other = 0;
vs[0].fbytes = out_bytes;
vs[0].fpacket = out_packets;
//內網ip記錄的數(shù)據
}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); //將數(shù)據傳給服務端
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;
}
/*數(shù)據包處理程序*/
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 檢測數(shù)據包是否為IP包
if(ntohs(ethernet->ether_type)==ETHERTYPE_IP) {
ip=(struct iphdr*)(content+14); /*content前14byte 為以太網包頭,將指針移動14byte之后為IP包頭開始位置 ,此處 從content中提取IP包頭數(shù)據 */
int tot_len=ntohs(ip->tot_len) + 18; /*計算數(shù)據包總長度 ip->tot_len代表 ip首部記錄的ip包數(shù)據包大小, 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的進流量、進包數(shù)、出流量、出包數(shù)
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;
}
//出網包 如果數(shù)據包是從服務端流向客戶端
if ( ((ip->saddr & maskp)==netp) && ((ip->daddr & maskp)!=netp) ){
//內網ip 記錄此內網Ip的出流量、出包數(shù)
hv->ip = ip->saddr; //數(shù)據包中的源IP地址 此處為內網IP地址
pthread_mutex_lock(&hash_lock);
hashtable_insert(ht, HASHSIZE, hv); //將hv添加到hash表
pthread_mutex_unlock(&hash_lock);
//外網ip 記錄服務端返回給此外網ip的返回流量、返回包數(shù)
hv_out->ip = ip->daddr; //數(shù)據包中的目標IP地址 此處為外網ip地址
pthread_mutex_lock(&hash_lock);
hashtable_insert(ht_out, HASHSIZEIN, hv_out); //將hv_out添加到hash表
out_bytes += tot_len; //出網流量增加
out_packets++; //出網報數(shù)增加
pthread_mutex_unlock(&hash_lock);
//進網包 如果數(shù)據包是從客戶端流向服務端
}else if( ((ip->daddr & maskp)==netp) && ((ip->saddr & maskp)!=netp) ){
//內網ip 記錄此內網ip的進流量、進包數(shù)
hv->fbytes = tot_len;
hv->fpacket = 1;
hv->ip = ip->daddr;
//數(shù)據包中的目標id 此處為內網IP地址
pthread_mutex_lock(&hash_lock);
hashtable_insert(ht, HASHSIZE, hv);
//將數(shù)據插入ht shah表
pthread_mutex_unlock(&hash_lock);
//外網ip 記錄此外網ip的請求流量,請求包數(shù)
hv_out->fbytes = tot_len;
hv_out->fpacket = 1;
hv_out->ip = ip->saddr;
//數(shù)據包中的源IP, 此處為外網IP
pthread_mutex_lock(&hash_lock);
hashtable_insert(ht_out, HASHSIZEIN, hv_out);
//將數(shù)據插入ht_out
in_bytes += tot_len;
//進網流量增加
in_packets++;
//進網包數(shù)增加
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++;
//將內網數(shù)據包當做進入流量
//外網包
}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); /* 循環(huán)抓包,并將抓取到的數(shù)據包作為參數(shù)傳給callPacket()函數(shù) */
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)); /*將網絡字節(jié)序IP 轉為 點分十進制IP*/
addr.s_addr = maskp;
strcpy(mask,inet_ntoa(addr)); /*原理同上,將網絡字節(jié)序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*)); /*動態(tài)分配內存,hash表*/
ht_out = (struct node **)calloc(HASHSIZEIN, sizeof(struct node*)); /*動態(tài)分配內存,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);
}
//創(chuàng)建進程 執(zhí)行th_works(devname)函數(shù)
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;
}
名稱欄目:C語言分析數(shù)據包程序
分享地址:http://www.chinadenli.net/article18/geicgp.html
成都網站建設公司_創(chuàng)新互聯(lián),為您提供網站排名、Google、微信公眾號、虛擬主機、移動網站建設、外貿建站
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)