feature: support crafting L3 packets with L3 payload

This commit is contained in:
luwenpeng
2024-08-12 10:49:53 +08:00
parent 12975e2da7
commit 8054b9c032
7 changed files with 306 additions and 219 deletions

View File

@@ -1,6 +1,7 @@
#include <gtest/gtest.h>
#include <arpa/inet.h>
#include "checksum.h"
#include "tcp_utils.h"
#include "udp_utils.h"
#include "ip4_utils.h"
@@ -1017,7 +1018,203 @@ TEST(PACKET_CRAFT_UDP, ETH_VLAN_IPv6_IPv4_GRE_PPP_IPv4_UDP_DNS)
continue;
}
printf(("idx: %d, orig: %02x, new: %02x\n"), i, orig_pkt_data[i], new_pkt_data[i]);
// printf(("idx: %d, orig: %02x, new: %02x\n"), i, orig_pkt_data[i], new_pkt_data[i]);
EXPECT_TRUE(orig_pkt_data[i] == new_pkt_data[i]);
}
packet_free(new_pkt);
}
#endif
/*
* craft_l3_packet()
* -> ETH->IPv4->ICMP
* -> ICMPv4 checkum not include the pseudo-header of IPv4 header
*/
#if 1
TEST(PACKET_CRAFT_L3, ETH_IP4_ICMP)
{
/*
* Internet Control Message Protocol
* Type: 8 (Echo (ping) request)
* Code: 0
* Checksum: 0xaa4f [correct]
* [Checksum Status: Good]
* Identifier (BE): 27498 (0x6b6a)
* Identifier (LE): 27243 (0x6a6b)
* Sequence Number (BE): 0 (0x0000)
* Sequence Number (LE): 0 (0x0000)
* [Response frame: 31]
* Timestamp from icmp data: Aug 2, 2024 10:51:12.214771000 CST
* [Timestamp from icmp data (relative): 0.000093000 seconds]
* Data (48 bytes)
* Data: 08090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f3031323334353637
* [Length: 48]
*/
unsigned char icmp_resp[] = {
0x08, 0x00, 0xaa, 0x4f, 0x6b, 0x6a, 0x00, 0x00, 0x66, 0xac, 0x49, 0xa0, 0x00, 0x03, 0x46, 0xf3, 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, 0x34, 0x35, 0x36, 0x37};
struct packet orig_pkt;
memset(&orig_pkt, 0, sizeof(orig_pkt));
packet_parse(&orig_pkt, (const char *)data1, sizeof(data1));
PRINT_GREEN("origin packet:");
packet_print(&orig_pkt);
struct icmphdr *icmp = (struct icmphdr *)icmp_resp;
icmp->checksum = 0;
icmp->checksum = checksum(icmp, sizeof(icmp_resp));
struct packet *new_pkt = craft_l3_packet(&orig_pkt, IPPROTO_ICMP, (const char *)icmp_resp, sizeof(icmp_resp));
EXPECT_TRUE(new_pkt != nullptr);
PRINT_GREEN("new packet:");
packet_print(new_pkt);
packet_dump_hex(new_pkt, STDOUT_FILENO);
packet_dump_pcap(new_pkt, "craft-eth-ipv4-icmpv4.pcap");
const char *orig_pkt_data = packet_get_raw_data(&orig_pkt);
uint16_t orig_pkt_len = packet_get_raw_len(&orig_pkt);
const char *new_pkt_data = packet_get_raw_data(new_pkt);
uint16_t new_pkt_len = packet_get_raw_len(new_pkt);
EXPECT_TRUE(orig_pkt_len - 20 - 6 == // trim Eth padding, trim TCP header
new_pkt_len - 64); // trim ICMP
struct layer layer;
PACKET_FOREACH_LAYER_INORDER(new_pkt, layer)
{
if (layer.proto == LAYER_PROTO_IPV4)
{
const struct ip *ip = (const struct ip *)layer.hdr.raw;
EXPECT_TRUE(ip4_hdr_get_total_len(ip) == 84);
EXPECT_TRUE(ip4_hdr_get_checksum(ip) == 0xb7cb);
break;
}
if (layer.proto == LAYER_PROTO_ICMP)
{
// TODO
break;
}
}
for (uint16_t i = 0; i < new_pkt_len - sizeof(icmp_resp); i++)
{
if ((16 <= i && i <= 17) || // skip IPv4 total length
23 == i || // skip IPv4 protocol
(24 <= i && i <= 25)) // skip IPv4 checksum
{
continue;
}
// printf(("idx: %d, orig: %02x, new: %02x\n"), i, orig_pkt_data[i], new_pkt_data[i]);
EXPECT_TRUE(orig_pkt_data[i] == new_pkt_data[i]);
}
packet_free(new_pkt);
}
#endif
/*
* craft_l3_packet()
* -> ETH->IPv4->IPv6->ICMPv6
* -> ICMPv6 checkum need include the pseudo-header of IPv6 header
*/
#if 1
TEST(PACKET_CRAFT_L3, ETH_IP6_ICMP)
{
/*
* Internet Control Message Protocol v6
* Type: Echo (ping) request (128)
* Code: 0
* Checksum: 0x7e8f [correct]
* [Checksum Status: Good]
* Identifier: 0x18dc
* Sequence: 0
* [Response In: 2]
* Data (52 bytes)
* Data: 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f30313233
* [Length: 52]
*/
unsigned char icmp_resp[] = {
0x80, 0x00, 0x7e, 0x8f, 0x18, 0xdc, 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};
struct packet orig_pkt;
memset(&orig_pkt, 0, sizeof(orig_pkt));
packet_parse(&orig_pkt, (const char *)data2, sizeof(data2));
PRINT_GREEN("origin packet:");
packet_print(&orig_pkt);
struct icmp6_hdr *icmp = (struct icmp6_hdr *)icmp_resp;
icmp->icmp6_cksum = 0;
struct layer layer;
PACKET_FOREACH_LAYER_REVERSE(&orig_pkt, layer)
{
if (layer.proto == LAYER_PROTO_IPV6)
{
struct ip6_hdr *ip6 = (struct ip6_hdr *)layer.hdr.raw;
icmp->icmp6_cksum = checksum_v6(icmp, sizeof(icmp_resp), IPPROTO_ICMPV6, &ip6->ip6_src, &ip6->ip6_dst);
break;
}
}
struct packet *new_pkt = craft_l3_packet(&orig_pkt, IPPROTO_ICMPV6, (const char *)icmp_resp, sizeof(icmp_resp));
EXPECT_TRUE(new_pkt != nullptr);
PRINT_GREEN("new packet:");
packet_print(new_pkt);
packet_dump_hex(new_pkt, STDOUT_FILENO);
packet_dump_pcap(new_pkt, "craft-eth-ipv4-ipv6-icmpv6.pcap");
const char *orig_pkt_data = packet_get_raw_data(&orig_pkt);
uint16_t orig_pkt_len = packet_get_raw_len(&orig_pkt);
const char *new_pkt_data = packet_get_raw_data(new_pkt);
uint16_t new_pkt_len = packet_get_raw_len(new_pkt);
EXPECT_TRUE(orig_pkt_len - 32 == // trim TCP header
new_pkt_len - 60); // trim ICMPv6 header
PACKET_FOREACH_LAYER_INORDER(new_pkt, layer)
{
if (layer.proto == LAYER_PROTO_IPV4)
{
const struct ip *ip = (const struct ip *)layer.hdr.raw;
EXPECT_TRUE(ip4_hdr_get_total_len(ip) == 120);
EXPECT_TRUE(ip4_hdr_get_checksum(ip) == 0x09ac);
break;
}
if (layer.proto == LAYER_PROTO_IPV6)
{
const struct ip6_hdr *ip6 = (const struct ip6_hdr *)layer.hdr.raw;
EXPECT_TRUE(ip6_hdr_get_payload_len(ip6) == 60);
break;
}
if (layer.proto == LAYER_PROTO_ICMP6)
{
// TODO
break;
}
}
for (uint16_t i = 0; i < new_pkt_len - 60; i++)
{
if ((16 <= i && i <= 17) || // skip IPv4 total length
(24 <= i && i <= 25)) // skip IPv4 checksum
{
continue;
}
if (38 <= i && i <= 39) // skip IPv6 payload length
{
continue;
}
if (40 == i) // skip IPv6 next header
{
continue;
}
// printf(("idx: %d, orig: %02x, new: %02x\n"), i, orig_pkt_data[i], new_pkt_data[i]);
EXPECT_TRUE(orig_pkt_data[i] == new_pkt_data[i]);
}