#include #include #include #include #include "ftp_decoder.h" #include "ftp_decoder_inner.h" #include "ftp_decoder_util.h" #ifdef __cplusplus extern "C" { #endif #include #include #include #include #ifdef __cplusplus } #endif /********************* Stellar Mock ********************/ int stellar_get_worker_thread_num(struct stellar *st) { return 1; } int stellar_get_current_thread_id(struct stellar *st) { return 0; } int session_get_current_thread_id(struct session *sess) { return 0; } const char *session_get0_readable_addr(struct session *sess) { return "TODO"; } struct session_addr *session_get0_addr(struct session *sess, enum session_addr_type *addr_type) { *addr_type = SESSION_ADDR_TYPE_UNKNOWN; return NULL; } int session_mq_publish_message(struct session *sess, int topic_id, void *msg) { return 0; } const char *session_get0_current_payload(struct session *sess, size_t *payload_len) { *payload_len = 0; return "TODO"; } void stellar_session_plugin_dettach_current_session(struct session *sess) { return; } enum session_state session_get_current_state(struct session *sess) { return SESSION_STATE_INVALID; } int stellar_session_mq_create_topic(struct stellar *st, const char *topic_name, session_msg_free_cb_func *msg_free_cb, void *msg_free_arg) { return 0; } int stellar_session_mq_subscribe(struct stellar *st, int topic_id, on_session_msg_cb_func *plugin_on_msg_cb, int plugin_id) { return 0; } int stellar_session_plugin_register(struct stellar *st, session_ctx_new_func session_ctx_new, session_ctx_free_func session_ctx_free, void *plugin_env) { return 0; } int stellar_session_mq_get_topic_id(struct stellar *st, const char *topic_name) { return 0; } const struct packet *session_get0_current_packet(struct session *sess) { return NULL; } int packet_get_direction(const struct packet *pkt) { return PACKET_DIRECTION_UNKNOWN; } /********************* Stellar Mock End ********************/ TEST(ftp_decoder, identify_by_payload) { // true ASSERT_TRUE(ftp_ctrl_identify_by_payload("USER", 4, PACKET_DIRECTION_C2S)); ASSERT_TRUE(ftp_ctrl_identify_by_payload("USER test", 9, PACKET_DIRECTION_C2S)); ASSERT_TRUE(ftp_ctrl_identify_by_payload("220 (vsFTPd 3.0.1)", strlen("220 (vsFTPd 3.0.1)"), PACKET_DIRECTION_S2C)); ASSERT_TRUE(ftp_ctrl_identify_by_payload("220 (vsFTPD 3.0.2)", strlen("220 (vsFTPD 3.0.2)"), PACKET_DIRECTION_S2C)); ASSERT_TRUE(ftp_ctrl_identify_by_payload("220 (ftpd 3.0.3)", strlen("220 (ftpd 3.0.3)"), PACKET_DIRECTION_S2C)); ASSERT_TRUE(ftp_ctrl_identify_by_payload("220-Microsoft FTP Service", strlen("220-Microsoft FTP Service"), PACKET_DIRECTION_S2C)); // false ASSERT_FALSE(ftp_ctrl_identify_by_payload("USR", 3, PACKET_DIRECTION_C2S)); ASSERT_FALSE(ftp_ctrl_identify_by_payload("USRxx", 5, PACKET_DIRECTION_C2S)); ASSERT_FALSE(ftp_ctrl_identify_by_payload("PASS", 4, PACKET_DIRECTION_C2S)); ASSERT_FALSE(ftp_ctrl_identify_by_payload("200 OK", 6, PACKET_DIRECTION_S2C)); ASSERT_FALSE(ftp_ctrl_identify_by_payload("220 (xxx 3.0.3)", strlen("220 (xxx 3.0.3)"), PACKET_DIRECTION_S2C)); } TEST(ftp_decoder, 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, "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)); } TEST(ftp_decoder, ftp_skip_tail_crlf) { ASSERT_EQ(ftp_skip_tail_crlf("", 0), 0); ASSERT_EQ(ftp_skip_tail_crlf("\r", 1), 0); ASSERT_EQ(ftp_skip_tail_crlf("\n", 1), 0); ASSERT_EQ(ftp_skip_tail_crlf("\r\n", 2), 0); ASSERT_EQ(ftp_skip_tail_crlf("a\r\n", 3), 1); ASSERT_EQ(ftp_skip_tail_crlf("abcdefg\r\n", 9), 7); } TEST(ftp_decoder, ipv4_port_style) { int ret; uint32_t ipv4_net; uint16_t port_net; 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_decoder, 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_decoder, 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); 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); 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); 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)); } static const char *gtest_cla_short_options = "hLf:"; static const struct option gtest_cla_long_options[] = { {"help", no_argument, NULL, 'h'}, {"gtest_list_tests", no_argument, NULL, 'L'}, {"gtest_filter", required_argument, NULL, 'f'}, {NULL, 0, NULL, 0}}; static void usage(int argc, char *argv[]) { printf("args example:\n"); printf("\t%s short-arg long-arg\n", argv[0]); printf("\t%s -v \t--version\n", argv[0]); printf("\t%s -L \t--gtest_list_tests\n", argv[0]); printf("\t%s -f \t--gtest_filter=ftp_decoder*\n", argv[0]); exit(0); } int main(int argc, char **argv) { int c; int to_gtest_argc = 1; char *to_gtest_args[4] = {(char *)"ftp_gtest", NULL, NULL, NULL}; char temp_string[1024] = {}; while (1) { c = getopt_long(argc, argv, gtest_cla_short_options, gtest_cla_long_options, NULL); if (c == -1) { break; } switch (c) { case 'h': usage(argc, argv); break; case 'L': to_gtest_args[1] = (char *)"--gtest_list_tests"; to_gtest_argc++; break; case 'f': strncpy(temp_string, "--gtest_filter=", strlen("--gtest_filter=") + 1); strcat(temp_string, optarg); to_gtest_argc++; to_gtest_args[1] = temp_string; break; case '?': /* invalid or unknown option */ return -1; break; } } testing::InitGoogleTest(&to_gtest_argc, to_gtest_args); int ret = RUN_ALL_TESTS(); return ret; }