pplayer(packet player)是我寫的一款小工具,支持主流協(xié)議,專門用來測試IPS和防火墻設備,經(jīng)長時間驗證,簡單可靠,故發(fā)布。
程序的原理很簡單,首先加載pcap包中的數(shù)據(jù)包,保存在內(nèi)存中,然后在回放環(huán)境中回放數(shù)據(jù)包。
拓撲:
原理:
防火墻的兩個網(wǎng)卡和linux pc的兩個網(wǎng)卡分別對接形成環(huán)路,pplayer程序運行在linux pc中。
1,加載pcap文件中網(wǎng)路數(shù)據(jù)包,識別出數(shù)據(jù)包發(fā)送方向(client to server or server to client)
2,修改數(shù)據(jù)包內(nèi)容(源/目的ip地址,校驗和)
3,按順序發(fā)送數(shù)據(jù)包,同時接收數(shù)據(jù)包
4,打印log,提示發(fā)送和接收情況,回放完畢。
使用方法:
pplayer -f filename [ -t time] | [-m] | [-v ipversion] | [-p portnum]
可用參數(shù):
-f: 必選,參數(shù)是pcap文件名。
-t: 可選,參數(shù)是等待接收一個已發(fā)送的數(shù)據(jù)報的時間;如不選默認30(微秒)。
-m: 可選,理想情況下pcap包中只包含兩個ip地址的數(shù)據(jù)包,但是如果存在第3方或3個以上ip地址,就形成了若干的回放關系。
默認情況下,只選擇數(shù)據(jù)包數(shù)量最多得一對ip進行回放。如需回放其他ip對的數(shù)據(jù)包,需要使用-m參數(shù),會以ip對為順序來回放數(shù)據(jù)包。
-v: 可選,4或6, 回放IPV4/6數(shù)據(jù)包, 默認4.
-p: 可選,選擇只回放指定端口的數(shù)據(jù)包,例如,指定回訪HTTP包, -p 80。
另外pplayer支持nat環(huán)境回放,使用方法見下面配置文件。
舉例:
1,./pplayer -f http.pcap(回放http.pcap的數(shù)據(jù)包)
2, ./pplayer -f http.pcap -v 6 (回放http.pcap的數(shù)據(jù)包,數(shù)據(jù)包格式是ipv6)
3,./pplayer -f http.pcap -v 6 -t 50 (回放http.pcap的數(shù)據(jù)包,數(shù)據(jù)包格式是ipv6, 每個數(shù)據(jù)包的等待接收時間設為50微秒)
配置文件:
配置名是conf,和pplayer程序在同一目錄下。
格式:
device1:eth0
device2:eth1
device1ip:1.1.1.1
device2ip:2.2.2.2
device1nat:3.3.3.3
device2nat:4.4.4.4
fwmac1:00:0C:29:25:63:6E
fwmac2:00:0C:29:25:63:78
注:冒號后面緊接內(nèi)容,不能有空格或換行
1.device1和device2表示linxu pc的兩個網(wǎng)卡
2.device1ip和device2ip表示linux pc的兩個網(wǎng)卡的ip地址
3.device1nat和device2nat是用來支持nat環(huán)境回放的。
例如:設備1的ip是1.1.1.1,設備1處于nat環(huán)境,轉換后的ip是3.3.3.3;
設備2的ip是2.2.2.2,設備2處于nat環(huán)境,轉換后的ip是4.4.4.4;
如果設備不處于nat環(huán)境之中,對應的nat配置項填0.0.0.0(ipv6的填::)
并發(fā)/批量回放:
目前pplayer只支持一次回放一個IP對,一次只能回放一個pcap文件,不支持并發(fā)和批量回放這兩種功能,后續(xù)我可能會以shell腳本調(diào)用pplayer的方式實現(xiàn)
這兩個功能。
核心代碼:
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 http://pan.baidu.com/share/link?shareid=550929&uk=85241834
fedora15 http://pan.baidu.com/share/link?shareid=550933&uk=85241834
cenos5.5 http://pan.baidu.com/share/link?shareid=550937&uk=85241834