C语言分析数据包程序

#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;
}
时间: 2024-10-10 05:20:31

C语言分析数据包程序的相关文章

tcpdump教程 - 从命令行抓取和分析数据包

前言 在介绍和使用tcpdump之前,请确保您已经掌握或者了解如下几个关键概念,否则后面的内容让你有点痛苦. 能够在Linux命令行下工作 理解OSI七层网络协议的概念 熟悉各层的协议头部,重点是IP/TCP/UDP 交换机和路由器对应于OSI的协议层 另外还需要注意的是: tcpdump是基于Unix系统的命令行式的数据包嗅探工具.如果要使用tcpdump抓取其他主机MAC地址的数据包,必须开启网卡混杂模式,所谓混杂模式,用最简单的语言就是让网卡抓取任何经过它的数据包,不管这个数据包是不是发给

Wireshark抓包分析---分析数据包

Wireshark数据抓包教程之认识捕获分析数据包 认识Wireshark捕获数据包 当我们对Wireshark主窗口各部分作用了解了,学会捕获数据了,接下来就该去认识这些捕获的数据包了.Wireshark将从网络中捕获到的二进制数据按照不同的协议包结构规范,显示在Packet Details面板中.为了帮助用户能够清楚的分析数据,本节将介绍识别数据包的方法. 在Wireshark中关于数据包的叫法有三个术语,分别是帧.包.段.下面通过分析一个数据包,来介绍这三个术语.在Wireshark中捕获

【毕业设计日记-4月】pcap编程之分析数据包

昨天看到了最重要的一部分,分析数据包. 这个分析UDP的程序基本上前面都能看得懂,主要还是对报文的分析这一部分. 在blog里找到的图,对于这个过程,反过来也就是:应用层数据,封装成UDP或者TCP报文,再加上IP首部,然后再加上以太网首部,就成为了可以在链路层传播的数据帧. 以太网驱动程序首先根据以太网首部中的"上层协议"字段确定该数据帧的有效载荷(payload,指除去协议首部之外实际传输的数据)是IP.ARP 还是RARP 协议的数据报,然后交给相应的协议处理.假如是IP 数据报

Wireshark数据抓包教程之认识捕获分析数据包

Wireshark数据抓包教程之认识捕获分析数据包 认识Wireshark捕获数据包 当我们对Wireshark主窗口各部分作用了解了,学会捕获数据了,接下来就该去认识这些捕获的数据包了.Wireshark将从网络中捕获到的二进制数据按照不同的协议包结构规范,显示在Packet Details面板中.为了帮助用户能够清楚的分析数据,本节将介绍识别数据包的方法. 在Wireshark中关于数据包的叫法有三个术语,分别是帧.包.段.下面通过分析一个数据包,来介绍这三个术语.在Wireshark中捕获

使用winpcap多线程抓包,以及简单的分析数据包

刚开始使用winpcap数据包的时候,我在抓包的时候使用了 pcap_loop(adhandle, 0, packet_handler, NULL); 这个回调函数进行抓包.同时在回调函数中分析IP地址后加入了新的线程进行分析数据包. pthread_create(&thread[threadnum], NULL,thread, &thread_ins); 我的新线程函数大致是这样的: void* thread(void *) { /*省略...*/ while((res = pcap_n

分析数据包(Microsoft Visual Studio 2010)

// Fenxi1.cpp : 定义控制台应用程序的入口点.//代码如下:#include "stdafx.h"#include "pcap.h"#include "bittypes.h"#pragma comment(lib,"ws2_32.lib")typedef struct ip_address{    u_char byte1;    u_char byte2;    u_char byte3;    u_char

eNSP中的路由器通过远程连接,并分析数据包

1)先在华为模拟器上新建一个拓扑:2)分别在AR4和AR3上的GE 0/0/2上配置IP地址,并标识出对应的IP地址.配置IP的命令如下:system-view //进入系统视图interface GigabitEthernet 0/0/2 //进入端口GE 0/0/2undo shutdown //开启端口ip address 192.168.1.1 255.255.255.0 //配置IP按上述命令,将AR3上的IP配置为192.168.1.23)在AR3上设置一个远程访问密码:huawei

#WEB安全基础 : HTTP协议 | 0x7 学会使用wireshark分析数据包

wireshark是开源,免费,跨平台的抓包分析工具 我们可以通过wireshark学习HTTP报文和进行抓包分析,在CTF中的流量分析需要用到抓包 1.下载和安装 这是wireshark的官网 https://www.wireshark.org/download.html windows下不必多说,大家肯定会傻瓜式安装,kali linux 系统下自带wireshark 2.wireshark介绍 本地连接是自己的物理机,上面的两个是虚拟机,因为没有开启所以没有数据流 如你所见这个版本的wir

利用libpcap分析网络上的数据包(入门级)

本文可任意转载,但请保留作者及出处作者:rainfish出处:http://blog.csdn.net/bat603/经过几天的突击,终于明白了怎样在局域网内抓包,这可是我多年来的梦想.首先说说我的学习过程,一开始从网上搜索了关于sniffer大量资料,大致学会了,可是仔细分析结果发现,都是本机上的数据包,而不是整个局域网的.于是又查资料,在 linuxsir上有高人指点,说,现在局域网内都是交换机联接,而不是以前的Hub所以,如果要抓整个局域网的数据包,必须用libpcap,于是又查了许多关于