热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C语言分析数据包程序

#include<pcap.h>#include<stdlib.h>#include<malloc.h>#include<stdio.h&
#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;
}



推荐阅读
  • Linux 中使用 clone 函数来创建线程
    2019独角兽企业重金招聘Python工程师标准Linux上创建线程一般使用的是pthread库实际上libc也给我们提供了创建线程的函数那就是cloneintclone(i ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • c语言\n不换行,c语言printf不换行
    本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 李逍遥寻找仙药的迷阵之旅
    本文讲述了少年李逍遥为了救治婶婶的病情,前往仙灵岛寻找仙药的故事。他需要穿越一个由M×N个方格组成的迷阵,有些方格内有怪物,有些方格是安全的。李逍遥需要避开有怪物的方格,并经过最少的方格,找到仙药。在寻找的过程中,他还会遇到神秘人物。本文提供了一个迷阵样例及李逍遥找到仙药的路线。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 如何在跨函数中使用内存?
    本文介绍了在跨函数中使用内存的方法,包括使用指针变量、动态分配内存和静态分配内存的区别。通过示例代码说明了如何正确地在不同函数中使用内存,并提醒程序员在使用动态分配内存时要手动释放内存,以防止内存泄漏。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • 本文介绍了Codeforces Round #321 (Div. 2)比赛中的问题Kefa and Dishes,通过状压和spfa算法解决了这个问题。给定一个有向图,求在不超过m步的情况下,能获得的最大权值和。点不能重复走。文章详细介绍了问题的题意、解题思路和代码实现。 ... [详细]
  • 深入解析Linux下的I/O多路转接epoll技术
    本文深入解析了Linux下的I/O多路转接epoll技术,介绍了select和poll函数的问题,以及epoll函数的设计和优点。同时讲解了epoll函数的使用方法,包括epoll_create和epoll_ctl两个系统调用。 ... [详细]
  • 不知道你是否还记得之前在进程中的信号处理时,提到过阻塞信号集与未决信号集的概念,如果你已经忘记了,请参考《阻塞信号与未决信号》一文回忆一下 ... [详细]
  • pthread_mutex_lockpthread_mutex_lock(pthread_mutex_t*mutex);intpthread_mutex_trylock(pthre ... [详细]
  • C语言编程gcc怎么生成静态库.a和动态库.so
    这篇文章将为大家详细讲解有关C语言编程gcc怎么生成静态库.a和动态库.so,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章 ... [详细]
  • 主要用的线程函数:1.创建线程:12intpthread_create(pthread_t*thread,constpthread_attr_ ... [详细]
author-avatar
苗Tinal3
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有