(作者:燕云   出处: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文件解析函数原型:

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

 int main()
{
struct pcap_file_header phdr;
char * filePathPtr="log.pcap";
int fd;
int i;
int packet_counter;
struct packet pkt; if ( ( fd=open(filePathPtr,O_RDONLY) )==- )
{
printf("error: open file error %s \n",filePathPtr);
return ;
}
if( is_pcap_file_format(fd,&phdr))
{
print_pcap_file_header(&phdr);
}
else
{
printf("error: file %s format not support \n",filePathPtr);
return ;
}
packet_counter=;
while()
{
if(pcap_file_get_next_packet(fd,&pkt))
{
packet_counter++;
printf("snaplen: %d actual_len: %d packet_counter: %d \n",pkt.len,pkt.actual_len,packet_counter);
for(i=; i<pkt.len; ++i)
{
printf(" %02x", pkt.data[i]);
if( (i + ) % == )
{
printf("\n");
}
}
printf("\n\n");
}
else
{
printf("done\n");
break;
}
}
close(fd);
}

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

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

 int pcap_ip_repaly( char * pcapFilePathPtr, int usecDelayPerPacket, char * devName)
{
struct pcap_file_header phdr;
struct ethernet_ip_hdr * hdrPtr;
int packet_counter;
struct packet pkt;
int fd;
int i; if ( ( fd=open(pcapFilePathPtr,O_RDONLY) )==- )
{
fprintf(stderr,"error: open file error %s",pcapFilePathPtr);
return ;
} if( is_pcap_file_format(fd,&phdr) )
{
print_pcap_file_header(&phdr);
}
else
{
fprintf(stderr, "error: the file %s is not .pcap format\n",pcapFilePathPtr);
return ;
} packet_counter=;
while()
{
if(pcap_file_get_next_packet(fd,&pkt))
{
usleep(usecDelayPerPacket);
packet_counter++;
//analyze packet and send it
hdrPtr=(struct ethernet_ip_hdr *) pkt.data;
if( hdrPtr->ether_type==0x0008) //filter: ip type: 0x0800 -> little endian 0x0008
{
// print packet information
printf("ether: %02x:%02x:%02x:%02x:%02x:%02x ->",hdrPtr->ether_shost[],hdrPtr->ether_shost[]
,hdrPtr->ether_shost[],hdrPtr->ether_shost[],hdrPtr->ether_shost[],hdrPtr->ether_shost[]);
printf(" %02x:%02x:%02x:%02x:%02x:%02x ",hdrPtr->ether_dhost[],hdrPtr->ether_dhost[]
,hdrPtr->ether_dhost[],hdrPtr->ether_dhost[],hdrPtr->ether_dhost[],hdrPtr->ether_dhost[]);
printf("ip: %d.%d.%d.%d ->",hdrPtr->ip_src[],hdrPtr->ip_src[],hdrPtr->ip_src[],hdrPtr->ip_src[]);
printf(" %d.%d.%d.%d \n",hdrPtr->ip_dst[],hdrPtr->ip_dst[],hdrPtr->ip_dst[],hdrPtr->ip_dst[]);
if(pkt.len==pkt.actual_len)
{
printf("whole packet:padPtr is %x,padLength is %d \n",pkt.data+,pkt.len-);
if (build_send_ethernet_packet(devName,, hdrPtr->ether_dhost,
hdrPtr->ether_shost,0x0800,pkt.data+,pkt.len-)
==
)
printf("resend packet success :) \n");
else
printf("resend packet fail :( \n");
}
else
{
fprintf(stderr,"this packet is not entire,cannot resend :(");
} }
else
{
if(hdrPtr->ether_type==0x0608) //filter: ip type: 0x0806 -> little endian 0x0608
{printf("arp packet \n");}
else if(hdrPtr->ether_type==0x3508) //filter: ip type: 0x0835 -> little endian 0x3508
{printf("rarp packet \n");}
else
{printf("unknown packet type\n");}
}
//print packet
printf("snaplen: %d actual_len: %d packet_counter: %d \n",pkt.len,pkt.actual_len,packet_counter);
for(i=; i<pkt.len; ++i)
{
printf(" %02x", pkt.data[i]);
if( (i + ) % == )
{
printf("\n");
}
}
printf("\n\n");
}
else
{
break;
}
} close(fd);
return ; }
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",,"eth0");
}

附录:

全部代码

 #include <sys/time.h>
#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/types.h>
#include <stdint.h>
#include <libnet.h> #define PCAP_MAGIC 0xa1b2c3d4 /* magic constants for various pcap file types */
#define DEFAULT_MTU 1500 /* Max Transmission Unit of standard ethernet
* don't forget *frames* are MTU + L2 header! */
#define MAXPACKET 16436 /* MTU of Linux loopback */
#define MAX_SNAPLEN 65535 /* tell libpcap to capture the entire packet */ struct pcap_file_header {
unsigned int magic;
unsigned short int version_major;
unsigned short int version_minor;
int thiszone; /* gmt to local correction */
unsigned int sigfigs; /* accuracy of timestamps */
unsigned int snaplen; /* max length saved portion of each pkt */
unsigned int linktype; /* data link type (LINKTYPE_*) */
};
struct pcap_pkthdr {
time_t ts;//struct timeval ts; /* time stamp */
unsigned int caplen; /* length of portion present */
unsigned int len; /* length this packet (off wire) */
}; struct packet {
unsigned char data[MAXPACKET]; /* pointer to packet contents */
unsigned int len; /* length of data (snaplen) */
unsigned int actual_len; /* actual length of the packet */
time_t ts; /* timestamp */
}; struct ethernet_ip_hdr
{
uint8_t ether_dhost[];/* destination ethernet address */
uint8_t ether_shost[];/* source ethernet address */
uint16_t ether_type; /* protocol */
uint8_t ip_ver_hdrlen;
uint8_t ip_tos;
uint16_t ip_total_len; /* total length */
uint16_t ip_id; /* identification */
uint16_t ip_frag;
uint8_t ip_ttl; /* time to live */
uint8_t ip_proto; /* protocol */
uint16_t ip_hdrCRC; /* checksum */
uint8_t ip_src[];
uint8_t ip_dst[];
}; /* return flag if this is a pcap file */
/*
retCode
0 fail
1 success
*/
int is_pcap_file_format(int fd,struct pcap_file_header * pcapFileHdrPtr)
{ if (lseek(fd, , SEEK_SET) != )
{
fprintf(stderr,"Unable to seek to start of file\n");
return ;
} if (read(fd, (void *) pcapFileHdrPtr, sizeof( struct pcap_file_header )) != sizeof( struct pcap_file_header ))
{
fprintf(stderr,"Unable to read whole pcap file hdr of file\n");
return ;
} switch (pcapFileHdrPtr->magic)
{
case PCAP_MAGIC:
break;
default:
{
fprintf(stderr,"Unable to resolve the magic number %d \n",pcapFileHdrPtr->magic);
return ;
}
} /* version, snaplen, & linktype magic */
if (pcapFileHdrPtr->version_major != )
{
fprintf(stderr,"Unable to resolve the version_major number %d \n",pcapFileHdrPtr->version_major);
return ;
} if (pcapFileHdrPtr->linktype != )
{
fprintf(stderr,"Only could resolve the ethernet linktype packet, not %d \n",pcapFileHdrPtr->linktype);
return ;
} return ;
} void print_pcap_file_header(struct pcap_file_header * pcapFileHdrPtr)
{
printf("magic number: %X \n",pcapFileHdrPtr->magic);
printf("version_major: %d \n",pcapFileHdrPtr->version_major);
printf("version_minor: %d \n",pcapFileHdrPtr->version_minor);
printf("gmt to local correction: %d \n",pcapFileHdrPtr->thiszone);
printf("accuracy of timestamps: %d \n",pcapFileHdrPtr->sigfigs);
printf("max snap length: %d \n",pcapFileHdrPtr->snaplen);
printf("linktype(1 for ethernet): %d \n",pcapFileHdrPtr->linktype);
} int
pcap_file_get_next_packet(int fd, struct packet *pkt)
{
struct pcap_pkthdr p1, *p; if (read(fd, &p1, sizeof(p1)) != sizeof(p1))
return ;
p = &p1; pkt->len = p->caplen;
/* stupid OpenBSD, won't let me just assign things, so I've got
* to use a memcpy() instead
*/
memcpy(&(pkt->ts), &(p->ts), sizeof(time_t));
pkt->actual_len = p->len; if (read(fd, &pkt->data, pkt->len) != pkt->len)
return ; return pkt->len;
} int pcap_file_print( char * pcapFilePathPtr )
{
struct pcap_file_header phdr;
int packet_counter;
struct packet pkt;
int fd;
int i; if ( ( fd=open(pcapFilePathPtr,O_RDONLY) )==- )
{
fprintf(stderr,"error: open file error %s",pcapFilePathPtr);
return ;
} if( is_pcap_file_format(fd,&phdr) )
{
print_pcap_file_header(&phdr);
}
else
{
fprintf(stderr, "error: the file %s is not .pcap format\n",pcapFilePathPtr);
return ;
} packet_counter=;
while()
{
if(pcap_file_get_next_packet(fd,&pkt))
{
packet_counter++;
printf("snaplen: %d actual_len: %d packet_counter: %d \n",pkt.len,pkt.actual_len,packet_counter);
for(i=; i<pkt.len; ++i)
{
printf(" %02x", pkt.data[i]);
if( (i + ) % == )
{
printf("\n");
}
}
printf("\n\n");
}
else
{
break;
}
} close(fd);
return ; } int build_send_ethernet_packet(const char * dev,const unsigned int sendTimes,
const unsigned char * dst_mac,const unsigned char * src_mac,
const uint16_t protoType,const unsigned char * padPtr,const unsigned int padLength
)
{
libnet_t *net_t = NULL;
char err_buf[LIBNET_ERRBUF_SIZE];
libnet_ptag_t p_tag;
unsigned int i=; //init the libnet context structure
net_t = libnet_init(LIBNET_LINK_ADV, dev, err_buf);
if(net_t == NULL)
{
fprintf(stderr,"libnet_init error:%s\n",err_buf);
return ;
} //build the ethernet packet
p_tag = libnet_build_ethernet(//create ethernet header
dst_mac,//dest mac addr
src_mac,//source mac addr
protoType,//protocol type
padPtr,//payload
padLength,//payload length
net_t,//libnet context
//0 to build a new one
);
if(- == p_tag)
{
fprintf(stderr,"libnet_build_ethernet error!\n");
fprintf(stderr,"BuildAndSendEthernetPacket: %s",net_t->err_buf);
goto FAIL;
} for(i=;i<sendTimes;i++)
if(- == libnet_write(net_t))
{
fprintf(stderr,"B libnet_write error!\n");
fprintf(stderr,"BuildAndSendEthernetPacket: %s",net_t->err_buf);
goto FAIL;
} libnet_destroy(net_t);
return ;
FAIL:
libnet_destroy(net_t);
return ;
} int pcap_ip_repaly( char * pcapFilePathPtr, int usecDelayPerPacket, char * devName)
{
struct pcap_file_header phdr;
struct ethernet_ip_hdr * hdrPtr;
int packet_counter;
struct packet pkt;
int fd;
int i; if ( ( fd=open(pcapFilePathPtr,O_RDONLY) )==- )
{
fprintf(stderr,"error: open file error %s",pcapFilePathPtr);
return ;
} if( is_pcap_file_format(fd,&phdr) )
{
print_pcap_file_header(&phdr);
}
else
{
fprintf(stderr, "error: the file %s is not .pcap format\n",pcapFilePathPtr);
return ;
} packet_counter=;
while()
{
if(pcap_file_get_next_packet(fd,&pkt))
{
usleep(usecDelayPerPacket);
packet_counter++;
//analyze packet and send it
hdrPtr=(struct ethernet_ip_hdr *) pkt.data;
if( hdrPtr->ether_type==0x0008) //filter: ip type: 0x0800 -> little endian 0x0008
{
// print packet information
printf("ether: %02x:%02x:%02x:%02x:%02x:%02x ->",hdrPtr->ether_shost[],hdrPtr->ether_shost[]
,hdrPtr->ether_shost[],hdrPtr->ether_shost[],hdrPtr->ether_shost[],hdrPtr->ether_shost[]);
printf(" %02x:%02x:%02x:%02x:%02x:%02x ",hdrPtr->ether_dhost[],hdrPtr->ether_dhost[]
,hdrPtr->ether_dhost[],hdrPtr->ether_dhost[],hdrPtr->ether_dhost[],hdrPtr->ether_dhost[]);
printf("ip: %d.%d.%d.%d ->",hdrPtr->ip_src[],hdrPtr->ip_src[],hdrPtr->ip_src[],hdrPtr->ip_src[]);
printf(" %d.%d.%d.%d \n",hdrPtr->ip_dst[],hdrPtr->ip_dst[],hdrPtr->ip_dst[],hdrPtr->ip_dst[]);
if(pkt.len==pkt.actual_len)
{
printf("whole packet:padPtr is %x,padLength is %d \n",pkt.data+,pkt.len-);
if (build_send_ethernet_packet(devName,, hdrPtr->ether_dhost,
hdrPtr->ether_shost,0x0800,pkt.data+,pkt.len-)
==
)
printf("resend packet success :) \n");
else
printf("resend packet fail :( \n");
}
else
{
fprintf(stderr,"this packet is not entire,cannot resend :(");
} }
else
{
if(hdrPtr->ether_type==0x0608) //filter: ip type: 0x0806 -> little endian 0x0608
{printf("arp packet \n");}
else if(hdrPtr->ether_type==0x3508) //filter: ip type: 0x0835 -> little endian 0x3508
{printf("rarp packet \n");}
else
{printf("unknown packet type\n");}
}
//print packet
printf("snaplen: %d actual_len: %d packet_counter: %d \n",pkt.len,pkt.actual_len,packet_counter);
for(i=; i<pkt.len; ++i)
{
printf(" %02x", pkt.data[i]);
if( (i + ) % == )
{
printf("\n");
}
}
printf("\n\n");
}
else
{
break;
}
} close(fd);
return ; } int main()
{
return pcap_ip_repaly("/home/yun/Codes/wp.pcap",,"eth0");
}

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

IP流量重放与pcap文件格式解析的更多相关文章

  1. pcap文件格式解析

    pcap文件格式是常用的数据报存储格式,包括wireshark在内的主流抓包软件都可以生成这种格式的数据包 下面对这种格式的文件简单分析一下:    pcap文件的格式为:  文件头    24字节  ...

  2. Pcap 数据报解析

    最近看了一下网络的书,信息系统也有实验任务,所以就学习了一下pcap包的解析. 主要是对内部以太网帧头,ip头部,tcp头部或者udp头部的解析.我因为用访问google.cn作为的样例,没有udp包 ...

  3. pcap文件格式及文件解析

    第一部分:PCAP包文件格式 一 基本格式: 文件头 数据包头数据报数据包头数据报...... 二.文件头: 文件头结构体 sturct pcap_file_header {      DWORD   ...

  4. Velodyne线性激光雷达pcap文件格式及写入、数据解析 Lebal:激光雷达

    转载自https://blog.csdn.net/qq_25241325/article/details/80766305 roslaunch loam_velodyne loam_velodyne. ...

  5. PCAP文件格式分析(做抓包软件之必备)

    转载源:http://blog.csdn.net/anzijin/article/details/2008333 http://www.ebnd.cn/2009/09/07/file-format-a ...

  6. ArcGIS三大文件格式解析

    原文:ArcGIS三大文件格式解析 Shape数据 Shapefile是ArcView GIS 3.x的原生数据格式,属于简单要素类,用点.线.多边形存储要素的形状,却不能存储拓扑关系,具有简单.快速 ...

  7. Android init.rc文件格式解析

    /***************************************************************************** * Android init.rc文件格式 ...

  8. pcap文件格式

      pcap文件格式 pcap文件格式是bpf保存原始数据包的格式,很多软件都在使用,比如tcpdump.wireshark等等,了解pcap格式可以加深对原始数据包的了解,自己也可以手工构造任意的数 ...

  9. mp4文件格式解析(转载)

    mp4文件格式解析 原作:http://blog.sina.com.cn/s/blog_48f93b530100jz4b.html 目前MP4的概念被炒得很火,也很乱.最开始MP4指的是音频(MP3的 ...

随机推荐

  1. php开发中一些前端知识杂总

    推荐几个jqyuey插件的好地方 http://jqueryui.com/ http://www.jq22.com/ 背景: 服务端采用ci3.0框架,twig作为模板嵌套. twig模板手册: ht ...

  2. java中的Reference

    这两天又重新学习了一下Reference,根据网上的资源做了汇总. Java中的引用主要有4种: 强引用 StrongReference: Object obj = new Object(); obj ...

  3. NOI2001 食物链【扩展域并查集】*

    NOI2001 食物链 动物王国中有三类动物 A,B,C,这三类动物的食物链构成了有趣的环形.A 吃 B,B吃 C,C 吃 A. 现有 N 个动物,以 1 - N 编号.每个动物都是 A,B,C 中的 ...

  4. 【EF】EntityFramework 更新数据库字段的三种方法

    实体类 public class TestDbContext : DbContext { public DbSet<Test> Tests { get; set; } public Tes ...

  5. 高并发的epoll+线程池,线程池专注实现业务

    我们知道,服务器并发模型通常可分为单线程和多线程模型,这里的线程通常是指“I/O线程”,即负责I/O操作,协调分配任务的“管理线程”,而实际的请求和任务通常交由所谓“工作者线程”处理.通常多线程模型下 ...

  6. arm_linux QT+v4l 显示视频

    1.参考(原创)基于ZedBoard的Webcam设计(三):视频的采集和动态显示 下载代码实测可用. 2.重新下载了csdn的代码,缺widget.h文件,后重新生成widget工程(自动产生wid ...

  7. FOR XML PATH 灵活运用

    FOR XML PATH 有的人可能知道有的人可能不知道,其实它就是将查询结果集以XML形式展现,有了它我们可以简化我们的查询语句实现一些以前可能需要借助函数活存储过程来完成的工作.那么以一个实例为主 ...

  8. C# Socket Post File

    ///<summary> ///向服务器发送混合型的请求,1:成功发送,0:发送失败 ///</summary> ///<param name="paranam ...

  9. textArea中的maxlength是无效的 解决办法

    --------------------------------------------------------------------------------------   <s:texta ...

  10. JEECG获取当前登录人的值

    TSUser user = ResourceUtil.getSessionUserName(); mv.addObject("fbillerid", user.getUserNam ...