zoukankan      html  css  js  c++  java
  • IP流量重放与pcap文件格式解析

     (作者:燕云   出处:http://www.cnblogs.com/SwordTao/ 欢迎转载,但也请保留这段声明,谢谢!)


      君不见 黄河之水 天上来 奔流到海不复回

      君不见 高堂明镜 悲白发 朝如青丝暮成雪

      人生得意须尽欢 莫使金樽空对月

    ——将进酒 

      pcap文件格式,为多数的tcpdump、wireshark等重量级的数据包抓取、分析应用程序所直接支持,所以,为我们的程序中嵌入此类文件的解析与生成功能,很是值得。

      具体信息请看wireshark wiki:http://wiki.wireshark.org/Development/LibpcapFileFormat

      笔者本来想借助开源的tcpreplay与libpcap中的代码片段来快速实现此目的,没想到被两个bug,卡住了几个小时,真是欲速则不达!

      第一处:tcpreplay,如果不是因为宏SEEK_SET恰巧等于0 ...... 不要多说,虽不致命,但祸患无穷。

      第二处:libpcap,关于packet header的结构定义,struct timeval长度为16字节,而实际上这段区域长度为8字节,所以,这个结构体根本不能正常工作。只会更糟!

      无碍,我们继续,最终的pcap文件解析函数原型:

      上图是即为解析的核心函数原型,对照着第一个图一起看会很清晰!下面进行测试 :)

     1 int main()
     2 {
     3   struct pcap_file_header phdr;
     4   char * filePathPtr="log.pcap";
     5   int fd;
     6   int i;
     7   int packet_counter;
     8   struct packet pkt;
     9   
    10   if ( ( fd=open(filePathPtr,O_RDONLY) )==-1 )
    11   {
    12     printf("error: open file error %s 
    ",filePathPtr);
    13     return 1;
    14   }
    15   if( is_pcap_file_format(fd,&phdr))
    16   {
    17     print_pcap_file_header(&phdr);
    18   }
    19   else
    20   {
    21     printf("error: file %s format not support 
    ",filePathPtr);
    22     return 1;
    23   }
    24   packet_counter=0;
    25   while(1)
    26   {
    27       if(pcap_file_get_next_packet(fd,&pkt))
    28       {
    29         packet_counter++;
    30         printf("snaplen: %d actual_len: %d packet_counter: %d 
    ",pkt.len,pkt.actual_len,packet_counter);
    31         for(i=0; i<pkt.len; ++i)
    32         {
    33           printf(" %02x", pkt.data[i]);
    34           if( (i + 1) % 16 == 0 )
    35           {
    36             printf("
    ");
    37           }
    38         }
    39         printf("
    
    ");
    40       }
    41       else 
    42       {
    43         printf("done
    ");
    44           break;
    45       }
    46   }
    47   close(fd);
    48 }
    View Code

      nice ! pcap文件解析已完成,接下来进行流量重放:

      其中,函数 build_send_ethernet_packet  是我们的老朋友了,无需多言,重点是 pcap_ip_repaly  的实现:

     1 int pcap_ip_repaly( char * pcapFilePathPtr, int usecDelayPerPacket, char * devName)
     2 {
     3     struct pcap_file_header phdr;
     4     struct ethernet_ip_hdr * hdrPtr;
     5     int packet_counter;
     6     struct packet pkt;
     7     int fd;
     8     int i;
     9     
    10     
    11     if ( ( fd=open(pcapFilePathPtr,O_RDONLY) )==-1 )
    12     {
    13       fprintf(stderr,"error: open file error %s",pcapFilePathPtr);
    14       return 1;
    15     }
    16     
    17     if( is_pcap_file_format(fd,&phdr) )
    18     {
    19       print_pcap_file_header(&phdr);
    20     }
    21     else
    22     {
    23       fprintf(stderr, "error: the file %s is not .pcap format
    ",pcapFilePathPtr);    
    24       return 1;
    25     }
    26     
    27     packet_counter=0;
    28     while(1)
    29     {
    30         if(pcap_file_get_next_packet(fd,&pkt))
    31         {
    32           usleep(usecDelayPerPacket);
    33           packet_counter++;
    34           //analyze packet and send it
    35           hdrPtr=(struct ethernet_ip_hdr *) pkt.data;
    36           if( hdrPtr->ether_type==0x0008) //filter: ip type: 0x0800 -> little endian 0x0008
    37               {
    38                 // print packet information
    39               printf("ether: %02x:%02x:%02x:%02x:%02x:%02x ->",hdrPtr->ether_shost[0],hdrPtr->ether_shost[1]
    40                 ,hdrPtr->ether_shost[2],hdrPtr->ether_shost[3],hdrPtr->ether_shost[4],hdrPtr->ether_shost[5]);
    41               printf(" %02x:%02x:%02x:%02x:%02x:%02x   ",hdrPtr->ether_dhost[0],hdrPtr->ether_dhost[1]
    42                 ,hdrPtr->ether_dhost[2],hdrPtr->ether_dhost[3],hdrPtr->ether_dhost[4],hdrPtr->ether_dhost[5]);
    43               printf("ip: %d.%d.%d.%d ->",hdrPtr->ip_src[0],hdrPtr->ip_src[1],hdrPtr->ip_src[2],hdrPtr->ip_src[3]);
    44               printf(" %d.%d.%d.%d 
    ",hdrPtr->ip_dst[0],hdrPtr->ip_dst[1],hdrPtr->ip_dst[2],hdrPtr->ip_dst[3]);
    45               if(pkt.len==pkt.actual_len)
    46               {
    47                 printf("whole packet:padPtr is %x,padLength is %d 
    ",pkt.data+14,pkt.len-14);
    48                     if (build_send_ethernet_packet(devName,1, hdrPtr->ether_dhost,
    49                                                hdrPtr->ether_shost,0x0800,pkt.data+14,pkt.len-14)
    50                         ==0
    51                         )
    52                         printf("resend packet success :) 
    ");
    53                     else
    54                         printf("resend packet fail :( 
    ");
    55               }
    56               else
    57               {
    58                 fprintf(stderr,"this packet is not entire,cannot resend :(");
    59               }
    60               
    61               }
    62           else
    63            { 
    64                if(hdrPtr->ether_type==0x0608) //filter: ip type: 0x0806 -> little endian 0x0608
    65                  {printf("arp packet 
    ");}
    66                else if(hdrPtr->ether_type==0x3508) //filter: ip type: 0x0835 -> little endian 0x3508
    67                  {printf("rarp packet 
    ");}
    68                else
    69                     {printf("unknown packet type
    ");}
    70            }
    71           //print packet
    72           printf("snaplen: %d actual_len: %d packet_counter: %d 
    ",pkt.len,pkt.actual_len,packet_counter);
    73           for(i=0; i<pkt.len; ++i)
    74           {
    75             printf(" %02x", pkt.data[i]);
    76             if( (i + 1) % 16 == 0 )
    77             {
    78               printf("
    ");
    79             }
    80           }
    81           printf("
    
    ");
    82         }
    83         else 
    84         {
    85           break;
    86         }
    87     }
    88     
    89     close(fd);
    90     return 0;
    91 
    92 }
    View Code
    int pcap_ip_repaly( char * pcapFilePathPtr, int usecDelayPerPacket, char * devName)
    char * pcapFilePathPtr : 待解析 pcap 文件路径

    int usecDelayPerPacket : 每隔多少us发一个包。。即控制发包速率
    char * devName : 你想让哪个网卡做坏事?写上他的”真名“吧!

      进行测试:

    int main()
    {
      return  pcap_ip_repaly("log.pcap",0,"eth0");
    }

      附录: 

        全部代码

      1 #include <sys/time.h>
      2 #include <sys/types.h>
      3 #include <stdio.h>
      4 #include <fcntl.h>
      5 #include <unistd.h>
      6 #include <sys/types.h>
      7 #include <sys/time.h>
      8 #include <sys/types.h>
      9 #include <stdint.h>
     10 #include <libnet.h>
     11 
     12                                     
     13 #define PCAP_MAGIC  0xa1b2c3d4  /* magic constants for various pcap file types */
     14 #define DEFAULT_MTU 1500        /* Max Transmission Unit of standard ethernet
     15                                                  * don't forget *frames* are MTU + L2 header! */
     16 #define MAXPACKET 16436         /* MTU of Linux loopback */
     17 #define MAX_SNAPLEN 65535       /* tell libpcap to capture the entire packet */
     18 
     19 struct pcap_file_header {
     20         unsigned int  magic;
     21         unsigned short int version_major;
     22         unsigned short int version_minor;
     23         int thiszone;     /* gmt to local correction */
     24         unsigned int sigfigs;    /* accuracy of timestamps */
     25         unsigned int snaplen;    /* max length saved portion of each pkt */
     26         unsigned int linktype;   /* data link type (LINKTYPE_*) */
     27 };
     28 struct pcap_pkthdr {
     29         time_t ts;//struct timeval ts;  /* time stamp */
     30         unsigned int caplen;     /* length of portion present */
     31         unsigned int len;        /* length this packet (off wire) */
     32 };
     33 
     34 struct packet {
     35     unsigned char data[MAXPACKET];       /* pointer to packet contents */
     36     unsigned int len;                    /* length of data (snaplen) */
     37     unsigned int actual_len;             /* actual length of the packet */
     38     time_t ts;          /* timestamp */
     39 };
     40 
     41 struct ethernet_ip_hdr
     42 {
     43     uint8_t  ether_dhost[6];/* destination ethernet address */
     44     uint8_t  ether_shost[6];/* source ethernet address */
     45     uint16_t ether_type;    /* protocol */
     46     uint8_t  ip_ver_hdrlen; 
     47     uint8_t  ip_tos;  
     48     uint16_t ip_total_len;         /* total length */
     49     uint16_t ip_id;          /* identification */
     50     uint16_t ip_frag;
     51     uint8_t  ip_ttl;          /* time to live */
     52     uint8_t  ip_proto;            /* protocol */
     53     uint16_t ip_hdrCRC;         /* checksum */
     54     uint8_t  ip_src[4];
     55     uint8_t  ip_dst[4];
     56 };
     57 
     58 /* return flag if this is a pcap file */
     59 /*
     60 retCode
     61 0 fail
     62 1 success
     63 */
     64 int is_pcap_file_format(int fd,struct pcap_file_header * pcapFileHdrPtr)
     65 {
     66 
     67     if (lseek(fd, 0, SEEK_SET) != 0) 
     68     {
     69         fprintf(stderr,"Unable to seek to start of file
    ");
     70         return 0;
     71     }
     72 
     73     if (read(fd, (void *) pcapFileHdrPtr, sizeof( struct pcap_file_header )) != sizeof( struct pcap_file_header ))
     74     {
     75         fprintf(stderr,"Unable to read whole pcap file hdr of file
    ");
     76         return 0;
     77        }
     78     
     79     switch (pcapFileHdrPtr->magic) 
     80     {
     81       case PCAP_MAGIC:
     82         break;    
     83       default:
     84           {
     85         fprintf(stderr,"Unable to resolve the magic number %d 
    ",pcapFileHdrPtr->magic);
     86         return 0;
     87           }
     88     }
     89 
     90     /* version, snaplen, & linktype magic */
     91     if (pcapFileHdrPtr->version_major != 2)
     92         {
     93         fprintf(stderr,"Unable to resolve the version_major number %d 
    ",pcapFileHdrPtr->version_major);
     94         return 0;
     95         }
     96 
     97     
     98     if (pcapFileHdrPtr->linktype != 1)
     99             {
    100             fprintf(stderr,"Only could resolve the ethernet linktype packet, not %d 
    ",pcapFileHdrPtr->linktype);
    101             return 0;
    102             }
    103     
    104     return 1;
    105 }
    106 
    107 void print_pcap_file_header(struct pcap_file_header * pcapFileHdrPtr)
    108 {
    109   printf("magic number: %X 
    ",pcapFileHdrPtr->magic);
    110   printf("version_major: %d 
    ",pcapFileHdrPtr->version_major);
    111   printf("version_minor: %d 
    ",pcapFileHdrPtr->version_minor);
    112   printf("gmt to local correction: %d 
    ",pcapFileHdrPtr->thiszone);
    113   printf("accuracy of timestamps: %d 
    ",pcapFileHdrPtr->sigfigs);
    114   printf("max snap length: %d 
    ",pcapFileHdrPtr->snaplen);
    115   printf("linktype(1 for ethernet): %d 
    ",pcapFileHdrPtr->linktype);
    116 }
    117 
    118 int
    119 pcap_file_get_next_packet(int fd, struct packet *pkt)
    120 {
    121     struct pcap_pkthdr p1, *p;
    122    
    123     if (read(fd, &p1, sizeof(p1)) != sizeof(p1))
    124         return 0;
    125     p = &p1;
    126 
    127     pkt->len = p->caplen;
    128         /* stupid OpenBSD, won't let me just assign things, so I've got
    129          * to use a memcpy() instead
    130          */
    131     memcpy(&(pkt->ts), &(p->ts), sizeof(time_t));
    132     pkt->actual_len = p->len;
    133 
    134     if (read(fd, &pkt->data, pkt->len) != pkt->len)
    135        return 0;
    136 
    137     return pkt->len;
    138 }
    139 
    140 int pcap_file_print( char * pcapFilePathPtr )
    141 {
    142     struct pcap_file_header phdr;
    143     int packet_counter;
    144     struct packet pkt;
    145     int fd;
    146     int i;
    147     
    148     
    149     if ( ( fd=open(pcapFilePathPtr,O_RDONLY) )==-1 )
    150     {
    151       fprintf(stderr,"error: open file error %s",pcapFilePathPtr);
    152       return 1;
    153     }
    154     
    155     if( is_pcap_file_format(fd,&phdr) )
    156     {
    157       print_pcap_file_header(&phdr);
    158     }
    159     else
    160     {
    161       fprintf(stderr, "error: the file %s is not .pcap format
    ",pcapFilePathPtr);    
    162       return 1;
    163     }
    164     
    165     packet_counter=0;
    166     while(1)
    167     {
    168         if(pcap_file_get_next_packet(fd,&pkt))
    169         {
    170           packet_counter++;
    171           printf("snaplen: %d actual_len: %d packet_counter: %d 
    ",pkt.len,pkt.actual_len,packet_counter);
    172           for(i=0; i<pkt.len; ++i)
    173           {
    174             printf(" %02x", pkt.data[i]);
    175             if( (i + 1) % 16 == 0 )
    176             {
    177               printf("
    ");
    178             }
    179           }
    180           printf("
    
    ");
    181         }
    182         else 
    183         {
    184           break;
    185         }
    186     }
    187     
    188     close(fd);
    189     return 0;
    190 
    191 }
    192 
    193 
    194 
    195 int build_send_ethernet_packet(const char * dev,const unsigned int sendTimes,
    196                    const unsigned char * dst_mac,const unsigned char * src_mac,
    197                                const uint16_t protoType,const unsigned char * padPtr,const unsigned int padLength
    198                                )
    199 {
    200          libnet_t *net_t = NULL; 
    201          char err_buf[LIBNET_ERRBUF_SIZE];
    202          libnet_ptag_t p_tag; 
    203          unsigned int i=0;
    204          
    205      //init the libnet context structure
    206          net_t  = libnet_init(LIBNET_LINK_ADV, dev, err_buf);     
    207          if(net_t == NULL)
    208          {
    209                  fprintf(stderr,"libnet_init error:%s
    ",err_buf);
    210                  return 1;
    211          }
    212       
    213       //build the ethernet packet
    214          p_tag = libnet_build_ethernet(//create ethernet header
    215                          dst_mac,//dest mac addr
    216                          src_mac,//source mac addr
    217                          protoType,//protocol type
    218                          padPtr,//payload
    219                          padLength,//payload length
    220                          net_t,//libnet context
    221                          0//0 to build a new one
    222          );
    223          if(-1 == p_tag)
    224          {
    225                  fprintf(stderr,"libnet_build_ethernet error!
    ");
    226                  fprintf(stderr,"BuildAndSendEthernetPacket: %s",net_t->err_buf);
    227                  goto FAIL;
    228          }
    229          
    230          for(i=0;i<sendTimes;i++)
    231            if(-1 == libnet_write(net_t))
    232            {
    233                  fprintf(stderr,"B libnet_write error!
    ");
    234                  fprintf(stderr,"BuildAndSendEthernetPacket: %s",net_t->err_buf);
    235                  goto FAIL;
    236            }
    237          
    238          libnet_destroy(net_t);
    239          return 0;
    240      FAIL:        
    241          libnet_destroy(net_t);
    242          return 1;
    243 }
    244 
    245 
    246 int pcap_ip_repaly( char * pcapFilePathPtr, int usecDelayPerPacket, char * devName)
    247 {
    248     struct pcap_file_header phdr;
    249     struct ethernet_ip_hdr * hdrPtr;
    250     int packet_counter;
    251     struct packet pkt;
    252     int fd;
    253     int i;
    254     
    255     
    256     if ( ( fd=open(pcapFilePathPtr,O_RDONLY) )==-1 )
    257     {
    258       fprintf(stderr,"error: open file error %s",pcapFilePathPtr);
    259       return 1;
    260     }
    261     
    262     if( is_pcap_file_format(fd,&phdr) )
    263     {
    264       print_pcap_file_header(&phdr);
    265     }
    266     else
    267     {
    268       fprintf(stderr, "error: the file %s is not .pcap format
    ",pcapFilePathPtr);    
    269       return 1;
    270     }
    271     
    272     packet_counter=0;
    273     while(1)
    274     {
    275         if(pcap_file_get_next_packet(fd,&pkt))
    276         {
    277           usleep(usecDelayPerPacket);
    278           packet_counter++;
    279           //analyze packet and send it
    280           hdrPtr=(struct ethernet_ip_hdr *) pkt.data;
    281           if( hdrPtr->ether_type==0x0008) //filter: ip type: 0x0800 -> little endian 0x0008
    282               {
    283                 // print packet information
    284               printf("ether: %02x:%02x:%02x:%02x:%02x:%02x ->",hdrPtr->ether_shost[0],hdrPtr->ether_shost[1]
    285                 ,hdrPtr->ether_shost[2],hdrPtr->ether_shost[3],hdrPtr->ether_shost[4],hdrPtr->ether_shost[5]);
    286               printf(" %02x:%02x:%02x:%02x:%02x:%02x   ",hdrPtr->ether_dhost[0],hdrPtr->ether_dhost[1]
    287                 ,hdrPtr->ether_dhost[2],hdrPtr->ether_dhost[3],hdrPtr->ether_dhost[4],hdrPtr->ether_dhost[5]);
    288               printf("ip: %d.%d.%d.%d ->",hdrPtr->ip_src[0],hdrPtr->ip_src[1],hdrPtr->ip_src[2],hdrPtr->ip_src[3]);
    289               printf(" %d.%d.%d.%d 
    ",hdrPtr->ip_dst[0],hdrPtr->ip_dst[1],hdrPtr->ip_dst[2],hdrPtr->ip_dst[3]);
    290               if(pkt.len==pkt.actual_len)
    291               {
    292                 printf("whole packet:padPtr is %x,padLength is %d 
    ",pkt.data+14,pkt.len-14);
    293                     if (build_send_ethernet_packet(devName,1, hdrPtr->ether_dhost,
    294                                                hdrPtr->ether_shost,0x0800,pkt.data+14,pkt.len-14)
    295                         ==0
    296                         )
    297                         printf("resend packet success :) 
    ");
    298                     else
    299                         printf("resend packet fail :( 
    ");
    300               }
    301               else
    302               {
    303                 fprintf(stderr,"this packet is not entire,cannot resend :(");
    304               }
    305               
    306               }
    307           else
    308            { 
    309                if(hdrPtr->ether_type==0x0608) //filter: ip type: 0x0806 -> little endian 0x0608
    310                  {printf("arp packet 
    ");}
    311                else if(hdrPtr->ether_type==0x3508) //filter: ip type: 0x0835 -> little endian 0x3508
    312                  {printf("rarp packet 
    ");}
    313                else
    314                     {printf("unknown packet type
    ");}
    315            }
    316           //print packet
    317           printf("snaplen: %d actual_len: %d packet_counter: %d 
    ",pkt.len,pkt.actual_len,packet_counter);
    318           for(i=0; i<pkt.len; ++i)
    319           {
    320             printf(" %02x", pkt.data[i]);
    321             if( (i + 1) % 16 == 0 )
    322             {
    323               printf("
    ");
    324             }
    325           }
    326           printf("
    
    ");
    327         }
    328         else 
    329         {
    330           break;
    331         }
    332     }
    333     
    334     close(fd);
    335     return 0;
    336 
    337 }
    338 
    339 int main()
    340 {
    341   return  pcap_ip_repaly("/home/yun/Codes/wp.pcap",0,"eth0");
    342 }
    View Code

      如有问题或者建议,欢迎留言讨论 :)      

  • 相关阅读:
    大白痴学习webmagic
    selenium docs
    centos6.5单用户模式拯救系统
    使用Squid做代理服务器,Squid单网卡透明代理配置详解(转)
    Redundant Call to Object.ToString()
    Specify a culture in string conversion explicitly
    Benefits of Cold Showers: 7 Reasons Why Taking Cool Showers Is Good For Your Health
    Why Creating a Meaningful Morning Routine Will Make You More Successful
    git图示所有分支的历史
    Rewriting History with Git Rebase
  • 原文地址:https://www.cnblogs.com/SwordTao/p/3740115.html
Copyright © 2011-2022 走看看