首页 > 学院 > 操作系统 > 正文

IP流量重放与pcap文件格式解析

2024-06-28 13:26:16
字体:
来源:转载
供稿:网友
ip流量重放与pcap文件格式解析

(作者:燕云 出处:http://www.CUOXin.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 /n",filePathPtr);13     return 1;14   }15   if( is_pcap_file_format(fd,&phdr))16   {17     print_pcap_file_header(&phdr);18   }19   else20   {21     printf("error: file %s format not support /n",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 /n",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("/n");37           }38         }39         printf("/n/n");40       }41       else 42       {43         printf("done/n");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     else22     {23       fprintf(stderr, "error: the file %s is not .pcap format/n",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 it35           hdrPtr=(struct ethernet_ip_hdr *) pkt.data;36           if( hdrPtr->ether_type==0x0008) //filter: ip type: 0x0800 -> little endian 0x000837               {38                 // print packet information39               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 /n",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 /n",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                         ==051                         )52                         printf("resend packet success :) /n");53                     else54                         printf("resend packet fail :( /n");55               }56               else57               {58                 fprintf(stderr,"this packet is not entire,cannot resend :(");59               }60               61               }62           else63            { 64                if(hdrPtr->ether_type==0x0608) //filter: ip type: 0x0806 -> little endian 0x060865                  {printf("arp packet /n");}66                else if(hdrPtr->ether_type==0x3508) //filter: ip type: 0x0835 -> little endian 0x350867                  {printf("rarp packet /n");}68                else69                     {printf("unknown packet type/n");}70            }71           //print packet72           printf("snaplen: %d actual_len: %d packet_counter: %d /n",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("/n");79             }80           }81           printf("/n/n");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/n"); 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/n"); 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 /n",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 /n",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 /n",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 /n",pcapFileHdrPtr->magic);110   printf("version_major: %d /n",pcapFileHdrPtr->version_major);111   printf("version_minor: %d /n",pcapFileHdrPtr->version_minor);112   printf("gmt to local correction: %d /n",pcapFileHdrPtr->thiszone);113   printf("accuracy of timestamps: %d /n",pcapFileHdrPtr->sigfigs);114   printf("max snap length: %d /n",pcapFileHdrPtr->snaplen);115   printf("linktype(1 for ethernet): %d /n",pcapFileHdrPtr->linktype);116 }117 118 int119 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 got129          * to use a memcpy() instead130          */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     else160     {161       fprintf(stderr, "error: the file %s is not .pcap format/n",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 /n",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("/n");178             }179           }180           printf("/n/n");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 padLength198                                )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 structure206          net_t  = libnet_init(LIBNET_LINK_ADV, dev, err_buf);     207          if(net_t == NULL)208          {209                  fprintf(stderr,"libnet_init error:%s/n",err_buf);210                  return 1;211          }212       213       //build the ethernet packet214          p_tag = libnet_build_ethernet(//create ethernet header215                          dst_mac,//dest mac addr216                          src_mac,//source mac addr217                          protoType,//protocol type218                          padPtr,//payload219                          padLength,//payload length220                          net_t,//libnet context221                          0//0 to build a new one222          );223          if(-1 == p_tag)224          {225                  fprintf(stderr,"libnet_build_ethernet error!/n");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!/n");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     else267     {268       fprintf(stderr, "error: the file %s is not .pcap format/n",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 it280           hdrPtr=(struct ethernet_ip_hdr *) pkt.data;281           if( hdrPtr->ether_type==0x0008) //filter: ip type: 0x0800 -> little endian 0x0008282               {283                 // print packet information284               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 /n",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 /n",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                         ==0296                         )297                         printf("resend packet success :) /n");298                     else299                         printf("resend packet fail :( /n");300               }301               else302               {303                 fprintf(stderr,"this packet is not entire,cannot resend :(");304               }305               306               }307           else308            { 309                if(hdrPtr->ether_type==0x0608) //filter: ip type: 0x0806 -> little endian 0x0608310                  {printf("arp packet /n");}311                else if(hdrPtr->ether_type==0x3508) //filter: ip type: 0x0835 -> little endian 0x3508312                  {printf("rarp packet /n");}313                else314                     {printf("unknown packet type/n");}315            }316           //print packet317           printf("snaplen: %d actual_len: %d packet_counter: %d /n",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("/n");324             }325           }326           printf("/n/n");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

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


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表