pplayer【linux环境下】
pplayer【linux环境下】
【博客园原创】 http://www.cnblogs.com/baiyan/archive/2013/05/10/pplayer.html
pplayer(packet player)是我写的一款小工具,支持主流协议,专门用来测试IPS和防火墙设备,经长时间验证,简单可靠,故发布。
程序的原理很简单,首先加载pcap包中的数据包,保存在内存中,然后在回放环境中回放数据包。
拓扑:
原理:
防火墙的两个网卡和linux pc的两个网卡分别对接形成环路,pplayer程序运行在linux pc中。
1,加载pcap文件中网路数据包,识别出数据包发送方向(client to server or server to client)
2,修改数据包内容(源/目的ip地址,校验和)
3,按顺序发送数据包,同时接收数据包
4,打印log,提示发送和接收情况,回放完毕。
使用方法:
pplayer -f filename [ -t time ] | [-m] | [-v ipversion ] | [-p portnum ]
可用参数:
-f: 必选,参数是pcap文件名。
-t: 可选,参数是等待接收一个已发送的数据报的时间;如不选默认30(微秒)。
-m: 可选,理想情况下pcap包中只包含两个ip地址的数据包,但是如果存在第3方或3个以上ip地址,就形成了若干的回放关系。
默认情况下,只选择数据包数量最多得一对ip进行回放。如需回放其他ip对的数据包,需要使用-m参数,会以ip对为顺序来回放数据包。
-v: 可选,4或6, 回放IPV4/6数据包, 默认4.
-p: 可选,选择只回放指定端口的数据包,例如,指定回访HTTP包, -p 80。
另外pplayer支持nat环境回放,使用方法见下面配置文件。
举例:
1,./pplayer -f http.pcap(回放http.pcap的数据包)
2, ./pplayer -f http.pcap -v 6 (回放http.pcap的数据包,数据包格式是ipv6)
3,./pplayer -f http.pcap -v 6 -t 50 (回放http.pcap的数据包,数据包格式是ipv6, 每个数据包的等待接收时间设为50微秒)
配置文件:
配置名是conf,和pplayer程序在同一目录下。
注:冒号后面紧接内容,不能有空格或换行
1.device1和device2表示linxu pc的两个网卡
2.device1ip和device2ip表示linux pc的两个网卡的ip地址
3.device1nat和device2nat是用来支持nat环境回放的。
例如:设备1的ip是1.1.1.1,设备1处于nat环境,转换后的ip是3.3.3.3;
设备2的ip是2.2.2.2,设备2处于nat环境,转换后的ip是4.4.4.4;
如果设备不处于nat环境之中,对应的nat配置项填0.0.0.0(ipv6的填::)
并发/批量回放:
目前pplayer只支持一次回放一个IP对,一次只能回放一个pcap文件,不支持并发和批量回放这两种功能, 后续我可能会以shell脚本调用pplayer的方式实现
这两个功能。
核心代码:
View Code
void LoadPacket ( const struct pcap_pkthdr *pcap_hdr, Trace *trace, Flow *flow, const u_char * data, int pkt_id) { Packet *pkt = NULL; struct ether_header *ph = NULL; struct iphdr *iph = NULL; struct ip6_hdr *iph6 = NULL; struct tcphdr *tcph = NULL; struct udphdr *udph = NULL; if (flow->pkt_cap == 0 ) { flow ->pkt_cap = 64 ; flow ->pkt = calloc( 64 , sizeof (Packet)); } else if (flow->pkt_num == flow-> pkt_cap) { flow ->pkt_cap += 64 ; flow ->pkt = realloc(flow->pkt, (flow->pkt_cap) * sizeof (Packet)); } pkt = &flow->pkt[flow-> pkt_num]; pkt ->id = pkt_id; if (my_file.ipversion == 4 ) { iph = ( struct iphdr *)(data + ETH_HLEN); int offset = (iph->ihl << 2 ) + ETH_HLEN; tcph = ( struct tcphdr *)(data + offset); if (my_file.port != 0 && htons(my_file.port) != tcph->th_dport && htons(my_file.port) != tcph-> th_sport) { return ; } pkt ->len = pcap_hdr->caplen; // ntohs(iph->tot_len) + ETH_HLEN; pkt->buf = malloc(pkt->len + ETHER_CRC_LEN); memcpy(pkt ->buf, data, pkt-> len); iph = ( struct iphdr *)(pkt->buf + ETH_HLEN); } else { iph6 = ( struct ip6_hdr *)(data + ETH_HLEN); int offset = 40 + ETH_HLEN; tcph = ( struct tcphdr *)(data + offset); if (my_file.port != 0 && htons(my_file.port) != tcph->th_dport && htons(my_file.port) != tcph-> th_sport) { return ; } pkt ->len = pcap_hdr->caplen; // ntohs(iph6->ip6_plen) + 40 + ETH_HLEN; pkt->buf = malloc(pkt->len + ETHER_CRC_LEN); memcpy(pkt ->buf, data, pkt-> len); iph6 = ( struct ip6_hdr *)(pkt->buf + ETH_HLEN); } flow ->pkt_num ++ ; trace ->total_pkt_num ++ ; if (my_file.ipversion == 4 ) { if (iph->saddr == flow-> sv4) { if (my_file.device2_in_nat) { iph ->saddr = interface .sv4; iph ->daddr = interface .device2nat4; } else { iph ->saddr = interface .sv4; iph ->daddr = interface .dv4; } pkt -> interface = 1 ; } else { if (my_file.device1_in_nat) { iph ->daddr = interface .device1nat4; iph ->saddr = interface .dv4; } else { iph ->daddr = interface .sv4; iph ->saddr = interface .dv4; } pkt -> interface = 2 ; } } else { if (!memcmp(&iph6->ip6_src, flow->sv6, 16 )) { if (my_file.device2_in_nat) { memcpy( &iph6->ip6_src, interface .sv6, 16 ); memcpy( &iph6->ip6_dst, interface .device2nat6, 16 ); } else { memcpy( &iph6->ip6_src, interface .sv6, 16 ); memcpy( &iph6->ip6_dst, interface .dv6, 16 ); } pkt -> interface = 1 ; } else { if (my_file.device1_in_nat) { memcpy( &iph6->ip6_src, interface .device1nat6, 16 ); memcpy( &iph6->ip6_dst, interface .sv6, 16 ); } else { memcpy( &iph6->ip6_src, interface .dv6, 16 ); memcpy( &iph6->ip6_dst, interface .sv6, 16 ); } pkt -> interface = 2 ; } } if (my_file.ipversion == 4 ) { ip_csum(iph); if ((iph->frag_off & htons( 0x1fff )) == 0 ) { int offset = (iph->ihl << 2 ) + ETH_HLEN; if (iph->protocol == IPPROTO_TCP) { tcp_csum(iph, pkt ->buf + offset); } else if (iph->protocol == IPPROTO_UDP) { udph = ( struct udphdr *)(pkt->buf + offset); if (udph->uh_sum != 0 ) { udp_csum(iph, (uint8_t * )udph); } } } } else { int offset = 40 + ETH_HLEN; if (iph6->ip6_nxt == IPPROTO_TCP) { tcp_csum6(iph6, pkt ->buf + offset, pkt-> id); } else if (iph6->ip6_nxt == IPPROTO_UDP) { udp_csum6(iph6, pkt ->buf + offset, pkt-> id); } } /* * Rewrite the mac addresses on the packet. */ ph = ( struct ether_header *)pkt-> buf; if (pkt-> interface == 1 ) { ph ->ether_shost[ 0 ] = interface .device1_mac[ 0 ]; ph ->ether_shost[ 1 ] = interface .device1_mac[ 1 ]; ph ->ether_shost[ 2 ] = interface .device1_mac[ 2 ]; ph ->ether_shost[ 3 ] = interface .device1_mac[ 3 ]; ph ->ether_shost[ 4 ] = interface .device1_mac[ 4 ]; ph ->ether_shost[ 5 ] = interface .device1_mac[ 5 ]; ph ->ether_dhost[ 0 ] = interface .fw_mac1[ 0 ]; ph ->ether_dhost[ 1 ] = interface .fw_mac1[ 1 ]; ph ->ether_dhost[ 2 ] = interface .fw_mac1[ 2 ]; ph ->ether_dhost[ 3 ] = interface .fw_mac1[ 3 ]; ph ->ether_dhost[ 4 ] = interface .fw_mac1[ 4 ]; ph ->ether_dhost[ 5 ] = interface .fw_mac1[ 5 ]; } else { ph ->ether_dhost[ 0 ] = interface .fw_mac2[ 0 ]; ph ->ether_dhost[ 1 ] = interface .fw_mac2[ 1 ]; ph ->ether_dhost[ 2 ] = interface .fw_mac2[ 2 ]; ph ->ether_dhost[ 3 ] = interface .fw_mac2[ 3 ]; ph ->ether_dhost[ 4 ] = interface .fw_mac2[ 4 ]; ph ->ether_dhost[ 5 ] = interface .fw_mac2[ 5 ]; ph ->ether_shost[ 0 ] = interface .device2_mac[ 0 ]; ph ->ether_shost[ 1 ] = interface .device2_mac[ 1 ]; ph ->ether_shost[ 2 ] = interface .device2_mac[ 2 ]; ph ->ether_shost[ 3 ] = interface .device2_mac[ 3 ]; ph ->ether_shost[ 4 ] = interface .device2_mac[ 4 ]; ph ->ether_shost[ 5 ] = interface .device2_mac[ 5 ]; } /* Compute the FCS on the Ethernet Frame * Some people say the hardare should do this, but it does not seem to. * Also for packets > 1510, the WriteInterface dies with a message too long error */ /* * This section actually calculates the FCS, but it's not currently * working correctly, so I've commented it out. The CRC32 function * needs to be verified. */ /* if ( pkt->len <= 15 + ETH_HLEN ) { uint32_t newFCS = CRC32( pkt->buf , pkt->len ); memcpy(pkt->buf + pkt->len , &newFCS , ETHER_CRC_LEN); } */ }
可用版本:
红帽9 https://files.cnblogs.com/baiyan/pplayer_redhat9.zip
fedora15 https://files.cnblogs.com/baiyan/pplayer_fedora15.zip
cenos5.5 https://files.cnblogs.com/baiyan/pplayer_centos5.5.zip
标签: 数据包回放 IPS测试 防火墙
作者: Leo_wl
出处: http://www.cnblogs.com/Leo_wl/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
版权信息查看更多关于pplayer【linux环境下】的详细内容...