Add tools packet_parser
This commit is contained in:
@@ -6,6 +6,7 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/ip.h>
|
||||
@@ -255,6 +256,25 @@ static inline void ipv4_hdr_set_opt_data(struct ip *hdr, const char *opt_data)
|
||||
memcpy((char *)hdr + sizeof(struct ip), opt_data, ipv4_hdr_get_opt_len(hdr));
|
||||
}
|
||||
|
||||
static inline int ipv4_hdr_to_str(const struct ip *hdr, char *buf, size_t size)
|
||||
{
|
||||
memset(buf, 0, size);
|
||||
char src_addr_str[INET6_ADDRSTRLEN] = {0};
|
||||
char dst_addr_str[INET6_ADDRSTRLEN] = {0};
|
||||
|
||||
struct in_addr src_addr = ipv4_hdr_get_src_in_addr(hdr);
|
||||
struct in_addr dst_addr = ipv4_hdr_get_dst_in_addr(hdr);
|
||||
inet_ntop(AF_INET, &src_addr, src_addr_str, sizeof(src_addr_str));
|
||||
inet_ntop(AF_INET, &dst_addr, dst_addr_str, sizeof(dst_addr_str));
|
||||
|
||||
return snprintf(buf, size, "IPv4: version=%u hdr_len=%u tos=%u total_len=%u ipid=%u flags=%u(rf=%u df=%u mf=%u) frag_offset=%u ttl=%u proto=%u checksum=%u src_addr=%s dst_addr=%s opt_len=%u",
|
||||
ipv4_hdr_get_version(hdr), ipv4_hdr_get_hdr_len(hdr), ipv4_hdr_get_tos(hdr),
|
||||
ipv4_hdr_get_total_len(hdr), ipv4_hdr_get_ipid(hdr), ipv4_hdr_get_flags(hdr),
|
||||
ipv4_hdr_get_rf_flag(hdr), ipv4_hdr_get_df_flag(hdr), ipv4_hdr_get_mf_flag(hdr),
|
||||
ipv4_hdr_get_frag_offset(hdr), ipv4_hdr_get_ttl(hdr), ipv4_hdr_get_proto(hdr),
|
||||
ipv4_hdr_get_checksum(hdr), src_addr_str, dst_addr_str, ipv4_hdr_get_opt_len(hdr));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -6,6 +6,7 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/ip6.h>
|
||||
|
||||
@@ -195,6 +196,22 @@ static inline void ipv6_frag_set_more(struct ip6_frag *frag, bool more)
|
||||
}
|
||||
}
|
||||
|
||||
static inline int ipv6_hdr_to_str(const struct ip6_hdr *hdr, char *buf, size_t size)
|
||||
{
|
||||
memset(buf, 0, size);
|
||||
char src_addr_str[INET6_ADDRSTRLEN] = {0};
|
||||
char dst_addr_str[INET6_ADDRSTRLEN] = {0};
|
||||
|
||||
struct in6_addr src_addr = ipv6_hdr_get_src_in6_addr(hdr);
|
||||
struct in6_addr dst_addr = ipv6_hdr_get_dst_in6_addr(hdr);
|
||||
inet_ntop(AF_INET6, &src_addr, src_addr_str, INET6_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET6, &dst_addr, dst_addr_str, INET6_ADDRSTRLEN);
|
||||
|
||||
return snprintf(buf, size, "IPv6: version=%u traffic_class=%u flow_label=%u payload_len=%u next_header=%u hop_limit=%u src_addr=%s dst_addr=%s",
|
||||
ipv6_hdr_get_version(hdr), ipv6_hdr_get_traffic_class(hdr), ipv6_hdr_get_flow_label(hdr), ipv6_hdr_get_payload_len(hdr),
|
||||
ipv6_hdr_get_next_header(hdr), ipv6_hdr_get_hop_limit(hdr), src_addr_str, dst_addr_str);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1021,9 +1021,9 @@ static inline const char *parse_ipv4(struct packet *pkt, const char *data, uint1
|
||||
// ip fragmented
|
||||
if (ipv4_hdr_get_mf_flag(hdr) || ipv4_hdr_get_frag_offset(hdr))
|
||||
{
|
||||
PACKET_LOG_WARN("ip is fragmented");
|
||||
PACKET_LOG_WARN("packet %p ip layer %p is fragmented", pkt, layer);
|
||||
pkt->frag_layer = layer;
|
||||
return layer->pld_ptr;
|
||||
// try continue parse
|
||||
}
|
||||
|
||||
// TESTED
|
||||
@@ -1057,9 +1057,9 @@ static inline const char *parse_ipv6(struct packet *pkt, const char *data, uint1
|
||||
// ipv6 fragment
|
||||
if (next_proto == IPPROTO_FRAGMENT)
|
||||
{
|
||||
PACKET_LOG_WARN("ipv6 is fragmented");
|
||||
PACKET_LOG_WARN("packet %p ipv6 layer %p is fragmented", pkt, layer);
|
||||
pkt->frag_layer = layer;
|
||||
return layer->pld_ptr;
|
||||
// try continue parse
|
||||
}
|
||||
|
||||
// TODO parse ipv6 extension headers
|
||||
@@ -1363,21 +1363,63 @@ void packet_print_str(const struct packet *pkt)
|
||||
return;
|
||||
}
|
||||
|
||||
char buffer[2048] = {0};
|
||||
printf("packet: %p, data_ptr: %p, data_len: %u, layers_used: %u, layers_size: %u\n",
|
||||
pkt, pkt->data_ptr, pkt->data_len,
|
||||
pkt->layers_used, pkt->layers_size);
|
||||
for (uint8_t i = 0; i < pkt->layers_used; i++)
|
||||
{
|
||||
int used = 0;
|
||||
const struct packet_layer *layer = &pkt->layers[i];
|
||||
printf(" layer[%u]: %p, type: %s, hdr_offset: %u, hdr_ptr: %p, hdr_len: %u, pld_ptr: %p, pld_len: %u\n",
|
||||
i, layer, layer_type_to_str(layer->type), layer->hdr_offset,
|
||||
layer->hdr_ptr, layer->hdr_len, layer->pld_ptr, layer->pld_len);
|
||||
}
|
||||
for (uint16_t i = 0; i < pkt->data_len; i++)
|
||||
switch (layer->type)
|
||||
{
|
||||
printf("0x%02x, ", (uint8_t)pkt->data_ptr[i]);
|
||||
case LAYER_TYPE_ETHER:
|
||||
break;
|
||||
case LAYER_TYPE_PPP:
|
||||
break;
|
||||
case LAYER_TYPE_HDLC:
|
||||
break;
|
||||
case LAYER_TYPE_L2TP:
|
||||
break;
|
||||
case LAYER_TYPE_VLAN:
|
||||
break;
|
||||
case LAYER_TYPE_PPPOE:
|
||||
break;
|
||||
case LAYER_TYPE_MPLS:
|
||||
break;
|
||||
case LAYER_TYPE_IPV4:
|
||||
used = ipv4_hdr_to_str((const struct ip *)layer->hdr_ptr, buffer, sizeof(buffer));
|
||||
break;
|
||||
case LAYER_TYPE_IPV6:
|
||||
used = ipv6_hdr_to_str((const struct ip6_hdr *)layer->hdr_ptr, buffer, sizeof(buffer));
|
||||
break;
|
||||
case LAYER_TYPE_GRE:
|
||||
break;
|
||||
case LAYER_TYPE_UDP:
|
||||
used = udp_hdr_to_str((const struct udphdr *)layer->hdr_ptr, buffer, sizeof(buffer));
|
||||
break;
|
||||
case LAYER_TYPE_TCP:
|
||||
used = tcp_hdr_to_str((const struct tcphdr *)layer->hdr_ptr, buffer, sizeof(buffer));
|
||||
break;
|
||||
case LAYER_TYPE_ICMP:
|
||||
break;
|
||||
case LAYER_TYPE_ICMP6:
|
||||
break;
|
||||
case LAYER_TYPE_VXLAN:
|
||||
break;
|
||||
case LAYER_TYPE_GTPV1_U:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (used)
|
||||
{
|
||||
printf(" %s\n", buffer);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void packet_print_table(const struct packet *pkt)
|
||||
|
||||
@@ -6,6 +6,7 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#define __FAVOR_BSD 1
|
||||
@@ -261,6 +262,23 @@ static inline void tcp_hdr_set_opt_data(struct tcphdr *hdr, const char *ptr)
|
||||
memcpy((char *)hdr + sizeof(struct tcphdr), ptr, tcp_hdr_get_opt_len(hdr));
|
||||
}
|
||||
|
||||
static inline int tcp_hdr_to_str(const struct tcphdr *hdr, char *buf, size_t size)
|
||||
{
|
||||
memset(buf, 0, size);
|
||||
return snprintf(buf, size, "TCP: src_port=%u dst_port=%u seq=%u ack=%u hdr_len=%u flags=0x%02x(%s%s%s%s%s%s) window=%u checksum=%u urg_ptr=%u opt_len=%u",
|
||||
tcp_hdr_get_src_port(hdr), tcp_hdr_get_dst_port(hdr),
|
||||
tcp_hdr_get_seq(hdr), tcp_hdr_get_ack(hdr),
|
||||
tcp_hdr_get_hdr_len(hdr), tcp_hdr_get_flags(hdr),
|
||||
tcp_hdr_get_urg_flag(hdr) ? "URG " : "",
|
||||
tcp_hdr_get_ack_flag(hdr) ? "ACK " : "",
|
||||
tcp_hdr_get_push_flag(hdr) ? "PSH " : "",
|
||||
tcp_hdr_get_rst_flag(hdr) ? "RST " : "",
|
||||
tcp_hdr_get_syn_flag(hdr) ? "SYN " : "",
|
||||
tcp_hdr_get_fin_flag(hdr) ? "FIN " : "",
|
||||
tcp_hdr_get_window(hdr), tcp_hdr_get_checksum(hdr),
|
||||
tcp_hdr_get_urg_ptr(hdr), tcp_hdr_get_opt_len(hdr));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -6,6 +6,7 @@ extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <arpa/inet.h>
|
||||
#define __FAVOR_BSD 1
|
||||
#include <netinet/udp.h>
|
||||
@@ -72,6 +73,14 @@ static inline void udp_hdr_set_checksum(struct udphdr *hdr, uint16_t sum)
|
||||
hdr->uh_sum = htons(sum);
|
||||
}
|
||||
|
||||
static inline int udp_hdr_to_str(const struct udphdr *hdr, char *buf, size_t size)
|
||||
{
|
||||
memset(buf, 0, size);
|
||||
return snprintf(buf, size, "UDP: src_port=%u dst_port=%u total_len=%u checksum=%u",
|
||||
udp_hdr_get_src_port(hdr), udp_hdr_get_dst_port(hdr),
|
||||
udp_hdr_get_total_len(hdr), udp_hdr_get_checksum(hdr));
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
# build packet_parser
|
||||
add_executable(packet_parser packet_parser.cpp)
|
||||
target_link_libraries(packet_parser packet pcap)
|
||||
|
||||
file(COPY split_pcap.sh DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
file(COPY cmp_layers.sh DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
|
||||
50
test/packet_parser/cmp_layers.sh
Normal file
50
test/packet_parser/cmp_layers.sh
Normal file
@@ -0,0 +1,50 @@
|
||||
#!/bin/bash
|
||||
|
||||
input=$1
|
||||
if [ -d "$input" ]; then
|
||||
input_dir=$input
|
||||
pcap_files=($(find ${input_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 replace() {
|
||||
file=$1
|
||||
array=(":data" ":ntp" ":rip" ":isakmp" ":esp" ":udpencap" ":sip" ":sdp" ":rtcp" ":rtp" ":ssh" ":dns" ":ssl" ":gquic" ":http-text-lines" ":http" ":msmms" ":bfd" ":ftp-data-text-lines" ":ftp" ":ssdp" ":mdns" ":radius" ":pop" ":smtp" ":rtmpt" ":bittorrent" ":oicq" ":json" ":media" ":x11" ":telnet" ":nbss:smb" ":memcache" ":rtspi" ":rdt" ":rtsp" ":nbns" ":nbdgm:smb:browser" ":lcp" ":chap" ":ipcp" ":comp_data" ":ccp" ":snmp" ":socks" ":bgp" ":eigrp" ":bootp" ":xml" ":echo" ":vssmonitoring" ":mndp" ":websocket-text-lines" ":websocket" ":image-jfif" ":png" ":pkix1implicit" ":x509sat" ":x509ce" ":pkix1explicit" ":llmnr")
|
||||
for key in "${array[@]}"; do
|
||||
sed "s/$key//g" ${file} >.tmp.txt
|
||||
mv .tmp.txt ${file}
|
||||
done
|
||||
}
|
||||
|
||||
output_dir="cmp_output/"
|
||||
for pcap in "${pcap_files[@]}"; do
|
||||
rm -rf ${output_dir} && mkdir ${output_dir}
|
||||
|
||||
# tshark output frame.protocols
|
||||
tshark -r ${pcap} -T fields -e frame.number -e frame.protocols >>${output_dir}/tshark.txt
|
||||
|
||||
# packet_parser output frame.protocols
|
||||
./packet_parser -f ${pcap} -p >>${output_dir}/parser.txt
|
||||
|
||||
# compare tshark and packet_parser output
|
||||
cp ${output_dir}/tshark.txt ${output_dir}/expect.txt
|
||||
replace ${output_dir}/expect.txt
|
||||
diff ${output_dir}/expect.txt ${output_dir}/parser.txt >>${output_dir}/diff.txt
|
||||
|
||||
# print result
|
||||
line_count=$(cat ${output_dir}/diff.txt | wc -l)
|
||||
if [ "$line_count" -ne 0 ]; then
|
||||
printf "\033[31m ${pcap} TEST FAILED \033[0m\n"
|
||||
cat ${output_dir}/diff.txt | head -n 100
|
||||
#exit 0
|
||||
else
|
||||
printf "\033[32m ${pcap} TEST PASSED \033[0m\n"
|
||||
fi
|
||||
|
||||
done
|
||||
@@ -2,11 +2,106 @@
|
||||
#include <pcap/pcap.h>
|
||||
#include "packet_priv.h"
|
||||
|
||||
struct options
|
||||
{
|
||||
char *file;
|
||||
int print_proto;
|
||||
int print_summary;
|
||||
};
|
||||
|
||||
static uint64_t number = 0;
|
||||
|
||||
static int packet_proto_to_str(const struct packet *pkt, char *buff, int size)
|
||||
{
|
||||
int used = 0;
|
||||
int8_t num = packet_get_layers_number(pkt);
|
||||
for (int8_t i = 0; i < num; i++)
|
||||
{
|
||||
const struct packet_layer *layer = packet_get_layer(pkt, i);
|
||||
switch (layer->type)
|
||||
{
|
||||
case LAYER_TYPE_ETHER:
|
||||
used += snprintf(buff + used, size - used, "eth:ethertype");
|
||||
break;
|
||||
case LAYER_TYPE_PPP:
|
||||
used += snprintf(buff + used, size - used, "ppp");
|
||||
break;
|
||||
case LAYER_TYPE_HDLC:
|
||||
used += snprintf(buff + used, size - used, "hdlc");
|
||||
break;
|
||||
case LAYER_TYPE_L2TP:
|
||||
used += snprintf(buff + used, size - used, "l2tp");
|
||||
break;
|
||||
case LAYER_TYPE_VLAN:
|
||||
used += snprintf(buff + used, size - used, "vlan:ethertype");
|
||||
break;
|
||||
case LAYER_TYPE_PPPOE:
|
||||
used += snprintf(buff + used, size - used, "pppoe");
|
||||
break;
|
||||
case LAYER_TYPE_MPLS:
|
||||
used += snprintf(buff + used, size - used, "mpls");
|
||||
break;
|
||||
case LAYER_TYPE_IPV4:
|
||||
used += snprintf(buff + used, size - used, "ip");
|
||||
break;
|
||||
case LAYER_TYPE_IPV6:
|
||||
used += snprintf(buff + used, size - used, "ipv6");
|
||||
break;
|
||||
case LAYER_TYPE_GRE:
|
||||
used += snprintf(buff + used, size - used, "gre");
|
||||
break;
|
||||
case LAYER_TYPE_UDP:
|
||||
used += snprintf(buff + used, size - used, "udp");
|
||||
break;
|
||||
case LAYER_TYPE_TCP:
|
||||
used += snprintf(buff + used, size - used, "tcp");
|
||||
break;
|
||||
case LAYER_TYPE_ICMP:
|
||||
used += snprintf(buff + used, size - used, "icmp");
|
||||
break;
|
||||
case LAYER_TYPE_ICMP6:
|
||||
used += snprintf(buff + used, size - used, "icmpv6");
|
||||
break;
|
||||
case LAYER_TYPE_VXLAN:
|
||||
used += snprintf(buff + used, size - used, "vxlan");
|
||||
break;
|
||||
case LAYER_TYPE_GTPV1_U:
|
||||
used += snprintf(buff + used, size - used, "gtp");
|
||||
break;
|
||||
default:
|
||||
used += snprintf(buff + used, size - used, "unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
if (i != num - 1)
|
||||
{
|
||||
used += snprintf(buff + used, size - used, ":");
|
||||
}
|
||||
}
|
||||
|
||||
return used;
|
||||
}
|
||||
|
||||
static void packet_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
|
||||
{
|
||||
struct options *opts = (struct options *)user;
|
||||
|
||||
struct packet pkt;
|
||||
packet_parse(&pkt, (const char *)bytes, h->caplen);
|
||||
packet_print_table(&pkt);
|
||||
number++;
|
||||
|
||||
if (opts->print_summary)
|
||||
{
|
||||
printf("\033[0;32m frame=%lu len=%u \033[0m", number, h->caplen);
|
||||
packet_print_str(&pkt);
|
||||
}
|
||||
|
||||
if (opts->print_proto)
|
||||
{
|
||||
char buff[1024] = {0};
|
||||
packet_proto_to_str(&pkt, buff, sizeof(buff));
|
||||
printf("%lu %s\n", number, buff);
|
||||
}
|
||||
}
|
||||
|
||||
static void usage(char *cmd)
|
||||
@@ -14,6 +109,8 @@ static void usage(char *cmd)
|
||||
printf("Usage: %s\n", cmd);
|
||||
printf("Options:\n");
|
||||
printf(" -f <pcap file> pcap file\n");
|
||||
printf(" -p print protocol\n");
|
||||
printf(" -s print summary\n");
|
||||
printf(" -h print help\n");
|
||||
printf("\n");
|
||||
}
|
||||
@@ -21,36 +118,40 @@ static void usage(char *cmd)
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int opt = 0;
|
||||
char *file = NULL;
|
||||
while ((opt = getopt(argc, argv, "f:h")) != -1)
|
||||
struct options opts = {0};
|
||||
while ((opt = getopt(argc, argv, "f:psh")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'f':
|
||||
file = optarg;
|
||||
opts.file = optarg;
|
||||
break;
|
||||
case 'p':
|
||||
opts.print_proto = 1;
|
||||
break;
|
||||
case 's':
|
||||
opts.print_summary = 1;
|
||||
break;
|
||||
case 'h':
|
||||
usage(argv[0]);
|
||||
return 0;
|
||||
default:
|
||||
usage(argv[0]);
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (file == NULL)
|
||||
if (opts.file == NULL)
|
||||
{
|
||||
usage(argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pcap_t *pcap = pcap_open_offline(file, NULL);
|
||||
pcap_t *pcap = pcap_open_offline(opts.file, NULL);
|
||||
if (pcap == NULL)
|
||||
{
|
||||
printf("pcap_open_offline() failed\n");
|
||||
return -1;
|
||||
}
|
||||
pcap_loop(pcap, -1, packet_handler, NULL);
|
||||
pcap_loop(pcap, -1, packet_handler, (u_char *)&opts);
|
||||
pcap_close(pcap);
|
||||
|
||||
return 0;
|
||||
|
||||
19
test/packet_parser/split_pcap.sh
Normal file
19
test/packet_parser/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