IP流量重放与pcap文件格式解析
(作者:燕云 出处: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文件格式解析的更多相关文章
- pcap文件格式解析
pcap文件格式是常用的数据报存储格式,包括wireshark在内的主流抓包软件都可以生成这种格式的数据包 下面对这种格式的文件简单分析一下: pcap文件的格式为: 文件头 24字节 ...
- Pcap 数据报解析
最近看了一下网络的书,信息系统也有实验任务,所以就学习了一下pcap包的解析. 主要是对内部以太网帧头,ip头部,tcp头部或者udp头部的解析.我因为用访问google.cn作为的样例,没有udp包 ...
- pcap文件格式及文件解析
第一部分:PCAP包文件格式 一 基本格式: 文件头 数据包头数据报数据包头数据报...... 二.文件头: 文件头结构体 sturct pcap_file_header { DWORD ...
- Velodyne线性激光雷达pcap文件格式及写入、数据解析 Lebal:激光雷达
转载自https://blog.csdn.net/qq_25241325/article/details/80766305 roslaunch loam_velodyne loam_velodyne. ...
- PCAP文件格式分析(做抓包软件之必备)
转载源:http://blog.csdn.net/anzijin/article/details/2008333 http://www.ebnd.cn/2009/09/07/file-format-a ...
- ArcGIS三大文件格式解析
原文:ArcGIS三大文件格式解析 Shape数据 Shapefile是ArcView GIS 3.x的原生数据格式,属于简单要素类,用点.线.多边形存储要素的形状,却不能存储拓扑关系,具有简单.快速 ...
- Android init.rc文件格式解析
/***************************************************************************** * Android init.rc文件格式 ...
- pcap文件格式
pcap文件格式 pcap文件格式是bpf保存原始数据包的格式,很多软件都在使用,比如tcpdump.wireshark等等,了解pcap格式可以加深对原始数据包的了解,自己也可以手工构造任意的数 ...
- mp4文件格式解析(转载)
mp4文件格式解析 原作:http://blog.sina.com.cn/s/blog_48f93b530100jz4b.html 目前MP4的概念被炒得很火,也很乱.最开始MP4指的是音频(MP3的 ...
随机推荐
- JAVA多线程----用--进阶--》网络编程1
http://www.cnblogs.com/springcsc/archive/2009/12/03/1616413.html 一个服务器端一般都需要同时为多个客户端提供通讯,如果需要同时支持多个客 ...
- 每天一个linux命令(权限):【转载】 /etc/group文件详解
Linux /etc/group文件与/etc/passwd和/etc/shadow文件都是有关于系统管理员对用户和用户组管理时相关的文件.linux /etc/group文件是有关于系统管理员对用户 ...
- java web构建学习(概念基础)
1.什么是Java Web Application 一个Java web应用程序生成交互式web页面包含各种类型的标记语言(HTML.XML等)和动态内容.它通常由web组件例如JavaServer ...
- BZOJ3444 最后的晚餐【细节题+组合数学】*
BZOJ3444 最后的晚餐 Description [问题背景] 高三的学长们就要离开学校,各奔东西了.某班n人在举行最后的离别晚餐时,饭店老板觉得十分纠结.因为有m名学生偷偷找他,要求和自己暗恋的 ...
- Atocder ARC082 F-Sandglass 【思维题】*
Atocder ARC082 F-Sandglass Problem Statement We have a sandglass consisting of two bulbs, bulb A and ...
- CentOS编译安装php7.2
介绍: 久闻php7的速度以及性能那可是比php5系列的任何一版本都要快,具体性能有多好,建议还是先尝试下再说.如果你是升级或新安装,那你首先需要考虑php7和程序是否存在兼容性,如果程序是基于php ...
- phoenxi elixir 框架几个方便的命令
1. 已有命令 mix app.start # Starts all registered apps mix app.tree # Prints the application tree mix ar ...
- 在Eclipse中配置Tomcat7.0
为了在Eclipse中进行struts2的测试,才发现自己机器上的Eclipse没有集成Tomcat,在网上找了半天,不是这个插件没有下载地址,就是那个有好多注意事项或者版本问题.结果,自己到tomc ...
- oracle之 v$sql_monitor 监视正在运行的SQL语句的统计信息
11g中引入了新的动态性能视图V$SQL_MONITOR,该视图用以显示Oracle监视的SQL语句信息.SQL监视会对那些并行执行或者消耗5秒以上cpu时间或I/O时间的SQL语句自动启动,同时在V ...
- ubuntu下eclipse安装maven插件
ubuntu科输入如下指令安装eclipse:sudo apt-get install eclipse ubuntu下安装maven插件打开Eclipse点击Help -> Install Ne ...