(作者:燕云   出处: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. BZOJ:5457: 城市(线段树合并)(尚待优化)

    5457: 城市 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 18  Solved: 12[Submit][Status][Discuss] Des ...

  2. win10/ubuntu双系统卸载删除ubuntu系统

    1.重启进入boot-设置windows启动项为首选项. 2.删除EFI中ubuntu引导启动项: a.将EFI分区挂载到M盘->(管理员权限)命令行输入:mountvol M: /s b.进入 ...

  3. 每天一个linux命令:【转载】head命令

    head 与 tail 就像它的名字一样的浅显易懂,它是用来显示开头或结尾某个数量的文字区块,head 用来显示档案的开头至标准输出中,而 tail 想当然尔就是看档案的结尾. 1.命令格式: hea ...

  4. 部署经验Docker

    从Docker 到Jenkins 到Ansible的部署经验 https://www.cnblogs.com/itdragon/p/10011816.html 工作中,除了开发功能,还负责系统的部署工 ...

  5. 《DSP using MATLAB》示例9.1

    前段时间发生许多事,主要是楼盘开发商资金链紧张,无法通过验收,拿不到两书一表(住宅质量保证书.住宅使用说明书.房屋建筑工程竣工验收备案表), 各种配套设施都没有,就在这条件下还强制我们业主收房,心塞, ...

  6. 【转】VC中MessageBox与AfxMessageBox用法与区别

    原文网址:http://blog.csdn.net/holybin/article/details/28403109 一.MessageBox()用法 1.函数原型 Messagebox函数在Win3 ...

  7. Linux环境安装配置Swftools

    系统:CentOS6.5的64位版本   这里有一位仁兄的几个错误处理办法,下面是swftools的安装配置步骤:   1.安装所需的库和组件.机器之前安装过了,主要安装的是下面几个组件.如果不安装会 ...

  8. Python中文报错问题

    异常信息:SyntaxError: Non-ASCII character '\xe6' in file D:/pythonlearning/HelloPython.py on line 8, but ...

  9. 关于FFT的硬件实现

    DFT在实际应用中非常重要,可以计算信号的频谱,功率谱和线性卷积等. 离散傅里叶变换的公式: 其中:  称为旋转因子. 由欧拉公式可得: 直接按DFT变换进行计算,当序列长度N很大时,计算量非常大,所 ...

  10. 1045 access denied for user 'root'@'localhost' using password yes

    mysql -u root -p 方法一:  # /etc/init.d/mysql stop  # mysqld_safe --user=mysql --skip-grant-tables --sk ...