diff --git a/src/packet/packet_utils.cpp b/src/packet/packet_utils.cpp index 8ffc0da..6318b35 100644 --- a/src/packet/packet_utils.cpp +++ b/src/packet/packet_utils.cpp @@ -120,16 +120,25 @@ struct packet *packet_dup(const struct packet *pkt) { return NULL; } - memcpy(dup_pkt, pkt, sizeof(struct packet)); - memcpy((char *)dup_pkt->data_ptr, pkt->data_ptr, pkt->data_len); - dup_pkt->origin = PACKET_ORIGIN_USERHEAP; - dup_pkt->origin_ctx = NULL; - // update layers + dup_pkt->layers_used = pkt->layers_used; + dup_pkt->layers_size = pkt->layers_size; + + memcpy((char *)dup_pkt->data_ptr, pkt->data_ptr, pkt->data_len); + dup_pkt->data_len = pkt->data_len; + + dup_pkt->origin_ctx = NULL; + dup_pkt->origin = PACKET_ORIGIN_USERHEAP; + dup_pkt->action = PACKET_ACTION_DROP; + for (int8_t i = 0; i < pkt->layers_used; i++) { + dup_pkt->layers[i].type = pkt->layers[i].type; dup_pkt->layers[i].hdr_ptr = dup_pkt->data_ptr + pkt->layers[i].hdr_offset; dup_pkt->layers[i].pld_ptr = dup_pkt->data_ptr + pkt->layers[i].hdr_offset + pkt->layers[i].hdr_len; + dup_pkt->layers[i].hdr_offset = pkt->layers[i].hdr_offset; + dup_pkt->layers[i].hdr_len = pkt->layers[i].hdr_len; + dup_pkt->layers[i].pld_len = pkt->layers[i].pld_len; } // update frag_layer diff --git a/src/packet_io/dumpfile_io.cpp b/src/packet_io/dumpfile_io.cpp index 127d3e5..f10d798 100644 --- a/src/packet_io/dumpfile_io.cpp +++ b/src/packet_io/dumpfile_io.cpp @@ -26,6 +26,7 @@ struct dumpfile_io struct io_stat stat[MAX_THREAD_NUM]; uint64_t io_thread_need_exit; uint64_t io_thread_is_runing; + uint64_t io_thread_wait_exit; }; struct pcap_pkt @@ -34,10 +35,90 @@ struct pcap_pkt int len; }; +struct pcap_file_hdr +{ + unsigned int magic; + unsigned short version_major; + unsigned short version_minor; + unsigned int thiszone; // gmt to local correction + unsigned int sigfigs; // accuracy of timestamps + unsigned int snaplen; // max length saved portion of each pkt + unsigned int linktype; // data link type (LINKTYPE_*) +}; + +struct pcap_pkt_hdr +{ + unsigned int tv_sec; // time stamp + unsigned int tv_usec; // time stamp + unsigned int caplen; // length of portion present + unsigned int len; // length this packet (off wire) +}; + +struct pcap_file_hdr DEFAULT_PCAP_FILE_HDR = + { + .magic = 0xA1B2C3D4, + .version_major = 0x0002, + .version_minor = 0x0004, + .thiszone = 0, + .sigfigs = 0, + .snaplen = 0xFFFF, + .linktype = 1}; + /****************************************************************************** * Private API ******************************************************************************/ +static void save_packet(struct packet *pkt, uint64_t idx) +{ + int len = 0; + FILE *fp = NULL; + struct tuple6 tuple; + struct timeval ts = {0}; + struct pcap_pkt_hdr pcap_hdr = {0}; + + char file[256] = {0}; + char src_addr[INET6_ADDRSTRLEN] = {0}; + char dst_addr[INET6_ADDRSTRLEN] = {0}; + + len = packet_get_len(pkt); + memset(&tuple, 0, sizeof(struct tuple6)); + packet_get_innermost_tuple6(pkt, &tuple); + + if (tuple.ip_type == IP_TYPE_V4) + { + inet_ntop(AF_INET, &tuple.src_addr.v4, src_addr, INET6_ADDRSTRLEN); + inet_ntop(AF_INET, &tuple.dst_addr.v4, dst_addr, INET6_ADDRSTRLEN); + } + else + { + inet_ntop(AF_INET6, &tuple.src_addr.v6, src_addr, INET6_ADDRSTRLEN); + inet_ntop(AF_INET6, &tuple.dst_addr.v6, dst_addr, INET6_ADDRSTRLEN); + } + snprintf(file, sizeof(file), "/tmp/inject-%s:%u-%s:%u-%lu.pcap", src_addr, ntohs(tuple.src_port), dst_addr, ntohs(tuple.dst_port), idx); + + fp = fopen(file, "w+"); + if (fp) + { + gettimeofday(&ts, NULL); + pcap_hdr.tv_sec = ts.tv_sec; + pcap_hdr.tv_usec = ts.tv_usec; + + pcap_hdr.caplen = len; + pcap_hdr.len = len; + + fwrite(&DEFAULT_PCAP_FILE_HDR, sizeof(DEFAULT_PCAP_FILE_HDR), 1, fp); + fwrite(&pcap_hdr, sizeof(struct pcap_pkt_hdr), 1, fp); + fwrite(packet_get_data(pkt), 1, len, fp); + fflush(fp); + fclose(fp); + PACKET_IO_LOG_DEBUG("save packet to %s", file); + } + else + { + PACKET_IO_LOG_ERROR("unable to write pcap file: %s, %s", file, strerror(errno)); + } +} + typedef int file_handle(const char *file, void *arg); static int scan_directory(const char *dir, file_handle *handler, void *arg) @@ -165,6 +246,18 @@ static int dumpfile_handler(const char *file, void *arg) return 0; } +static int all_packet_processed(struct dumpfile_io *handle) +{ + for (uint16_t i = 0; i < handle->nr_threads; i++) + { + if (!lock_free_queue_empty(handle->queue[i])) + { + return 0; + } + } + return 1; +} + static void *dumpfile_thread(void *arg) { struct dumpfile_io *handle = (struct dumpfile_io *)arg; @@ -176,6 +269,11 @@ static void *dumpfile_thread(void *arg) while (ATOMIC_READ(&handle->io_thread_need_exit) == 0) { + if (all_packet_processed(handle)) + { + ATOMIC_SET(&handle->io_thread_wait_exit, 1); + } + PACKET_IO_LOG_STATE("dumpfile io thread waiting"); sleep(1); } @@ -259,6 +357,11 @@ void dumpfile_io_free(struct dumpfile_io *handle) } } +int dumpfile_io_wait_exit(struct dumpfile_io *handle) +{ + return ATOMIC_READ(&handle->io_thread_wait_exit); +} + int dumpfile_io_init(struct dumpfile_io *handle, uint16_t thr_idx) { return 0; @@ -365,6 +468,8 @@ int dumpfile_io_inject(struct dumpfile_io *handle, uint16_t thr_idx, struct pack stat->dev_tx_pkts++; stat->dev_tx_bytes += len; + save_packet(pkt, stat->inject_pkts); + packet_free(pkt); } diff --git a/src/packet_io/dumpfile_io.h b/src/packet_io/dumpfile_io.h index 0951882..fb9c7a8 100644 --- a/src/packet_io/dumpfile_io.h +++ b/src/packet_io/dumpfile_io.h @@ -11,6 +11,7 @@ extern "C" struct dumpfile_io; struct dumpfile_io *dumpfile_io_new(const char *directory, uint16_t nr_threads); void dumpfile_io_free(struct dumpfile_io *handle); +int dumpfile_io_wait_exit(struct dumpfile_io *handle); int dumpfile_io_init(struct dumpfile_io *handle, uint16_t thr_idx); int dumpfile_io_ingress(struct dumpfile_io *handle, uint16_t thr_idx, struct packet *pkts, int nr_pkts); diff --git a/src/packet_io/lock_free_queue.cpp b/src/packet_io/lock_free_queue.cpp index 0fd036a..a8d03e2 100644 --- a/src/packet_io/lock_free_queue.cpp +++ b/src/packet_io/lock_free_queue.cpp @@ -78,3 +78,9 @@ void lock_free_queue_pop(struct lock_free_queue *queue, void **data) *data = (void *)read; queue->head = (queue->head + 1) % queue->size; } + +int lock_free_queue_empty(struct lock_free_queue *queue) +{ + uint64_t read = ATOMIC_READ(&queue->queue[queue->head]); + return read == 0; +} \ No newline at end of file diff --git a/src/packet_io/lock_free_queue.h b/src/packet_io/lock_free_queue.h index 1dab21d..e6e0978 100644 --- a/src/packet_io/lock_free_queue.h +++ b/src/packet_io/lock_free_queue.h @@ -15,6 +15,7 @@ struct lock_free_queue; struct lock_free_queue *lock_free_queue_new(uint32_t size); void lock_free_queue_free(struct lock_free_queue *queue); +int lock_free_queue_empty(struct lock_free_queue *queue); int lock_free_queue_push(struct lock_free_queue *queue, void *data); void lock_free_queue_pop(struct lock_free_queue *queue, void **data); diff --git a/src/packet_io/packet_io.cpp b/src/packet_io/packet_io.cpp index 3b545d2..822c35d 100644 --- a/src/packet_io/packet_io.cpp +++ b/src/packet_io/packet_io.cpp @@ -58,6 +58,18 @@ void packet_io_free(struct packet_io *packet_io) } } +int packet_io_wait_exit(struct packet_io *packet_io) // used for dumpfile mode +{ + if (likely(packet_io->mode == PACKET_IO_MARSIO)) + { + return 0; + } + else + { + return dumpfile_io_wait_exit(packet_io->dumpfile); + } +} + int packet_io_init(struct packet_io *packet_io, uint16_t thr_idx) { if (likely(packet_io->mode == PACKET_IO_MARSIO)) diff --git a/src/packet_io/packet_io.h b/src/packet_io/packet_io.h index 7415b2d..59bf049 100644 --- a/src/packet_io/packet_io.h +++ b/src/packet_io/packet_io.h @@ -83,6 +83,7 @@ struct inject_packet_meta struct packet_io; struct packet_io *packet_io_new(struct packet_io_options *opts); void packet_io_free(struct packet_io *packet_io); +int packet_io_wait_exit(struct packet_io *packet_io); // used for dumpfile mode int packet_io_init(struct packet_io *packet_io, uint16_t thr_idx); int packet_io_ingress(struct packet_io *packet_io, uint16_t thr_idx, struct packet *pkts, int nr_pkts); diff --git a/src/session/session.cpp b/src/session/session.cpp index a72ae87..5b6f127 100644 --- a/src/session/session.cpp +++ b/src/session/session.cpp @@ -177,7 +177,7 @@ void session_get_route_ctx(const struct session *sess, enum flow_direction dir, void session_set_first_packet(struct session *sess, enum flow_direction dir, const struct packet *pkt) { - sess->first_pkt[dir] = packet_dup(pkt); + sess->first_pkt[dir] = pkt; } const struct packet *session_get_first_packet(const struct session *sess, enum flow_direction dir) diff --git a/src/session/session_manager.cpp b/src/session/session_manager.cpp index 034790c..d63f4b9 100644 --- a/src/session/session_manager.cpp +++ b/src/session/session_manager.cpp @@ -571,7 +571,7 @@ static void session_update(struct session *sess, enum session_state next_state, packet_get_route_ctx(pkt, &ctx); packet_get_sid_list(pkt, &list); - session_set_first_packet(sess, dir, pkt); + session_set_first_packet(sess, dir, packet_dup(pkt)); session_set_route_ctx(sess, dir, &ctx); session_set_sid_list(sess, dir, &list); } diff --git a/src/stellar/main.cpp b/src/stellar/main.cpp index 51fbd2f..aba22be 100644 --- a/src/stellar/main.cpp +++ b/src/stellar/main.cpp @@ -115,6 +115,11 @@ int main(int argc, char **argv) stellar_stat_output(runtime->stat); } usleep(1000); // 1ms + + if (packet_io_wait_exit(runtime->packet_io)) + { + ATOMIC_SET(&runtime->need_exit, 1); + } } error_out: diff --git a/src/stellar/stellar.cpp b/src/stellar/stellar.cpp index ee33fc6..61c49d8 100644 --- a/src/stellar/stellar.cpp +++ b/src/stellar/stellar.cpp @@ -123,6 +123,7 @@ static void *work_thread(void *arg) while (ATOMIC_READ(&runtime->need_exit) == 0) { now = timestamp_get_msec(); + memset(packets, 0, sizeof(packets)); nr_recv = packet_io_ingress(packet_io, thr_idx, packets, RX_BURST_MAX); if (nr_recv == 0) { diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f65ebdf..e7e3f36 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,15 +1,11 @@ -add_executable(gtest_build_tcp_packet gtest_build_tcp_packet.cpp) -target_link_libraries(gtest_build_tcp_packet core gtest) - -add_executable(gtest_build_udp_packet gtest_build_udp_packet.cpp) -target_link_libraries(gtest_build_udp_packet core gtest) +add_executable(gtest_inject_tcp_rst gtest_inject_tcp_rst.cpp packet_injector_test_frame.cpp) +target_link_libraries(gtest_inject_tcp_rst core gtest) include(GoogleTest) -gtest_discover_tests(gtest_build_tcp_packet) -gtest_discover_tests(gtest_build_udp_packet) +gtest_discover_tests(gtest_inject_tcp_rst) add_executable(packet_injector packet_injector.cpp) target_link_libraries(packet_injector core gtest) -file(COPY ./conf/log.toml DESTINATION ./conf/) -file(COPY ./conf/stellar.toml DESTINATION ./conf/) \ No newline at end of file +file(COPY ./conf/ DESTINATION ./conf/) +file(COPY ./pcap/ DESTINATION ./pcap/) \ No newline at end of file diff --git a/test/README.md b/test/README.md index d1ad5e6..258c239 100644 --- a/test/README.md +++ b/test/README.md @@ -29,4 +29,12 @@ tcpdump -i virtio_dign_s host 192.0.2.110 and port 80 -n -v -w virtio_dign_s.pca ``` shell kubectl -n tsg-os-system exec -it dign-client-9h8rm -c dign-client sh curl -v http://http.badssl.selftest.gdnt-cloud.website --resolve "http.badssl.selftest.gdnt-cloud.website:80:192.0.2.110" -``` \ No newline at end of file +``` + +## 结果 + +| -t | -c | -n | Note | result | +| ----------- | ----------- | ----------- | ---------------------------- | ----------- | +| tcp-rst | c2s-packet | 1 | After recv SYN | Failed | +| tcp-rst | s2c-packet | 1 | After recv SYN-ACK | Success | +| tcp-rst | c2s-packet | 2 | After recv Sub-ACK | Success | \ No newline at end of file diff --git a/test/gtest_build_tcp_packet.cpp b/test/gtest_build_tcp_packet.cpp deleted file mode 100644 index 8166b75..0000000 --- a/test/gtest_build_tcp_packet.cpp +++ /dev/null @@ -1,63 +0,0 @@ -#include - -#include "inject_priv.h" - -/****************************************************************************** - * BUILD_TCP_PACKET - ******************************************************************************/ - -// IPv4 -TEST(BUILD_IPV4_BASED_TCP_PACKET, WITH_RST) -{ - // TODO -} - -TEST(BUILD_IPV4_BASED_TCP_PACKET, WITH_FIN) -{ - // TODO -} - -TEST(BUILD_IPV4_BASED_TCP_PACKET, WITH_PAYLOD) -{ - // TODO -} - -// IPv6 -TEST(BUILD_IPV6_BASED_TCP_PACKET, WITH_RST) -{ - // TODO -} - -TEST(BUILD_IPV6_BASED_TCP_PACKET, WITH_FIN) -{ - // TODO -} - -TEST(BUILD_IPV6_BASED_TCP_PACKET, WITH_PAYLOD) -{ - // TODO -} - -// IPv4 + IPv6 -TEST(BUILD_IPV4_IPV6_BASED_TCP_PACKET, WITH_RST) -{ - // TODO -} - -// IPv6 + IPv4 -TEST(BUILD_IPV6_IPV4_BASED_TCP_PACKET, WITH_RST) -{ - // TODO -} - -// GRE -TEST(BUILD_GRE_BASED_TCP_PACKET, WITH_RST) -{ - // TODO -} - -int main(int argc, char **argv) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/test/gtest_build_udp_packet.cpp b/test/gtest_build_udp_packet.cpp deleted file mode 100644 index eee7ebb..0000000 --- a/test/gtest_build_udp_packet.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include - -#include "inject_priv.h" - -/****************************************************************************** - * BUILD_UDP_PACKET - ******************************************************************************/ - -// IPv4 -TEST(BUILD_IPV4_BASED_UDP_PACKET, NO_PAYLOD) -{ - // TODO -} - -TEST(BUILD_IPV4_BASED_UDP_PACKET, WITH_PAYLOD) -{ - // TODO -} - -// IPv6 -TEST(BUILD_IPV6_BASED_UDP_PACKET, NO_PAYLOD) -{ - // TODO -} - -TEST(BUILD_IPV6_BASED_UDP_PACKET, WITH_PAYLOD) -{ - // TODO -} - -// IPv4 + IPv6 -TEST(BUILD_IPV4_IPV6_BASED_UDP_PACKET, WITH_PAYLOD) -{ - // TODO -} - -// IPv6 + IPv4 -TEST(BUILD_IPV6_IPV4_BASED_UDP_PACKET, WITH_PAYLOD) -{ - // TODO -} - -// GRE -TEST(BUILD_GRE_BASED_UDP_PACKET, WITH_PAYLOD) -{ - // TODO -} - -int main(int argc, char **argv) -{ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} diff --git a/test/gtest_inject_tcp_rst.cpp b/test/gtest_inject_tcp_rst.cpp new file mode 100644 index 0000000..79e6e47 --- /dev/null +++ b/test/gtest_inject_tcp_rst.cpp @@ -0,0 +1,39 @@ +#include + +#include "packet_injector_test_frame.h" + +TEST(INJECT_IPV4_BASED_TCP_RST, AFTER_RECV_SYN_ACK) +{ + struct packet_injector_case test = { + // descriptor + .finish_clean_work_dir = 1, + .descriptor = "Inject IPv4 based TCP RST after receiving SYN-ACK packet.", + .work_dir = "/tmp/inject_ipv4_based_tcp_rst_after_recv_syn_ack/", // user defined work directory + + // prefix + .input_prefix = "pcap/inject_ipv4_based_tcp_rst_after_recv_syn_ack/test/", + .output_prefix = "/tmp/", + + // input pcap + .input_pcap = "input.pcap", + + // compare + .c2s_expect_pcap = "expect-192.0.2.211:59942-192.0.2.110:80-1.pcap", + .c2s_output_pcap = "inject-192.0.2.211:59942-192.0.2.110:80-1.pcap", + + .s2c_expect_pcap = "expect-192.0.2.110:80-192.0.2.211:59942-2.pcap", + .s2c_output_pcap = "inject-192.0.2.110:80-192.0.2.211:59942-2.pcap", + + // packet injector command + .packet_injector_cmd = "./packet_injector -t tcp-rst -c s2c-packet -n 1", + .diff_skip_pattern = "-I frame.time -I frame.time_epoch -I ip.id -I ip.ttl -I ip.checksum -I tcp.checksum -I tcp.window_size", + }; + + packet_injector_test_frame_run(&test); +} + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/packet_injector.cpp b/test/packet_injector.cpp index 9bc5abc..f21b084 100644 --- a/test/packet_injector.cpp +++ b/test/packet_injector.cpp @@ -339,12 +339,12 @@ static int parse_cmdline(int argc, char **argv, struct inject_rule *rule) printf("invalid count\n"); return -1; } - printf("load inject rule:\n"); - printf(" host : %s\n", host); - printf(" port : %d\n", ntohs(rule->port)); - printf(" type : %s\n", type); - printf(" condition : %s\n", condition); - printf(" count : %lu\n\n", rule->count_num); + printf("%s load inject rule:\n", argv[0]); + printf(" host : %s\n", host); + printf(" port : %d\n", ntohs(rule->port)); + printf(" type : %s\n", type); + printf(" condition : %s\n", condition); + printf(" count : %lu\n\n", rule->count_num); return 0; } @@ -368,7 +368,6 @@ int main(int argc, char **argv) STELLAR_LOG_ERROR("unable to init log"); goto error_out; } - STELLAR_LOG_STATE("start stellar (version: %s)\n %s", __stellar_version, logo_str); if (stellar_load_config(stellar_config_file, config) != 0) { @@ -427,6 +426,11 @@ int main(int argc, char **argv) stellar_stat_output(runtime->stat); } usleep(1000); // 1ms + + if (packet_io_wait_exit(runtime->packet_io)) + { + ATOMIC_SET(&runtime->need_exit, 1); + } } error_out: diff --git a/test/packet_injector_test_frame.cpp b/test/packet_injector_test_frame.cpp new file mode 100644 index 0000000..d049eb6 --- /dev/null +++ b/test/packet_injector_test_frame.cpp @@ -0,0 +1,205 @@ +#include + +#include +#include +#include +#include "packet_injector_test_frame.h" + +static void system_cmd(const char *cmd, ...) +{ + char buf[1024] = {0}; + va_list args; + + va_start(args, cmd); + vsnprintf(buf, sizeof(buf), cmd, args); + va_end(args); + + system(buf); +} + +static int replace_file_string(const char *file, const char *old_str, const char *new_str) +{ +#define BUFFER_SIZE 1024 + + FILE *in_fp = fopen(file, "r"); + if (in_fp == NULL) + { + printf("Open file %s failed, %s\n", file, strerror(errno)); + return -1; + } + + FILE *tmp_fp = tmpfile(); + if (tmp_fp == NULL) + { + printf("Create temporary file failed, %s\n", strerror(errno)); + fclose(in_fp); + return -1; + } + + size_t old_len = strlen(old_str); + size_t new_len = strlen(new_str); + char buff[BUFFER_SIZE]; + + while (fgets(buff, BUFFER_SIZE, in_fp)) + { + char *pos = buff; + if ((pos = strstr(pos, old_str))) + { + fwrite(buff, 1, pos - buff, tmp_fp); // Write characters before the old_str + fwrite(new_str, 1, new_len, tmp_fp); // Write the new_str + pos += old_len; // Move past the old_str + fwrite(pos, 1, strlen(pos), tmp_fp); // Write characters after the old_str + } + else + { + fputs(buff, tmp_fp); // Write the remaining part of the line + } + } + + fclose(in_fp); + fseek(tmp_fp, 0, SEEK_SET); + + FILE *out_fp = fopen(file, "w"); + if (out_fp == NULL) + { + printf("Open file %s for writing failed, %s\n", file, strerror(errno)); + fclose(tmp_fp); + return -1; + } + + while (fgets(buff, BUFFER_SIZE, tmp_fp)) + { + fputs(buff, out_fp); // Write the contents of the temporary file to the original file + } + + fclose(tmp_fp); + fclose(out_fp); + + return 0; +} + +static void expect_cmp_inject(const char *work_dir, + const char *expect_dir_abs_path, const char *expect_pcap_file, + const char *output_dir_abs_path, const char *output_pcap_file, + const char *diff_skip_pattern, const char *flow_dir) +{ + printf("\033[32m ============================================= \033[0m\n"); + printf("\033[32m Compare [%s] expect pcap and output pcap \033[0m\n", flow_dir); + printf("\033[32m ============================================= \033[0m\n"); + + struct stat s; + char expect_pcap_file_abs_path[1024] = {0}; + char output_pcap_file_abs_path[1024] = {0}; + char expect_json_file_abs_path[1024] = {0}; + char output_json_file_abs_path[1024] = {0}; + char diff_txt_file_abs_path[1024] = {0}; + + // absulute path + snprintf(expect_pcap_file_abs_path, sizeof(expect_pcap_file_abs_path), "%s/%s", expect_dir_abs_path, expect_pcap_file); + snprintf(output_pcap_file_abs_path, sizeof(output_pcap_file_abs_path), "%s/%s", output_dir_abs_path, output_pcap_file); + snprintf(expect_json_file_abs_path, sizeof(expect_json_file_abs_path), "%s/expect_%s.json", work_dir, flow_dir); + snprintf(output_json_file_abs_path, sizeof(output_json_file_abs_path), "%s/output_%s.json", work_dir, flow_dir); + snprintf(diff_txt_file_abs_path, sizeof(diff_txt_file_abs_path), "%s/diff_%s.txt", work_dir, flow_dir); + + // check pcap file size + stat(expect_pcap_file_abs_path, &s); + EXPECT_TRUE(s.st_size > 0); + + stat(output_pcap_file_abs_path, &s); + EXPECT_TRUE(s.st_size > 0); + + // tcpdump + printf("\033[32m tcpdump read [%s] expect pcap (%s) \033[0m\n", flow_dir, expect_pcap_file); + system_cmd("tcpdump -r %s", expect_pcap_file_abs_path); + + printf("\033[32m tcpdump read [%s] output pcap (%s) \033[0m\n", flow_dir, output_pcap_file); + system_cmd("tcpdump -r %s", output_pcap_file_abs_path); + + // tshark + system_cmd("tshark -r %s -T json | jq >> %s", expect_pcap_file_abs_path, expect_json_file_abs_path); + system_cmd("tshark -r %s -T json | jq >> %s", output_pcap_file_abs_path, output_json_file_abs_path); + + // check json file size + stat(expect_json_file_abs_path, &s); + EXPECT_TRUE(s.st_size > 0); + + stat(output_json_file_abs_path, &s); + EXPECT_TRUE(s.st_size > 0); + + // diff + system_cmd("diff %s %s %s >> %s", diff_skip_pattern, expect_json_file_abs_path, output_json_file_abs_path, diff_txt_file_abs_path); + + // check diff file size + stat(diff_txt_file_abs_path, &s); + EXPECT_TRUE(s.st_size == 0); +} + +void packet_injector_test_frame_run(struct packet_injector_case *test) +{ + printf("\033[32mTest: %s\033[0m\n", test->descriptor); + + char config_file_abs_path[1024] = {0}; + char input_dir_abs_path[1024] = {0}; + char output_dir_abs_path[1024] = {0}; + char expect_dir_abs_path[1024] = {0}; + + // absulute path + snprintf(config_file_abs_path, sizeof(config_file_abs_path), "%s/conf/stellar.toml", test->work_dir); + snprintf(input_dir_abs_path, sizeof(input_dir_abs_path), "%s/input/", test->work_dir); + snprintf(output_dir_abs_path, sizeof(output_dir_abs_path), "%s/output/", test->work_dir); + snprintf(expect_dir_abs_path, sizeof(expect_dir_abs_path), "%s/expect/", test->work_dir); + + // create directory + system_cmd("rm -rf %s", test->work_dir); + system_cmd("mkdir -p %s", input_dir_abs_path); + system_cmd("mkdir -p %s", output_dir_abs_path); + system_cmd("mkdir -p %s", expect_dir_abs_path); + + // copy file to work directory + if (test->c2s_expect_pcap) + { + system_cmd("cp %s/%s %s", test->input_prefix, test->c2s_expect_pcap, expect_dir_abs_path); + } + if (test->s2c_expect_pcap) + { + system_cmd("cp %s/%s %s", test->input_prefix, test->s2c_expect_pcap, expect_dir_abs_path); + } + system_cmd("cp %s/%s %s", test->input_prefix, test->input_pcap, input_dir_abs_path); + system_cmd("cp -r conf %s/", test->work_dir); + system_cmd("cp packet_injector %s/", test->work_dir); + + // replace config file + char temp[2048] = {0}; + snprintf(temp, sizeof(temp), "dumpfile_dir = \"%s\"", input_dir_abs_path); + EXPECT_TRUE(replace_file_string(config_file_abs_path, "mode = marsio", "mode = dumpfile") == 0); + EXPECT_TRUE(replace_file_string(config_file_abs_path, "dumpfile_dir = \"/tmp/dumpfile/\"", temp) == 0); + + // run packet injector + chdir(test->work_dir); + system_cmd(test->packet_injector_cmd); + chdir("../"); + + // compare pcap + if (test->c2s_output_pcap && test->c2s_expect_pcap) + { + system_cmd("mv %s/%s %s", test->output_prefix, test->c2s_output_pcap, output_dir_abs_path); + expect_cmp_inject(test->work_dir, + expect_dir_abs_path, test->c2s_expect_pcap, + output_dir_abs_path, test->c2s_output_pcap, + test->diff_skip_pattern, "C2S"); + } + if (test->s2c_output_pcap && test->s2c_expect_pcap) + { + system_cmd("mv %s/%s %s", test->output_prefix, test->s2c_output_pcap, output_dir_abs_path); + expect_cmp_inject(test->work_dir, + expect_dir_abs_path, test->s2c_expect_pcap, + output_dir_abs_path, test->s2c_output_pcap, + test->diff_skip_pattern, "S2C"); + } + + // clean work directory + if (test->finish_clean_work_dir) + { + system_cmd("rm -rf %s", test->work_dir); + } +} diff --git a/test/packet_injector_test_frame.h b/test/packet_injector_test_frame.h new file mode 100644 index 0000000..ade3f30 --- /dev/null +++ b/test/packet_injector_test_frame.h @@ -0,0 +1,41 @@ +#ifndef _PACKET_INJECTOR_TEST_FRAME_H +#define _PACKET_INJECTOR_TEST_FRAME_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +struct packet_injector_case +{ + // descriptor + int finish_clean_work_dir; + const char *descriptor; + const char *work_dir; + + // prefix + const char *input_prefix; + const char *output_prefix; + + // input pcap + const char *input_pcap; + + // compare + const char *c2s_expect_pcap; + const char *c2s_output_pcap; + + const char *s2c_expect_pcap; + const char *s2c_output_pcap; + + // packet injector command + const char *packet_injector_cmd; + const char *diff_skip_pattern; +}; + +void packet_injector_test_frame_run(struct packet_injector_case *test); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/test/pcap/inject_ipv4_based_tcp_rst_after_recv_sub_ack/raw/fw.pcap b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_sub_ack/raw/fw.pcap new file mode 100644 index 0000000..9a64332 Binary files /dev/null and b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_sub_ack/raw/fw.pcap differ diff --git a/test/pcap/inject_ipv4_based_tcp_rst_after_recv_sub_ack/raw/virtio_dign_c.pcap b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_sub_ack/raw/virtio_dign_c.pcap new file mode 100644 index 0000000..9d69b1c Binary files /dev/null and b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_sub_ack/raw/virtio_dign_c.pcap differ diff --git a/test/pcap/inject_ipv4_based_tcp_rst_after_recv_sub_ack/raw/virtio_dign_s.pcap b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_sub_ack/raw/virtio_dign_s.pcap new file mode 100644 index 0000000..06833e6 Binary files /dev/null and b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_sub_ack/raw/virtio_dign_s.pcap differ diff --git a/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn/raw/fw.pcap b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn/raw/fw.pcap new file mode 100644 index 0000000..0368354 Binary files /dev/null and b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn/raw/fw.pcap differ diff --git a/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn/raw/virtio_dign_c.pcap b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn/raw/virtio_dign_c.pcap new file mode 100644 index 0000000..c08e327 Binary files /dev/null and b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn/raw/virtio_dign_c.pcap differ diff --git a/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn/raw/virtio_dign_s.pcap b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn/raw/virtio_dign_s.pcap new file mode 100644 index 0000000..cdf92ba Binary files /dev/null and b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn/raw/virtio_dign_s.pcap differ diff --git a/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn_ack/raw/fw.pcap b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn_ack/raw/fw.pcap new file mode 100644 index 0000000..81a8b70 Binary files /dev/null and b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn_ack/raw/fw.pcap differ diff --git a/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn_ack/raw/virtio_dign_c.pcap b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn_ack/raw/virtio_dign_c.pcap new file mode 100644 index 0000000..a826169 Binary files /dev/null and b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn_ack/raw/virtio_dign_c.pcap differ diff --git a/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn_ack/raw/virtio_dign_s.pcap b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn_ack/raw/virtio_dign_s.pcap new file mode 100644 index 0000000..9e870f4 Binary files /dev/null and b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn_ack/raw/virtio_dign_s.pcap differ diff --git a/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn_ack/test/expect-192.0.2.110:80-192.0.2.211:59942-2.pcap b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn_ack/test/expect-192.0.2.110:80-192.0.2.211:59942-2.pcap new file mode 100644 index 0000000..66a6ee3 Binary files /dev/null and b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn_ack/test/expect-192.0.2.110:80-192.0.2.211:59942-2.pcap differ diff --git a/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn_ack/test/expect-192.0.2.211:59942-192.0.2.110:80-1.pcap b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn_ack/test/expect-192.0.2.211:59942-192.0.2.110:80-1.pcap new file mode 100644 index 0000000..bca10d5 Binary files /dev/null and b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn_ack/test/expect-192.0.2.211:59942-192.0.2.110:80-1.pcap differ diff --git a/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn_ack/test/input.pcap b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn_ack/test/input.pcap new file mode 100644 index 0000000..01e5164 Binary files /dev/null and b/test/pcap/inject_ipv4_based_tcp_rst_after_recv_syn_ack/test/input.pcap differ