support craft packet from scratch
This commit is contained in:
5
test/packet_tool/CMakeLists.txt
Normal file
5
test/packet_tool/CMakeLists.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
add_executable(packet_tool packet_tool.cpp)
|
||||
target_link_libraries(packet_tool packet pcap)
|
||||
|
||||
file(COPY split_pcap.sh DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
file(COPY cmp_layers.sh DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
197
test/packet_tool/cmp_layers.sh
Normal file
197
test/packet_tool/cmp_layers.sh
Normal file
@@ -0,0 +1,197 @@
|
||||
#!/bin/bash
|
||||
|
||||
input=$1
|
||||
if [ -d "$input" ]; then
|
||||
pcap_dir=$input
|
||||
pcap_files=($(find ${pcap_dir} -type f -name "*.pcap"))
|
||||
elif [ -f "$input" ]; then
|
||||
input_file=$input
|
||||
pcap_files=($input_file)
|
||||
else
|
||||
echo "Usage: $0 input_pcap_dir or input_pcap_file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# remove l7 protocol fields
|
||||
function preprocess_tshark_ouput() {
|
||||
input_file=$1
|
||||
output_file=$2
|
||||
cp ${input_file} ${output_file}
|
||||
kv_array=(
|
||||
":tcp:pptp" ":tcp"
|
||||
":tcp-text-lines" ":tcp"
|
||||
":icmp:ip:udp" ":icmp"
|
||||
":icmpv6:ipv6:udp" ":icmpv6"
|
||||
":ieee8021ad" ":vlan"
|
||||
":x509sat" ""
|
||||
":x509ce" ""
|
||||
":pkix1implicit" ""
|
||||
":pkix1explicit" ""
|
||||
":data-text-lines" ""
|
||||
":http-text-lines" ""
|
||||
":websocket" ""
|
||||
":ssl" ""
|
||||
":ftp-data" ""
|
||||
":x11" ""
|
||||
":ntp" ""
|
||||
":rip" ""
|
||||
":isakmp" ""
|
||||
":esp" ""
|
||||
":udpencap" ""
|
||||
":sip:sdp" ""
|
||||
":sip" ""
|
||||
":sdp" ""
|
||||
":rtcp" ""
|
||||
":rtp" ""
|
||||
":ssh" ""
|
||||
":dns" ""
|
||||
":gquic" ""
|
||||
":http:data-text-lines" ""
|
||||
":http:data" ""
|
||||
":msmms" ""
|
||||
":bfd" ""
|
||||
":ssdp" ""
|
||||
":mdns" ""
|
||||
":radius" ""
|
||||
":pop" ""
|
||||
":smtp" ""
|
||||
":rtmpt" ""
|
||||
":bittorrent" ""
|
||||
":oicq" ""
|
||||
":json" ""
|
||||
":media" ""
|
||||
":telnet" ""
|
||||
":nbdgm:smb:browser" ""
|
||||
":smb2" ""
|
||||
":smb" ""
|
||||
":nbss" ""
|
||||
":memcache" ""
|
||||
":rtspi" ""
|
||||
":rdt" ""
|
||||
":rtsp" ""
|
||||
":nbns" ""
|
||||
":lcp" ""
|
||||
":chap" ""
|
||||
":ipcp" ""
|
||||
":comp_data" ""
|
||||
":ccp" ""
|
||||
":snmp" ""
|
||||
":socks:http:data" ""
|
||||
":socks:http" ""
|
||||
":socks" ""
|
||||
":bgp" ""
|
||||
":eigrp" ""
|
||||
":bootp" ""
|
||||
":xml" ""
|
||||
":echo" ""
|
||||
":vssmonitoring" ""
|
||||
":mndp" ""
|
||||
":websocket-text-lines" ""
|
||||
":image-jfif" ""
|
||||
":png" ""
|
||||
":llmnr" ""
|
||||
":pkcs-1" ""
|
||||
":bitcoin:bitcoin" ""
|
||||
":bitcoin" ""
|
||||
":image-gif" ""
|
||||
":dhcpv6" ""
|
||||
":arp" ""
|
||||
":ccsrl" ""
|
||||
":h245" ""
|
||||
":srp" ""
|
||||
":amr" ""
|
||||
":mp4v-es" ""
|
||||
":ajp13" ""
|
||||
":ocsp" ""
|
||||
":irc" ""
|
||||
":http" ""
|
||||
":ftp" ""
|
||||
":data" ""
|
||||
":sctp:m3ua" ""
|
||||
":sctp" ""
|
||||
":igmp" ""
|
||||
":icmp:ip:tcp" ":icmp"
|
||||
":pwethheuristic:pwethnocw" ""
|
||||
":ospf" ""
|
||||
":teredo" ""
|
||||
)
|
||||
for ((i = 0; i < ${#kv_array[@]}; i += 2)); do
|
||||
key=${kv_array[i]}
|
||||
val=${kv_array[i + 1]}
|
||||
sed -i "s/$key/$val/g" ${output_file}
|
||||
done
|
||||
}
|
||||
|
||||
# When MPLS is nested, packet_tool will output multiple mpls fields, and tshark will only output one mpls field, so we need to preprocess the output
|
||||
function preprocess_tool_ouput() {
|
||||
input_file=$1
|
||||
output_file=$2
|
||||
cp ${input_file} ${output_file}
|
||||
kv_array=(
|
||||
":mpls:mpls" ":mpls"
|
||||
)
|
||||
for ((i = 0; i < ${#kv_array[@]}; i += 2)); do
|
||||
key=${kv_array[i]}
|
||||
val=${kv_array[i + 1]}
|
||||
sed -i "s/$key/$val/g" ${output_file}
|
||||
done
|
||||
}
|
||||
|
||||
err_count=0
|
||||
pass_count=0
|
||||
curr_count=0
|
||||
total_count=${#pcap_files[@]}
|
||||
tmp_file_dir="cmp_tmp_files/"
|
||||
err_pcap_dir="cmp_err_pcaps/"
|
||||
|
||||
rm -rf ${err_pcap_dir} && mkdir ${err_pcap_dir}
|
||||
for pcap in "${pcap_files[@]}"; do
|
||||
rm -rf ${tmp_file_dir} && mkdir ${tmp_file_dir}
|
||||
|
||||
curr_count=$((curr_count + 1))
|
||||
|
||||
# tshark output
|
||||
tshark -r ${pcap} -T fields \
|
||||
-e frame.number \
|
||||
-e frame.protocols \
|
||||
-e eth.src \
|
||||
-e eth.dst \
|
||||
-e vlan.id \
|
||||
-e ip.src \
|
||||
-e ip.dst \
|
||||
-e ipv6.src \
|
||||
-e ipv6.dst \
|
||||
-e tcp.srcport \
|
||||
-e tcp.dstport \
|
||||
-e udp.srcport \
|
||||
-e udp.dstport \
|
||||
>>${tmp_file_dir}/tshark_output.txt
|
||||
|
||||
# packet_tool output
|
||||
./packet_tool -f ${pcap} -t >>${tmp_file_dir}/tool_output.txt
|
||||
|
||||
# compare tshark and packet_tool output
|
||||
preprocess_tshark_ouput ${tmp_file_dir}/tshark_output.txt ${tmp_file_dir}/tshark_format.txt
|
||||
preprocess_tool_ouput ${tmp_file_dir}/tool_output.txt ${tmp_file_dir}/tool_format.txt
|
||||
diff ${tmp_file_dir}/tshark_format.txt ${tmp_file_dir}/tool_format.txt >>${tmp_file_dir}/diff.txt
|
||||
|
||||
# print result
|
||||
line_count=$(cat ${tmp_file_dir}/diff.txt | wc -l)
|
||||
if [ "$line_count" -ne 0 ]; then
|
||||
printf "\033[31m [${curr_count}/${total_count}] ${pcap} TEST FAILED \033[0m\n"
|
||||
cat ${tmp_file_dir}/diff.txt | head -n 100
|
||||
cp ${pcap} ${err_pcap_dir}
|
||||
err_count=$((err_count + 1))
|
||||
else
|
||||
printf "\033[32m [${curr_count}/${total_count}] ${pcap} TEST PASSED \033[0m\n"
|
||||
pass_count=$((pass_count + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
printf "\033[33m Total : ${total_count} \033[0m\n"
|
||||
printf "\033[32m Passed : ${pass_count} \033[0m\n"
|
||||
printf "\033[31m Failed : ${err_count} \033[0m\n"
|
||||
|
||||
if [ "$err_count" -ne 0 ]; then
|
||||
printf "\n\033[31m failed pcap: ${err_pcap_dir} \033[0m\n"
|
||||
fi
|
||||
434
test/packet_tool/packet_tool.cpp
Normal file
434
test/packet_tool/packet_tool.cpp
Normal file
@@ -0,0 +1,434 @@
|
||||
#include <unistd.h>
|
||||
#include <pcap/pcap.h>
|
||||
|
||||
#include "eth_utils.h"
|
||||
#include "vlan_utils.h"
|
||||
#include "ipv4_utils.h"
|
||||
#include "ipv6_utils.h"
|
||||
#include "tcp_utils.h"
|
||||
#include "udp_utils.h"
|
||||
#include "packet_def.h"
|
||||
#include "packet_layer.h"
|
||||
#include "packet_parse.h"
|
||||
#include "packet_utils.h"
|
||||
|
||||
#define MAX_BUFF_SIZE 2048
|
||||
#define PRINT_GREEN(fmt, ...) printf("\033[0;32m" fmt "\033[0m\n", ##__VA_ARGS__)
|
||||
#define PRINT_RED(fmt, ...) printf("\033[0;31m" fmt "\033[0m\n", ##__VA_ARGS__)
|
||||
|
||||
struct str_buff
|
||||
{
|
||||
char data[MAX_BUFF_SIZE];
|
||||
int used;
|
||||
char elimiter;
|
||||
};
|
||||
|
||||
struct runtime
|
||||
{
|
||||
char *pcap_file;
|
||||
uint64_t pcap_count;
|
||||
int tshark_format;
|
||||
int print_verbose;
|
||||
int craft_compare;
|
||||
};
|
||||
|
||||
static void str_buff_push(struct str_buff *buff, const char *str)
|
||||
{
|
||||
int len = strlen(str);
|
||||
if (buff->used + len + 1 >= MAX_BUFF_SIZE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (buff->used)
|
||||
{
|
||||
buff->data[buff->used++] = buff->elimiter;
|
||||
}
|
||||
memcpy(buff->data + buff->used, str, len);
|
||||
buff->used += len;
|
||||
}
|
||||
|
||||
static void dump_pcap(const char *file, const char *data, uint16_t len)
|
||||
{
|
||||
struct pcap_pkt_hdr
|
||||
{
|
||||
unsigned int tv_sec; // time stamp
|
||||
unsigned int tv_usec; // time stamp
|
||||
unsigned int caplen; // length of portion present
|
||||
unsigned int len; // length this packet (off wire)
|
||||
} pcap_pkt_hdr = {0};
|
||||
|
||||
struct pcap_file_hdr
|
||||
{
|
||||
unsigned int magic;
|
||||
unsigned short version_major;
|
||||
unsigned short version_minor;
|
||||
unsigned 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_*)
|
||||
} pcap_file_hdr = {
|
||||
.magic = 0xA1B2C3D4,
|
||||
.version_major = 0x0002,
|
||||
.version_minor = 0x0004,
|
||||
.thiszone = 0,
|
||||
.sigfigs = 0,
|
||||
.snaplen = 0xFFFF,
|
||||
.linktype = 1};
|
||||
|
||||
if (file == NULL || data == NULL || len == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FILE *fp = fopen(file, "w+");
|
||||
if (fp == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
struct timeval ts = {0};
|
||||
gettimeofday(&ts, NULL);
|
||||
|
||||
pcap_pkt_hdr.tv_sec = ts.tv_sec;
|
||||
pcap_pkt_hdr.tv_usec = ts.tv_usec;
|
||||
pcap_pkt_hdr.caplen = len;
|
||||
pcap_pkt_hdr.len = len;
|
||||
|
||||
fwrite(&pcap_file_hdr, sizeof(struct pcap_file_hdr), 1, fp);
|
||||
fwrite(&pcap_pkt_hdr, sizeof(struct pcap_pkt_hdr), 1, fp);
|
||||
fwrite(data, 1, len, fp);
|
||||
fflush(fp);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
static void tshark_format(const struct runtime *rte, const struct packet *pkt)
|
||||
{
|
||||
/*
|
||||
tshark -r ${pcap} -T fields \
|
||||
-e frame.number \
|
||||
-e frame.protocols \
|
||||
-e eth.src \
|
||||
-e eth.dst \
|
||||
-e vlan.id \
|
||||
-e ip.src \
|
||||
-e ip.dst \
|
||||
-e ipv6.src \
|
||||
-e ipv6.dst \
|
||||
-e tcp.srcport \
|
||||
-e tcp.dstport \
|
||||
-e udp.srcport \
|
||||
-e udp.dstport \
|
||||
>> tshark_output.txt
|
||||
*/
|
||||
|
||||
struct str_buff buff_proto = {.data = {0}, .used = 0, .elimiter = ':'};
|
||||
struct str_buff buff_eth_src = {.data = {0}, .used = 0, .elimiter = ','};
|
||||
struct str_buff buff_eth_dst = {.data = {0}, .used = 0, .elimiter = ','};
|
||||
struct str_buff buff_vlan_id = {.data = {0}, .used = 0, .elimiter = ','};
|
||||
struct str_buff buff_ipv4_src = {.data = {0}, .used = 0, .elimiter = ','};
|
||||
struct str_buff buff_ipv4_dst = {.data = {0}, .used = 0, .elimiter = ','};
|
||||
struct str_buff buff_ipv6_src = {.data = {0}, .used = 0, .elimiter = ','};
|
||||
struct str_buff buff_ipv6_dst = {.data = {0}, .used = 0, .elimiter = ','};
|
||||
struct str_buff buff_tcp_src = {.data = {0}, .used = 0, .elimiter = ','};
|
||||
struct str_buff buff_tcp_dst = {.data = {0}, .used = 0, .elimiter = ','};
|
||||
struct str_buff buff_udp_src = {.data = {0}, .used = 0, .elimiter = ','};
|
||||
struct str_buff buff_udp_dst = {.data = {0}, .used = 0, .elimiter = ','};
|
||||
|
||||
const struct ethhdr *eth_hdr = NULL;
|
||||
const struct vlan_hdr *vlan_hdr = NULL;
|
||||
const struct ip *ip4_hdr = NULL;
|
||||
const struct ip6_hdr *ip6_hdr = NULL;
|
||||
const struct tcphdr *tcp_hdr = NULL;
|
||||
const struct udphdr *udp_hdr = NULL;
|
||||
|
||||
struct in_addr src_addr_v4 = {0};
|
||||
struct in_addr dst_addr_v4 = {0};
|
||||
struct in6_addr src_addr_v6 = {0};
|
||||
struct in6_addr dst_addr_v6 = {0};
|
||||
|
||||
uint16_t src_port = 0;
|
||||
uint16_t dst_port = 0;
|
||||
uint16_t vlan_id = 0;
|
||||
|
||||
char tmp_src_buff[256] = {0};
|
||||
char tmp_dst_buff[256] = {0};
|
||||
|
||||
int num = packet_get_layer_count(pkt);
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
memset(tmp_src_buff, 0, sizeof(tmp_src_buff));
|
||||
memset(tmp_dst_buff, 0, sizeof(tmp_dst_buff));
|
||||
const struct raw_layer *layer = packet_get_raw_layer(pkt, i);
|
||||
switch (layer->proto)
|
||||
{
|
||||
case LAYER_PROTO_ETHER:
|
||||
str_buff_push(&buff_proto, "eth:ethertype");
|
||||
|
||||
eth_hdr = (const struct ethhdr *)layer->hdr_ptr;
|
||||
eth_hdr_get_source(eth_hdr, tmp_src_buff, sizeof(tmp_src_buff));
|
||||
eth_hdr_get_dest(eth_hdr, tmp_dst_buff, sizeof(tmp_dst_buff));
|
||||
str_buff_push(&buff_eth_src, tmp_src_buff);
|
||||
str_buff_push(&buff_eth_dst, tmp_dst_buff);
|
||||
break;
|
||||
case LAYER_PROTO_PWETH:
|
||||
str_buff_push(&buff_proto, "pwethheuristic:pwethcw");
|
||||
break;
|
||||
case LAYER_PROTO_PPP:
|
||||
str_buff_push(&buff_proto, "ppp");
|
||||
break;
|
||||
case LAYER_PROTO_L2TP:
|
||||
str_buff_push(&buff_proto, "l2tp");
|
||||
break;
|
||||
case LAYER_PROTO_VLAN:
|
||||
str_buff_push(&buff_proto, "vlan:ethertype");
|
||||
|
||||
vlan_hdr = (const struct vlan_hdr *)layer->hdr_ptr;
|
||||
vlan_id = vlan_hdr_get_vid(vlan_hdr);
|
||||
snprintf(tmp_src_buff, sizeof(tmp_src_buff), "%u", vlan_id);
|
||||
str_buff_push(&buff_vlan_id, tmp_src_buff);
|
||||
break;
|
||||
case LAYER_PROTO_PPPOE:
|
||||
str_buff_push(&buff_proto, "pppoes");
|
||||
break;
|
||||
case LAYER_PROTO_MPLS:
|
||||
str_buff_push(&buff_proto, "mpls");
|
||||
break;
|
||||
case LAYER_PROTO_IPV4:
|
||||
str_buff_push(&buff_proto, "ip");
|
||||
|
||||
ip4_hdr = (const struct ip *)layer->hdr_ptr;
|
||||
src_addr_v4 = ipv4_hdr_get_src_in_addr(ip4_hdr);
|
||||
dst_addr_v4 = ipv4_hdr_get_dst_in_addr(ip4_hdr);
|
||||
inet_ntop(AF_INET, &src_addr_v4, tmp_src_buff, sizeof(tmp_src_buff));
|
||||
inet_ntop(AF_INET, &dst_addr_v4, tmp_dst_buff, sizeof(tmp_dst_buff));
|
||||
str_buff_push(&buff_ipv4_src, tmp_src_buff);
|
||||
str_buff_push(&buff_ipv4_dst, tmp_dst_buff);
|
||||
break;
|
||||
case LAYER_PROTO_IPV6:
|
||||
str_buff_push(&buff_proto, "ipv6");
|
||||
ip6_hdr = (const struct ip6_hdr *)layer->hdr_ptr;
|
||||
switch (ipv6_hdr_get_next_header(ip6_hdr))
|
||||
{
|
||||
case IPPROTO_HOPOPTS:
|
||||
str_buff_push(&buff_proto, "ipv6.hopopts");
|
||||
break;
|
||||
case IPPROTO_ROUTING:
|
||||
str_buff_push(&buff_proto, "ipv6.routing");
|
||||
break;
|
||||
case IPPROTO_AH:
|
||||
str_buff_push(&buff_proto, "ah");
|
||||
break;
|
||||
case IPPROTO_DSTOPTS:
|
||||
str_buff_push(&buff_proto, "ipv6.dstopts");
|
||||
break;
|
||||
case IPPROTO_FRAGMENT:
|
||||
str_buff_push(&buff_proto, "ipv6.fraghdr");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
src_addr_v6 = ipv6_hdr_get_src_in6_addr(ip6_hdr);
|
||||
dst_addr_v6 = ipv6_hdr_get_dst_in6_addr(ip6_hdr);
|
||||
inet_ntop(AF_INET6, &src_addr_v6, tmp_src_buff, sizeof(tmp_src_buff));
|
||||
inet_ntop(AF_INET6, &dst_addr_v6, tmp_dst_buff, sizeof(tmp_dst_buff));
|
||||
str_buff_push(&buff_ipv6_src, tmp_src_buff);
|
||||
str_buff_push(&buff_ipv6_dst, tmp_dst_buff);
|
||||
break;
|
||||
case LAYER_PROTO_IPAH:
|
||||
str_buff_push(&buff_proto, "ah");
|
||||
break;
|
||||
case LAYER_PROTO_GRE:
|
||||
str_buff_push(&buff_proto, "gre");
|
||||
break;
|
||||
case LAYER_PROTO_UDP:
|
||||
str_buff_push(&buff_proto, "udp");
|
||||
|
||||
udp_hdr = (const struct udphdr *)layer->hdr_ptr;
|
||||
src_port = udp_hdr_get_src_port(udp_hdr);
|
||||
dst_port = udp_hdr_get_dst_port(udp_hdr);
|
||||
snprintf(tmp_src_buff, sizeof(tmp_src_buff), "%u", src_port);
|
||||
snprintf(tmp_dst_buff, sizeof(tmp_dst_buff), "%u", dst_port);
|
||||
str_buff_push(&buff_udp_src, tmp_src_buff);
|
||||
str_buff_push(&buff_udp_dst, tmp_dst_buff);
|
||||
break;
|
||||
case LAYER_PROTO_TCP:
|
||||
str_buff_push(&buff_proto, "tcp");
|
||||
|
||||
tcp_hdr = (const struct tcphdr *)layer->hdr_ptr;
|
||||
src_port = tcp_hdr_get_src_port(tcp_hdr);
|
||||
dst_port = tcp_hdr_get_dst_port(tcp_hdr);
|
||||
snprintf(tmp_src_buff, sizeof(tmp_src_buff), "%u", src_port);
|
||||
snprintf(tmp_dst_buff, sizeof(tmp_dst_buff), "%u", dst_port);
|
||||
str_buff_push(&buff_tcp_src, tmp_src_buff);
|
||||
str_buff_push(&buff_tcp_dst, tmp_dst_buff);
|
||||
break;
|
||||
case LAYER_PROTO_ICMP:
|
||||
str_buff_push(&buff_proto, "icmp");
|
||||
break;
|
||||
case LAYER_PROTO_ICMP6:
|
||||
str_buff_push(&buff_proto, "icmpv6");
|
||||
break;
|
||||
case LAYER_PROTO_VXLAN:
|
||||
str_buff_push(&buff_proto, "vxlan");
|
||||
break;
|
||||
case LAYER_PROTO_GTP:
|
||||
str_buff_push(&buff_proto, "gtp");
|
||||
break;
|
||||
default:
|
||||
str_buff_push(&buff_proto, "unknown");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
printf("%lu\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
|
||||
rte->pcap_count,
|
||||
buff_proto.data,
|
||||
buff_eth_src.data,
|
||||
buff_eth_dst.data,
|
||||
buff_vlan_id.data,
|
||||
buff_ipv4_src.data,
|
||||
buff_ipv4_dst.data,
|
||||
buff_ipv6_src.data,
|
||||
buff_ipv6_dst.data,
|
||||
buff_tcp_src.data,
|
||||
buff_tcp_dst.data,
|
||||
buff_udp_src.data,
|
||||
buff_udp_dst.data);
|
||||
}
|
||||
|
||||
static void craft_compare(const struct runtime *rte, const struct packet *raw_pkt)
|
||||
{
|
||||
struct layer layers[PACKET_MAX_LAYERS];
|
||||
int layer_count = PACKET_GETALL_LAYERS(raw_pkt, layers);
|
||||
|
||||
struct packet *new_pkt = craft_packet_from_scratch(layers, layer_count, packet_get_payload(raw_pkt), packet_get_payload_len(raw_pkt));
|
||||
if (new_pkt == NULL)
|
||||
{
|
||||
PRINT_RED("craft compare: failed (craft error)");
|
||||
return;
|
||||
}
|
||||
|
||||
if (rte->print_verbose)
|
||||
{
|
||||
packet_print(new_pkt);
|
||||
}
|
||||
|
||||
if (rte->tshark_format)
|
||||
{
|
||||
tshark_format(rte, new_pkt);
|
||||
}
|
||||
|
||||
const char *raw_pkt_data = packet_get_raw_data(raw_pkt);
|
||||
const char *new_pkt_data = packet_get_raw_data(new_pkt);
|
||||
uint16_t raw_pkt_len = packet_get_raw_len(raw_pkt);
|
||||
uint16_t new_pkt_len = packet_get_raw_len(new_pkt);
|
||||
|
||||
if (raw_pkt_len != new_pkt_len)
|
||||
{
|
||||
PRINT_RED("craft compare: failed (length mismatch)");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
if (memcmp(raw_pkt_data, new_pkt_data, raw_pkt_len) != 0)
|
||||
{
|
||||
PRINT_RED("craft compare: failed (data mismatch)");
|
||||
goto error_out;
|
||||
}
|
||||
|
||||
PRINT_GREEN("craft compare: success");
|
||||
|
||||
error_out:
|
||||
char file[256] = {0};
|
||||
snprintf(file, sizeof(file), "craft%lu.pcap", rte->pcap_count);
|
||||
dump_pcap(file, new_pkt_data, new_pkt_len);
|
||||
packet_free(new_pkt);
|
||||
}
|
||||
|
||||
static void packet_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
|
||||
{
|
||||
struct runtime *rte = (struct runtime *)user;
|
||||
|
||||
struct packet pkt;
|
||||
memset(&pkt, 0, sizeof(pkt));
|
||||
packet_parse(&pkt, (const char *)bytes, h->caplen);
|
||||
rte->pcap_count++;
|
||||
|
||||
if (rte->print_verbose)
|
||||
{
|
||||
PRINT_GREEN("frame=%lu len=%u", rte->pcap_count, h->caplen);
|
||||
packet_print(&pkt);
|
||||
}
|
||||
|
||||
if (rte->tshark_format)
|
||||
{
|
||||
tshark_format(rte, &pkt);
|
||||
}
|
||||
|
||||
if (rte->craft_compare)
|
||||
{
|
||||
craft_compare(rte, &pkt);
|
||||
}
|
||||
}
|
||||
|
||||
static void usage(char *cmd)
|
||||
{
|
||||
printf("Usage: %s\n", cmd);
|
||||
printf("Options:\n");
|
||||
printf(" -f <pcap file> pcap file\n");
|
||||
printf(" -t print tshark format\n");
|
||||
printf(" -v print verbose info\n");
|
||||
printf(" -c compare recrafted packet\n");
|
||||
printf(" -h print help\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int opt = 0;
|
||||
struct runtime rte = {0};
|
||||
while ((opt = getopt(argc, argv, "f:tvch")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'f':
|
||||
rte.pcap_file = optarg;
|
||||
break;
|
||||
case 't':
|
||||
rte.tshark_format = 1;
|
||||
break;
|
||||
case 'v':
|
||||
rte.print_verbose = 1;
|
||||
break;
|
||||
case 'c':
|
||||
rte.craft_compare = 1;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
usage(argv[0]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (rte.pcap_file == NULL)
|
||||
{
|
||||
usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rte.print_verbose)
|
||||
{
|
||||
PRINT_GREEN("pcap=%s", rte.pcap_file);
|
||||
}
|
||||
|
||||
pcap_t *pcap = pcap_open_offline(rte.pcap_file, NULL);
|
||||
if (pcap == NULL)
|
||||
{
|
||||
printf("pcap_open_offline() failed\n");
|
||||
return -1;
|
||||
}
|
||||
pcap_loop(pcap, -1, packet_handler, (u_char *)&rte);
|
||||
pcap_close(pcap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
19
test/packet_tool/split_pcap.sh
Normal file
19
test/packet_tool/split_pcap.sh
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 input.pcap"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
input_pcap="$1"
|
||||
output_dir="split_output/"
|
||||
rm -rf $output_dir && mkdir -p $output_dir
|
||||
|
||||
num=$(tshark -r "$input_pcap" -T fields -e frame.number | tail -n 1)
|
||||
echo -e "\e[32m input pcap $input_pcap has $num packets\e[0m"
|
||||
|
||||
for ((i = 1; i <= num; i++)); do
|
||||
tshark -r "$input_pcap" -Y "frame.number==$i" -w "$output_dir/packet_$i.pcap"
|
||||
done
|
||||
|
||||
echo -e "\e[32m split pcap is saved in $output_dir\e[0m"
|
||||
Reference in New Issue
Block a user