C语言分析数据包程序

发布时间:2020-08-01 17:20:28 作者:hanchengen
来源:网络 阅读:1032
#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;
}


推荐阅读:
  1. LVS-DR数据包流向分析介绍
  2. LTM系统并联接入方式数据包交互分析

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

ip tcp

上一篇:hadoop2.7环境的编译安装

下一篇:Stackoverflow热门问题

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》