diff --git a/include/packet.h b/include/packet.h index b3a85a5..0f8d8e8 100644 --- a/include/packet.h +++ b/include/packet.h @@ -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), diff --git a/src/duplicated_packet_filter/duplicated_packet_filter.cpp b/src/duplicated_packet_filter/duplicated_packet_filter.cpp index cdfa8c3..4235378 100644 --- a/src/duplicated_packet_filter/duplicated_packet_filter.cpp +++ b/src/duplicated_packet_filter/duplicated_packet_filter.cpp @@ -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; diff --git a/src/packet/packet.cpp b/src/packet/packet.cpp index 2224041..2984073 100644 --- a/src/packet/packet.cpp +++ b/src/packet/packet.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #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; diff --git a/src/packet/test/gtest_packet.cpp b/src/packet/test/gtest_packet.cpp index a4a3e5d..a434197 100644 --- a/src/packet/test/gtest_packet.cpp +++ b/src/packet/test/gtest_packet.cpp @@ -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) {