Add support for parsing ICMP and ICMPv6 packets in packet parser

This commit is contained in:
luwenpeng
2024-04-22 16:38:24 +08:00
parent dd32f0f231
commit 8a41a79f06
4 changed files with 332 additions and 8 deletions

View File

@@ -34,11 +34,13 @@ enum layer_type
// L4 -- transport layer
LAYER_TYPE_UDP = 1 << 9,
LAYER_TYPE_TCP = 1 << 10,
LAYER_TYPE_L4 = (LAYER_TYPE_UDP | LAYER_TYPE_TCP),
LAYER_TYPE_ICMP = 1 << 11,
LAYER_TYPE_ICMP6 = 1 << 12,
LAYER_TYPE_L4 = (LAYER_TYPE_UDP | LAYER_TYPE_TCP | LAYER_TYPE_ICMP | LAYER_TYPE_ICMP6),
// L4 -- tunnel
LAYER_TYPE_VXLAN = 1 << 11,
LAYER_TYPE_GTPV1_U = 1 << 12,
LAYER_TYPE_VXLAN = 1 << 13,
LAYER_TYPE_GTPV1_U = 1 << 14,
// ALL
LAYER_TYPE_ALL = (LAYER_TYPE_L2 | LAYER_TYPE_L2_TUN | LAYER_TYPE_L3 | LAYER_TYPE_L3_TUN | LAYER_TYPE_L4 | LAYER_TYPE_VXLAN | LAYER_TYPE_GTPV1_U),

View File

@@ -39,7 +39,7 @@ static inline int duplicated_packet_key_get(const struct packet *packet, struct
{
return -1;
}
const struct packet_layer *l4_layer = packet_get_innermost_layer(packet, LAYER_TYPE_L4);
const struct packet_layer *l4_layer = packet_get_innermost_layer(packet, (enum layer_type)(LAYER_TYPE_TCP | LAYER_TYPE_UDP));
if (l4_layer == NULL)
{
return -1;

View File

@@ -6,6 +6,8 @@
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <netinet/ether.h>
#include <netinet/icmp6.h>
#include <netinet/ip_icmp.h>
#include <linux/ppp_defs.h>
#include "uthash.h"
@@ -75,6 +77,8 @@ static inline const char *parse_gre(struct packet *pkt, const char *data, uint16
// 传输层
static inline const char *parse_udp(struct packet *pkt, const char *data, uint16_t len);
static inline const char *parse_tcp(struct packet *pkt, const char *data, uint16_t len);
static inline const char *parse_icmp(struct packet *pkt, const char *data, uint16_t len);
static inline const char *parse_icmp6(struct packet *pkt, const char *data, uint16_t len);
// 传输层 -- 隧道
static inline const char *parse_vxlan(struct packet *pkt, const char *data, uint16_t len);
static inline const char *parse_gtpv1_u(struct packet *pkt, const char *data, uint16_t len);
@@ -1009,6 +1013,42 @@ static inline const char *parse_tcp(struct packet *pkt, const char *data, uint16
return layer->pld_ptr;
}
static inline const char *parse_icmp(struct packet *pkt, const char *data, uint16_t len)
{
if (unlikely(len < sizeof(struct icmphdr)))
{
PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_ICMP);
return data;
}
struct packet_layer *layer = get_free_layer(pkt);
if (unlikely(layer == NULL))
{
return data;
}
SET_LAYER(pkt, layer, LAYER_TYPE_ICMP, sizeof(struct icmphdr), data, len);
return layer->pld_ptr;
}
static inline const char *parse_icmp6(struct packet *pkt, const char *data, uint16_t len)
{
if (unlikely(len < sizeof(struct icmp6_hdr)))
{
PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_ICMP6);
return data;
}
struct packet_layer *layer = get_free_layer(pkt);
if (unlikely(layer == NULL))
{
return data;
}
SET_LAYER(pkt, layer, LAYER_TYPE_ICMP6, sizeof(struct icmp6_hdr), data, len);
return layer->pld_ptr;
}
static inline const char *parse_vxlan(struct packet *pkt, const char *data, uint16_t len)
{
struct vxlan_hdr
@@ -1113,6 +1153,12 @@ static inline const char *parse_l4(struct packet *pkt, uint8_t next_proto, const
// TESTED
case IPPROTO_GRE:
return parse_gre(pkt, data, len);
// TESTED
case IPPROTO_ICMP:
return parse_icmp(pkt, data, len);
// TESTED
case IPPROTO_ICMPV6:
return parse_icmp6(pkt, data, len);
default:
PACKET_LOG_UNSUPPORT_IPPROTO("l4", next_proto);
return data;
@@ -1216,7 +1262,7 @@ int packet_get_innermost_tuple4(const struct packet *pkt, struct tuple4 *tuple)
layer = &pkt->layers[i];
// first get L4 layer
if (layer->type & LAYER_TYPE_L4)
if (layer->type & (LAYER_TYPE_UDP | LAYER_TYPE_TCP))
{
layer_l4 = layer;
continue;
@@ -1263,7 +1309,7 @@ int packet_get_outermost_tuple4(const struct packet *pkt, struct tuple4 *tuple)
}
// second get L4 layer
if (layer->type & LAYER_TYPE_L4)
if (layer->type & (LAYER_TYPE_UDP | LAYER_TYPE_TCP))
{
layer_l4 = layer;
break;
@@ -1297,7 +1343,7 @@ int packet_get_innermost_tuple6(const struct packet *pkt, struct tuple6 *tuple)
layer = &pkt->layers[i];
// first get L4 layer
if (layer->type & LAYER_TYPE_L4)
if (layer->type & (LAYER_TYPE_UDP | LAYER_TYPE_TCP))
{
layer_l4 = layer;
continue;
@@ -1345,7 +1391,7 @@ int packet_get_outermost_tuple6(const struct packet *pkt, struct tuple6 *tuple)
}
// second get L4 layer
if (layer->type & LAYER_TYPE_L4)
if (layer->type & (LAYER_TYPE_UDP | LAYER_TYPE_TCP))
{
layer_l4 = layer;
break;

View File

@@ -2678,6 +2678,282 @@ TEST(PACKET, ETH_MPLS_MPLS_PWETHCW_ETH_ARP)
}
#endif
/******************************************************************************
* [Protocols in frame: eth:ethertype:ip:icmp:data]
******************************************************************************
*
* Frame 1: 98 bytes on wire (784 bits), 98 bytes captured (784 bits)
* Ethernet II, Src: EvocIntellig_36:51:46 (00:22:46:36:51:46), Dst: EvocIntellig_36:51:3c (00:22:46:36:51:3c)
* Destination: EvocIntellig_36:51:3c (00:22:46:36:51:3c)
* Source: EvocIntellig_36:51:46 (00:22:46:36:51:46)
* Type: IPv4 (0x0800)
* Internet Protocol Version 4, Src: 192.168.40.138, Dst: 192.168.40.134
* 0100 .... = Version: 4
* .... 0101 = Header Length: 20 bytes (5)
* Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
* 0000 00.. = Differentiated Services Codepoint: Default (0)
* .... ..00 = Explicit Congestion Notification: Not ECN-Capable Transport (0)
* Total Length: 84
* Identification: 0x22f6 (8950)
* 010. .... = Flags: 0x2, Don't fragment
* 0... .... = Reserved bit: Not set
* .1.. .... = Don't fragment: Set
* ..0. .... = More fragments: Not set
* ...0 0000 0000 0000 = Fragment Offset: 0
* Time to Live: 64
* Protocol: ICMP (1)
* Header Checksum: 0x4552 [correct]
* [Header checksum status: Good]
* [Calculated Checksum: 0x4552]
* Source Address: 192.168.40.138
* Destination Address: 192.168.40.134
* Internet Control Message Protocol
* Type: 8 (Echo (ping) request)
* Code: 0
* Checksum: 0xab05 [correct]
* [Checksum Status: Good]
* Identifier (BE): 24363 (0x5f2b)
* Identifier (LE): 11103 (0x2b5f)
* Sequence Number (BE): 1 (0x0001)
* Sequence Number (LE): 256 (0x0100)
* [Response frame: 2]
* Timestamp from icmp data: Jun 17, 2020 14:17:58.190124000 CST
* [Timestamp from icmp data (relative): -0.134576000 seconds]
* Data (40 bytes)
* Data: 101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
* [Length: 40]
*/
unsigned char data13[] = {
0x00, 0x22, 0x46, 0x36, 0x51, 0x3c, 0x00, 0x22, 0x46, 0x36, 0x51, 0x46, 0x08, 0x00, 0x45, 0x00, 0x00, 0x54, 0x22, 0xf6, 0x40, 0x00, 0x40, 0x01, 0x45, 0x52,
0xc0, 0xa8, 0x28, 0x8a, 0xc0, 0xa8, 0x28, 0x86, 0x08, 0x00, 0xab, 0x05, 0x5f, 0x2b, 0x00, 0x01, 0x96, 0xb5, 0xe9, 0x5e, 0x00, 0x00, 0x00, 0x00, 0xac, 0xe6,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37};
#if 1
TEST(PACKET, ETH_IP4_ICMP)
{
char buffer[256];
struct packet handler;
const char *payload = packet_parse(&handler, (const char *)data13, sizeof(data13));
EXPECT_TRUE(payload != nullptr);
EXPECT_TRUE((char *)payload - (char *)&data13 == 14 + 20 + 8);
packet_print(&handler);
/******************************************************
* packet_get_outermost/innermost_layer
******************************************************/
// LAYER_TYPE_ETHER
const struct packet_layer *outer_eth_record = packet_get_outermost_layer(&handler, LAYER_TYPE_ETHER);
const struct packet_layer *inner_eth_record = packet_get_innermost_layer(&handler, LAYER_TYPE_ETHER);
EXPECT_TRUE(outer_eth_record != nullptr);
EXPECT_TRUE(inner_eth_record != nullptr);
EXPECT_TRUE(outer_eth_record == inner_eth_record);
EXPECT_TRUE(outer_eth_record->hdr_offset == 0);
EXPECT_TRUE(outer_eth_record->hdr_len == 14);
EXPECT_TRUE(outer_eth_record->pld_len == 84);
// LAYER_TYPE_L2
const struct packet_layer *outer_l2_record = packet_get_outermost_layer(&handler, LAYER_TYPE_L2);
const struct packet_layer *inner_l2_record = packet_get_innermost_layer(&handler, LAYER_TYPE_L2);
EXPECT_TRUE(outer_l2_record != nullptr);
EXPECT_TRUE(inner_l2_record != nullptr);
EXPECT_TRUE(outer_l2_record == inner_l2_record);
EXPECT_TRUE(outer_l2_record == outer_eth_record);
// LAYER_TYPE_IPV4
const struct packet_layer *outer_ipv4_record = packet_get_outermost_layer(&handler, LAYER_TYPE_IPV4);
const struct packet_layer *inner_ipv4_record = packet_get_innermost_layer(&handler, LAYER_TYPE_IPV4);
EXPECT_TRUE(outer_ipv4_record != nullptr);
EXPECT_TRUE(inner_ipv4_record != nullptr);
EXPECT_TRUE(outer_ipv4_record == inner_ipv4_record);
EXPECT_TRUE(outer_ipv4_record->hdr_offset == 14);
EXPECT_TRUE(outer_ipv4_record->hdr_len == 20);
EXPECT_TRUE(outer_ipv4_record->pld_len == 64);
// LAYER_TYPE_L3
const struct packet_layer *outer_l3_record = packet_get_outermost_layer(&handler, LAYER_TYPE_L3);
const struct packet_layer *inner_l3_record = packet_get_innermost_layer(&handler, LAYER_TYPE_L3);
EXPECT_TRUE(outer_l3_record != nullptr);
EXPECT_TRUE(inner_l3_record != nullptr);
EXPECT_TRUE(outer_l3_record == inner_l3_record);
EXPECT_TRUE(outer_l3_record == outer_ipv4_record);
// LAYER_TYPE_ICMP
const struct packet_layer *outer_icmp_record = packet_get_outermost_layer(&handler, LAYER_TYPE_ICMP);
const struct packet_layer *inner_icmp_record = packet_get_innermost_layer(&handler, LAYER_TYPE_ICMP);
EXPECT_TRUE(outer_icmp_record != nullptr);
EXPECT_TRUE(inner_icmp_record != nullptr);
EXPECT_TRUE(outer_icmp_record == inner_icmp_record);
EXPECT_TRUE(outer_icmp_record->hdr_offset == 34);
EXPECT_TRUE(outer_icmp_record->hdr_len == 8);
EXPECT_TRUE(outer_icmp_record->pld_len == 56);
// LAYER_TYPE_L4
const struct packet_layer *outer_l4_record = packet_get_outermost_layer(&handler, LAYER_TYPE_L4);
const struct packet_layer *inner_l4_record = packet_get_innermost_layer(&handler, LAYER_TYPE_L4);
EXPECT_TRUE(outer_l4_record != nullptr);
EXPECT_TRUE(inner_l4_record != nullptr);
EXPECT_TRUE(outer_l4_record == inner_l4_record);
EXPECT_TRUE(outer_l4_record == outer_icmp_record);
/******************************************************
* packet_get_outermost/innermost_tuple2
******************************************************/
struct tuple2 outer_tuple2;
struct tuple2 inner_tuple2;
EXPECT_TRUE(packet_get_outermost_tuple2(&handler, &outer_tuple2) == 0);
EXPECT_TRUE(packet_get_innermost_tuple2(&handler, &inner_tuple2) == 0);
memset(buffer, 0, sizeof(buffer));
tuple2_to_str(&outer_tuple2, buffer, sizeof(buffer));
EXPECT_STREQ(buffer, "192.168.40.138 -> 192.168.40.134");
memset(buffer, 0, sizeof(buffer));
tuple2_to_str(&inner_tuple2, buffer, sizeof(buffer));
EXPECT_STREQ(buffer, "192.168.40.138 -> 192.168.40.134");
}
#endif
/******************************************************************************
* [Protocols in frame: eth:ethertype:ipv6:icmpv6:data]
******************************************************************************
*
* Frame 1: 114 bytes on wire (912 bits), 114 bytes captured (912 bits)
* Ethernet II, Src: c2:00:51:fa:00:00 (c2:00:51:fa:00:00), Dst: c2:01:51:fa:00:00 (c2:01:51:fa:00:00)
* Destination: c2:01:51:fa:00:00 (c2:01:51:fa:00:00)
* Source: c2:00:51:fa:00:00 (c2:00:51:fa:00:00)
* Type: IPv6 (0x86dd)
* Internet Protocol Version 6, Src: 2001:db8:0:12::1, Dst: 2001:db8:0:12::2
* 0110 .... = Version: 6
* .... 0000 0000 .... .... .... .... .... = Traffic Class: 0x00 (DSCP: CS0, ECN: Not-ECT)
* .... 0000 00.. .... .... .... .... .... = Differentiated Services Codepoint: Default (0)
* .... .... ..00 .... .... .... .... .... = Explicit Congestion Notification: Not ECN-Capable Transport (0)
* .... 0000 0000 0000 0000 0000 = Flow Label: 0x00000
* Payload Length: 60
* Next Header: ICMPv6 (58)
* Hop Limit: 64
* Source Address: 2001:db8:0:12::1
* Destination Address: 2001:db8:0:12::2
* Internet Control Message Protocol v6
* Type: Echo (ping) request (128)
* Code: 0
* Checksum: 0x863c [correct]
* [Checksum Status: Good]
* Identifier: 0x110d
* Sequence: 0
* [Response In: 2]
* Data (52 bytes)
* Data: 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233
* [Length: 52]
*/
unsigned char data14[] = {
0xc2, 0x01, 0x51, 0xfa, 0x00, 0x00, 0xc2, 0x00, 0x51, 0xfa, 0x00, 0x00, 0x86, 0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x3a, 0x40, 0x20, 0x01, 0x0d, 0xb8,
0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x80, 0x00, 0x86, 0x3c, 0x11, 0x0d, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29,
0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33};
#if 1
TEST(PACKET, ETH_IP6_ICMP6)
{
char buffer[256];
struct packet handler;
const char *payload = packet_parse(&handler, (const char *)data14, sizeof(data14));
EXPECT_TRUE(payload != nullptr);
EXPECT_TRUE((char *)payload - (char *)&data14 == 14 + 40 + 8);
packet_print(&handler);
/******************************************************
* packet_get_outermost/innermost_layer
******************************************************/
// LAYER_TYPE_ETHER
const struct packet_layer *outer_eth_record = packet_get_outermost_layer(&handler, LAYER_TYPE_ETHER);
const struct packet_layer *inner_eth_record = packet_get_innermost_layer(&handler, LAYER_TYPE_ETHER);
EXPECT_TRUE(outer_eth_record != nullptr);
EXPECT_TRUE(inner_eth_record != nullptr);
EXPECT_TRUE(outer_eth_record == inner_eth_record);
EXPECT_TRUE(outer_eth_record->hdr_offset == 0);
EXPECT_TRUE(outer_eth_record->hdr_len == 14);
EXPECT_TRUE(outer_eth_record->pld_len == 100);
// LAYER_TYPE_L2
const struct packet_layer *outer_l2_record = packet_get_outermost_layer(&handler, LAYER_TYPE_L2);
const struct packet_layer *inner_l2_record = packet_get_innermost_layer(&handler, LAYER_TYPE_L2);
EXPECT_TRUE(outer_l2_record != nullptr);
EXPECT_TRUE(inner_l2_record != nullptr);
EXPECT_TRUE(outer_l2_record == inner_l2_record);
EXPECT_TRUE(outer_l2_record == outer_eth_record);
// LAYER_TYPE_IPV6
const struct packet_layer *outer_ipv6_record = packet_get_outermost_layer(&handler, LAYER_TYPE_IPV6);
const struct packet_layer *inner_ipv6_record = packet_get_innermost_layer(&handler, LAYER_TYPE_IPV6);
EXPECT_TRUE(outer_ipv6_record != nullptr);
EXPECT_TRUE(inner_ipv6_record != nullptr);
EXPECT_TRUE(outer_ipv6_record == inner_ipv6_record);
EXPECT_TRUE(outer_ipv6_record->hdr_offset == 14);
EXPECT_TRUE(outer_ipv6_record->hdr_len == 40);
EXPECT_TRUE(outer_ipv6_record->pld_len == 60);
// LAYER_TYPE_L3
const struct packet_layer *outer_l3_record = packet_get_outermost_layer(&handler, LAYER_TYPE_L3);
const struct packet_layer *inner_l3_record = packet_get_innermost_layer(&handler, LAYER_TYPE_L3);
EXPECT_TRUE(outer_l3_record != nullptr);
EXPECT_TRUE(inner_l3_record != nullptr);
EXPECT_TRUE(outer_l3_record == inner_l3_record);
EXPECT_TRUE(outer_l3_record == outer_ipv6_record);
// LAYER_TYPE_ICMP6
const struct packet_layer *outer_icmp6_record = packet_get_outermost_layer(&handler, LAYER_TYPE_ICMP6);
const struct packet_layer *inner_icmp6_record = packet_get_innermost_layer(&handler, LAYER_TYPE_ICMP6);
EXPECT_TRUE(outer_icmp6_record != nullptr);
EXPECT_TRUE(inner_icmp6_record != nullptr);
EXPECT_TRUE(outer_icmp6_record == inner_icmp6_record);
EXPECT_TRUE(outer_icmp6_record->hdr_offset == 54);
EXPECT_TRUE(outer_icmp6_record->hdr_len == 8);
EXPECT_TRUE(outer_icmp6_record->pld_len == 52);
// LAYER_TYPE_L4
const struct packet_layer *outer_l4_record = packet_get_outermost_layer(&handler, LAYER_TYPE_L4);
const struct packet_layer *inner_l4_record = packet_get_innermost_layer(&handler, LAYER_TYPE_L4);
EXPECT_TRUE(outer_l4_record != nullptr);
EXPECT_TRUE(inner_l4_record != nullptr);
EXPECT_TRUE(outer_l4_record == inner_l4_record);
EXPECT_TRUE(outer_l4_record == outer_icmp6_record);
/******************************************************
* packet_get_outermost/innermost_tuple2
******************************************************/
struct tuple2 outer_tuple2;
struct tuple2 inner_tuple2;
EXPECT_TRUE(packet_get_outermost_tuple2(&handler, &outer_tuple2) == 0);
EXPECT_TRUE(packet_get_innermost_tuple2(&handler, &inner_tuple2) == 0);
memset(buffer, 0, sizeof(buffer));
tuple2_to_str(&outer_tuple2, buffer, sizeof(buffer));
EXPECT_STREQ(buffer, "2001:db8:0:12::1 -> 2001:db8:0:12::2");
memset(buffer, 0, sizeof(buffer));
tuple2_to_str(&inner_tuple2, buffer, sizeof(buffer));
EXPECT_STREQ(buffer, "2001:db8:0:12::1 -> 2001:db8:0:12::2");
}
#endif
#if 1
TEST(PACKET, HASH_VALUE)
{