(作者:燕云 出处: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
如有问题或者建议,欢迎留言讨论:)
新闻热点
疑难解答