#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进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。