Add tools packet_parser

This commit is contained in:
luwenpeng
2024-05-29 17:55:44 +08:00
parent ba1e651876
commit 963aa259b1
9 changed files with 299 additions and 20 deletions

View File

@@ -6,6 +6,7 @@ extern "C"
{ {
#endif #endif
#include <stdio.h>
#include <string.h> #include <string.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netinet/ip.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)); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@@ -6,6 +6,7 @@ extern "C"
{ {
#endif #endif
#include <stdio.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netinet/ip6.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 #ifdef __cplusplus
} }
#endif #endif

View File

@@ -1021,9 +1021,9 @@ static inline const char *parse_ipv4(struct packet *pkt, const char *data, uint1
// ip fragmented // ip fragmented
if (ipv4_hdr_get_mf_flag(hdr) || ipv4_hdr_get_frag_offset(hdr)) 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; pkt->frag_layer = layer;
return layer->pld_ptr; // try continue parse
} }
// TESTED // TESTED
@@ -1057,9 +1057,9 @@ static inline const char *parse_ipv6(struct packet *pkt, const char *data, uint1
// ipv6 fragment // ipv6 fragment
if (next_proto == IPPROTO_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; pkt->frag_layer = layer;
return layer->pld_ptr; // try continue parse
} }
// TODO parse ipv6 extension headers // TODO parse ipv6 extension headers
@@ -1363,21 +1363,63 @@ void packet_print_str(const struct packet *pkt)
return; return;
} }
char buffer[2048] = {0};
printf("packet: %p, data_ptr: %p, data_len: %u, layers_used: %u, layers_size: %u\n", printf("packet: %p, data_ptr: %p, data_len: %u, layers_used: %u, layers_size: %u\n",
pkt, pkt->data_ptr, pkt->data_len, pkt, pkt->data_ptr, pkt->data_len,
pkt->layers_used, pkt->layers_size); pkt->layers_used, pkt->layers_size);
for (uint8_t i = 0; i < pkt->layers_used; i++) for (uint8_t i = 0; i < pkt->layers_used; i++)
{ {
int used = 0;
const struct packet_layer *layer = &pkt->layers[i]; 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", 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, i, layer, layer_type_to_str(layer->type), layer->hdr_offset,
layer->hdr_ptr, layer->hdr_len, layer->pld_ptr, layer->pld_len); layer->hdr_ptr, layer->hdr_len, layer->pld_ptr, layer->pld_len);
switch (layer->type)
{
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);
}
} }
for (uint16_t i = 0; i < pkt->data_len; i++)
{
printf("0x%02x, ", (uint8_t)pkt->data_ptr[i]);
}
printf("\n");
} }
void packet_print_table(const struct packet *pkt) void packet_print_table(const struct packet *pkt)

View File

@@ -6,6 +6,7 @@ extern "C"
{ {
#endif #endif
#include <stdio.h>
#include <string.h> #include <string.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#define __FAVOR_BSD 1 #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)); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@@ -6,6 +6,7 @@ extern "C"
{ {
#endif #endif
#include <stdio.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#define __FAVOR_BSD 1 #define __FAVOR_BSD 1
#include <netinet/udp.h> #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); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@@ -1,3 +1,6 @@
# build packet_parser # build packet_parser
add_executable(packet_parser packet_parser.cpp) add_executable(packet_parser packet_parser.cpp)
target_link_libraries(packet_parser packet pcap) 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})

View 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

View File

@@ -2,11 +2,106 @@
#include <pcap/pcap.h> #include <pcap/pcap.h>
#include "packet_priv.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) 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; struct packet pkt;
packet_parse(&pkt, (const char *)bytes, h->caplen); 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) static void usage(char *cmd)
@@ -14,6 +109,8 @@ static void usage(char *cmd)
printf("Usage: %s\n", cmd); printf("Usage: %s\n", cmd);
printf("Options:\n"); printf("Options:\n");
printf(" -f <pcap file> pcap file\n"); printf(" -f <pcap file> pcap file\n");
printf(" -p print protocol\n");
printf(" -s print summary\n");
printf(" -h print help\n"); printf(" -h print help\n");
printf("\n"); printf("\n");
} }
@@ -21,36 +118,40 @@ static void usage(char *cmd)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int opt = 0; int opt = 0;
char *file = NULL; struct options opts = {0};
while ((opt = getopt(argc, argv, "f:h")) != -1) while ((opt = getopt(argc, argv, "f:psh")) != -1)
{ {
switch (opt) switch (opt)
{ {
case 'f': case 'f':
file = optarg; opts.file = optarg;
break;
case 'p':
opts.print_proto = 1;
break;
case 's':
opts.print_summary = 1;
break; break;
case 'h': case 'h':
usage(argv[0]);
return 0;
default: default:
usage(argv[0]); usage(argv[0]);
return -1; return 0;
} }
} }
if (file == NULL) if (opts.file == NULL)
{ {
usage(argv[0]); usage(argv[0]);
return -1; return -1;
} }
pcap_t *pcap = pcap_open_offline(file, NULL); pcap_t *pcap = pcap_open_offline(opts.file, NULL);
if (pcap == NULL) if (pcap == NULL)
{ {
printf("pcap_open_offline() failed\n"); printf("pcap_open_offline() failed\n");
return -1; return -1;
} }
pcap_loop(pcap, -1, packet_handler, NULL); pcap_loop(pcap, -1, packet_handler, (u_char *)&opts);
pcap_close(pcap); pcap_close(pcap);
return 0; return 0;

View 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"