static FtpEolReturn ftp_parse_response(const uint8_t* data, uint16_t& offset,
uint16_t size, ServiceFTPData& fd, FTPReplyState rstate)
{
- for (; offset < size; ++offset)
+ while (offset < size)
{
if (data[offset] == 0x0D)
{
fd.rstate = rstate;
return FTP_FOUND_EOL;
}
+
+ if (offset == UINT16_MAX)
+ {
+ return FTP_NOT_FOUND_EOL;
+ }
+
+ ++offset;
}
return FTP_NOT_FOUND_EOL;
}
FtpEolReturn parse_ret;
FTPReplyState tmp_state;
- for (; offset < size; ++offset)
+ while (offset < size)
{
/* Trim any blank lines (be a little tolerant) */
- for (; offset < size; ++offset)
+ while (offset < size)
{
if (data[offset] != 0x0D and data[offset] != 0x0A)
break;
+ if (offset == UINT16_MAX)
+ {
+ return 0;
+ }
+ ++offset;
}
switch (fd.rstate)
parse_ret = ftp_parse_response(data, offset, size, fd, FTP_REPLY_LONG);
if (parse_ret == FTP_INCORRECT_EOL)
return -1;
+ if (offset == UINT16_MAX)
+ return 0;
if (++offset >= size)
{
offset = size;
}
if (fd.rstate == FTP_REPLY_BEGIN)
{
- for (; offset < size; ++offset)
+ while (offset < size)
{
if (data[offset] == 0x0D)
{
}
else if (!isspace(data[offset]))
break;
+
+ if (offset == UINT16_MAX)
+ {
+ return 0;
+ }
+ ++offset;
}
return fd.code;
}
+ if (offset == UINT16_MAX)
+ {
+ return 0;
+ }
+ ++offset;
}
return 0;
}
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2022-2025 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation. You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//--------------------------------------------------------------------------
+//
+// service_ftp_test.cc author Oleksandr Stepanov <ostepano@cisco.com>
+
+#define FTP_UNIT_TEST
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "../service_ftp.h"
+#include "../service_ftp.cc"
+#include "service_plugin_mock.h"
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+
+const uint8_t* service_strstr(const uint8_t* p, unsigned,
+ const uint8_t*, unsigned)
+{
+ return nullptr;
+}
+
+AppIdModule::AppIdModule()
+ : Module("a", "b") { }
+AppIdModule::~AppIdModule() = default;
+
+AppIdConfig test_app_config;
+
+static ServiceFTPData mock_service_data;
+static ServiceDiscovery mock_service_discovery;
+static FtpServiceDetector test_detector(&mock_service_discovery);
+
+AppIdInspector::AppIdInspector(AppIdModule&) : config(&test_app_config), ctxt(test_app_config) { }
+
+AppIdFlowData* AppIdDetector::data_get(const AppIdSession&)
+{
+ return &mock_service_data;
+}
+
+TEST_GROUP(ftp_parsing_tests)
+{
+ void setup() override
+ {
+
+ }
+ void teardown() override
+ {
+
+ }
+};
+
+TEST(ftp_parsing_tests, ftp_parse_invalid_offset_reply)
+{
+ uint8_t* data = new uint8_t[65535];
+ uint16_t offset = 65530;
+ ServiceFTPData fd;
+ fd.rstate = FTP_REPLY_MULTI;
+
+ memset(data, 0, 65535);
+ data[65534] = 0x0D;
+ data[65533] = 0x0D;
+
+ auto res = ftp_validate_reply(data, offset, 65535, fd);
+ CHECK_EQUAL(0, res);
+ delete[] data;
+}
+
+TEST(ftp_parsing_tests, ftp_parse_invalid_offset_response)
+{
+ uint8_t* data = new uint8_t[65535];
+ uint16_t offset = 65533;
+ ServiceFTPData fd;
+ fd.rstate = FTP_REPLY_MULTI;
+
+ memset(data, 0, 65535);
+ data[65534] = 0x0D;
+ data[65533] = 0x0D;
+ data[65532] = 0x0D;
+
+ auto res = ftp_parse_response(data, offset, 65535, fd, FTP_REPLY_MULTI);
+ CHECK_EQUAL(FTP_PARTIAL_EOL, res);
+
+ offset = 65534;
+ memset(data, 0, 65535);
+ res = ftp_parse_response(data, offset, 65535, fd, FTP_REPLY_MULTI);
+ CHECK_EQUAL(FTP_NOT_FOUND_EOL, res);
+
+ delete[] data;
+}
+
+int main(int argc, char** argv)
+{
+ int return_value = CommandLineTestRunner::RunAllTests(argc, argv);
+ return return_value;
+}
\ No newline at end of file
int AppIdDetector::initialize(AppIdInspector&){return 0;}
int AppIdDetector::data_add(AppIdSession&, AppIdFlowData*){return 0;}
+#ifndef FTP_UNIT_TEST
AppIdFlowData* AppIdDetector::data_get(const AppIdSession&) {return nullptr;}
+#endif
void AppIdDetector::add_user(AppIdSession&, const char*, AppId, bool, AppidChangeBits&){}
void AppIdDetector::add_payload(AppIdSession&, AppId){}
void AppIdDetector::add_app(const snort::Packet&, AppIdSession&, AppidSessionDirection, AppId, AppId, const char*, AppidChangeBits&){}
AppIdHttpSession* AppIdSession::create_http_session(int64_t stream_id) { return nullptr; }
void AppIdHttpSession::set_field(HttpFieldIds id, const std::string* str, AppidChangeBits&) { }
+void AppIdModule::reset_stats() {}
+void AppIdModule::sum_stats(bool) { }
+AppIdInspector::~AppIdInspector() = default;
+SfIpRet snort::SfIp::set(void const*, int) { return SFIP_SUCCESS; }
+SfIpRet snort::SfIp::set(void const*) { return SFIP_SUCCESS; }
+SfIpRet snort::SfIp::pton(const int, const char* ) { return SFIP_SUCCESS; }
+void AppIdInspector::eval(snort::Packet*) { }
+void AppIdInspector::show(const snort::SnortConfig*) const { }
+void AppIdInspector::tinit() { }
+void AppIdInspector::tterm() { }
+void AppIdInspector::tear_down(snort::SnortConfig*) { }
+snort::ProfileStats* AppIdModule::get_profile(
+ unsigned, const char*&, const char*&) const
+{
+ return nullptr;
+}
+bool AppIdInspector::configure(snort::SnortConfig*) { return true; }
+PegCount snort::Module::get_global_count(char const*) const { return 0; }
+snort::Module::Module(char const*, char const*) {}
+
void snort::DataBus::publish(unsigned, unsigned, snort::DataEvent&, snort::Flow*) { }
void snort::DataBus::publish(unsigned, unsigned, const uint8_t*, unsigned, snort::Flow*) { }
void snort::DataBus::publish(unsigned, unsigned, snort::Packet*, snort::Flow*) { }