diff --git a/include/stellar/layer.h b/include/stellar/layer.h index 947d373..6250481 100644 --- a/include/stellar/layer.h +++ b/include/stellar/layer.h @@ -56,15 +56,16 @@ struct layer uint16_t hdr_len; union { - struct ethhdr *eth; - struct ip *ip4; - struct ip6_hdr *ip6; - struct tcphdr *tcp; - struct udphdr *udp; - struct icmphdr *icmp4; - struct icmp6_hdr *icmp6; - struct mpls_label *mpls; - char *raw; + // all hdr ptr refer to raw packet, read-only + const struct ethhdr *eth; + const struct ip *ip4; + const struct ip6_hdr *ip6; + const struct tcphdr *tcp; + const struct udphdr *udp; + const struct icmphdr *icmp4; + const struct icmp6_hdr *icmp6; + const struct mpls_label *mpls; + const char *raw; // e.g. pppoe, l2tp, gre, gtp, etc. } hdr; }; diff --git a/include/stellar/packet.h b/include/stellar/packet.h index a540046..2d760e9 100644 --- a/include/stellar/packet.h +++ b/include/stellar/packet.h @@ -42,10 +42,10 @@ uint16_t packet_get_payload_len(const struct packet *pkt); * tcp_options_len: the length of the options (must be a multiple of 4) */ struct packet *craft_tcp_packet(const struct packet *origin_pkt, uint32_t tcp_seq, uint32_t tcp_ack, uint8_t tcp_flags, - const char *tcp_options, uint16_t tcp_options_len, - const char *tcp_payload, uint16_t tcp_payload_len); + const char *tcp_options, uint16_t tcp_options_len, + const char *tcp_payload, uint16_t tcp_payload_len); struct packet *craft_udp_packet(const struct packet *origin_pkt, const char *udp_payload, uint16_t udp_payload_len); -struct packet *craft_packet_from_scratch(const struct layer larers[], uint16_t layer_count, const char *payload, uint16_t payload_len); +struct packet *craft_l3_packet(const struct packet *origin_pkt, uint8_t ip_proto, const char *l3_payload, uint16_t l3_payload_len); struct tcp_segment; const char *tcp_segment_get_data(const struct tcp_segment *seg); diff --git a/src/packet/packet_craft.cpp b/src/packet/packet_craft.cpp index 3388feb..e6ac39a 100644 --- a/src/packet/packet_craft.cpp +++ b/src/packet/packet_craft.cpp @@ -51,20 +51,6 @@ static inline void calc_packet_fingerprint(struct fingerprint *finger) } } -static void update_tcp_hdr(struct tcphdr *tcp, uint32_t seq, uint32_t ack, uint16_t win, uint8_t flags, uint16_t opts_len) -{ - tcp_hdr_set_seq(tcp, seq); - tcp_hdr_set_ack(tcp, ack); - tcp_hdr_set_hdr_len(tcp, sizeof(struct tcphdr) + opts_len); - tcp_hdr_set_flags(tcp, flags); - if (win) - { - tcp_hdr_set_window(tcp, win); - } - tcp_hdr_set_urg_ptr(tcp, 0); - tcp_hdr_set_checksum(tcp, 0); -} - static void update_udp_hdr(struct udphdr *udp, int trim_len) { uint16_t total = udp_hdr_get_total_len(udp); @@ -121,9 +107,36 @@ static void update_gre1_hdr(struct gre1_hdr *gre, int trim_len) gre1_hdr_set_payload_length(gre, payload_len - trim_len); } -static void update_packet_hdr(const struct packet *origin_pkt, - char *new_pkt_data, uint16_t new_pkt_len, int trim_len, - uint32_t tcp_seq, uint32_t tcp_ack, uint8_t tcp_flags, uint16_t tcp_opts_len) +// L2 -- data link layer +// LAYER_PROTO_ETHER: // SKIP +// LAYER_PROTO_PWETH: // SKIP +// LAYER_PROTO_PPP: // SKIP +// LAYER_PROTO_L2TP: // TODO ??? + +// L2 -- tunnel +// LAYER_PROTO_VLAN: // SKIP +// LAYER_PROTO_PPPOE: // TODO ???? +// LAYER_PROTO_MPLS: // SKIP + +// L3 -- network layer +// LAYER_PROTO_IPV4: // DONE +// LAYER_PROTO_IPV6: // DONE +// LAYER_PROTO_IPAH: // TODO ???? + +// L3 -- tunnel +// LAYER_PROTO_GRE: // DONE + +// L4 -- transport layer +// LAYER_PROTO_UDP: // DONE +// LAYER_PROTO_TCP: // DONE +// LAYER_PROTO_ICMP: +// LAYER_PROTO_ICMP6: + +// L4 -- tunnel +// LAYER_PROTO_VXLAN: // SKIP +// LAYER_PROTO_GTP_U: // DONE +// LAYER_PROTO_GTP_C: +static void calculate_length_and_checksum(const struct packet *origin_pkt, int layer_count, char *new_pkt_data, uint16_t new_pkt_len, int trim_len) { uint8_t version = 0; uint16_t sum = 0; @@ -141,8 +154,7 @@ static void update_packet_hdr(const struct packet *origin_pkt, struct raw_layer *last_layer = NULL; struct fingerprint finger = {0}; calc_packet_fingerprint(&finger); - int count = packet_get_layer_count(origin_pkt); - for (int i = count - 1; i >= 0; i--) + for (int i = layer_count - 1; i >= 0; i--) { curr_layer = (struct raw_layer *)packet_get_raw_layer(origin_pkt, i); last_layer = (struct raw_layer *)packet_get_raw_layer(origin_pkt, i + 1); @@ -152,7 +164,11 @@ static void update_packet_hdr(const struct packet *origin_pkt, { case LAYER_PROTO_TCP: tcp = (struct tcphdr *)curr_hdr_ptr; - update_tcp_hdr(tcp, tcp_seq, tcp_ack, finger.tcp_win, tcp_flags, tcp_opts_len); + if (finger.tcp_win) + { + tcp_hdr_set_window(tcp, finger.tcp_win); + } + tcp_hdr_set_checksum(tcp, 0); break; case LAYER_PROTO_UDP: udp = (struct udphdr *)curr_hdr_ptr; @@ -253,8 +269,8 @@ struct packet *craft_tcp_packet(const struct packet *origin_pkt, uint32_t tcp_se } // check the innermost layer of the original packet - int layers = packet_get_layer_count(origin_pkt); - const struct raw_layer *tcp_layer = packet_get_raw_layer(origin_pkt, layers - 1); + int layer_count = packet_get_layer_count(origin_pkt); + const struct raw_layer *tcp_layer = packet_get_raw_layer(origin_pkt, layer_count - 1); if (tcp_layer == NULL || tcp_layer->proto != LAYER_PROTO_TCP) { PACKET_CRAFT_LOG_ERROR("craft TCP packet failed, the innermost layer of the original packet is not TCP"); @@ -279,9 +295,13 @@ struct packet *craft_tcp_packet(const struct packet *origin_pkt, uint32_t tcp_se memcpy(new_pkt_data + tcp_layer->hdr_offset + sizeof(struct tcphdr), tcp_options, tcp_options_len); } memcpy(new_pkt_data + tcp_layer->hdr_offset + sizeof(struct tcphdr) + tcp_options_len, tcp_payload, tcp_payload_len); + struct tcphdr *hdr = (struct tcphdr *)(new_pkt_data + tcp_layer->hdr_offset); + tcp_hdr_set_seq(hdr, tcp_seq); + tcp_hdr_set_ack(hdr, tcp_ack); + tcp_hdr_set_flags(hdr, tcp_flags); + tcp_hdr_set_hdr_len(hdr, sizeof(struct tcphdr) + tcp_options_len); - // update the headers of the new packet - update_packet_hdr(origin_pkt, new_pkt_data, new_pkt_len, trim_len, tcp_seq, tcp_ack, tcp_flags, tcp_options_len); + calculate_length_and_checksum(origin_pkt, layer_count, new_pkt_data, new_pkt_len, trim_len); packet_parse(new_pkt, new_pkt_data, new_pkt_len); memcpy(&new_pkt->meta, &origin_pkt->meta, sizeof(struct metadata)); @@ -300,8 +320,8 @@ struct packet *craft_udp_packet(const struct packet *origin_pkt, const char *udp } // check the innermost layer of the original packet - int layers = packet_get_layer_count(origin_pkt); - const struct raw_layer *udp_layer = packet_get_raw_layer(origin_pkt, layers - 1); + int layer_count = packet_get_layer_count(origin_pkt); + const struct raw_layer *udp_layer = packet_get_raw_layer(origin_pkt, layer_count - 1); if (udp_layer == NULL || udp_layer->proto != LAYER_PROTO_UDP) { PACKET_CRAFT_LOG_ERROR("craft UDP packet failed, the innermost layer of the original packet is not UDP"); @@ -323,8 +343,7 @@ struct packet *craft_udp_packet(const struct packet *origin_pkt, const char *udp memcpy(new_pkt_data, packet_get_raw_data(origin_pkt), udp_layer->hdr_offset + sizeof(struct udphdr)); memcpy(new_pkt_data + udp_layer->hdr_offset + sizeof(struct udphdr), udp_payload, udp_payload_len); - // update the headers of the new packet - update_packet_hdr(origin_pkt, new_pkt_data, new_pkt_len, trim_len, 0, 0, 0, 0); + calculate_length_and_checksum(origin_pkt, layer_count, new_pkt_data, new_pkt_len, trim_len); packet_parse(new_pkt, new_pkt_data, new_pkt_len); memcpy(&new_pkt->meta, &origin_pkt->meta, sizeof(struct metadata)); @@ -333,143 +352,71 @@ struct packet *craft_udp_packet(const struct packet *origin_pkt, const char *udp return new_pkt; } -struct packet *craft_packet_from_scratch(const struct layer layers[], uint16_t layer_count, const char *payload, uint16_t payload_len) +struct packet *craft_l3_packet(const struct packet *origin_pkt, uint8_t ip_proto, const char *l3_payload, uint16_t l3_payload_len) { - // check arguments - if (layers == NULL || layer_count == 0 || (payload == NULL && payload_len != 0) || (payload != NULL && payload_len == 0)) + if (origin_pkt == NULL || (l3_payload == NULL && l3_payload_len != 0) || (l3_payload != NULL && l3_payload_len == 0)) { - PACKET_CRAFT_LOG_ERROR("craft packet from scratch failed, invalid arguments"); + PACKET_CRAFT_LOG_ERROR("craft L3 packet failed, invalid arguments"); + return NULL; + } + + int i = 0; + int layers = packet_get_layer_count(origin_pkt); + const struct raw_layer *l3_layer = NULL; + for (i = layers - 1; i >= 0; i--) + { + l3_layer = packet_get_raw_layer(origin_pkt, i); + if (l3_layer->proto == LAYER_PROTO_IPV4 || l3_layer->proto == LAYER_PROTO_IPV6) + { + break; + } + else + { + l3_layer = NULL; + } + } + if (l3_layer == NULL) + { + PACKET_CRAFT_LOG_ERROR("craft L3 packet failed, the original packet does not contain an IP layer"); return NULL; } // calculate the new packet length - uint16_t new_pkt_len = 0; - for (int i = 0; i < layer_count; i++) - { - if (layers[i].hdr.raw == NULL || layers[i].hdr_len == 0) - { - PACKET_CRAFT_LOG_ERROR("craft packet from scratch failed, the header of layer %d is invalid", i); - return NULL; - } - new_pkt_len += layers[i].hdr_len; - } - new_pkt_len += payload_len; + // trim IPv4 options + // trim IPv6 extension headers + int l3_hdr_len = l3_layer->proto == LAYER_PROTO_IPV4 ? sizeof(struct ip) : sizeof(struct ip6_hdr); + int trim_len = l3_layer->hdr_len + l3_layer->pld_len - l3_payload_len - l3_hdr_len; + uint16_t new_pkt_len = origin_pkt->data_len - origin_pkt->trim_len - trim_len; struct packet *new_pkt = packet_new(new_pkt_len); if (new_pkt == NULL) { - PACKET_CRAFT_LOG_ERROR("craft packet from scratch failed, no space to allocate new packet"); + PACKET_CRAFT_LOG_ERROR("craft L3 packet failed, no space to allocate new packet"); return NULL; } // copy the data to the new packet char *new_pkt_data = (char *)packet_get_raw_data(new_pkt); - int offset = 0; - for (int i = 0; i < layer_count; i++) + memcpy(new_pkt_data, packet_get_raw_data(origin_pkt), l3_layer->hdr_offset + l3_hdr_len); + if (l3_payload) { - memcpy(new_pkt_data + offset, layers[i].hdr.raw, layers[i].hdr_len); - offset += layers[i].hdr_len; + memcpy(new_pkt_data + l3_layer->hdr_offset + l3_hdr_len, l3_payload, l3_payload_len); } - memcpy(new_pkt_data + offset, payload, payload_len); - - // update the headers of the new packet - uint8_t version = 0; - uint16_t curr_hdr_len = 0; - char *curr_hdr_ptr = NULL; - struct tcphdr *tcp = NULL; - struct udphdr *udp = NULL; - struct ip *ip4 = NULL; - struct ip6_hdr *ip6 = NULL; - struct gtp1_hdr *gtp1 = NULL; - struct gtp2_hdr *gtp2 = NULL; - // update checksums and lengths - uint16_t curr_payload_len = payload_len; - for (int i = layer_count - 1; i >= 0; i--) + // update ip_proto + if (l3_layer->proto == LAYER_PROTO_IPV4) { - curr_hdr_len = layers[i].hdr_len; - curr_hdr_ptr = new_pkt_data + new_pkt_len - curr_hdr_len - curr_payload_len; - switch (layers[i].proto) - { - case LAYER_PROTO_TCP: - tcp = (struct tcphdr *)curr_hdr_ptr; - // update the TCP header - tcp_hdr_set_hdr_len(tcp, curr_hdr_len); - tcp_hdr_set_checksum(tcp, 0); - curr_payload_len += curr_hdr_len; - break; - case LAYER_PROTO_UDP: - udp = (struct udphdr *)curr_hdr_ptr; - // update the UDP header - udp_hdr_set_total_len(udp, curr_hdr_len + curr_payload_len); - udp_hdr_set_checksum(udp, 0); - curr_payload_len += curr_hdr_len; - break; - case LAYER_PROTO_IPV4: - ip4 = (struct ip *)curr_hdr_ptr; - // update the checksums of the upper layer - if (i + 1 < layer_count && layers[i + 1].proto == LAYER_PROTO_TCP) - { - tcp = (struct tcphdr *)(new_pkt_data + new_pkt_len - curr_payload_len); - tcp->th_sum = checksum_v4(tcp, curr_payload_len, IPPROTO_TCP, &ip4->ip_src, &ip4->ip_dst); - } - if (i + 1 < layer_count && layers[i + 1].proto == LAYER_PROTO_UDP) - { - udp = (struct udphdr *)(new_pkt_data + new_pkt_len - curr_payload_len); - udp->uh_sum = checksum_v4(udp, curr_payload_len, IPPROTO_UDP, &ip4->ip_src, &ip4->ip_dst); - } - // update the IPv4 header - ip4_hdr_set_hdr_len(ip4, curr_hdr_len); - ip4_hdr_set_total_len(ip4, curr_hdr_len + curr_payload_len); - ip4->ip_sum = 0; - ip4->ip_sum = checksum((const void *)ip4, curr_hdr_len); - curr_payload_len += curr_hdr_len; - break; - case LAYER_PROTO_IPV6: - ip6 = (struct ip6_hdr *)curr_hdr_ptr; - // update the checksums of the upper layer - if (i + 1 < layer_count && layers[i + 1].proto == LAYER_PROTO_TCP) - { - tcp = (struct tcphdr *)(new_pkt_data + new_pkt_len - curr_payload_len); - tcp->th_sum = checksum_v6(tcp, curr_payload_len, IPPROTO_TCP, &ip6->ip6_src, &ip6->ip6_dst); - } - if (i + 1 < layer_count && layers[i + 1].proto == LAYER_PROTO_UDP) - { - udp = (struct udphdr *)(new_pkt_data + new_pkt_len - curr_payload_len); - udp->uh_sum = checksum_v6(udp, curr_payload_len, IPPROTO_UDP, &ip6->ip6_src, &ip6->ip6_dst); - } - // update the IPv6 header - ip6_hdr_set_payload_len(ip6, curr_hdr_len + curr_payload_len - sizeof(struct ip6_hdr)); - curr_payload_len += curr_hdr_len; - break; - case LAYER_PROTO_GTP_C: /* fall through */ - case LAYER_PROTO_GTP_U: - version = peek_gtp_version(curr_hdr_ptr, curr_hdr_len); - if (version == 1) - { - gtp1 = (struct gtp1_hdr *)curr_hdr_ptr; - // update the GTP header - gtp1_hdr_set_msg_len(gtp1, curr_hdr_len + curr_payload_len - sizeof(struct gtp1_hdr)); - } - if (version == 2) - { - gtp2 = (struct gtp2_hdr *)curr_hdr_ptr; - // update the GTP header - gtp2_hdr_set_msg_len(gtp2, curr_hdr_len + curr_payload_len - 4); - } - curr_payload_len += curr_hdr_len; - break; - case LAYER_PROTO_GRE: - // TODO - curr_payload_len += curr_hdr_len; - break; - default: - curr_payload_len += curr_hdr_len; - break; - } + struct ip *ip4 = (struct ip *)(new_pkt_data + l3_layer->hdr_offset); + ip4_hdr_set_protocol(ip4, ip_proto); } + else + { + struct ip6_hdr *ip6 = (struct ip6_hdr *)(new_pkt_data + l3_layer->hdr_offset); + ip6_hdr_set_next_header(ip6, ip_proto); + } + calculate_length_and_checksum(origin_pkt, i + 1, new_pkt_data, new_pkt_len, trim_len); packet_parse(new_pkt, new_pkt_data, new_pkt_len); - // no metadata for the new packet from scratch + memcpy(&new_pkt->meta, &origin_pkt->meta, sizeof(struct metadata)); new_pkt->meta.origin_ctx = NULL; return new_pkt; -} +} \ No newline at end of file diff --git a/src/packet/packet_craft.h b/src/packet/packet_craft.h index 70ea011..cfd7cf4 100644 --- a/src/packet/packet_craft.h +++ b/src/packet/packet_craft.h @@ -18,7 +18,7 @@ struct packet *craft_tcp_packet(const struct packet *origin_pkt, uint32_t tcp_se const char *tcp_options, uint16_t tcp_options_len, const char *tcp_payload, uint16_t tcp_payload_len); struct packet *craft_udp_packet(const struct packet *origin_pkt, const char *udp_payload, uint16_t udp_payload_len); -struct packet *craft_packet_from_scratch(const struct layer larers[], uint16_t layer_count, const char *payload, uint16_t payload_len); +struct packet *craft_l3_packet(const struct packet *origin_pkt, uint8_t ip_proto, const char *l3_payload, uint16_t l3_payload_len); #ifdef __cplusplus } diff --git a/src/packet/test/gtest_packet_craft.cpp b/src/packet/test/gtest_packet_craft.cpp index a084862..6c8f08a 100644 --- a/src/packet/test/gtest_packet_craft.cpp +++ b/src/packet/test/gtest_packet_craft.cpp @@ -1,6 +1,7 @@ #include #include +#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]); } diff --git a/src/stellar/version.map b/src/stellar/version.map index 3c3daf8..6581205 100644 --- a/src/stellar/version.map +++ b/src/stellar/version.map @@ -16,7 +16,7 @@ global: packet_get_payload_len; craft_tcp_packet; craft_udp_packet; - craft_packet_from_scratch; + craft_l3_packet; tcp_segment_get_data; tcp_segment_get_len; diff --git a/test/packet_tool/packet_tool.cpp b/test/packet_tool/packet_tool.cpp index 9966a10..cd5af41 100644 --- a/test/packet_tool/packet_tool.cpp +++ b/test/packet_tool/packet_tool.cpp @@ -30,7 +30,6 @@ struct runtime uint64_t pcap_count; int tshark_format; int print_verbose; - int craft_compare; }; static void str_buff_push(struct str_buff *buff, const char *str) @@ -245,54 +244,6 @@ static void tshark_format(const struct runtime *rte, const struct packet *pkt) buff_udp_dst.data); } -static void craft_compare(const struct runtime *rte, const struct packet *raw_pkt) -{ - struct layer layers[PACKET_MAX_LAYERS]; - int layer_count = PACKET_GETALL_LAYERS(raw_pkt, layers); - - struct packet *new_pkt = craft_packet_from_scratch(layers, layer_count, packet_get_payload(raw_pkt), packet_get_payload_len(raw_pkt)); - if (new_pkt == NULL) - { - PRINT_RED("craft compare: failed (craft error)"); - return; - } - - if (rte->print_verbose) - { - packet_print(new_pkt); - } - - if (rte->tshark_format) - { - tshark_format(rte, new_pkt); - } - - const char *raw_pkt_data = packet_get_raw_data(raw_pkt); - const char *new_pkt_data = packet_get_raw_data(new_pkt); - uint16_t raw_pkt_len = packet_get_raw_len(raw_pkt); - uint16_t new_pkt_len = packet_get_raw_len(new_pkt); - - if (raw_pkt_len != new_pkt_len) - { - PRINT_RED("craft compare: failed (length mismatch)"); - goto error_out; - } - - if (memcmp(raw_pkt_data, new_pkt_data, raw_pkt_len) != 0) - { - PRINT_RED("craft compare: failed (data mismatch)"); - goto error_out; - } - - PRINT_GREEN("craft compare: success"); - -error_out: - char file[256] = {0}; - snprintf(file, sizeof(file), "craft%lu.pcap", rte->pcap_count); - packet_dump_pcap(new_pkt, file); - packet_free(new_pkt); -} - static void packet_handler(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes) { struct runtime *rte = (struct runtime *)user; @@ -312,11 +263,6 @@ static void packet_handler(u_char *user, const struct pcap_pkthdr *h, const u_ch { tshark_format(rte, &pkt); } - - if (rte->craft_compare) - { - craft_compare(rte, &pkt); - } } static void usage(char *cmd) @@ -326,7 +272,6 @@ static void usage(char *cmd) printf(" -f pcap file\n"); printf(" -t print tshark format\n"); printf(" -v print verbose info\n"); - printf(" -c compare recrafted packet\n"); printf(" -h print help\n"); printf("\n"); } @@ -335,7 +280,7 @@ int main(int argc, char **argv) { int opt = 0; struct runtime rte = {0}; - while ((opt = getopt(argc, argv, "f:tvch")) != -1) + while ((opt = getopt(argc, argv, "f:tvh")) != -1) { switch (opt) { @@ -348,9 +293,6 @@ int main(int argc, char **argv) case 'v': rte.print_verbose = 1; break; - case 'c': - rte.craft_compare = 1; - break; case 'h': default: usage(argv[0]);