summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorlijia <[email protected]>2024-11-07 09:52:08 +0800
committerlijia <[email protected]>2024-11-18 11:10:22 +0800
commita3d3efc5490c59684036a794b8f63f81b59685ea (patch)
treee4283d083e1172b814412f3af826f1cf1784068e /test
parentd0a868591470a4a9d71a65a5d540058e72c8d92c (diff)
ftp decoder rebase develop-2.0dev-ftp-v2.0
Diffstat (limited to 'test')
-rw-r--r--test/CMakeLists.txt5
-rw-r--r--test/decoders/ftp/CMakeLists.txt64
-rw-r--r--test/decoders/ftp/ftp_gtest_main.cpp97
-rw-r--r--test/decoders/ftp/ftp_gtest_module.cpp250
-rw-r--r--test/decoders/ftp/ftp_module.toml13
-rw-r--r--test/decoders/ftp/gtest_ftp_decoder.cpp236
-rw-r--r--test/decoders/ftp/json/01-ftp-port-upload-download.json147
-rw-r--r--test/decoders/ftp/json/01-ftp-port-upload-download_C2S.json78
-rw-r--r--test/decoders/ftp/json/01-ftp-port-upload-download_S2C.json28
-rw-r--r--test/decoders/ftp/json/02-ftp_v6_1.json160
-rw-r--r--test/decoders/ftp/json/03-ipv6_eport_upload_download.json167
-rw-r--r--test/decoders/ftp/json/04-ftp-banner-no-ftp-characters.json54
-rw-r--r--test/decoders/ftp/json/05-only-ctrl-link.json33
-rw-r--r--test/decoders/ftp/json/06-ftp_pasv-upload-download.json135
-rw-r--r--test/decoders/ftp/json/06-ftp_pasv-upload-download_C2S.json54
-rw-r--r--test/decoders/ftp/json/06-ftp_pasv-upload-download_S2C.json46
-rw-r--r--test/decoders/ftp/json/07-ftp-start-with-syst-command.json37
-rw-r--r--test/decoders/ftp/json/08-ftp_EPSV_229_ipv4.json34
-rw-r--r--test/decoders/ftp/json/10-ftp-sdedu.json101
-rw-r--r--test/decoders/ftp/json/11-ftp-sjtu.json354
-rw-r--r--test/decoders/ftp/json/empty.json1
-rw-r--r--test/decoders/ftp/pcap/01-ftp-port-upload-download.pcapbin0 -> 1745959 bytes
-rw-r--r--test/decoders/ftp/pcap/01-ftp-port-upload-download_C2S.pcapbin0 -> 722094 bytes
-rw-r--r--test/decoders/ftp/pcap/01-ftp-port-upload-download_S2C.pcapbin0 -> 1023889 bytes
-rw-r--r--test/decoders/ftp/pcap/02-ftp_v6_1.pcapbin0 -> 12915 bytes
-rw-r--r--test/decoders/ftp/pcap/03-ipv6_eport_upload_download.pcapbin0 -> 12210 bytes
-rw-r--r--test/decoders/ftp/pcap/04-ftp-banner-no-ftp-characters.pcapbin0 -> 5424 bytes
-rw-r--r--test/decoders/ftp/pcap/05-only-ctrl-link.pcapbin0 -> 3083 bytes
-rw-r--r--test/decoders/ftp/pcap/06-ftp_pasv-upload-download.pcapbin0 -> 244252 bytes
-rw-r--r--test/decoders/ftp/pcap/06-ftp_pasv-upload-download_C2S.pcapbin0 -> 3991 bytes
-rw-r--r--test/decoders/ftp/pcap/06-ftp_pasv-upload-download_S2C.pcapbin0 -> 4036 bytes
-rw-r--r--test/decoders/ftp/pcap/07-ftp-start-with-syst-command.pcapbin0 -> 4347 bytes
-rw-r--r--test/decoders/ftp/pcap/08-ftp_EPSV_229_ipv4.pcapbin0 -> 3679 bytes
-rw-r--r--test/decoders/ftp/pcap/10-ftp-sdedu.pcapbin0 -> 45153 bytes
-rw-r--r--test/decoders/ftp/pcap/11-ftp-sjtu.pcapbin0 -> 6310804 bytes
35 files changed, 2092 insertions, 2 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 11d1abc..2533e01 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -1,9 +1,10 @@
#add_subdirectory(packet_inject)
add_subdirectory(packet_tool)
add_subdirectory(session_debugger)
-add_subdirectory(lpi_plus)
+# add_subdirectory(lpi_plus)
#add_subdirectory(decoders/http)
#add_subdirectory(decoders/socks)
#add_subdirectory(decoders/stratum)
#add_subdirectory(decoders/session_flags)
-add_subdirectory(monitor) \ No newline at end of file
+add_subdirectory(monitor)
+add_subdirectory(decoders/ftp)
diff --git a/test/decoders/ftp/CMakeLists.txt b/test/decoders/ftp/CMakeLists.txt
new file mode 100644
index 0000000..25f8ee2
--- /dev/null
+++ b/test/decoders/ftp/CMakeLists.txt
@@ -0,0 +1,64 @@
+cmake_minimum_required (VERSION 2.8...3.10)
+include_directories(${CMAKE_SOURCE_DIR}/include/)
+include_directories(${CMAKE_SOURCE_DIR}/decoders/ftp/)
+
+add_executable(gtest_ftp_decoder gtest_ftp_decoder.cpp
+ ${CMAKE_SOURCE_DIR}/decoders/ftp/ftp_decoder_util.c
+ ${CMAKE_SOURCE_DIR}/decoders/ftp/ftp_decoder_proto.c
+ ${CMAKE_SOURCE_DIR}/decoders/ftp/ftp_decoder_hash.c
+ ${CMAKE_SOURCE_DIR}/decoders/ftp/ftp_decoder_stat.c
+ ${CMAKE_SOURCE_DIR}/decoders/ftp/ftp_decoder_entry.c)
+target_link_libraries(gtest_ftp_decoder gtest stellar_lib cjson-static )
+
+add_executable(ftp_gtest_main ftp_gtest_main.cpp ftp_gtest_module.cpp )
+target_link_libraries(ftp_gtest_main gtest stellar_lib fieldstat4 cjson-static
+ -Wl,--whole-archive stellar_lib ftp -Wl,--no-whole-archive
+ dl "-rdynamic"
+ gtest gmock)
+
+set(FTP_GTEST_MAIN ${CMAKE_CURRENT_BINARY_DIR}/ftp_gtest_main)
+set(TEST_PREFIX FTP)
+add_test(NAME ${TEST_PREFIX}.SETUP COMMAND sh -c "
+ mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/conf &&
+ mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/log &&
+ cp ${CMAKE_SOURCE_DIR}/conf/stellar.toml ${CMAKE_CURRENT_BINARY_DIR}/conf/ &&
+ cat ${CMAKE_SOURCE_DIR}/test/decoders/ftp/ftp_module.toml >> ${CMAKE_CURRENT_BINARY_DIR}/conf/stellar.toml &&
+ tomlq -t -i '.packet_io.pcap_path=\"-\"' ${CMAKE_CURRENT_BINARY_DIR}/conf/stellar.toml &&
+ tomlq -t -i '.packet_io.mode=\"pcaplist\"' ${CMAKE_CURRENT_BINARY_DIR}/conf/stellar.toml &&
+ tomlq -t -i '.packet_io.thread_num=1' ${CMAKE_CURRENT_BINARY_DIR}/conf/stellar.toml &&
+ tomlq -t -i '.session_manager.tcp_session_max=100' ${CMAKE_CURRENT_BINARY_DIR}/conf/stellar.toml &&
+ tomlq -t -i '.session_manager.udp_session_max=100' ${CMAKE_CURRENT_BINARY_DIR}/conf/stellar.toml &&
+ tomlq -t -i '.session_manager.tcp_reassembly.buffered_segments_max=1024' ${CMAKE_CURRENT_BINARY_DIR}/conf/stellar.toml
+ ")
+set_tests_properties(${TEST_PREFIX}.SETUP
+ PROPERTIES FIXTURES_SETUP ${TEST_PREFIX}.SETUP)
+
+set(FTP_TEST_JSON ftp_gtest_result.json)
+
+set(TEST_RUN_DIR ${CMAKE_CURRENT_BINARY_DIR})
+set(TEST_JSON_DIR ${CMAKE_SOURCE_DIR}/test/decoders/ftp/json)
+set(TEST_PCAP_DIR ${CMAKE_SOURCE_DIR}/test/decoders/ftp/pcap)
+
+set(FTP_BENCHMARK_CAESES
+ 01-ftp-port-upload-download_C2S
+ 01-ftp-port-upload-download
+ 01-ftp-port-upload-download_S2C
+ 02-ftp_v6_1
+ 03-ipv6_eport_upload_download
+ 04-ftp-banner-no-ftp-characters
+ 05-only-ctrl-link
+ 06-ftp_pasv-upload-download_C2S
+ 06-ftp_pasv-upload-download
+ 06-ftp_pasv-upload-download_S2C
+ 07-ftp-start-with-syst-command
+ 08-ftp_EPSV_229_ipv4
+ 10-ftp-sdedu
+ 11-ftp-sjtu
+)
+foreach(case_name ${FTP_BENCHMARK_CAESES})
+ add_test(NAME ${TEST_PREFIX}.${case_name} COMMAND sh -c "find ${TEST_PCAP_DIR}/ -name ${case_name}.pcap | sort -V | ${FTP_GTEST_MAIN} ${TEST_JSON_DIR}/${case_name}.json ${FTP_TEST_JSON}" ${TEST_RUN_DIR})
+ set_tests_properties(${TEST_PREFIX}.${case_name} PROPERTIES FIXTURES_REQUIRED ${TEST_PREFIX}.SETUP)
+endforeach()
+
+include(GoogleTest)
+gtest_discover_tests(gtest_ftp_decoder)
diff --git a/test/decoders/ftp/ftp_gtest_main.cpp b/test/decoders/ftp/ftp_gtest_main.cpp
new file mode 100644
index 0000000..64203c7
--- /dev/null
+++ b/test/decoders/ftp/ftp_gtest_main.cpp
@@ -0,0 +1,97 @@
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <assert.h>
+#include <gtest/gtest.h>
+#include "stellar/stellar.h"
+#include "cJSON.h"
+
+static cJSON *load_result_from_jsonfile(const char *json_path)
+{
+ if (json_path == NULL)
+ return NULL;
+
+ long file_len = 0;
+ char *file_content = NULL;
+ FILE *fp = NULL;
+
+ fp = fopen(json_path, "r+");
+ if (NULL == fp)
+ {
+ return NULL;
+ }
+ fseek(fp, 0, SEEK_END);
+ file_len = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+ if (file_len == 0)
+ {
+ fclose(fp);
+ return NULL;
+ }
+ file_content = (char *)malloc(file_len + 1);
+ fread(file_content, file_len, 1, fp);
+ file_content[file_len] = '\0';
+ cJSON *load = cJSON_Parse(file_content);
+ free(file_content);
+ fclose(fp);
+ return load;
+}
+
+static void show_json_diff(cJSON *expect_json_root, cJSON *test_module_root)
+{
+ if (NULL == expect_json_root || NULL == test_module_root)
+ {
+ return;
+ }
+ cJSON *t_load = expect_json_root->child, *t_test = test_module_root->child;
+ int ret;
+ char *load_json_str = NULL;
+ char *result_json_str = NULL;
+ while (t_load != NULL && t_test != NULL)
+ {
+ ret = cJSON_Compare(t_load, t_test, 0);
+ if (ret != 1)
+ {
+ load_json_str = cJSON_Print(t_load);
+ printf("LOAD Diff:\n%s\n", load_json_str);
+ free(load_json_str);
+ result_json_str = cJSON_Print(t_test);
+ printf("TEST Diff:\n%s\n", result_json_str);
+ free(result_json_str);
+ }
+ t_load = t_load->next;
+ t_test = t_test->next;
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ if (argc != 3)
+ {
+ fprintf(stderr, "\nUsage: ./%s <expect-result> <test-module-result>\n\n", argv[0]);
+ exit(1);
+ }
+ ::testing::InitGoogleTest(&argc, (char **)argv);
+ const char *expect_json_path = argv[1];
+ const char *test_module_json_path = argv[2];
+
+ struct stellar *st = stellar_new("./conf/stellar.toml");
+ EXPECT_TRUE(st != NULL);
+ stellar_run(st);
+ stellar_free(st);
+
+ cJSON *expect_json_root = load_result_from_jsonfile(expect_json_path);
+ EXPECT_TRUE(expect_json_root != NULL);
+ cJSON *test_json_root = load_result_from_jsonfile(test_module_json_path);
+ EXPECT_TRUE(test_json_root != NULL);
+
+ int ret = cJSON_Compare(expect_json_root, test_json_root, 0);
+ EXPECT_EQ(1, ret);
+ if (ret != 1)
+ {
+ show_json_diff(expect_json_root, test_json_root);
+ }
+ cJSON_Delete(expect_json_root);
+ cJSON_Delete(test_json_root);
+ return ::testing::Test::HasFailure() ? 1 : 0;
+}
diff --git a/test/decoders/ftp/ftp_gtest_module.cpp b/test/decoders/ftp/ftp_gtest_module.cpp
new file mode 100644
index 0000000..fb174d7
--- /dev/null
+++ b/test/decoders/ftp/ftp_gtest_module.cpp
@@ -0,0 +1,250 @@
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+#include "cJSON.h"
+#include "stellar/ftp.h"
+#include "ftp_decoder_inner.h"
+#include "ftp_decoder_util.h"
+#include <stellar/session.h>
+#include <stellar/exdata.h>
+#include <stellar/mq.h>
+#include <stellar/stellar.h>
+
+#define GTEST_RESULT_FILENAME "ftp_gtest_result.json"
+ static cJSON *gtest_ftp_json_root;
+
+ struct ftp_gtest_env
+ {
+ struct module_manager *mod_mgr;
+ int control_request_exdata_idx;
+ int control_response_exdata_idx;
+ int control_dtp_exdata_idx;
+ int data_dtp_exdata_idx;
+ };
+
+ struct ftp_gtest_ext
+ {
+ int cmd_index;
+ int reply_index;
+ int ctrl_dtp_index;
+ int is_data_link;
+ size_t data_link_bytes;
+ size_t data_link_offset;
+ int data_link_finished;
+ cJSON *lastest_data_dtp_obj;
+ cJSON *control_request_root;
+ cJSON *control_response_root;
+ cJSON *control_dtp_root; // multiple ctrl dtp
+ cJSON *data_dtp_root;
+ };
+
+ static void cjson_add_non_c_string(cJSON *root, const char *key, const char *value, size_t len)
+ {
+ char *str = (char *)calloc(1, len + 1);
+ memcpy(str, value, len);
+ cJSON_AddStringToObject(root, key, str);
+ free(str);
+ }
+
+ static void gtest_ftp_on_control_request_cb(struct session *sess, enum ftp_command cmd, const char *para, size_t para_len, const char *command_line, size_t cmd_line_len, void *arg)
+ {
+ (void)para;
+ (void)para_len;
+ (void)cmd_line_len;
+ struct ftp_gtest_env *env = (struct ftp_gtest_env *)arg;
+ struct ftp_gtest_ext *ext = (struct ftp_gtest_ext *)session_get_exdata(sess, env->control_request_exdata_idx);
+ if (NULL == ext)
+ {
+ ext = (struct ftp_gtest_ext *)calloc(1, sizeof(struct ftp_gtest_ext));
+ session_set_exdata(sess, env->control_request_exdata_idx, ext);
+ ext->control_request_root = cJSON_CreateObject();
+ cJSON_AddStringToObject(ext->control_request_root, "topic", "control_request");
+ cJSON_AddStringToObject(ext->control_request_root, "session", session_get_readable_addr(sess));
+ }
+ char cmd_name[64] = {};
+ const char *cmd_readable_str = ftp_command_type_to_string(cmd);
+ snprintf(cmd_name, sizeof(cmd_name), "%d.%s", ext->cmd_index++, cmd_readable_str);
+ cjson_add_non_c_string(ext->control_request_root, cmd_name, command_line, cmd_line_len);
+ // printf("gtest_ftp_on_control_request_cb\n");
+ }
+
+ static void gtest_ftp_on_control_response_cb(struct session *sess, enum ftp_reply_code reply_code, const char *reply_line, size_t reply_len, void *arg)
+ {
+ struct ftp_gtest_env *env = (struct ftp_gtest_env *)arg;
+ struct ftp_gtest_ext *ext = (struct ftp_gtest_ext *)session_get_exdata(sess, env->control_response_exdata_idx);
+ if (NULL == ext)
+ {
+ ext = (struct ftp_gtest_ext *)calloc(1, sizeof(struct ftp_gtest_ext));
+ session_set_exdata(sess, env->control_response_exdata_idx, ext);
+ ext->control_response_root = cJSON_CreateObject();
+ cJSON_AddStringToObject(ext->control_response_root, "topic", "control_response");
+ cJSON_AddStringToObject(ext->control_response_root, "session", session_get_readable_addr(sess));
+ }
+ char reply_name[64] = {};
+ const char *reply_readable_str = ftp_reply_type_to_string(reply_code);
+ snprintf(reply_name, sizeof(reply_name), "%d.%s", ext->reply_index++, reply_readable_str);
+ cjson_add_non_c_string(ext->control_response_root, reply_name, reply_line, reply_len);
+ // printf("gtest_ftp_on_control_response_cb\n");
+ }
+
+ static void gtest_ftp_dtp_add_to_json(cJSON *dtp_obj, const struct ftp_login *login_info, const struct ftp_dtp *dtp)
+ {
+ if (login_info) // S2C asymmetric flow
+ {
+ if (login_info->username && strlen(login_info->username) > 0)
+ {
+ cJSON_AddStringToObject(dtp_obj, "username", login_info->username);
+ }
+ if (login_info->password && strlen(login_info->password) > 0)
+ {
+ cJSON_AddStringToObject(dtp_obj, "password", login_info->password);
+ }
+ }
+ if (dtp) // S2C asymmetric flow
+ {
+ if (dtp->uri)
+ {
+ cJSON_AddStringToObject(dtp_obj, "uri", dtp->uri);
+ }
+ cJSON_AddStringToObject(dtp_obj, "dir", dtp->dir == FTP_TRANSFER_RETR ? "retr" : "stor");
+ cJSON_AddStringToObject(dtp_obj, "mode", dtp->mode == FTP_TRANSFER_PASV ? "pasv" : "port");
+ cJSON_AddStringToObject(dtp_obj, "cmd", ftp_command_type_to_string(dtp->cmd));
+ }
+ }
+
+ static void gtest_ftp_on_control_dtp_cb(struct session *sess, const struct ftp_login *login_info, const struct ftp_dtp *dtp, void *arg)
+ {
+ (void)sess;
+ (void)login_info;
+ (void)dtp;
+ (void)arg;
+ struct ftp_gtest_env *env = (struct ftp_gtest_env *)arg;
+ struct ftp_gtest_ext *ext = (struct ftp_gtest_ext *)session_get_exdata(sess, env->control_dtp_exdata_idx);
+ if (NULL == ext)
+ {
+ ext = (struct ftp_gtest_ext *)calloc(1, sizeof(struct ftp_gtest_ext));
+ session_set_exdata(sess, env->control_dtp_exdata_idx, ext);
+ ext->control_dtp_root = cJSON_CreateObject();
+ cJSON_AddStringToObject(ext->control_dtp_root, "topic", "control_dtp");
+ cJSON_AddStringToObject(ext->control_dtp_root, "session", session_get_readable_addr(sess));
+ }
+ cJSON *dtp_obj = cJSON_CreateObject();
+ gtest_ftp_dtp_add_to_json(dtp_obj, login_info, dtp);
+ char dtp_index_name[16] = {};
+ snprintf(dtp_index_name, sizeof(dtp_index_name), "%d.dtp", ext->ctrl_dtp_index++);
+ cJSON_AddItemToObject(ext->control_dtp_root, dtp_index_name, dtp_obj);
+ // printf("gtest_ftp_on_control_dtp_cb\n");
+ }
+
+ static void gtest_ftp_on_data_connection_cb(struct session *sess, const struct ftp_login *login_info, const struct ftp_dtp *dtp,
+ const char *chunk, size_t chunk_len, size_t offset, int is_finished, void *arg)
+ {
+ (void)chunk;
+ struct ftp_gtest_env *env = (struct ftp_gtest_env *)arg;
+ struct ftp_gtest_ext *ext = (struct ftp_gtest_ext *)session_get_exdata(sess, env->data_dtp_exdata_idx);
+ if (NULL == ext)
+ {
+ ext = (struct ftp_gtest_ext *)calloc(1, sizeof(struct ftp_gtest_ext));
+ session_set_exdata(sess, env->data_dtp_exdata_idx, ext);
+ ext->data_dtp_root = cJSON_CreateObject();
+ cJSON_AddStringToObject(ext->data_dtp_root, "topic", "data_dtp");
+ cJSON_AddStringToObject(ext->data_dtp_root, "session", session_get_readable_addr(sess));
+
+ if (dtp)
+ {
+ cJSON *dtp_obj = cJSON_CreateObject();
+ gtest_ftp_dtp_add_to_json(dtp_obj, login_info, dtp);
+ cJSON_AddItemToObject(ext->data_dtp_root, "dtp", dtp_obj);
+ }
+ }
+
+ ext->data_link_bytes += chunk_len;
+ ext->data_link_offset = offset;
+ ext->data_link_finished = is_finished;
+ if (1 == is_finished)
+ {
+ cJSON_AddNumberToObject(ext->data_dtp_root, "offset", ext->data_link_offset);
+ cJSON_AddNumberToObject(ext->data_dtp_root, "total_bytes", ext->data_link_bytes);
+ cJSON_AddNumberToObject(ext->data_dtp_root, "is_finished", ext->data_link_finished);
+ }
+ }
+
+ static void gtest_ftp_ctrl_req_exdata_free(int idx, void *ex_ptr, void *arg)
+ {
+ (void)idx;
+ (void)arg;
+ struct ftp_gtest_ext *ext = (struct ftp_gtest_ext *)ex_ptr;
+ cJSON_AddItemToArray(gtest_ftp_json_root, ext->control_request_root);
+ free(ext);
+ }
+
+ static void gtest_ftp_ctrl_res_exdata_free(int idx, void *ex_ptr, void *arg)
+ {
+ (void)idx;
+ (void)arg;
+ struct ftp_gtest_ext *ext = (struct ftp_gtest_ext *)ex_ptr;
+ cJSON_AddItemToArray(gtest_ftp_json_root, ext->control_response_root);
+ free(ext);
+ }
+
+ static void gtest_ftp_ctrl_dtp_exdata_free(int idx, void *ex_ptr, void *arg)
+ {
+ (void)idx;
+ (void)arg;
+ struct ftp_gtest_ext *ext = (struct ftp_gtest_ext *)ex_ptr;
+ cJSON_AddItemToArray(gtest_ftp_json_root, ext->control_dtp_root);
+ free(ext);
+ }
+
+ static void gtest_ftp_data_dtp_exdata_free(int idx, void *ex_ptr, void *arg)
+ {
+ (void)idx;
+ (void)arg;
+ struct ftp_gtest_ext *ext = (struct ftp_gtest_ext *)ex_ptr;
+ cJSON_AddItemToArray(gtest_ftp_json_root, ext->data_dtp_root);
+ free(ext);
+ }
+
+ struct module *gtest_ftp_init(struct module_manager *mod_mgr)
+ {
+ gtest_ftp_json_root = cJSON_CreateArray();
+ struct ftp_gtest_env *env = (struct ftp_gtest_env *)calloc(1, sizeof(struct ftp_gtest_env));
+ env->mod_mgr = mod_mgr;
+
+ struct module *ftp_mod = module_manager_get_module(mod_mgr, FTP_MODULE_NAME);
+ struct ftp_decoder *ftp = module_to_ftp_decoder(ftp_mod);
+
+ ftp_subscribe(ftp,
+ gtest_ftp_on_control_request_cb,
+ gtest_ftp_on_control_response_cb,
+ gtest_ftp_on_control_dtp_cb,
+ gtest_ftp_on_data_connection_cb, env);
+
+ struct module *sess_mod = module_manager_get_module(mod_mgr, SESSION_MANAGER_MODULE_NAME);
+ struct session_manager *sess_mgr = module_to_session_manager(sess_mod);
+ env->control_request_exdata_idx = session_manager_new_session_exdata_index(sess_mgr, "FTP_GTEST_CTRL_REQ_EXDATA", gtest_ftp_ctrl_req_exdata_free, env);
+ env->control_response_exdata_idx = session_manager_new_session_exdata_index(sess_mgr, "FTP_GTEST_CTRL_RES_EXDATA", gtest_ftp_ctrl_res_exdata_free, env);
+ env->control_dtp_exdata_idx = session_manager_new_session_exdata_index(sess_mgr, "FTP_GTEST_CTRL_DTP_EXDATA", gtest_ftp_ctrl_dtp_exdata_free, env);
+ env->data_dtp_exdata_idx = session_manager_new_session_exdata_index(sess_mgr, "FTP_GTEST_DATA_DTP_EXDATA", gtest_ftp_data_dtp_exdata_free, env);
+ return module_new("GTEST_FTP_MODULE", env);
+ }
+
+ void gtest_ftp_exit(struct module_manager *mod_mgr, struct module *mod)
+ {
+ (void)mod_mgr;
+ struct ftp_gtest_env *env = (struct ftp_gtest_env *)module_get_ctx(mod);
+ free(env);
+ char *json_str = cJSON_PrintUnformatted(gtest_ftp_json_root);
+ FILE *json_fp = fopen(GTEST_RESULT_FILENAME, "w+");
+ fwrite(json_str, strlen(json_str), 1, json_fp);
+ fclose(json_fp);
+ free(json_str);
+ cJSON_Delete(gtest_ftp_json_root);
+ module_free(mod);
+ return;
+ }
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/test/decoders/ftp/ftp_module.toml b/test/decoders/ftp/ftp_module.toml
new file mode 100644
index 0000000..9e6f4e0
--- /dev/null
+++ b/test/decoders/ftp/ftp_module.toml
@@ -0,0 +1,13 @@
+#load ftp module
+[[module]]
+path = ""
+init = "ftp_init"
+exit = "ftp_exit"
+thread_init = "ftp_on_thread_init"
+thread_exit = "ftp_on_thread_exit"
+
+#load ftp gtest module
+[[module]]
+path = ""
+init = "gtest_ftp_init"
+exit = "gtest_ftp_exit"
diff --git a/test/decoders/ftp/gtest_ftp_decoder.cpp b/test/decoders/ftp/gtest_ftp_decoder.cpp
new file mode 100644
index 0000000..cbf4d5a
--- /dev/null
+++ b/test/decoders/ftp/gtest_ftp_decoder.cpp
@@ -0,0 +1,236 @@
+#include <gtest/gtest.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <arpa/inet.h>
+#include <libgen.h>
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+#include "stellar/ftp.h"
+#include "ftp_decoder_inner.h"
+#include "ftp_decoder_util.h"
+#include <stellar/session.h>
+#include <stellar/exdata.h>
+#include <stellar/mq.h>
+#include <stellar/stellar.h>
+#ifdef __cplusplus
+}
+#endif
+
+TEST(FTP_GTEST, identify_by_payload)
+{
+ // true
+ ASSERT_TRUE(ftp_ctrl_identify_by_payload("USER", 4, FLOW_TYPE_C2S));
+ ASSERT_TRUE(ftp_ctrl_identify_by_payload("USER test", 9, FLOW_TYPE_C2S));
+ ASSERT_TRUE(ftp_ctrl_identify_by_payload("220 (vsFTPd 3.0.1)", strlen("220 (vsFTPd 3.0.1)"), FLOW_TYPE_S2C));
+ ASSERT_TRUE(ftp_ctrl_identify_by_payload("220 (vsFTPD 3.0.2)", strlen("220 (vsFTPD 3.0.2)"), FLOW_TYPE_S2C));
+ ASSERT_TRUE(ftp_ctrl_identify_by_payload("220 (ftpd 3.0.3)", strlen("220 (ftpd 3.0.3)"), FLOW_TYPE_S2C));
+ ASSERT_TRUE(ftp_ctrl_identify_by_payload("220-Microsoft FTP Service", strlen("220-Microsoft FTP Service"), FLOW_TYPE_S2C));
+
+ // false
+ ASSERT_FALSE(ftp_ctrl_identify_by_payload("USR", 3, FLOW_TYPE_C2S));
+ ASSERT_FALSE(ftp_ctrl_identify_by_payload("USRxx", 5, FLOW_TYPE_C2S));
+ ASSERT_FALSE(ftp_ctrl_identify_by_payload("PASS", 4, FLOW_TYPE_C2S));
+ ASSERT_FALSE(ftp_ctrl_identify_by_payload("200 OK", 6, FLOW_TYPE_S2C));
+ ASSERT_FALSE(ftp_ctrl_identify_by_payload("220 (xxx 3.0.3)", strlen("220 (xxx 3.0.3)"), FLOW_TYPE_S2C));
+}
+
+TEST(FTP_GTEST, ftp_cmd_readline)
+{
+ struct ftp_interact_line line;
+ ftp_cmd_readline(&line, "USER test", strlen("USER test"));
+ ASSERT_EQ(line.cmd_refer.iov_len, 4);
+ ASSERT_EQ(line.arg_refer.iov_len, 4);
+ ASSERT_EQ(0, strncmp("USER", (char *)line.cmd_refer.iov_base, 4));
+ ASSERT_EQ(0, strncmp("test", (char *)line.arg_refer.iov_base, 4));
+
+ ftp_cmd_readline(&line, "PASS 123456\r\n", strlen("PASS 123456\r\n"));
+ ASSERT_EQ(line.cmd_refer.iov_len, 4);
+ ASSERT_EQ(line.arg_refer.iov_len, 6);
+ ASSERT_EQ(0, strncmp("PASS", (char *)line.cmd_refer.iov_base, 4));
+ ASSERT_EQ(0, strncmp("123456", (char *)line.arg_refer.iov_base, 6));
+
+ ftp_cmd_readline(&line, "CUSTOM xx1 xx2 xx3", strlen("CUSTOM xx1 xx2 xx3"));
+ ASSERT_EQ(line.cmd_refer.iov_len, 6);
+ ASSERT_EQ(line.arg_refer.iov_len, 11);
+ ASSERT_EQ(0, strncmp("CUSTOM", (char *)line.cmd_refer.iov_base, 6));
+ ASSERT_EQ(0, strncmp("xx1 xx2 xx3", (char *)line.arg_refer.iov_base, 11));
+
+ ftp_cmd_readline(&line, "LIST\n", strlen("LIST\n"));
+ ASSERT_EQ(line.cmd_refer.iov_len, 4);
+ ASSERT_TRUE(line.arg_refer.iov_base == NULL);
+ ASSERT_EQ(line.arg_refer.iov_len, 0);
+ ASSERT_EQ(0, strncmp("LIST", (char *)line.cmd_refer.iov_base, 4));
+}
+
+TEST(FTP_GTEST, ftp_skip_tail_crlf)
+{
+ ASSERT_EQ(ftp_strip_crlf("", 0), 0);
+ ASSERT_EQ(ftp_strip_crlf("\r", 1), 0);
+ ASSERT_EQ(ftp_strip_crlf("\n", 1), 0);
+ ASSERT_EQ(ftp_strip_crlf("\r\n", 2), 0);
+ ASSERT_EQ(ftp_strip_crlf("a\r\n", 3), 1);
+ ASSERT_EQ(ftp_strip_crlf("abcdefg\r\n", 9), 7);
+}
+
+TEST(FTP_GTEST, ipv4_port_style)
+{
+ int ret;
+ uint32_t ipv4_net = 0;
+ uint16_t port_net = 0;
+ fstring ip_port_style = {};
+ // normal
+ ip_port_style.iov_base = (void *)"192,168,38,2,202,95";
+ ip_port_style.iov_len = strlen("192,168,38,2,202,95");
+ ret = ftp_parse_ipv4_port_style(&ip_port_style, &ipv4_net, &port_net);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(ipv4_net, htonl(0xC0A82602));
+ ASSERT_EQ(port_net, htons(51807));
+
+ // add tab and blank
+ ip_port_style.iov_base = (void *)" 192,168,38,2,202,95 ";
+ ip_port_style.iov_len = strlen(" 192,168,38,2,202,95 ");
+ ret = ftp_parse_ipv4_port_style(&ip_port_style, &ipv4_net, &port_net);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(ipv4_net, htonl(0xC0A82602));
+ ASSERT_EQ(port_net, htons(51807));
+
+ // add bracket
+ ip_port_style.iov_base = (void *)"(192,168,38,2,202,95)";
+ ip_port_style.iov_len = strlen("(192,168,38,2,202,95)");
+ ret = ftp_parse_ipv4_port_style(&ip_port_style, &ipv4_net, &port_net);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(ipv4_net, htonl(0xC0A82602));
+ ASSERT_EQ(port_net, htons(51807));
+
+ // PASV response
+ ip_port_style.iov_base = (void *)"Entering Passive Mode(192,168,38,2,202,95)";
+ ip_port_style.iov_len = strlen("Entering Passive Mode(192,168,38,2,202,95)");
+ ret = ftp_parse_ipv4_port_style(&ip_port_style, &ipv4_net, &port_net);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(ipv4_net, htonl(0xC0A82602));
+ ASSERT_EQ(port_net, htons(51807));
+
+ // PASV response with blank
+ ip_port_style.iov_base = (void *)"Entering Passive Mode ( 192,168,38,2,202,95 )";
+ ip_port_style.iov_len = strlen("Entering Passive Mode ( 192,168,38,2,202,95 )");
+ ret = ftp_parse_ipv4_port_style(&ip_port_style, &ipv4_net, &port_net);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(ipv4_net, htonl(0xC0A82602));
+ ASSERT_EQ(port_net, htons(51807));
+}
+
+TEST(FTP_GTEST, ipv6_port_style)
+{
+ int ret;
+ uint16_t port_net;
+ fstring ip_port_style;
+ // normal
+ ip_port_style.iov_base = (void *)"Entering Extended Passive Mode (|||12345|)";
+ ip_port_style.iov_len = strlen("Entering Extended Passive Mode (|||12345|)");
+ ret = ftp_parse_ipv6_port_style(&ip_port_style, &port_net);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(port_net, htons(12345));
+
+ // add blank
+ ip_port_style.iov_base = (void *)"Entering Extended Passive Mode ( |||12345| )";
+ ip_port_style.iov_len = strlen("Entering Extended Passive Mode ( |||12345| )");
+ ret = ftp_parse_ipv6_port_style(&ip_port_style, &port_net);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(port_net, htons(12345));
+}
+
+TEST(FTP_GTEST, ipv6_eprt_style)
+{
+ int ret;
+ uint16_t port_net = 0;
+ fstring eprt_style;
+ struct in6_addr ipv6addr = {};
+ // normal
+ eprt_style.iov_base = (void *)"|2|1234::abcd|12345|";
+ eprt_style.iov_len = strlen("|2|1234::abcd|12345|");
+ ret = ftp_parse_eprt_ipport_style(&eprt_style, &ipv6addr, &port_net, NULL);
+ ASSERT_EQ(ret, 0);
+ struct in6_addr tmpaddr;
+ inet_pton(AF_INET6, "1234::abcd", &tmpaddr);
+ ASSERT_EQ(0, memcmp(&tmpaddr, &ipv6addr, sizeof(struct in6_addr)));
+ ASSERT_EQ(port_net, htons(12345));
+
+ // loopback address
+ eprt_style.iov_base = (void *)"|2|::1|12345|";
+ eprt_style.iov_len = strlen("|2|::1|12345|");
+ ret = ftp_parse_eprt_ipport_style(&eprt_style, &ipv6addr, &port_net, NULL);
+ ASSERT_EQ(ret, 0);
+ inet_pton(AF_INET6, "::1", &tmpaddr);
+ ASSERT_EQ(0, memcmp(&tmpaddr, &ipv6addr, sizeof(struct in6_addr)));
+ ASSERT_EQ(port_net, htons(12345));
+
+ // add blank
+ eprt_style.iov_base = (void *)" |2|1234:4321::abcd|12345| ";
+ eprt_style.iov_len = strlen(" |2|1234:4321::abcd|12345| ");
+ ret = ftp_parse_eprt_ipport_style(&eprt_style, &ipv6addr, &port_net, NULL);
+ ASSERT_EQ(ret, 0);
+ inet_pton(AF_INET6, "1234:4321::abcd", &tmpaddr);
+ ASSERT_EQ(0, memcmp(&tmpaddr, &ipv6addr, sizeof(struct in6_addr)));
+ ASSERT_EQ(port_net, htons(12345));
+}
+
+TEST(FTP_GTEST, join_dir_file_path)
+{
+ char ab_path[PATH_MAX] = {};
+ ftp_join_absolute_path(NULL, NULL, ab_path, PATH_MAX);
+ ASSERT_STREQ(ab_path, "");
+
+ ftp_join_absolute_path("", "", ab_path, PATH_MAX);
+ ASSERT_STREQ(ab_path, "/");
+
+ ftp_join_absolute_path("/", "", ab_path, PATH_MAX);
+ ASSERT_STREQ(ab_path, "/");
+
+ ftp_join_absolute_path("/", ".", ab_path, PATH_MAX);
+ ASSERT_STREQ(ab_path, "/");
+
+ ftp_join_absolute_path("/", "ftp", ab_path, PATH_MAX);
+ ASSERT_STREQ(ab_path, "/ftp");
+
+ ftp_join_absolute_path("/", "./ftp", ab_path, PATH_MAX);
+ ASSERT_STREQ(ab_path, "/ftp");
+
+ ftp_join_absolute_path("/ftp", "../pub", ab_path, PATH_MAX);
+ ASSERT_STREQ(ab_path, "/pub");
+
+ ftp_join_absolute_path("/ftp/pub", "/home/foo/bar.txt", ab_path, PATH_MAX);
+ ASSERT_STREQ(ab_path, "/home/foo/bar.txt");
+
+ ftp_join_absolute_path("/home", "test.txt", ab_path, PATH_MAX);
+ ASSERT_STREQ(ab_path, "/home/test.txt");
+
+ ftp_join_absolute_path("/home", "./test.txt", ab_path, PATH_MAX);
+ ASSERT_STREQ(ab_path, "/home/test.txt");
+
+ ftp_join_absolute_path("", "test.txt", ab_path, PATH_MAX);
+ ASSERT_STREQ(ab_path, "/test.txt");
+
+ ftp_join_absolute_path("/home", "/test.txt", ab_path, PATH_MAX);
+ ASSERT_STREQ(ab_path, "/test.txt");
+
+ ftp_join_absolute_path("/home", "../test.txt", ab_path, PATH_MAX);
+ ASSERT_STREQ(ab_path, "/test.txt");
+
+ ftp_join_absolute_path("/home/foo/bar", "../test.txt", ab_path, PATH_MAX);
+ ASSERT_STREQ(ab_path, "/home/foo/test.txt");
+
+ ftp_join_absolute_path("/home/foo/bar", "../../test.txt", ab_path, PATH_MAX);
+ ASSERT_STREQ(ab_path, "/home/test.txt");
+
+ ftp_join_absolute_path("/home/foo", "../../../../../../../test.txt", ab_path, PATH_MAX);
+ ASSERT_STREQ(ab_path, "/test.txt");
+}
+
+int main(int argc, char **argv)
+{
+ testing::InitGoogleTest(&argc, argv);
+ int ret = RUN_ALL_TESTS();
+ return ret;
+}
diff --git a/test/decoders/ftp/json/01-ftp-port-upload-download.json b/test/decoders/ftp/json/01-ftp-port-upload-download.json
new file mode 100644
index 0000000..9541844
--- /dev/null
+++ b/test/decoders/ftp/json/01-ftp-port-upload-download.json
@@ -0,0 +1,147 @@
+[
+ {
+ "topic": "data_dtp",
+ "session": "192.168.40.139:20-192.168.38.2:51808-6-0",
+ "dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://192.168.40.139/ftp/2001.03147v1.pdf",
+ "dir": "stor",
+ "mode": "port",
+ "cmd": "STOR"
+ },
+ "offset": 681116,
+ "total_bytes": 681116,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "192.168.40.139:20-192.168.38.2:51809-6-0",
+ "dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "stor",
+ "mode": "port",
+ "cmd": "LIST"
+ },
+ "offset": 76,
+ "total_bytes": 76,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "192.168.40.139:20-192.168.38.2:51810-6-0",
+ "dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://192.168.40.139/pub/3cdaemon-v2r10.zip",
+ "dir": "retr",
+ "mode": "port",
+ "cmd": "RETR"
+ },
+ "offset": 953457,
+ "total_bytes": 953457,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "192.168.40.139:20-192.168.38.2:51811-6-0",
+ "dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "retr",
+ "mode": "port",
+ "cmd": "LIST"
+ },
+ "offset": 76,
+ "total_bytes": 76,
+ "is_finished": 1
+ },
+ {
+ "topic": "control_request",
+ "session": "192.168.38.2:51805-192.168.40.139:21-6-0",
+ "0.OTHERS": "OPTS UTF8 ON",
+ "1.USER": "USER ftp",
+ "2.PASS": "PASS 111111",
+ "3.CWD": "CWD ftp",
+ "4.PORT": "PORT 192,168,38,2,202,95",
+ "5.LIST": "LIST",
+ "6.PORT": "PORT 192,168,38,2,202,96",
+ "7.STOR": "STOR 2001.03147v1.pdf",
+ "8.CWD": "CWD ../pub",
+ "9.PORT": "PORT 192,168,38,2,202,97",
+ "10.LIST": "LIST",
+ "11.PORT": "PORT 192,168,38,2,202,98",
+ "12.RETR": "RETR 3cdaemon-v2r10.zip",
+ "13.PORT": "PORT 192,168,38,2,202,99",
+ "14.LIST": "LIST",
+ "15.OTHERS": "QUIT"
+ },
+ {
+ "topic": "control_response",
+ "session": "192.168.38.2:51805-192.168.40.139:21-6-0",
+ "0.220": "220 Welcome to blah FTP service.",
+ "1.200": "200 Always in UTF8 mode.",
+ "2.OTHERS": "331 Please specify the password.",
+ "3.OTHERS": "230 Login successful.",
+ "4.OTHERS": "250 Directory successfully changed.",
+ "5.200": "200 PORT command successful. Consider using PASV.",
+ "6.OTHERS": "150 Here comes the directory listing.",
+ "7.OTHERS": "226 Directory send OK.",
+ "8.200": "200 PORT command successful. Consider using PASV.",
+ "9.OTHERS": "150 Ok to send data.",
+ "10.OTHERS": "226 Transfer complete.",
+ "11.OTHERS": "250 Directory successfully changed.",
+ "12.200": "200 PORT command successful. Consider using PASV.",
+ "13.OTHERS": "150 Here comes the directory listing.",
+ "14.OTHERS": "226 Directory send OK.",
+ "15.200": "200 PORT command successful. Consider using PASV.",
+ "16.OTHERS": "150 Opening ASCII mode data connection for 3cdaemon-v2r10.zip (949571 bytes).",
+ "17.OTHERS": "226 Transfer complete.",
+ "18.200": "200 PORT command successful. Consider using PASV.",
+ "19.OTHERS": "150 Here comes the directory listing.",
+ "20.OTHERS": "226 Directory send OK.",
+ "21.OTHERS": "221 Goodbye."
+ },
+ {
+ "topic": "control_dtp",
+ "session": "192.168.38.2:51805-192.168.40.139:21-6-0",
+ "0.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "retr",
+ "mode": "port",
+ "cmd": "LIST"
+ },
+ "1.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://192.168.40.139/ftp/2001.03147v1.pdf",
+ "dir": "stor",
+ "mode": "port",
+ "cmd": "STOR"
+ },
+ "2.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "stor",
+ "mode": "port",
+ "cmd": "LIST"
+ },
+ "3.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://192.168.40.139/pub/3cdaemon-v2r10.zip",
+ "dir": "retr",
+ "mode": "port",
+ "cmd": "RETR"
+ },
+ "4.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "retr",
+ "mode": "port",
+ "cmd": "LIST"
+ }
+ }
+] \ No newline at end of file
diff --git a/test/decoders/ftp/json/01-ftp-port-upload-download_C2S.json b/test/decoders/ftp/json/01-ftp-port-upload-download_C2S.json
new file mode 100644
index 0000000..9511c25
--- /dev/null
+++ b/test/decoders/ftp/json/01-ftp-port-upload-download_C2S.json
@@ -0,0 +1,78 @@
+[
+ {
+ "topic": "data_dtp",
+ "session": "192.168.40.139:20-192.168.38.2:51808-6-0",
+ "dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://192.168.40.139/ftp/2001.03147v1.pdf",
+ "dir": "stor",
+ "mode": "port",
+ "cmd": "STOR"
+ },
+ "offset": 681116,
+ "total_bytes": 681116,
+ "is_finished": 1
+ },
+ {
+ "topic": "control_request",
+ "session": "192.168.38.2:51805-192.168.40.139:21-6-0",
+ "0.OTHERS": "OPTS UTF8 ON",
+ "1.USER": "USER ftp",
+ "2.PASS": "PASS 111111",
+ "3.CWD": "CWD ftp",
+ "4.PORT": "PORT 192,168,38,2,202,95",
+ "5.LIST": "LIST",
+ "6.PORT": "PORT 192,168,38,2,202,96",
+ "7.STOR": "STOR 2001.03147v1.pdf",
+ "8.CWD": "CWD ../pub",
+ "9.PORT": "PORT 192,168,38,2,202,97",
+ "10.LIST": "LIST",
+ "11.PORT": "PORT 192,168,38,2,202,98",
+ "12.RETR": "RETR 3cdaemon-v2r10.zip",
+ "13.PORT": "PORT 192,168,38,2,202,99",
+ "14.LIST": "LIST",
+ "15.OTHERS": "QUIT"
+ },
+ {
+ "topic": "control_dtp",
+ "session": "192.168.38.2:51805-192.168.40.139:21-6-0",
+ "0.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "retr",
+ "mode": "port",
+ "cmd": "LIST"
+ },
+ "1.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://192.168.40.139/ftp/2001.03147v1.pdf",
+ "dir": "stor",
+ "mode": "port",
+ "cmd": "STOR"
+ },
+ "2.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "stor",
+ "mode": "port",
+ "cmd": "LIST"
+ },
+ "3.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://192.168.40.139/pub/3cdaemon-v2r10.zip",
+ "dir": "retr",
+ "mode": "port",
+ "cmd": "RETR"
+ },
+ "4.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "retr",
+ "mode": "port",
+ "cmd": "LIST"
+ }
+ }
+] \ No newline at end of file
diff --git a/test/decoders/ftp/json/01-ftp-port-upload-download_S2C.json b/test/decoders/ftp/json/01-ftp-port-upload-download_S2C.json
new file mode 100644
index 0000000..83a2a7e
--- /dev/null
+++ b/test/decoders/ftp/json/01-ftp-port-upload-download_S2C.json
@@ -0,0 +1,28 @@
+[
+ {
+ "topic": "control_response",
+ "session": "192.168.38.2:51805-192.168.40.139:21-6-0",
+ "0.220": "220 Welcome to blah FTP service.",
+ "1.200": "200 Always in UTF8 mode.",
+ "2.OTHERS": "331 Please specify the password.",
+ "3.OTHERS": "230 Login successful.",
+ "4.OTHERS": "250 Directory successfully changed.",
+ "5.200": "200 PORT command successful. Consider using PASV.",
+ "6.OTHERS": "150 Here comes the directory listing.",
+ "7.OTHERS": "226 Directory send OK.",
+ "8.200": "200 PORT command successful. Consider using PASV.",
+ "9.OTHERS": "150 Ok to send data.",
+ "10.OTHERS": "226 Transfer complete.",
+ "11.OTHERS": "250 Directory successfully changed.",
+ "12.200": "200 PORT command successful. Consider using PASV.",
+ "13.OTHERS": "150 Here comes the directory listing.",
+ "14.OTHERS": "226 Directory send OK.",
+ "15.200": "200 PORT command successful. Consider using PASV.",
+ "16.OTHERS": "150 Opening ASCII mode data connection for 3cdaemon-v2r10.zip (949571 bytes).",
+ "17.OTHERS": "226 Transfer complete.",
+ "18.200": "200 PORT command successful. Consider using PASV.",
+ "19.OTHERS": "150 Here comes the directory listing.",
+ "20.OTHERS": "226 Directory send OK.",
+ "21.OTHERS": "221 Goodbye."
+ }
+] \ No newline at end of file
diff --git a/test/decoders/ftp/json/02-ftp_v6_1.json b/test/decoders/ftp/json/02-ftp_v6_1.json
new file mode 100644
index 0000000..7ea06d3
--- /dev/null
+++ b/test/decoders/ftp/json/02-ftp_v6_1.json
@@ -0,0 +1,160 @@
+[
+ {
+ "topic": "data_dtp",
+ "session": "::1:39002-::1:10791-6-0",
+ "dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "LIST"
+ },
+ "offset": 65,
+ "total_bytes": 65,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "::1:41426-::1:20987-6-0",
+ "dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://::1/pub/123.txt",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "RETR"
+ },
+ "offset": 44,
+ "total_bytes": 44,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "::1:59846-::1:50928-6-0",
+ "dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://::1/pub/test.txt",
+ "dir": "stor",
+ "mode": "pasv",
+ "cmd": "STOR"
+ },
+ "offset": 140,
+ "total_bytes": 140,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "::1:50872-::1:14779-6-0",
+ "dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "stor",
+ "mode": "pasv",
+ "cmd": "LIST"
+ },
+ "offset": 131,
+ "total_bytes": 131,
+ "is_finished": 1
+ },
+ {
+ "topic": "control_request",
+ "session": "::1:47756-::1:21-6-0",
+ "0.OTHERS": "FEAT",
+ "1.OTHERS": "AUTH TLS",
+ "2.OTHERS": "OPTS UTF8 ON",
+ "3.USER": "USER ftp",
+ "4.PASS": "PASS 111111",
+ "5.OTHERS": "PWD",
+ "6.CWD": "CWD /pub",
+ "7.EPSV": "EPSV",
+ "8.LIST": "LIST",
+ "9.OTHERS": "TYPE I",
+ "10.OTHERS": "SIZE 123.txt",
+ "11.OTHERS": "MDTM 123.txt",
+ "12.EPSV": "EPSV",
+ "13.RETR": "RETR 123.txt",
+ "14.EPSV": "EPSV",
+ "15.OTHERS": "ALLO 140",
+ "16.STOR": "STOR test.txt",
+ "17.OTHERS": "SITE UTIME 20240721024406 test.txt",
+ "18.OTHERS": "TYPE A",
+ "19.EPSV": "EPSV",
+ "20.LIST": "LIST",
+ "21.OTHERS": "QUIT"
+ },
+ {
+ "topic": "control_response",
+ "session": "::1:47756-::1:21-6-0",
+ "0.220": "220 Welcome to blah FTP service.",
+ "1.OTHERS": "211-Features:",
+ "2.OTHERS": " EPRT",
+ "3.OTHERS": " EPSV",
+ "4.OTHERS": " MDTM",
+ "5.OTHERS": " PASV",
+ "6.OTHERS": " REST STREAM",
+ "7.OTHERS": " SIZE",
+ "8.OTHERS": " TVFS",
+ "9.OTHERS": " UTF8",
+ "10.OTHERS": "211 End",
+ "11.OTHERS": "530 Please login with USER and PASS.",
+ "12.200": "200 Always in UTF8 mode.",
+ "13.OTHERS": "331 Please specify the password.",
+ "14.OTHERS": "230 Login successful.",
+ "15.OTHERS": "257 \"/\" is the current directory",
+ "16.OTHERS": "250 Directory successfully changed.",
+ "17.229": "229 Entering Extended Passive Mode (|||10791|)",
+ "18.OTHERS": "150 Here comes the directory listing.",
+ "19.OTHERS": "226 Directory send OK.",
+ "20.200": "200 Switching to Binary mode.",
+ "21.OTHERS": "213 44",
+ "22.OTHERS": "213 20240721024145",
+ "23.229": "229 Entering Extended Passive Mode (|||20987|)",
+ "24.OTHERS": "150 Opening BINARY mode data connection for 123.txt (44 bytes).",
+ "25.OTHERS": "226 Transfer complete.",
+ "26.229": "229 Entering Extended Passive Mode (|||50928|)",
+ "27.OTHERS": "202 ALLO command ignored.",
+ "28.OTHERS": "150 Ok to send data.",
+ "29.OTHERS": "226 Transfer complete.",
+ "30.OTHERS": "550 Permission denied.",
+ "31.200": "200 Switching to ASCII mode.",
+ "32.229": "229 Entering Extended Passive Mode (|||14779|)",
+ "33.OTHERS": "150 Here comes the directory listing.",
+ "34.OTHERS": "226 Directory send OK.",
+ "35.OTHERS": "221 Goodbye."
+ },
+ {
+ "topic": "control_dtp",
+ "session": "::1:47756-::1:21-6-0",
+ "0.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "LIST"
+ },
+ "1.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://::1/pub/123.txt",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "RETR"
+ },
+ "2.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://::1/pub/test.txt",
+ "dir": "stor",
+ "mode": "pasv",
+ "cmd": "STOR"
+ },
+ "3.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "stor",
+ "mode": "pasv",
+ "cmd": "LIST"
+ }
+ }
+] \ No newline at end of file
diff --git a/test/decoders/ftp/json/03-ipv6_eport_upload_download.json b/test/decoders/ftp/json/03-ipv6_eport_upload_download.json
new file mode 100644
index 0000000..db35746
--- /dev/null
+++ b/test/decoders/ftp/json/03-ipv6_eport_upload_download.json
@@ -0,0 +1,167 @@
+[
+ {
+ "topic": "data_dtp",
+ "session": "::1:20-::1:49998-6-0",
+ "dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "retr",
+ "mode": "port",
+ "cmd": "LIST"
+ },
+ "offset": 65,
+ "total_bytes": 65,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "::1:20-::1:40784-6-0",
+ "dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://::1/pub/123.txt",
+ "dir": "retr",
+ "mode": "port",
+ "cmd": "RETR"
+ },
+ "offset": 44,
+ "total_bytes": 44,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "::1:20-::1:32865-6-0",
+ "dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "retr",
+ "mode": "port",
+ "cmd": "LIST"
+ },
+ "offset": 65,
+ "total_bytes": 65,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "::1:20-::1:55267-6-0",
+ "dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://::1/pub/test.txt",
+ "dir": "stor",
+ "mode": "port",
+ "cmd": "STOR"
+ },
+ "offset": 140,
+ "total_bytes": 140,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "::1:20-::1:34844-6-0",
+ "dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "stor",
+ "mode": "port",
+ "cmd": "LIST"
+ },
+ "offset": 131,
+ "total_bytes": 131,
+ "is_finished": 1
+ },
+ {
+ "topic": "control_request",
+ "session": "::1:49594-::1:21-6-0",
+ "0.USER": "USER ftp",
+ "1.PASS": "PASS 111111",
+ "2.SYST": "SYST",
+ "3.CWD": "CWD pub",
+ "4.EPRT": "EPRT |2|::1|49998|",
+ "5.LIST": "LIST",
+ "6.OTHERS": "TYPE I",
+ "7.EPRT": "EPRT |2|::1|40784|",
+ "8.RETR": "RETR 123.txt",
+ "9.OTHERS": "TYPE A",
+ "10.EPRT": "EPRT |2|::1|32865|",
+ "11.LIST": "LIST",
+ "12.OTHERS": "TYPE I",
+ "13.EPRT": "EPRT |2|::1|55267|",
+ "14.STOR": "STOR test.txt",
+ "15.OTHERS": "TYPE A",
+ "16.EPRT": "EPRT |2|::1|34844|",
+ "17.LIST": "LIST",
+ "18.OTHERS": "QUIT"
+ },
+ {
+ "topic": "control_response",
+ "session": "::1:49594-::1:21-6-0",
+ "0.220": "220 Welcome to blah FTP service.",
+ "1.OTHERS": "331 Please specify the password.",
+ "2.OTHERS": "230 Login successful.",
+ "3.OTHERS": "215 UNIX Type: L8",
+ "4.OTHERS": "250 Directory successfully changed.",
+ "5.200": "200 EPRT command successful. Consider using EPSV.",
+ "6.OTHERS": "150 Here comes the directory listing.",
+ "7.OTHERS": "226 Directory send OK.",
+ "8.200": "200 Switching to Binary mode.",
+ "9.200": "200 EPRT command successful. Consider using EPSV.",
+ "10.OTHERS": "150 Opening BINARY mode data connection for 123.txt (44 bytes).",
+ "11.OTHERS": "226 Transfer complete.",
+ "12.200": "200 Switching to ASCII mode.",
+ "13.200": "200 EPRT command successful. Consider using EPSV.",
+ "14.OTHERS": "150 Here comes the directory listing.",
+ "15.OTHERS": "226 Directory send OK.",
+ "16.200": "200 Switching to Binary mode.",
+ "17.200": "200 EPRT command successful. Consider using EPSV.",
+ "18.OTHERS": "150 Ok to send data.",
+ "19.OTHERS": "226 Transfer complete.",
+ "20.200": "200 Switching to ASCII mode.",
+ "21.200": "200 EPRT command successful. Consider using EPSV.",
+ "22.OTHERS": "150 Here comes the directory listing.",
+ "23.OTHERS": "226 Directory send OK.",
+ "24.OTHERS": "221 Goodbye."
+ },
+ {
+ "topic": "control_dtp",
+ "session": "::1:49594-::1:21-6-0",
+ "0.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "retr",
+ "mode": "port",
+ "cmd": "LIST"
+ },
+ "1.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://::1/pub/123.txt",
+ "dir": "retr",
+ "mode": "port",
+ "cmd": "RETR"
+ },
+ "2.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "retr",
+ "mode": "port",
+ "cmd": "LIST"
+ },
+ "3.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://::1/pub/test.txt",
+ "dir": "stor",
+ "mode": "port",
+ "cmd": "STOR"
+ },
+ "4.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "stor",
+ "mode": "port",
+ "cmd": "LIST"
+ }
+ }
+] \ No newline at end of file
diff --git a/test/decoders/ftp/json/04-ftp-banner-no-ftp-characters.json b/test/decoders/ftp/json/04-ftp-banner-no-ftp-characters.json
new file mode 100644
index 0000000..ef8cda1
--- /dev/null
+++ b/test/decoders/ftp/json/04-ftp-banner-no-ftp-characters.json
@@ -0,0 +1,54 @@
+[
+ {
+ "topic": "data_dtp",
+ "session": "10.20.144.150:35976-10.20.144.151:16013-6-0",
+ "dtp": {
+ "username": "cdts3500",
+ "password": "cdts3500",
+ "uri": "ftp://10.20.144.151/qgpl/apkeyf.apkeyf",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "RETR"
+ },
+ "offset": 439,
+ "total_bytes": 439,
+ "is_finished": 1
+ },
+ {
+ "topic": "control_request",
+ "session": "10.20.144.150:35974-10.20.144.151:21-6-0",
+ "0.USER": "USER cdts3500",
+ "1.PASS": "PASS cdts3500",
+ "2.SYST": "SYST",
+ "3.OTHERS": "SITE NAMEFMT",
+ "4.OTHERS": "PWD",
+ "5.PASV": "PASV",
+ "6.RETR": "RETR qgpl/apkeyf.apkeyf",
+ "7.OTHERS": "QUIT"
+ },
+ {
+ "topic": "control_response",
+ "session": "10.20.144.150:35974-10.20.144.151:21-6-0",
+ "0.OTHERS": "331 Enter password.",
+ "1.OTHERS": "230 CDTS3500 logged on.",
+ "2.OTHERS": "215 OS/400 is the remote operating system. The TCP/IP version is \"V5R2M0\".",
+ "3.OTHERS": "250 Now using naming format \"0\".",
+ "4.OTHERS": "257 \"CDTS3500\" is current library.",
+ "5.227": "227 Entering Passive Mode (10,20,144,151,62,141).",
+ "6.OTHERS": "150 Retrieving member APKEYF in file APKEYF in library QGPL.",
+ "7.OTHERS": "250 File transfer completed successfully.",
+ "8.OTHERS": "221 QUIT subcommand received."
+ },
+ {
+ "topic": "control_dtp",
+ "session": "10.20.144.150:35974-10.20.144.151:21-6-0",
+ "0.dtp": {
+ "username": "cdts3500",
+ "password": "cdts3500",
+ "uri": "ftp://10.20.144.151/qgpl/apkeyf.apkeyf",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "RETR"
+ }
+ }
+] \ No newline at end of file
diff --git a/test/decoders/ftp/json/05-only-ctrl-link.json b/test/decoders/ftp/json/05-only-ctrl-link.json
new file mode 100644
index 0000000..036bf70
--- /dev/null
+++ b/test/decoders/ftp/json/05-only-ctrl-link.json
@@ -0,0 +1,33 @@
+[
+ {
+ "topic": "control_request",
+ "session": "192.168.20.1:40920-192.168.60.1:21-6-0",
+ "0.USER": "USER test1",
+ "1.PASS": "PASS iiecas2021",
+ "2.OTHERS": "TYPE I",
+ "3.PASV": "PASV",
+ "4.STOR": "STOR /home/test1/20210622201359人肉炸弹.txt"
+ },
+ {
+ "topic": "control_response",
+ "session": "192.168.20.1:40920-192.168.60.1:21-6-0",
+ "0.220": "220 (vsFTPd 3.0.2)",
+ "1.OTHERS": "331 Please specify the password.",
+ "2.OTHERS": "230 Login successful.",
+ "3.200": "200 Switching to Binary mode.",
+ "4.227": "227 Entering Passive Mode (192,168,60,1,39,16).",
+ "5.OTHERS": "150 Ok to send data."
+ },
+ {
+ "topic": "control_dtp",
+ "session": "192.168.20.1:40920-192.168.60.1:21-6-0",
+ "0.dtp": {
+ "username": "test1",
+ "password": "iiecas2021",
+ "uri": "ftp://192.168.60.1/home/test1/20210622201359人肉炸弹.txt",
+ "dir": "stor",
+ "mode": "pasv",
+ "cmd": "STOR"
+ }
+ }
+] \ No newline at end of file
diff --git a/test/decoders/ftp/json/06-ftp_pasv-upload-download.json b/test/decoders/ftp/json/06-ftp_pasv-upload-download.json
new file mode 100644
index 0000000..9a383e4
--- /dev/null
+++ b/test/decoders/ftp/json/06-ftp_pasv-upload-download.json
@@ -0,0 +1,135 @@
+[
+ {
+ "topic": "data_dtp",
+ "session": "127.0.0.1:59814-127.0.0.1:13144-6-0",
+ "dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "LIST"
+ },
+ "offset": 61,
+ "total_bytes": 61,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "127.0.0.1:38754-127.0.0.1:15810-6-0",
+ "dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "LIST"
+ },
+ "offset": 131,
+ "total_bytes": 131,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "127.0.0.1:52584-127.0.0.1:6554-6-0",
+ "dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://127.0.0.1/pub/123.txt",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "RETR"
+ },
+ "offset": 44,
+ "total_bytes": 44,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "127.0.0.1:32799-127.0.0.1:58439-6-0",
+ "dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://127.0.0.1/pub/test.txt",
+ "dir": "stor",
+ "mode": "pasv",
+ "cmd": "STOR"
+ },
+ "offset": 140,
+ "total_bytes": 140,
+ "is_finished": 1
+ },
+ {
+ "topic": "control_request",
+ "session": "127.0.0.1:42042-127.0.0.1:21-6-0",
+ "0.USER": "USER ftp",
+ "1.PASS": "PASS 111111",
+ "2.SYST": "SYST",
+ "3.PASV": "PASV",
+ "4.LIST": "LIST",
+ "5.CWD": "CWD pub",
+ "6.PASV": "PASV",
+ "7.LIST": "LIST",
+ "8.OTHERS": "TYPE I",
+ "9.PASV": "PASV",
+ "10.RETR": "RETR 123.txt",
+ "11.PASV": "PASV",
+ "12.STOR": "STOR test.txt",
+ "13.OTHERS": "QUIT"
+ },
+ {
+ "topic": "control_response",
+ "session": "127.0.0.1:42042-127.0.0.1:21-6-0",
+ "0.220": "220 Welcome to blah FTP service.",
+ "1.OTHERS": "331 Please specify the password.",
+ "2.OTHERS": "230 Login successful.",
+ "3.OTHERS": "215 UNIX Type: L8",
+ "4.227": "227 Entering Passive Mode (127,0,0,1,51,88).",
+ "5.OTHERS": "150 Here comes the directory listing.",
+ "6.OTHERS": "226 Directory send OK.",
+ "7.OTHERS": "250 Directory successfully changed.",
+ "8.227": "227 Entering Passive Mode (127,0,0,1,61,194).",
+ "9.OTHERS": "150 Here comes the directory listing.",
+ "10.OTHERS": "226 Directory send OK.",
+ "11.200": "200 Switching to Binary mode.",
+ "12.227": "227 Entering Passive Mode (127,0,0,1,25,154).",
+ "13.OTHERS": "150 Opening BINARY mode data connection for 123.txt (44 bytes).",
+ "14.OTHERS": "226 Transfer complete.",
+ "15.227": "227 Entering Passive Mode (127,0,0,1,228,71).",
+ "16.OTHERS": "150 Ok to send data.",
+ "17.OTHERS": "226 Transfer complete.",
+ "18.OTHERS": "221 Goodbye."
+ },
+ {
+ "topic": "control_dtp",
+ "session": "127.0.0.1:42042-127.0.0.1:21-6-0",
+ "0.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "LIST"
+ },
+ "1.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "LIST"
+ },
+ "2.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://127.0.0.1/pub/123.txt",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "RETR"
+ },
+ "3.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://127.0.0.1/pub/test.txt",
+ "dir": "stor",
+ "mode": "pasv",
+ "cmd": "STOR"
+ }
+ }
+] \ No newline at end of file
diff --git a/test/decoders/ftp/json/06-ftp_pasv-upload-download_C2S.json b/test/decoders/ftp/json/06-ftp_pasv-upload-download_C2S.json
new file mode 100644
index 0000000..efd0e2b
--- /dev/null
+++ b/test/decoders/ftp/json/06-ftp_pasv-upload-download_C2S.json
@@ -0,0 +1,54 @@
+[
+ {
+ "topic": "control_request",
+ "session": "127.0.0.1:42042-127.0.0.1:21-6-0",
+ "0.USER": "USER ftp",
+ "1.PASS": "PASS 111111",
+ "2.SYST": "SYST",
+ "3.PASV": "PASV",
+ "4.LIST": "LIST",
+ "5.CWD": "CWD pub",
+ "6.PASV": "PASV",
+ "7.LIST": "LIST",
+ "8.OTHERS": "TYPE I",
+ "9.PASV": "PASV",
+ "10.RETR": "RETR 123.txt",
+ "11.PASV": "PASV",
+ "12.STOR": "STOR test.txt",
+ "13.OTHERS": "QUIT"
+ },
+ {
+ "topic": "control_dtp",
+ "session": "127.0.0.1:42042-127.0.0.1:21-6-0",
+ "0.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "LIST"
+ },
+ "1.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "LIST"
+ },
+ "2.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://127.0.0.1/pub/123.txt",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "RETR"
+ },
+ "3.dtp": {
+ "username": "ftp",
+ "password": "111111",
+ "uri": "ftp://127.0.0.1/pub/test.txt",
+ "dir": "stor",
+ "mode": "pasv",
+ "cmd": "STOR"
+ }
+ }
+] \ No newline at end of file
diff --git a/test/decoders/ftp/json/06-ftp_pasv-upload-download_S2C.json b/test/decoders/ftp/json/06-ftp_pasv-upload-download_S2C.json
new file mode 100644
index 0000000..a0d28ef
--- /dev/null
+++ b/test/decoders/ftp/json/06-ftp_pasv-upload-download_S2C.json
@@ -0,0 +1,46 @@
+[
+ {
+ "topic": "data_dtp",
+ "session": "127.0.0.1:59814-127.0.0.1:13144-6-0",
+ "offset": 61,
+ "total_bytes": 61,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "127.0.0.1:38754-127.0.0.1:15810-6-0",
+ "offset": 131,
+ "total_bytes": 131,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "127.0.0.1:52584-127.0.0.1:6554-6-0",
+ "offset": 44,
+ "total_bytes": 44,
+ "is_finished": 1
+ },
+ {
+ "topic": "control_response",
+ "session": "127.0.0.1:42042-127.0.0.1:21-6-0",
+ "0.220": "220 Welcome to blah FTP service.",
+ "1.OTHERS": "331 Please specify the password.",
+ "2.OTHERS": "230 Login successful.",
+ "3.OTHERS": "215 UNIX Type: L8",
+ "4.227": "227 Entering Passive Mode (127,0,0,1,51,88).",
+ "5.OTHERS": "150 Here comes the directory listing.",
+ "6.OTHERS": "226 Directory send OK.",
+ "7.OTHERS": "250 Directory successfully changed.",
+ "8.227": "227 Entering Passive Mode (127,0,0,1,61,194).",
+ "9.OTHERS": "150 Here comes the directory listing.",
+ "10.OTHERS": "226 Directory send OK.",
+ "11.200": "200 Switching to Binary mode.",
+ "12.227": "227 Entering Passive Mode (127,0,0,1,25,154).",
+ "13.OTHERS": "150 Opening BINARY mode data connection for 123.txt (44 bytes).",
+ "14.OTHERS": "226 Transfer complete.",
+ "15.227": "227 Entering Passive Mode (127,0,0,1,228,71).",
+ "16.OTHERS": "150 Ok to send data.",
+ "17.OTHERS": "226 Transfer complete.",
+ "18.OTHERS": "221 Goodbye."
+ }
+] \ No newline at end of file
diff --git a/test/decoders/ftp/json/07-ftp-start-with-syst-command.json b/test/decoders/ftp/json/07-ftp-start-with-syst-command.json
new file mode 100644
index 0000000..08755d1
--- /dev/null
+++ b/test/decoders/ftp/json/07-ftp-start-with-syst-command.json
@@ -0,0 +1,37 @@
+[
+ {
+ "topic": "control_request",
+ "session": "10.100.237.39:48406-172.2.1.200:21-6-0",
+ "0.SYST": "SYST",
+ "1.USER": "USER administrator",
+ "2.PASS": "PASS admin@123",
+ "3.OTHERS": "TYPE I",
+ "4.PASV": "PASV",
+ "5.RETR": "RETR JS_XuZhou_1_1_App4",
+ "6.OTHERS": "QUIT"
+ },
+ {
+ "topic": "control_response",
+ "session": "10.100.237.39:48406-172.2.1.200:21-6-0",
+ "0.220": "220 Microsoft FTP Service",
+ "1.OTHERS": "215 Windows_NT",
+ "2.OTHERS": "331 Password required for administrator.",
+ "3.OTHERS": "230 User logged in.",
+ "4.200": "200 Type set to I.",
+ "5.227": "227 Entering Passive Mode (172,2,1,200,250,142).",
+ "6.OTHERS": "550 The system cannot find the file specified. ",
+ "7.OTHERS": "221 Goodbye."
+ },
+ {
+ "topic": "control_dtp",
+ "session": "10.100.237.39:48406-172.2.1.200:21-6-0",
+ "0.dtp": {
+ "username": "administrator",
+ "password": "admin@123",
+ "uri": "ftp://172.2.1.200/JS_XuZhou_1_1_App4",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "RETR"
+ }
+ }
+] \ No newline at end of file
diff --git a/test/decoders/ftp/json/08-ftp_EPSV_229_ipv4.json b/test/decoders/ftp/json/08-ftp_EPSV_229_ipv4.json
new file mode 100644
index 0000000..1556318
--- /dev/null
+++ b/test/decoders/ftp/json/08-ftp_EPSV_229_ipv4.json
@@ -0,0 +1,34 @@
+[
+ {
+ "topic": "control_request",
+ "session": "10.128.22.236:56976-172.17.0.74:21-6-0",
+ "0.USER": "USER YaaoFtpAdmin",
+ "1.PASS": "PASS JSyaao@2008",
+ "2.OTHERS": "TYPE I",
+ "3.EPSV": "EPSV",
+ "4.STOR": "STOR 32011143800147_20220503_134754_01.jpg"
+ },
+ {
+ "topic": "control_response",
+ "session": "10.128.22.236:56976-172.17.0.74:21-6-0",
+ "0.220": "220 Microsoft FTP Service",
+ "1.OTHERS": "331 Password required",
+ "2.OTHERS": "230 User logged in.",
+ "3.200": "200 Type set to I.",
+ "4.229": "229 Entering Extended Passive Mode (|||50929|)",
+ "5.OTHERS": "125 Data connection already open; Transfer starting.",
+ "6.OTHERS": "550 There is not enough space on the disk. "
+ },
+ {
+ "topic": "control_dtp",
+ "session": "10.128.22.236:56976-172.17.0.74:21-6-0",
+ "0.dtp": {
+ "username": "YaaoFtpAdmin",
+ "password": "JSyaao@2008",
+ "uri": "ftp://172.17.0.74/32011143800147_20220503_134754_01.jpg",
+ "dir": "stor",
+ "mode": "pasv",
+ "cmd": "STOR"
+ }
+ }
+] \ No newline at end of file
diff --git a/test/decoders/ftp/json/10-ftp-sdedu.json b/test/decoders/ftp/json/10-ftp-sdedu.json
new file mode 100644
index 0000000..bf41792
--- /dev/null
+++ b/test/decoders/ftp/json/10-ftp-sdedu.json
@@ -0,0 +1,101 @@
+[
+ {
+ "topic": "data_dtp",
+ "session": "192.168.32.27:63221-218.13.32.6:20008-6-0",
+ "dtp": {
+ "username": "anonymous",
+ "password": "IEUser@",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "LIST"
+ },
+ "offset": 1247,
+ "total_bytes": 1247,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "192.168.32.27:63234-218.13.32.6:20009-6-0",
+ "dtp": {
+ "username": "anonymous",
+ "password": "IEUser@",
+ "uri": "ftp://218.13.32.6/temp/�ĵ�1.docx",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "RETR"
+ },
+ "offset": 33598,
+ "total_bytes": 33598,
+ "is_finished": 1
+ },
+ {
+ "topic": "control_request",
+ "session": "192.168.32.27:63219-218.13.32.6:21-6-0",
+ "0.USER": "USER anonymous",
+ "1.PASS": "PASS IEUser@",
+ "2.OTHERS": "opts utf8 on",
+ "3.OTHERS": "PWD",
+ "4.CWD": "CWD /temp/",
+ "5.OTHERS": "TYPE A",
+ "6.PASV": "PASV",
+ "7.LIST": "LIST",
+ "8.OTHERS": "noop",
+ "9.CWD": "CWD /temp/",
+ "10.OTHERS": "noop",
+ "11.CWD": "CWD /temp/",
+ "12.OTHERS": "PWD",
+ "13.CWD": "CWD /temp/",
+ "14.OTHERS": "TYPE I",
+ "15.PASV": "PASV",
+ "16.OTHERS": "SIZE �ĵ�1.docx",
+ "17.RETR": "RETR �ĵ�1.docx",
+ "18.CWD": "CWD /temp/"
+ },
+ {
+ "topic": "control_response",
+ "session": "192.168.32.27:63219-218.13.32.6:21-6-0",
+ "0.220": "220-Microsoft FTP Service",
+ "1.220": "220 FTP Server",
+ "2.OTHERS": "331 Anonymous access allowed, send identity (e-mail name) as password.",
+ "3.OTHERS": "230-Welcome!",
+ "4.OTHERS": "230 Anonymous user logged in.",
+ "5.OTHERS": "501 option not supported",
+ "6.OTHERS": "257 \"/\" is current directory.",
+ "7.OTHERS": "250 CWD command successful.",
+ "8.200": "200 Type set to A.",
+ "9.227": "227 Entering Passive Mode (218,13,32,6,78,40).",
+ "10.OTHERS": "125 Data connection already open; Transfer starting.",
+ "11.OTHERS": "226 Transfer complete.",
+ "12.200": "200 NOOP command successful.",
+ "13.OTHERS": "250 CWD command successful.",
+ "14.200": "200 NOOP command successful.",
+ "15.OTHERS": "250 CWD command successful.",
+ "16.OTHERS": "257 \"/temp\" is current directory.",
+ "17.OTHERS": "250 CWD command successful.",
+ "18.200": "200 Type set to I.",
+ "19.227": "227 Entering Passive Mode (218,13,32,6,78,41).",
+ "20.OTHERS": "213 33598",
+ "21.OTHERS": "125 Data connection already open; Transfer starting.",
+ "22.OTHERS": "226 Transfer complete.",
+ "23.OTHERS": "250 CWD command successful."
+ },
+ {
+ "topic": "control_dtp",
+ "session": "192.168.32.27:63219-218.13.32.6:21-6-0",
+ "0.dtp": {
+ "username": "anonymous",
+ "password": "IEUser@",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "LIST"
+ },
+ "1.dtp": {
+ "username": "anonymous",
+ "password": "IEUser@",
+ "uri": "ftp://218.13.32.6/temp/�ĵ�1.docx",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "RETR"
+ }
+ }
+] \ No newline at end of file
diff --git a/test/decoders/ftp/json/11-ftp-sjtu.json b/test/decoders/ftp/json/11-ftp-sjtu.json
new file mode 100644
index 0000000..cdf8696
--- /dev/null
+++ b/test/decoders/ftp/json/11-ftp-sjtu.json
@@ -0,0 +1,354 @@
+[
+ {
+ "topic": "data_dtp",
+ "session": "192.168.32.27:64300-202.38.97.230:14978-6-0",
+ "dtp": {
+ "username": "anonymous",
+ "password": "IEUser@",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "LIST"
+ },
+ "offset": 2644,
+ "total_bytes": 2644,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "192.168.32.27:64308-202.38.97.230:64553-6-0",
+ "dtp": {
+ "username": "anonymous",
+ "password": "IEUser@",
+ "uri": "ftp://202.38.97.230/sjtu.edu.cn.html",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "RETR"
+ },
+ "offset": 333,
+ "total_bytes": 333,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "192.168.32.27:64312-202.38.97.230:58085-6-0",
+ "dtp": {
+ "username": "anonymous",
+ "password": "IEUser@",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "LIST"
+ },
+ "offset": 784,
+ "total_bytes": 784,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "192.168.32.27:64317-202.38.97.230:46331-6-0",
+ "dtp": {
+ "username": "anonymous",
+ "password": "IEUser@",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "LIST"
+ },
+ "offset": 455,
+ "total_bytes": 455,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "192.168.32.27:64321-202.38.97.230:25603-6-0",
+ "dtp": {
+ "username": "anonymous",
+ "password": "IEUser@",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "LIST"
+ },
+ "offset": 80,
+ "total_bytes": 80,
+ "is_finished": 1
+ },
+ {
+ "topic": "data_dtp",
+ "session": "192.168.32.27:64333-202.38.97.230:56773-6-0",
+ "dtp": {
+ "username": "anonymous",
+ "password": "IEUser@",
+ "uri": "ftp://202.38.97.230/pub/software/chinese/zhcon-0.2.3-1.i386.rpm",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "RETR"
+ },
+ "offset": 5079386,
+ "total_bytes": 5079386,
+ "is_finished": 1
+ },
+ {
+ "topic": "control_request",
+ "session": "192.168.32.27:64299-202.38.97.230:21-6-0",
+ "0.USER": "USER anonymous",
+ "1.PASS": "PASS IEUser@",
+ "2.OTHERS": "opts utf8 on",
+ "3.OTHERS": "syst",
+ "4.OTHERS": "site help",
+ "5.OTHERS": "PWD",
+ "6.OTHERS": "TYPE A",
+ "7.PASV": "PASV",
+ "8.LIST": "LIST",
+ "9.OTHERS": "PWD",
+ "10.CWD": "CWD Linux-HOWTO",
+ "11.CWD": "CWD /",
+ "12.CWD": "CWD archlinux",
+ "13.CWD": "CWD /",
+ "14.CWD": "CWD centos",
+ "15.CWD": "CWD /",
+ "16.CWD": "CWD csw",
+ "17.CWD": "CWD /",
+ "18.CWD": "CWD debian",
+ "19.CWD": "CWD /",
+ "20.CWD": "CWD debian-cd",
+ "21.CWD": "CWD /",
+ "22.CWD": "CWD debian-security",
+ "23.CWD": "CWD /",
+ "24.CWD": "CWD deepin",
+ "25.CWD": "CWD /",
+ "26.CWD": "CWD deepin-cd",
+ "27.CWD": "CWD /",
+ "28.CWD": "CWD docker-ce",
+ "29.CWD": "CWD /",
+ "30.CWD": "CWD fedora",
+ "31.CWD": "CWD /",
+ "32.CWD": "CWD linuxmint",
+ "33.CWD": "CWD /",
+ "34.CWD": "CWD linuxmint-cd",
+ "35.CWD": "CWD /",
+ "36.CWD": "CWD mageia",
+ "37.CWD": "CWD /",
+ "38.CWD": "CWD opensuse",
+ "39.CWD": "CWD /",
+ "40.CWD": "CWD openvz",
+ "41.CWD": "CWD /",
+ "42.CWD": "CWD remi",
+ "43.CWD": "CWD /",
+ "44.CWD": "CWD scientific",
+ "45.CWD": "CWD /",
+ "46.CWD": "CWD ubuntu",
+ "47.CWD": "CWD /",
+ "48.CWD": "CWD ubuntu-cd",
+ "49.CWD": "CWD /",
+ "50.OTHERS": "noop",
+ "51.CWD": "CWD /",
+ "52.OTHERS": "noop",
+ "53.CWD": "CWD /",
+ "54.OTHERS": "PWD",
+ "55.CWD": "CWD /",
+ "56.OTHERS": "TYPE I",
+ "57.PASV": "PASV",
+ "58.OTHERS": "SIZE sjtu.edu.cn.html",
+ "59.RETR": "RETR sjtu.edu.cn.html",
+ "60.OTHERS": "noop",
+ "61.CWD": "CWD /pub/",
+ "62.OTHERS": "TYPE A",
+ "63.PASV": "PASV",
+ "64.LIST": "LIST",
+ "65.OTHERS": "PWD",
+ "66.CWD": "CWD CPAN",
+ "67.CWD": "CWD /pub",
+ "68.CWD": "CWD LDP",
+ "69.CWD": "CWD /pub",
+ "70.CWD": "CWD fedora",
+ "71.CWD": "CWD /pub",
+ "72.CWD": "CWD internet-drafts",
+ "73.CWD": "CWD /pub",
+ "74.CWD": "CWD rfc",
+ "75.CWD": "CWD /pub",
+ "76.OTHERS": "noop",
+ "77.CWD": "CWD /pub/software/",
+ "78.OTHERS": "TYPE A",
+ "79.PASV": "PASV",
+ "80.LIST": "LIST",
+ "81.OTHERS": "noop",
+ "82.CWD": "CWD /pub/software/chinese/",
+ "83.OTHERS": "TYPE A",
+ "84.PASV": "PASV",
+ "85.LIST": "LIST",
+ "86.OTHERS": "noop",
+ "87.CWD": "CWD /pub/software/chinese/",
+ "88.OTHERS": "noop",
+ "89.CWD": "CWD /pub/software/chinese/",
+ "90.OTHERS": "PWD",
+ "91.CWD": "CWD /pub/software/chinese/",
+ "92.OTHERS": "TYPE I",
+ "93.PASV": "PASV",
+ "94.OTHERS": "SIZE zhcon-0.2.3-1.i386.rpm",
+ "95.RETR": "RETR zhcon-0.2.3-1.i386.rpm",
+ "96.CWD": "CWD /pub/software/chinese/"
+ },
+ {
+ "topic": "control_response",
+ "session": "192.168.32.27:64299-202.38.97.230:21-6-0",
+ "0.220": "220 (vsFTPd 3.0.2)",
+ "1.OTHERS": "331 Please specify the password.",
+ "2.OTHERS": "230 Login successful.",
+ "3.200": "200 Always in UTF8 mode.",
+ "4.OTHERS": "215 UNIX Type: L8",
+ "5.OTHERS": "550 Permission denied.",
+ "6.OTHERS": "257 \"/\"",
+ "7.200": "200 Switching to ASCII mode.",
+ "8.227": "227 Entering Passive Mode (202,38,97,230,58,130).",
+ "9.OTHERS": "150 Here comes the directory listing.",
+ "10.OTHERS": "226 Directory send OK.",
+ "11.OTHERS": "257 \"/\"",
+ "12.OTHERS": "250 Directory successfully changed.",
+ "13.OTHERS": "250 Directory successfully changed.",
+ "14.OTHERS": "250 Directory successfully changed.",
+ "15.OTHERS": "250 Directory successfully changed.",
+ "16.OTHERS": "250 Directory successfully changed.",
+ "17.OTHERS": "250 Directory successfully changed.",
+ "18.OTHERS": "250 Directory successfully changed.",
+ "19.OTHERS": "250 Directory successfully changed.",
+ "20.OTHERS": "250 Directory successfully changed.",
+ "21.OTHERS": "250 Directory successfully changed.",
+ "22.OTHERS": "250 Directory successfully changed.",
+ "23.OTHERS": "250 Directory successfully changed.",
+ "24.OTHERS": "250 Directory successfully changed.",
+ "25.OTHERS": "250 Directory successfully changed.",
+ "26.OTHERS": "250 Directory successfully changed.",
+ "27.OTHERS": "250 Directory successfully changed.",
+ "28.OTHERS": "250 Directory successfully changed.",
+ "29.OTHERS": "250 Directory successfully changed.",
+ "30.OTHERS": "250 Directory successfully changed.",
+ "31.OTHERS": "250 Directory successfully changed.",
+ "32.OTHERS": "250 Directory successfully changed.",
+ "33.OTHERS": "250 Directory successfully changed.",
+ "34.OTHERS": "250 Directory successfully changed.",
+ "35.OTHERS": "250 Directory successfully changed.",
+ "36.OTHERS": "250 Directory successfully changed.",
+ "37.OTHERS": "250 Directory successfully changed.",
+ "38.OTHERS": "250 Directory successfully changed.",
+ "39.OTHERS": "250 Directory successfully changed.",
+ "40.OTHERS": "250 Directory successfully changed.",
+ "41.OTHERS": "250 Directory successfully changed.",
+ "42.OTHERS": "250-",
+ "43.OTHERS": "250- OpenVZ consists of a kernel, user-level tools and templates.",
+ "44.OTHERS": "250- Kernel and tools are needed to install OpenVZ, and templates are",
+ "45.OTHERS": "250- needed to create containers.",
+ "46.OTHERS": "250- installation. For information about templates, read [4]this document.",
+ "47.OTHERS": "250- Yum repository",
+ "48.OTHERS": "250- 4. http://wiki.openvz.org/OS_template_cache_preparation",
+ "49.OTHERS": "250 Directory successfully changed.",
+ "50.OTHERS": "250 Directory successfully changed.",
+ "51.OTHERS": "250 Directory successfully changed.",
+ "52.OTHERS": "250 Directory successfully changed.",
+ "53.OTHERS": "250 Directory successfully changed.",
+ "54.OTHERS": "250 Directory successfully changed.",
+ "55.OTHERS": "250 Directory successfully changed.",
+ "56.OTHERS": "250 Directory successfully changed.",
+ "57.OTHERS": "250 Directory successfully changed.",
+ "58.200": "200 NOOP ok.",
+ "59.OTHERS": "250 Directory successfully changed.",
+ "60.200": "200 NOOP ok.",
+ "61.OTHERS": "250 Directory successfully changed.",
+ "62.OTHERS": "257 \"/\"",
+ "63.OTHERS": "250 Directory successfully changed.",
+ "64.200": "200 Switching to Binary mode.",
+ "65.227": "227 Entering Passive Mode (202,38,97,230,252,41).",
+ "66.OTHERS": "213 333",
+ "67.OTHERS": "150 Opening BINARY mode data connection for sjtu.edu.cn.html (333 bytes).",
+ "68.OTHERS": "226 Transfer complete.",
+ "69.200": "200 NOOP ok.",
+ "70.OTHERS": "250 Directory successfully changed.",
+ "71.200": "200 Switching to ASCII mode.",
+ "72.227": "227 Entering Passive Mode (202,38,97,230,226,229).",
+ "73.OTHERS": "150 Here comes the directory listing.",
+ "74.OTHERS": "226 Directory send OK.",
+ "75.OTHERS": "257 \"/pub\"",
+ "76.OTHERS": "250-The Comprehensive Perl Archive Network (http://www.cpan.org/)",
+ "77.OTHERS": "250-master site has been from the very beginning (1995) hosted at FUNET,",
+ "78.OTHERS": "250-the Finnish University NETwork.",
+ "79.OTHERS": "250-",
+ "80.OTHERS": "250 Directory successfully changed.",
+ "81.OTHERS": "250 Directory successfully changed.",
+ "82.OTHERS": "250 Directory successfully changed.",
+ "83.OTHERS": "250 Directory successfully changed.",
+ "84.OTHERS": "250 Directory successfully changed.",
+ "85.OTHERS": "250 Directory successfully changed.",
+ "86.OTHERS": "250 Directory successfully changed.",
+ "87.OTHERS": "250 Directory successfully changed.",
+ "88.OTHERS": "250 Directory successfully changed.",
+ "89.200": "200 NOOP ok.",
+ "90.OTHERS": "250 Directory successfully changed.",
+ "91.200": "200 Switching to ASCII mode.",
+ "92.227": "227 Entering Passive Mode (202,38,97,230,180,251).",
+ "93.OTHERS": "150 Here comes the directory listing.",
+ "94.OTHERS": "226 Directory send OK.",
+ "95.200": "200 NOOP ok.",
+ "96.OTHERS": "250 Directory successfully changed.",
+ "97.200": "200 Switching to ASCII mode.",
+ "98.227": "227 Entering Passive Mode (202,38,97,230,100,3).",
+ "99.OTHERS": "150 Here comes the directory listing.",
+ "100.OTHERS": "226 Directory send OK.",
+ "101.200": "200 NOOP ok.",
+ "102.OTHERS": "250 Directory successfully changed.",
+ "103.200": "200 NOOP ok.",
+ "104.OTHERS": "250 Directory successfully changed.",
+ "105.OTHERS": "257 \"/pub/software/chinese\"",
+ "106.OTHERS": "250 Directory successfully changed.",
+ "107.200": "200 Switching to Binary mode.",
+ "108.227": "227 Entering Passive Mode (202,38,97,230,221,197).",
+ "109.OTHERS": "213 5079386",
+ "110.OTHERS": "150 Opening BINARY mode data connection for zhcon-0.2.3-1.i386.rpm (5079386 bytes).",
+ "111.OTHERS": "226 Transfer complete.",
+ "112.OTHERS": "250 Directory successfully changed."
+ },
+ {
+ "topic": "control_dtp",
+ "session": "192.168.32.27:64299-202.38.97.230:21-6-0",
+ "0.dtp": {
+ "username": "anonymous",
+ "password": "IEUser@",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "LIST"
+ },
+ "1.dtp": {
+ "username": "anonymous",
+ "password": "IEUser@",
+ "uri": "ftp://202.38.97.230/sjtu.edu.cn.html",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "RETR"
+ },
+ "2.dtp": {
+ "username": "anonymous",
+ "password": "IEUser@",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "LIST"
+ },
+ "3.dtp": {
+ "username": "anonymous",
+ "password": "IEUser@",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "LIST"
+ },
+ "4.dtp": {
+ "username": "anonymous",
+ "password": "IEUser@",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "LIST"
+ },
+ "5.dtp": {
+ "username": "anonymous",
+ "password": "IEUser@",
+ "uri": "ftp://202.38.97.230/pub/software/chinese/zhcon-0.2.3-1.i386.rpm",
+ "dir": "retr",
+ "mode": "pasv",
+ "cmd": "RETR"
+ }
+ }
+] \ No newline at end of file
diff --git a/test/decoders/ftp/json/empty.json b/test/decoders/ftp/json/empty.json
new file mode 100644
index 0000000..fe51488
--- /dev/null
+++ b/test/decoders/ftp/json/empty.json
@@ -0,0 +1 @@
+[]
diff --git a/test/decoders/ftp/pcap/01-ftp-port-upload-download.pcap b/test/decoders/ftp/pcap/01-ftp-port-upload-download.pcap
new file mode 100644
index 0000000..314fa6f
--- /dev/null
+++ b/test/decoders/ftp/pcap/01-ftp-port-upload-download.pcap
Binary files differ
diff --git a/test/decoders/ftp/pcap/01-ftp-port-upload-download_C2S.pcap b/test/decoders/ftp/pcap/01-ftp-port-upload-download_C2S.pcap
new file mode 100644
index 0000000..d8f9b06
--- /dev/null
+++ b/test/decoders/ftp/pcap/01-ftp-port-upload-download_C2S.pcap
Binary files differ
diff --git a/test/decoders/ftp/pcap/01-ftp-port-upload-download_S2C.pcap b/test/decoders/ftp/pcap/01-ftp-port-upload-download_S2C.pcap
new file mode 100644
index 0000000..c0e9cc7
--- /dev/null
+++ b/test/decoders/ftp/pcap/01-ftp-port-upload-download_S2C.pcap
Binary files differ
diff --git a/test/decoders/ftp/pcap/02-ftp_v6_1.pcap b/test/decoders/ftp/pcap/02-ftp_v6_1.pcap
new file mode 100644
index 0000000..9b7a924
--- /dev/null
+++ b/test/decoders/ftp/pcap/02-ftp_v6_1.pcap
Binary files differ
diff --git a/test/decoders/ftp/pcap/03-ipv6_eport_upload_download.pcap b/test/decoders/ftp/pcap/03-ipv6_eport_upload_download.pcap
new file mode 100644
index 0000000..167507a
--- /dev/null
+++ b/test/decoders/ftp/pcap/03-ipv6_eport_upload_download.pcap
Binary files differ
diff --git a/test/decoders/ftp/pcap/04-ftp-banner-no-ftp-characters.pcap b/test/decoders/ftp/pcap/04-ftp-banner-no-ftp-characters.pcap
new file mode 100644
index 0000000..f646ff2
--- /dev/null
+++ b/test/decoders/ftp/pcap/04-ftp-banner-no-ftp-characters.pcap
Binary files differ
diff --git a/test/decoders/ftp/pcap/05-only-ctrl-link.pcap b/test/decoders/ftp/pcap/05-only-ctrl-link.pcap
new file mode 100644
index 0000000..8a5da68
--- /dev/null
+++ b/test/decoders/ftp/pcap/05-only-ctrl-link.pcap
Binary files differ
diff --git a/test/decoders/ftp/pcap/06-ftp_pasv-upload-download.pcap b/test/decoders/ftp/pcap/06-ftp_pasv-upload-download.pcap
new file mode 100644
index 0000000..1a391ae
--- /dev/null
+++ b/test/decoders/ftp/pcap/06-ftp_pasv-upload-download.pcap
Binary files differ
diff --git a/test/decoders/ftp/pcap/06-ftp_pasv-upload-download_C2S.pcap b/test/decoders/ftp/pcap/06-ftp_pasv-upload-download_C2S.pcap
new file mode 100644
index 0000000..753f328
--- /dev/null
+++ b/test/decoders/ftp/pcap/06-ftp_pasv-upload-download_C2S.pcap
Binary files differ
diff --git a/test/decoders/ftp/pcap/06-ftp_pasv-upload-download_S2C.pcap b/test/decoders/ftp/pcap/06-ftp_pasv-upload-download_S2C.pcap
new file mode 100644
index 0000000..5ccd508
--- /dev/null
+++ b/test/decoders/ftp/pcap/06-ftp_pasv-upload-download_S2C.pcap
Binary files differ
diff --git a/test/decoders/ftp/pcap/07-ftp-start-with-syst-command.pcap b/test/decoders/ftp/pcap/07-ftp-start-with-syst-command.pcap
new file mode 100644
index 0000000..9f1dff6
--- /dev/null
+++ b/test/decoders/ftp/pcap/07-ftp-start-with-syst-command.pcap
Binary files differ
diff --git a/test/decoders/ftp/pcap/08-ftp_EPSV_229_ipv4.pcap b/test/decoders/ftp/pcap/08-ftp_EPSV_229_ipv4.pcap
new file mode 100644
index 0000000..926613b
--- /dev/null
+++ b/test/decoders/ftp/pcap/08-ftp_EPSV_229_ipv4.pcap
Binary files differ
diff --git a/test/decoders/ftp/pcap/10-ftp-sdedu.pcap b/test/decoders/ftp/pcap/10-ftp-sdedu.pcap
new file mode 100644
index 0000000..cf53ce9
--- /dev/null
+++ b/test/decoders/ftp/pcap/10-ftp-sdedu.pcap
Binary files differ
diff --git a/test/decoders/ftp/pcap/11-ftp-sjtu.pcap b/test/decoders/ftp/pcap/11-ftp-sjtu.pcap
new file mode 100644
index 0000000..648dd55
--- /dev/null
+++ b/test/decoders/ftp/pcap/11-ftp-sjtu.pcap
Binary files differ