#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/**/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;
}
文章名称:C语言分析数据包程序
标题路径:
http://chengdu.cdxwcx.cn/article/geicgp.html