(作者:燕云   出处: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. 【排序】归并排序,C++实现

    原创文章,转载请注明出处! 博客文章索引地址 博客文章中代码的github地址 # 基本思想(分治法)       归并排序中, “归”代表递归的意思,即递归的将数组通过折半的方式分离为单个数组. “ ...

  2. nodejs调用百度统计api摆脱人肉数据统计

    var http = require("https"); var url = require('url'); var postData = JSON.stringify( { &q ...

  3. SEO - H标签

    前言 这两天在做网站的SEO.虽然之前SEO的资料看过很多,但是因为正职是美工的缘故,SEO的具体实施参与的较少.现在的公司有点特殊,SEO团队基本不懂代码,所以需要参与的比较多.以下内容主要是通过自 ...

  4. HDU1520 Anniversary party 树形DP基础

    There is going to be a party to celebrate the 80-th Anniversary of the Ural State University. The Un ...

  5. spring mvc 思想

    目录 一.前言 二.spring mvc 核心类与接口 三.spring mvc 核心流程图 四.spring mvc DispatcherServlet说明 五.spring mvc 父子上下文的说 ...

  6. BZOJ2131 免费的馅饼【线段树优化DP】

    Input 第一行是用空格隔开的二个正整数,分别给出了舞台的宽度W(1到10^8之间)和馅饼的个数n(1到10^5). 接下来n行,每一行给出了一块馅饼的信息.由三个正整数组成,分别表示了每个馅饼落到 ...

  7. jest js 测试框架-简单方便人性化

    1. 安装 yarn global add jest-cli or npm install -g jest-cli 备注:可以安装为依赖不用全局安装 2. 项目代码 a. 项目初始化 yarn ini ...

  8. Avro和Thrift区别(未完待续)

    两者都是优秀的序列化框架: Avro创造之初是Hadoop之父Doug为了创造一种更加快捷的序列化方案(此时已经有了thrift),用于Hadoop的HDFS的文件序列化问题. Thrift一个成熟的 ...

  9. php的闭包

    闭包是指在创建时封装周围状态的函数,即使闭包所在的环境的不存在了,闭包中封装的状态依然存在. 匿名函数其实就是没有名称的函数,匿名函数可以赋值给变量,还能像其他任何PHP函数对象那样传递.不过匿名函数 ...

  10. dubbox实现REST服务

    一.dubbox的由来 dubbox是当当网基于dubbo的基础上开发的扩展版,也可以认为是dubbo的升级版,根据当前互联网的应用需求,增加了很多扩展的功能. dubbox并没有发布到maven中央 ...