diff --git a/src/packet/test/CMakeLists.txt b/src/packet/test/CMakeLists.txt index 72a6b86..d4d0de3 100644 --- a/src/packet/test/CMakeLists.txt +++ b/src/packet/test/CMakeLists.txt @@ -37,6 +37,9 @@ target_link_libraries(gtest_packet_frag packet gtest) add_executable(gtest_packet_parse gtest_packet_parse.cpp) target_link_libraries(gtest_packet_parse packet gtest) +add_executable(gtest_packet_build gtest_packet_build.cpp) +target_link_libraries(gtest_packet_build packet gtest) + add_executable(gtest_packet_ldbc gtest_packet_ldbc.cpp) target_link_libraries(gtest_packet_ldbc packet gtest) @@ -54,4 +57,5 @@ gtest_discover_tests(gtest_gre_utils) gtest_discover_tests(gtest_l2tp_utils) gtest_discover_tests(gtest_packet_frag) gtest_discover_tests(gtest_packet_parse) +gtest_discover_tests(gtest_packet_build) gtest_discover_tests(gtest_packet_ldbc) \ No newline at end of file diff --git a/src/packet/test/gtest_packet_build.cpp b/src/packet/test/gtest_packet_build.cpp new file mode 100644 index 0000000..5684219 --- /dev/null +++ b/src/packet/test/gtest_packet_build.cpp @@ -0,0 +1,175 @@ +#include +#include + +#include "packet_def.h" +#include "packet_parse.h" +#include "packet_build.h" +#include "packet_dump.h" + +#define PRINT_GREEN(fmt, ...) printf("\033[0;32m" fmt "\033[0m\n", ##__VA_ARGS__) +#define PRINT_RED(fmt, ...) printf("\033[0;31m" fmt "\033[0m\n", ##__VA_ARGS__) + +// https://dox.ipxe.org/tcp_8h_source.html +#define TCP_OPTION_TS 8 +#define TCP_OPTION_NOP 1 +struct tcp_timestamp_option +{ + uint8_t kind; + uint8_t length; + uint32_t tsval; + uint32_t tsecr; +} __attribute__((packed)); + +struct tcp_timestamp_padded_option +{ + uint8_t nop[2]; + struct tcp_timestamp_option tsopt; +} __attribute__((packed)); + +struct tcp_timestamp_padded_option ts_pad_opt = + { + .nop = {TCP_OPTION_NOP, TCP_OPTION_NOP}, + .tsopt = { + .kind = TCP_OPTION_TS, + .length = 10, + .tsval = 0x12345678, + .tsecr = 0x87654321, + }, +}; + +/****************************************************************************** + * [Protocols in frame: eth:ethertype:ip:tcp] + ****************************************************************************** + * + * Frame 1: 60 bytes on wire (480 bits), 60 bytes captured (480 bits) + * Ethernet II, Src: 52:54:00:94:27:9b (52:54:00:94:27:9b), Dst: 52:54:00:19:8f:63 (52:54:00:19:8f:63) + * Destination: 52:54:00:19:8f:63 (52:54:00:19:8f:63) + * Source: 52:54:00:94:27:9b (52:54:00:94:27:9b) + * Type: IPv4 (0x0800) + * Padding: 000000000000 + * Internet Protocol Version 4, Src: 192.168.122.202, Dst: 192.168.122.100 + * 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: 40 + * Identification: 0x0c5e (3166) + * 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: TCP (6) + * Header Checksum: 0xb7f2 [correct] + * [Header checksum status: Good] + * [Calculated Checksum: 0xb7f2] + * Source Address: 192.168.122.202 + * Destination Address: 192.168.122.100 + * Transmission Control Protocol, Src Port: 1080, Dst Port: 62395, Seq: 1457975085, Ack: 1047768425, Len: 0 + * Source Port: 1080 + * Destination Port: 62395 + * [Stream index: 0] + * [Conversation completeness: Incomplete (4)] + * ..0. .... = RST: Absent + * ...0 .... = FIN: Absent + * .... 0... = Data: Absent + * .... .1.. = ACK: Present + * .... ..0. = SYN-ACK: Absent + * .... ...0 = SYN: Absent + * [Completeness Flags: ···A··] + * [TCP Segment Len: 0] + * Sequence Number: 1457975085 + * [Next Sequence Number: 1457975085] + * Acknowledgment Number: 1047768425 + * 0101 .... = Header Length: 20 bytes (5) + * Flags: 0x010 (ACK) + * 000. .... .... = Reserved: Not set + * ...0 .... .... = Accurate ECN: Not set + * .... 0... .... = Congestion Window Reduced: Not set + * .... .0.. .... = ECN-Echo: Not set + * .... ..0. .... = Urgent: Not set + * .... ...1 .... = Acknowledgment: Set + * .... .... 0... = Push: Not set + * .... .... .0.. = Reset: Not set + * .... .... ..0. = Syn: Not set + * .... .... ...0 = Fin: Not set + * [TCP Flags: ·······A····] + * Window: 457 + * [Calculated window size: 457] + * [Window size scaling factor: -1 (unknown)] + * Checksum: 0x0da7 [correct] + * [Calculated Checksum: 0x0da7] + * [Checksum Status: Good] + * Urgent Pointer: 0 + * [Timestamps] + * [Time since first frame in this TCP stream: 0.000000000 seconds] + * [Time since previous frame in this TCP stream: 0.000000000 seconds] + */ + +unsigned char data1[] = { + 0x52, 0x54, 0x00, 0x19, 0x8f, 0x63, 0x52, 0x54, 0x00, 0x94, 0x27, 0x9b, 0x08, 0x00, 0x45, 0x00, 0x00, 0x28, 0x0c, 0x5e, 0x40, 0x00, 0x40, 0x06, 0xb7, 0xf2, + 0xc0, 0xa8, 0x7a, 0xca, 0xc0, 0xa8, 0x7a, 0x64, 0x04, 0x38, 0xf3, 0xbb, 0x56, 0xe6, 0xef, 0x2d, 0x3e, 0x73, 0xad, 0x69, 0x50, 0x10, 0x01, 0xc9, 0x0d, 0xa7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +/* + * imitate_tcp_packet() + * -> ETH->IPv4->TCP + * -> with TCP options + * -> with TCP payload + */ +#if 1 +TEST(PACKET_BUILD, ETH_IP4_TCP) +{ + 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 packet *new_pkt = imitate_tcp_packet(&orig_pkt, 1, 2, TH_ACK, (const char *)&ts_pad_opt, sizeof(ts_pad_opt), "Hello", 5); + 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, "imitate-eth-ipv4-tcp.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 - 6 == // trim Eth padding: 000000000000 + new_pkt_len - 12 - 5 // trim TCP options, TCP payload + ); + for (uint16_t i = 0; i < new_pkt_len - 12 - 5; i++) + { + if ((16 <= i && i <= 17) || // skip IPv4 total length + (18 <= i && i <= 19) || // skip IPv4 identification + i == 22 || // skip IPv4 TTL + (24 <= i && i <= 25) || // skip IPv4 checksum + (38 <= i && i <= 41) || // skip TCP seq + (42 <= i && i <= 45) || // skip TCP ack + i == 46 || // skip TCP data offset + i == 47 || // skip TCP flags + (48 <= i && i <= 49) || // skip TCP window + (50 <= i && i <= 51) // skip TCP 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]); + } +} +#endif + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}