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 \n",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 \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     else
22     {
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 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 \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                         ==0
51                         )
52                         printf("resend packet success :) \n");
53                     else
54                         printf("resend packet fail :( \n");
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 \n");}
66                else if(hdrPtr->ether_type==0x3508) //filter: ip type: 0x0835 -> little endian 0x3508
67                  {printf("rarp packet \n");}
68                else
69                     {printf("unknown packet type\n");}
70            }
71           //print packet
72           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 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\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 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\n",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!\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     else
267     {
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 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 \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                         ==0
296                         )
297                         printf("resend packet success :) \n");
298                     else
299                         printf("resend packet fail :( \n");
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 \n");}
311                else if(hdrPtr->ether_type==0x3508) //filter: ip type: 0x0835 -> little endian 0x3508
312                  {printf("rarp packet \n");}
313                else
314                     {printf("unknown packet type\n");}
315            }
316           //print packet
317           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

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

 

posted @ 2014-05-20 23:25  燕云  阅读(3756)  评论(0编辑  收藏  举报