feature: support crafting L3 packets with L3 payload
This commit is contained in:
@@ -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]);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user