(作者:燕云   出处: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. webdriver元素定位

    #1 通过id定位 driver.find_element_by_id("pop_setting_save").click() #2 通过name定位 driver.find_el ...

  2. Oracle数据库安装完成后相关问题的解决

    笔者一直以来都是使用公司服务器上的oracle数据库,突然一天公司服务器宕机了,项目无法访问数据库跟着瘫痪了,所以准备在自己的机器上安装一个oracle数据库. 从官网下载安装了oracle 11g后 ...

  3. cocos2d-x 3.2 关闭按钮点击立马销毁自己报错

    cocos2d-x 3.2 Button点击事件里调用移除当前层报错 http://www.th7.cn/program/ios/201408/271227.shtml 诡异的错误,点击关闭按钮,居然 ...

  4. gitlab安装、配置与阿里云产品集成

    https://www.ilanni.com/?p=12819 一.gitlab安装与部署 gitlab的安装可以分为源码安装和通过安装包进行安装,要是按照我以前的写作习惯的话,我也会把源码安装在本文 ...

  5. 完美版js金钱正则表达式校验

    <!doctype html> <html lang="en">  <head>   <meta charset="UTF-8& ...

  6. strcpy手写——面试

    #include<stdio.h> #include<string.h> ]={]; char* strcpy(char *to,char *from){ if(NULL==t ...

  7. 常见企业IT支撑【1、办公网络IP地址规划】

    规划思路如下,可灵活变化

  8. Ubuntu上kubeadm安装Kubernetes集群

    一 创建VM 3台VM,其中一台为master节点,2台work node: 二 安装相关软件 在所有节点上运行: apt-get update apt-get install apt-transpo ...

  9. js的delegate回调例子

    暂时没发现有具体的实际用处,先记录下 <!DOCTYPE html> <html> <head lang="en"> <meta char ...

  10. mac下导出JetBrains IDE Support插件给linux

    自从google被和谐以后,上google的store安装插件是如此的费劲,好在mac下的chrome已经装好了,直接导出给linux就可以 mac下chrome的插件目录为 ~/Library/Ap ...