]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Pull request #4848: appid: out-of-range readings fix
authorOleksandr Stepanov -X (ostepano - SOFTSERVE INC at Cisco) <ostepano@cisco.com>
Thu, 7 Aug 2025 12:05:22 +0000 (12:05 +0000)
committerChris Sherwin (chsherwi) <chsherwi@cisco.com>
Thu, 7 Aug 2025 12:05:22 +0000 (12:05 +0000)
Merge in SNORT/snort3 from ~OSTEPANO/snort3:misc_out_of_range to master

Squashed commit of the following:

commit 3a72fb5d4060e7c0d5aa4b2a7f326cf70d7ea567
Author: Oleksandr Stepanov <ostepano@cisco.com>
Date:   Wed Jul 30 08:26:34 2025 -0400

    appid: out-of-range readings fix

21 files changed:
src/network_inspectors/appid/detector_plugins/detector_dns.cc
src/network_inspectors/appid/detector_plugins/detector_pop3.cc
src/network_inspectors/appid/detector_plugins/detector_smtp.cc
src/network_inspectors/appid/detector_plugins/http_url_patterns.cc
src/network_inspectors/appid/detector_plugins/test/CMakeLists.txt
src/network_inspectors/appid/detector_plugins/test/detector_plugins_mock.h
src/network_inspectors/appid/detector_plugins/test/detector_pop3_test.cc [new file with mode: 0644]
src/network_inspectors/appid/detector_plugins/test/detector_sip_test.cc
src/network_inspectors/appid/detector_plugins/test/detector_smtp_test.cc
src/network_inspectors/appid/detector_plugins/test/http_url_patterns_test.cc
src/network_inspectors/appid/service_plugins/service_netbios.cc
src/network_inspectors/appid/service_plugins/service_rtmp.cc
src/network_inspectors/appid/service_plugins/service_snmp.cc
src/network_inspectors/appid/service_plugins/test/CMakeLists.txt
src/network_inspectors/appid/service_plugins/test/service_netbios_test.cc [new file with mode: 0644]
src/network_inspectors/appid/service_plugins/test/service_plugin_mock.h
src/network_inspectors/appid/service_plugins/test/service_rtmp_test.cc [new file with mode: 0644]
src/network_inspectors/appid/service_plugins/test/service_snmp_test.cc [new file with mode: 0644]
src/protocols/ssl.cc
src/protocols/test/CMakeLists.txt
src/protocols/test/ssl_protocol_test.cc [new file with mode: 0644]

index db1d19b39980e25d3f60676f46fbfa1102d949c0..851997b233a7288f735d74a54d8ccddf66c84d86 100644 (file)
@@ -361,50 +361,50 @@ int DnsValidator::dns_validate_query(const uint8_t* data, uint16_t* offset, uint
     uint16_t id, bool host_reporting, AppIdSession& asd, AppidChangeBits& change_bits)
 {
     int ret;
-    const uint8_t* host;
-    uint8_t host_len;
-    bool host_len_valid;
-    uint16_t host_offset;
+    const uint8_t* host = data + *offset;
+    uint8_t host_len = 0;
+    bool host_len_valid = false;
+    uint16_t host_offset = *offset;
 
-    host = data + *offset;
-    host_offset = *offset;
     ret = dns_validate_label(data, *offset, size, host_len, host_len_valid);
 
-    if (ret == APPID_SUCCESS)
+    if ((ret == APPID_SUCCESS) and (host_reporting))
     {
+        if ((*offset > size) || ((size - *offset) < (uint16_t)sizeof(DNSQueryFixed)))
+            return APPID_NOMATCH;
+
         const DNSQueryFixed* query = (const DNSQueryFixed*)(data + *offset);
+
         *offset += sizeof(DNSQueryFixed);
 
-        if (host_reporting)
-        {
-            uint16_t record_type = ntohs(query->QType);
+        uint16_t record_type = ntohs(query->QType);
 
-            if ((host_len == 0) || (!host_len_valid))
-            {
-                host        = nullptr;
-                host_len    = 0;
-                host_offset = 0;
-            }
-            switch (record_type)
-            {
-            case PATTERN_A_REC:
-            case PATTERN_AAAA_REC:
-            case PATTERN_CNAME_REC:
-            case PATTERN_SRV_REC:
-            case PATTERN_TXT_REC:
-            case PATTERN_MX_REC:
-            case PATTERN_SOA_REC:
-            case PATTERN_NS_REC:
-            case PATTERN_ANY_REC:
-                ret = add_dns_query_info(asd, id, host, host_len, host_offset, record_type, *offset, change_bits);
-                break;
-            case PATTERN_PTR_REC:
-                ret = add_dns_query_info(asd, id, nullptr, 0, 0, record_type, *offset, change_bits);
-                break;
-            default:
-                break;
-            }
+        if ((host_len == 0) || (!host_len_valid))
+        {
+            host        = nullptr;
+            host_len    = 0;
+            host_offset = 0;
+        }
+        switch (record_type)
+        {
+        case PATTERN_A_REC:
+        case PATTERN_AAAA_REC:
+        case PATTERN_CNAME_REC:
+        case PATTERN_SRV_REC:
+        case PATTERN_TXT_REC:
+        case PATTERN_MX_REC:
+        case PATTERN_SOA_REC:
+        case PATTERN_NS_REC:
+        case PATTERN_ANY_REC:
+            ret = add_dns_query_info(asd, id, host, host_len, host_offset, record_type, *offset, change_bits);
+            break;
+        case PATTERN_PTR_REC:
+            ret = add_dns_query_info(asd, id, nullptr, 0, 0, record_type, *offset, change_bits);
+            break;
+        default:
+            break;
         }
+    
     }
     return ret;
 }
index d598c1b941cb48b0e47285711d4e0c8d1cf7775a..44f24855c645d2fab3783c5d5ad662655951e23b 100644 (file)
@@ -290,7 +290,7 @@ static int pop3_check_line(const uint8_t** data, const uint8_t* end)
 
 int Pop3ServiceDetector::pop3_server_validate(POP3DetectorData* dd, const uint8_t* data, uint16_t size,
     AppIdSession& asd, int server, AppidChangeBits& change_bits)
-{
+{    
     ServicePOP3Data* pd = &dd->server;
     const uint8_t* begin = nullptr;
 
@@ -305,7 +305,7 @@ int Pop3ServiceDetector::pop3_server_validate(POP3DetectorData* dd, const uint8_
         // fallthrough
 
     case POP3_STATE_RESPONSE:
-        if (!begin && data[0] == '+' && data[1] == ' ')
+        if (!begin && size >= 2 && data[0] == '+' && data[1] == ' ')
         {
             data += 2;
             if (pop3_check_line(&data, end))
index 6f8c3c76c761697d16b56f0430ca47e52265efcd..e554eeebf77be8c2a51779fde342e539025f7154 100644 (file)
@@ -525,8 +525,8 @@ int SmtpClientDetector::validate(AppIdDiscoveryArgs& args)
             if (*args.data == '.')
             {
                 if (len == 0 ||
-                    args.data[1] == '\n' ||
-                    (len >= 2 && args.data[1] == '\r' && args.data[2] == '\n'))
+                    (len >= 2 && args.data[1] == '\n') ||
+                    (len >= 3 && args.data[1] == '\r' && args.data[2] == '\n'))
                 {
                     add_app(args.asd, APP_ID_SMTP, APP_ID_SMTP, nullptr, args.change_bits);
                     goto done;
index 333a21d3baa528549488b4f4ea8b63c6c004106d..af769d9b304b7a6e1182e95f22b44e6101e039cd 100644 (file)
@@ -1614,7 +1614,7 @@ void HttpPatternMatchers::get_server_vendor_version(const char* data, int len, c
         vendor_len = ver - data;
         ver++;
 
-        for (p = ver; *p && p < end; p++)
+        for (p = ver; p < end && *p; p++)
         {
             if ( *p == '(' )
             {
index 5b63a4ff583c087aa5d30e4b09098c71fa5f795a..4852e9173c84108ac324550044b5190391ae0aec 100644 (file)
@@ -1,8 +1,19 @@
 
 include_directories ( appid PRIVATE ${APPID_INCLUDE_DIR} )
 
-add_cpputest( detector_smtp_test )
+add_cpputest( detector_smtp_test 
+    SOURCES
+        ../../../../utils/util_cstring.cc )
 
-add_cpputest( http_url_patterns_test )
+add_cpputest( http_url_patterns_test
+    SOURCES
+        ../../../../utils/util_cstring.cc )
 
-add_cpputest( detector_sip_test )
+add_cpputest( detector_sip_test 
+    SOURCES
+        ../../../../utils/util_cstring.cc
+        ../../appid_utils/sf_mlmp.cc )
+
+add_cpputest( detector_pop3_test
+    SOURCES
+        ../../../../utils/util_cstring.cc )
index 6b0442b6ca2ab7267763237fdbbff32b28c15412..ced4f9622bc5e9343945427a5322fa6f00cafc3a 100644 (file)
 #include "config.h"
 #endif
 
+#include <utils/util_cstring.h>
+#include <framework/module.h>
+#include <appid/service_plugins/service_detector.h>
+#include <appid/client_plugins/client_detector.h>
+#include <appid/appid_inspector.h>
+
 #include "log/messages.h"
 #include "utils/stats.h"
 
@@ -93,18 +99,6 @@ void show_stats(PegCount*, const PegInfo*, unsigned, const char*) { }
 void show_stats(PegCount*, const PegInfo*, const std::vector<unsigned>&, const char*, FILE*) { }
 // LCOV_EXCL_STOP
 
-#ifndef SIP_UNIT_TEST
-class AppIdInspector : public snort::Inspector
-{
-public:
-    AppIdInspector(AppIdModule&) { }
-    ~AppIdInspector() override = default;
-    bool configure(snort::SnortConfig*) override;
-private:
-    AppIdContext* ctxt = nullptr;
-};
-#endif
-
 // Stubs for modules, config
 AppIdConfig::~AppIdConfig() = default;
 AppIdModule::AppIdModule()
@@ -127,7 +121,7 @@ bool AppIdModule::end(const char*, int, snort::SnortConfig*)
     return false;
 }
 
-const Command* AppIdModule::get_commands() const
+const snort::Command* AppIdModule::get_commands() const
 {
     return nullptr;
 }
@@ -148,8 +142,8 @@ snort::ProfileStats* AppIdModule::get_profile(
     return nullptr;
 }
 
-void AppIdModule::set_trace(const Trace*) const { }
-const TraceOption* AppIdModule::get_trace_options() const { return nullptr; }
+void AppIdModule::set_trace(const snort::Trace*) const { }
+const snort::TraceOption* AppIdModule::get_trace_options() const { return nullptr; }
 // LCOV_EXCL_STOP
 
 // Stubs for inspectors
@@ -157,15 +151,15 @@ unsigned AppIdSession::inspector_id = 0;
 AppIdConfig stub_config;
 AppIdContext stub_ctxt(stub_config);
 OdpContext stub_odp_ctxt(stub_config, nullptr);
-AppIdSession::AppIdSession(IpProtocol, const SfIp* ip, uint16_t, AppIdInspector& inspector,
+AppIdSession::AppIdSession(IpProtocol, const snort::SfIp* ip, uint16_t, AppIdInspector& inspector,
     OdpContext& odpctxt, uint32_t
 #ifndef DISABLE_TENANT_ID
     ,uint32_t
 #endif
     ) : snort::FlowData(inspector_id, (snort::Inspector*)&inspector),
-        config(stub_config), api(*(new AppIdSessionApi(this, *ip))), odp_ctxt(odpctxt)
+        config(stub_config), api(*(new snort::AppIdSessionApi(this, *ip))), odp_ctxt(odpctxt)
 {
-    this->set_session_flags(APPID_SESSION_DISCOVER_APP);
+    
 }
 AppIdSession::~AppIdSession() { delete &api; }
 AppIdHttpSession::AppIdHttpSession(AppIdSession& asd, int64_t http2_stream_id)
@@ -235,4 +229,76 @@ OdpContext::OdpContext(const AppIdConfig&, snort::SnortConfig*)
 { }
 
 THREAD_LOCAL OdpContext* pkt_thread_odp_ctxt = nullptr;
+
+// Stubs for module
+snort::Module::Module(char const*, char const*) {}
+void snort::Module::sum_stats(bool) {}
+void snort::Module::show_interval_stats(std::vector<unsigned>&, FILE*) {}
+void snort::Module::show_stats() {}
+void snort::Module::init_stats(bool) {}
+void snort::Module::reset_stats() {}
+void snort::Module::main_accumulate_stats() {}
+PegCount snort::Module::get_global_count(char const*) const { return 0; }
+
+
+void ApplicationDescriptor::set_id(const snort::Packet&, AppIdSession&, AppidSessionDirection, AppId, AppidChangeBits&) { }
+AppIdDiscovery::~AppIdDiscovery() = default;
+void ClientDiscovery::initialize(AppIdInspector&) { }
+void ClientDiscovery::reload() { }
+void AppIdDiscovery::register_detector(const string&, AppIdDetector*, IpProtocol) { }
+void AppIdDiscovery::add_pattern_data(AppIdDetector*, snort::SearchTool&, int, unsigned char const*, unsigned int, unsigned int) { }
+void AppIdDiscovery::register_tcp_pattern(AppIdDetector*, unsigned char const*, unsigned int, int, unsigned int) { }
+void AppIdDiscovery::register_udp_pattern(AppIdDetector*, unsigned char const*, unsigned int, int, unsigned int) { }
+int AppIdDiscovery::add_service_port(AppIdDetector*, ServiceDetectorPort const&) { return 0; }
+DnsPatternMatchers::~DnsPatternMatchers() = default;
+EveCaPatternMatchers::~EveCaPatternMatchers() = default;
+#ifndef SIP_UNIT_TEST
+SipPatternMatchers::~SipPatternMatchers() = default;
+#endif
+HostPatternMatchers::~HostPatternMatchers() = default;
+AlpnPatternMatchers::~AlpnPatternMatchers() = default;
+#ifndef HTTP_PATTERNS_UNIT_TEST
+HttpPatternMatchers::~HttpPatternMatchers() = default;
+#endif
+UserDataMap::~UserDataMap() = default;
+CipPatternMatchers::~CipPatternMatchers() = default;
+bool HostPatternMatchers::scan_url(const uint8_t*, size_t, AppId&, AppId&, bool*){ return true; }   
+void AppIdModule::reset_stats() {}
+bool AppIdInspector::configure(snort::SnortConfig*) { return true; }
+void appid_log(const snort::Packet*, unsigned char, char const*, ...) { }
+void HostPatternMatchers::add_host_pattern(unsigned char const*, unsigned long, unsigned char, int, int, HostPatternType, bool, bool) {}
+
+#ifndef SIP_UNIT_TEST
+snort::SearchTool::SearchTool(bool, const char*) { }
+#endif
+
+ServiceDetector::ServiceDetector() {}
+void ServiceDetector::register_appid(AppId appId, unsigned extractsInfo, OdpContext& odp_ctxt) {}
+int ServiceDetector::add_service_consume_subtype(AppIdSession& asd, const snort::Packet* pkt,
+    AppidSessionDirection dir, AppId appId, const char* vendor, const char* version,
+    AppIdServiceSubtype* subtype, AppidChangeBits& change_bits)
+    { return 0; }
+int ServiceDetector::add_service(AppidChangeBits& change_bits, AppIdSession& asd,
+    const snort::Packet* pkt, AppidSessionDirection dir, AppId appId, const char* vendor,
+    const char* version, AppIdServiceSubtype* subtype)
+    { return 0; }
+int ServiceDetector::service_inprocess(AppIdSession& asd, const snort::Packet* pkt, AppidSessionDirection dir) { return 0; }
+
+snort::AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&)
+{ }
+
+AppIdInspector::~AppIdInspector() = default;
+
+void ClientDetector::register_appid(int, unsigned int, OdpContext&) { }
+
+void AppIdInspector::eval(snort::Packet*) { }
+void AppIdInspector::show(const snort::SnortConfig*) const { }
+void AppIdInspector::tinit() { }
+void AppIdInspector::tterm() { }
+void AppIdInspector::tear_down(snort::SnortConfig*) { }
+
+ClientDetector::ClientDetector() { }
+
+void AppIdSession::set_client_appid_data(AppId, AppidChangeBits&, char*) { }
+int AppIdSession::add_flow_data_id(uint16_t, ServiceDetector*) { return 0; }
 #endif
diff --git a/src/network_inspectors/appid/detector_plugins/test/detector_pop3_test.cc b/src/network_inspectors/appid/detector_plugins/test/detector_pop3_test.cc
new file mode 100644 (file)
index 0000000..5045dee
--- /dev/null
@@ -0,0 +1,96 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-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.
+//--------------------------------------------------------------------------
+
+// detector_pop3_test.cc author Oleksandr Stepanov <ostepano@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "appid_inspector.h"
+#include "appid_session.h"
+#include "detector_plugins_mock.h"
+
+#include "../detector_pop3.h"
+#include "../detector_pop3.cc"
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+
+using namespace snort;
+
+static ServiceDiscovery test_discovery;
+
+// Stubs for AppIdInspector
+AppIdConfig test_app_config;
+AppIdInspector::AppIdInspector(AppIdModule&) : config(&test_app_config), ctxt(test_app_config) { }
+
+void snort::SearchTool::reload() { }
+int snort::SearchTool::find_all(const char*, unsigned, MpseMatch, bool, void* mp_arg, const snort::SnortConfig*)
+{
+    return 0;
+}
+
+void AppIdDetector::add_user(AppIdSession&, const char*, AppId, bool, AppidChangeBits&){}
+int AppIdDetector::data_add(AppIdSession&, AppIdFlowData*) { return 1; }
+AppIdFlowData* AppIdDetector::data_get(const AppIdSession&)
+{
+    return nullptr;
+}
+
+int ServiceDetector::fail_service(AppIdSession& asd, const Packet* pkt, AppidSessionDirection dir) { return 1; }
+
+
+TEST_GROUP(detector_pop_tests)
+{
+    Pop3ServiceDetector* test_detector = nullptr;
+    void setup() override
+    {
+        test_detector = new Pop3ServiceDetector(&test_discovery);
+    }
+
+    void teardown() override
+    {
+        delete test_detector;
+        test_detector = nullptr;
+    }
+};
+
+TEST(detector_pop_tests, pop_validate_incorrect_packet_len)
+{
+    OdpContext test_odp_ctxt(test_app_config, nullptr);
+    AppIdModule test_module;
+    AppIdInspector test_inspector(test_module);
+    AppIdSession test_asd(IpProtocol::TCP, nullptr, (uint16_t)0, test_inspector, test_odp_ctxt, (uint32_t)0, 0);
+    const uint8_t* test_data = (const uint8_t*)".";
+    uint16_t test_data_size = 1;
+    AppidChangeBits cb;
+
+    POP3DetectorData dd;
+    dd.server.state = POP3_STATE_CONNECT;
+
+    auto result = test_detector->pop3_server_validate(&dd, test_data, test_data_size, test_asd, 1, cb);
+    CHECK_EQUAL(-1, result);
+}
+
+int main(int argc, char** argv)
+{
+    int return_value = CommandLineTestRunner::RunAllTests(argc, argv);
+    return return_value;
+}
index ba5ddf3374d36b6bfa3766183a20aa7d9354957a..6230ba001cacba7e08808070b4aba551ddace28f 100644 (file)
 #include "detector_plugins/detector_sip.cc"
 #include "detector_plugins/sip_patterns.cc"
 
-#include "framework/data_bus.h"
-#include "framework/module.cc"
 #include "framework/mpse_batch.h"
-#include "main/thread_config.h"
-#include "network_inspectors/appid/appid_utils/sf_mlmp.cc"
-#include "protocols/protocol_ids.h"
 #include "service_inspectors/sip/sip_parser.h"
-#include "utils/util_cstring.cc"
 
 #include "appid_inspector.h"
 #include "detector_plugins_mock.h"
@@ -58,11 +52,13 @@ ClientSIPData* sip_data = nullptr;
 MpseGroup mpse_group;
 static bool prep_patterns = true;
 
+// Stubs for AppIdInspector
+AppIdConfig test_app_config;
+AppIdInspector::AppIdInspector(AppIdModule&) : config(&test_app_config), ctxt(test_app_config) { }
+
 namespace snort
 {
 AppIdApi appid_api;
-AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&)
-{ }
 Flow::~Flow() = default;
 AppIdSession* AppIdApi::get_appid_session(snort::Flow const&) { return nullptr; }
 
@@ -83,23 +79,6 @@ unsigned get_instance_id()
 unsigned ThreadConfig::get_instance_max() { return 1; }
 }
 
-AppIdInspector::AppIdInspector(AppIdModule&) : config(&s_config), ctxt(s_config)
-{ }
-
-bool AppIdInspector::configure(snort::SnortConfig*)
-{
-    return true;
-}
-
-// LCOV_EXCL_START
-void AppIdInspector::eval(Packet*) { }
-void AppIdInspector::show(const SnortConfig*) const { }
-void AppIdInspector::tinit() { }
-void AppIdInspector::tterm() { }
-void AppIdInspector::tear_down(SnortConfig*) { }
-// LCOV_EXCL_STOP
-
-AppIdInspector::~AppIdInspector() = default;
 
 void AppIdContext::create_odp_ctxt()
 {
@@ -139,40 +118,8 @@ AppIdSession* AppIdSession::allocate_session(snort::Packet const*, IpProtocol,
 }
 
 void AppIdSession::publish_appid_event(AppidChangeBits&, const Packet&, bool, uint32_t) { }
-AppIdDiscovery::~AppIdDiscovery() = default;
-
-// LCOV_EXCL_START
-void ApplicationDescriptor::set_id(const Packet&, AppIdSession&, AppidSessionDirection,
-    AppId, AppidChangeBits&) { }
-void ClientDiscovery::initialize(AppIdInspector&) { }
-void ClientDiscovery::reload() { }
-// LCOV_EXCL_STOP
-
-void AppIdDiscovery::register_detector(const string&, AppIdDetector*, IpProtocol) { }
-
-// LCOV_EXCL_START
-void AppIdDiscovery::add_pattern_data(AppIdDetector*, snort::SearchTool&, int,
-    unsigned char const*, unsigned int, unsigned int) { }
-void AppIdDiscovery::register_tcp_pattern(AppIdDetector*, unsigned char const*, unsigned int,
-    int, unsigned int) { }
-void AppIdDiscovery::register_udp_pattern(AppIdDetector*, unsigned char const*, unsigned int,
-    int, unsigned int) { }
-int AppIdDiscovery::add_service_port(AppIdDetector*, ServiceDetectorPort const&) { return 0; }
-void AppIdModule::reset_stats() { }
-// LCOV_EXCL_STOP
-
-DnsPatternMatchers::~DnsPatternMatchers() = default;
-EveCaPatternMatchers::~EveCaPatternMatchers() = default;
-HostPatternMatchers::~HostPatternMatchers() = default;
-HttpPatternMatchers::~HttpPatternMatchers() = default;
-AlpnPatternMatchers::~AlpnPatternMatchers() = default;
-CipPatternMatchers::~CipPatternMatchers() = default;
-UserDataMap::~UserDataMap() = default;
-
-ClientDetector::ClientDetector() { }
 
 // LCOV_EXCL_START
-void ClientDetector::register_appid(int, unsigned int, OdpContext&) { }
 int AppIdDetector::initialize(AppIdInspector&) { return 1; }
 int AppIdDetector::data_add(AppIdSession&, AppIdFlowData*) { return 1; }
 void AppIdDetector::add_user(AppIdSession&, char const*, int, bool, AppidChangeBits&) { }
index 6c123c0f508b97ce7da96144c43dd8203978ffa8..179850c1f65dab62969698f5e6b28072ff94612c 100644 (file)
 #include "config.h"
 #endif
 
-#if 0
-#include "network_inspectors/appid/detector_plugins/detector_smtp.cc"
+#include "appid_inspector.h"
+#include "appid_session.h"
+#include "detector_plugins_mock.h"
+
+
+#include "../detector_smtp.h"
+#include "../detector_smtp.cc"
+
 
 #include <CppUTest/CommandLineTestRunner.h>
 #include <CppUTest/TestHarness.h>
 #include <CppUTestExt/MockSupport.h>
 
-#include <string>
+using namespace snort;
 
+#if 0
 struct AddAppData
 {
     AppId client_id = 0;
@@ -239,15 +246,87 @@ TEST(client_app_smtp, identify_client_version_mozilla_thunderbird)
     check_client_version(client_str, APP_ID_THUNDERBIRD, "5.0",
         &appid_stats.smtp_thunderbird_clients);
 }
-
 #endif
-//  FIXIT-M Add additional tests for other client types (Outlook, etc).
 
-int main(int, char**)
+
+static ClientDiscovery test_discovery;
+
+// Stubs for AppIdInspector
+AppIdConfig test_app_config;
+AppIdInspector::AppIdInspector(AppIdModule&) : config(&test_app_config), ctxt(test_app_config) { }
+
+int AppIdDetector::data_add(AppIdSession&, AppIdFlowData*) { return 1; }
+
+SMTPDetectorData* test_data_get = nullptr;
+
+AppIdFlowData* AppIdDetector::data_get(const AppIdSession&)
+{
+    return test_data_get;
+}
+
+int ServiceDetector::fail_service(AppIdSession& asd, const Packet* pkt, AppidSessionDirection dir) { return 1; }
+
+TEST_GROUP(detector_smtp_tests)
+{
+    SmtpClientDetector *test_detector = nullptr;
+    void setup() override
+    {
+        test_detector = new SmtpClientDetector(&test_discovery);
+    }
+
+    void teardown() override
+    {
+        delete test_detector;
+        test_detector = nullptr;
+    }
+};
+
+TEST(detector_smtp_tests, client_message_wrong_len_1)
+{
+    OdpContext test_odp_ctxt(test_app_config, nullptr);
+    AppIdModule test_module;
+    AppIdInspector test_inspector(test_module);
+    AppIdSession test_asd(IpProtocol::TCP, nullptr, (uint16_t)0, test_inspector, test_odp_ctxt, (uint32_t)0, 0);
+    const uint8_t* test_data = (const uint8_t*)".";
+    uint16_t test_data_size = 1;
+    AppidChangeBits cb;
+
+    test_data_get = new SMTPDetectorData;
+    test_data_get->client.state = SMTP_CLIENT_STATE_MESSAGE;
+
+    AppIdDiscoveryArgs test_args(test_data, test_data_size, AppidSessionDirection::APP_ID_FROM_INITIATOR, test_asd, nullptr, cb);
+
+    auto result = test_detector->validate(test_args);
+    CHECK_EQUAL(result, APPID_INPROCESS);
+    CHECK_EQUAL(test_asd.is_client_detected(), false);
+
+    delete test_data_get;
+}
+
+TEST(detector_smtp_tests, client_message_wrong_len_2)
+{
+    OdpContext test_odp_ctxt(test_app_config, nullptr);
+    AppIdModule test_module;
+    AppIdInspector test_inspector(test_module);
+    AppIdSession test_asd(IpProtocol::TCP, nullptr, (uint16_t)0, test_inspector, test_odp_ctxt, (uint32_t)0, 0);
+    const uint8_t* test_data = (const uint8_t*)".\t";
+    uint16_t test_data_size = 2;
+    AppidChangeBits cb;
+
+    test_data_get = new SMTPDetectorData;
+    test_data_get->client.state = SMTP_CLIENT_STATE_MESSAGE;
+
+    AppIdDiscoveryArgs test_args(test_data, test_data_size, AppidSessionDirection::APP_ID_FROM_INITIATOR, test_asd, nullptr, cb);
+
+    auto result = test_detector->validate(test_args);
+    CHECK_EQUAL(result, APPID_INPROCESS);
+    CHECK_EQUAL(test_asd.is_client_detected(), false);
+
+    delete test_data_get;
+}
+
+int main(int argc, char** argv)
 {
-#if 0
     int return_value = CommandLineTestRunner::RunAllTests(argc, argv);
     return return_value;
-#endif
 }
-
index 8f454effb258f24d8bd9f827255785a32cd34f26..005be98e0f793e8f1dd64dd2c90cd00d61895e45 100644 (file)
 #include "config.h"
 #endif
 
-#include "network_inspectors/appid/detector_plugins/http_url_patterns.cc"
+#define HTTP_PATTERNS_UNIT_TEST
+
+#include "../http_url_patterns.h"
+#include "../http_url_patterns.cc"
 
-#include "main/thread_config.h"
-#include "protocols/protocol_ids.h"
-#include "framework/module.cc"
 #include "network_inspectors/appid/appid_utils/sf_mlmp.cc"
-#include "utils/util_cstring.cc"
+
 #include "detector_plugins_mock.h"
 
 #include <CppUTest/CommandLineTestRunner.h>
@@ -61,15 +61,16 @@ static AppId service_id = APP_ID_NONE;
 static AppId client_id = APP_ID_NONE;
 static DetectorHTTPPattern mpattern;
 
+// Stubs for AppIdInspector
+AppIdConfig test_app_config;
+AppIdInspector::AppIdInspector(AppIdModule&) : config(&test_app_config), ctxt(test_app_config) { }
+
 namespace snort
 {
-AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&)
-{ }
-SearchTool::SearchTool(bool, const char*) { }
-void SearchTool::reload() { }
 static bool test_find_all_done = false;
 static bool test_find_all_enabled = false;
 static MatchedPatterns* mock_mp = nullptr;
+void SearchTool::reload() { }
 int SearchTool::find_all(const char*, unsigned, MpseMatch, bool, void* mp_arg, const SnortConfig*)
 {
     test_find_all_done = true;
@@ -77,33 +78,8 @@ int SearchTool::find_all(const char*, unsigned, MpseMatch, bool, void* mp_arg, c
         memcpy(mp_arg, &mock_mp, sizeof(MatchedPatterns*));
     return 0;
 }
-unsigned get_instance_id()
-{ return 0; }
-unsigned ThreadConfig::get_instance_max() { return 1; }
 }
 
-void ApplicationDescriptor::set_id(const Packet&, AppIdSession&, AppidSessionDirection, AppId, AppidChangeBits&) { }
-AppIdDiscovery::~AppIdDiscovery() = default;
-void ClientDiscovery::initialize(AppIdInspector&) { }
-void ClientDiscovery::reload() { }
-void AppIdDiscovery::register_detector(const string&, AppIdDetector*, IpProtocol) { }
-void AppIdDiscovery::add_pattern_data(AppIdDetector*, snort::SearchTool&, int, unsigned char const*, unsigned int, unsigned int) { }
-void AppIdDiscovery::register_tcp_pattern(AppIdDetector*, unsigned char const*, unsigned int, int, unsigned int) { }
-void AppIdDiscovery::register_udp_pattern(AppIdDetector*, unsigned char const*, unsigned int, int, unsigned int) { }
-int AppIdDiscovery::add_service_port(AppIdDetector*, ServiceDetectorPort const&) { return 0; }
-DnsPatternMatchers::~DnsPatternMatchers() = default;
-EveCaPatternMatchers::~EveCaPatternMatchers() = default;
-SipPatternMatchers::~SipPatternMatchers() = default;
-HostPatternMatchers::~HostPatternMatchers() = default;
-AlpnPatternMatchers::~AlpnPatternMatchers() = default;
-UserDataMap::~UserDataMap() = default;
-CipPatternMatchers::~CipPatternMatchers() = default;
-bool HostPatternMatchers::scan_url(const uint8_t*, size_t, AppId&, AppId&, bool*){ return true; }   
-void AppIdModule::reset_stats() {}
-bool AppIdInspector::configure(snort::SnortConfig*) { return true; }
-void appid_log(const snort::Packet*, unsigned char, char const*, ...) { }
-void HostPatternMatchers::add_host_pattern(unsigned char const*, unsigned long, unsigned char, int, int, HostPatternType, bool, bool) {}
-
 TEST_GROUP(http_url_patterns_tests)
 {
     void setup() override
@@ -558,6 +534,23 @@ TEST(http_url_patterns_tests, identify_user_agent_skypedirect)
     test_find_all_enabled = false;
 }
 
+TEST(http_url_patterns_tests, empty_server_vendor_version)
+{
+    char* version = nullptr;
+    char* vendor = nullptr;
+    AppIdServiceSubtype* subtype = nullptr;
+    hm->get_server_vendor_version("test/", 5, &version, &vendor, &subtype);
+
+    CHECK(version);
+    CHECK(version[0] == '\0');
+
+    CHECK(vendor);
+    CHECK_EQUAL(strcmp(vendor, "test"), 0);
+
+    snort_free(version);
+    snort_free(vendor);
+}
+
 int main(int argc, char** argv)
 {
     int return_value = CommandLineTestRunner::RunAllTests(argc, argv);
index 16c47310edeb93baf2b2de89643e4f1a68963d0d..ab89509e82cd03850bd0646a32d6f26831fe3449 100644 (file)
@@ -230,6 +230,8 @@ static int netbios_validate_name_and_decode(const uint8_t** data,
         *data += sizeof(NBNSLabelData);
         break;
     case 0xC0:
+        if (end - *data < (int)sizeof(NBNSLabelPtr))
+            return -1;
         lbl_ptr = (const NBNSLabelPtr*)(*data);
         *data += sizeof(NBNSLabelPtr);
         if (begin + lbl_ptr->position + sizeof(NBNSLabelData) > end)
@@ -286,6 +288,8 @@ static int netbios_validate_name(const uint8_t** data,
         *data += sizeof(NBNSLabelData);
         break;
     case 0xC0:
+        if (end - *data < (int)sizeof(NBNSLabelPtr))
+            return -1;
         lbl_ptr = (const NBNSLabelPtr*)(*data);
         *data += sizeof(NBNSLabelPtr);
         if (begin + lbl_ptr->position + sizeof(NBNSLabelData) > end)
index 0df64cf1a6b53734fda6f207124402ddf5ddbe85..3646002a8d94feb1d5ff9bd837838ff81779fdda 100644 (file)
@@ -125,9 +125,9 @@ static int parse_rtmp_chunk_basic_header(const uint8_t** data_inout, uint16_t* s
     }
     else if (*chunk_stream_id == 1)
     {
-        *chunk_stream_id = data[2] * 256 + data[1] + 64;
         if (size < 3)
             return 0;
+        *chunk_stream_id = data[2] * 256 + data[1] + 64;
         data += 3;
         size -= 3;
     }
index 5064040da2c6717a9156bfa5ad7c82394cdbcc24..87e406435f858a0d9f0f5dff0c1d41b7893601fb 100644 (file)
@@ -166,7 +166,7 @@ static int snmp_verify_packet(const uint8_t** const data,
         return -1;
     if (snmp_ans1_length(data, end, &overall_length))
         return -1;
-    if (overall_length < 3 || (int)overall_length > end-(*data))
+    if (overall_length < 3 || (*data >= end) || overall_length > static_cast<uint32_t>(end - *data))
         return -1;
     if (**data != 0x02)
         return -1;
index de668cdb2946e8a70a507bbc39bb8191d2fd14e7..a80b83fb83c0c92430be1b5b369115ee7ab0732d 100644 (file)
@@ -3,4 +3,6 @@ include_directories ( appid PRIVATE ${APPID_INCLUDE_DIR} )
 
 add_cpputest( service_rsync_test )
 add_cpputest( alpn_patterns_tests )
-
+add_cpputest( service_snmp_test )
+add_cpputest( service_rtmp_test )
+add_cpputest( service_netbios_test )
diff --git a/src/network_inspectors/appid/service_plugins/test/service_netbios_test.cc b/src/network_inspectors/appid/service_plugins/test/service_netbios_test.cc
new file mode 100644 (file)
index 0000000..00d0620
--- /dev/null
@@ -0,0 +1,99 @@
+//--------------------------------------------------------------------------
+// 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_netbios_test.cc author Oleksandr Stepanov <ostepano@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "../service_netbios.h"
+#include "../service_netbios.cc"
+#include "service_plugin_mock.h"
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+
+void AppIdSessionApi::set_netbios_name(AppidChangeBits& change_bits, const char* name) { }
+
+TEST_GROUP(netbios_parsing_tests)
+{
+    void setup() override
+    {
+        
+    }
+    void teardown() override
+    {
+        
+    }
+};
+
+TEST(netbios_parsing_tests, netbios_parse_invalid_len_missing_position)
+{
+    const uint8_t* data = (const uint8_t*)"\xC0"; // Invalid length
+    const uint8_t* original_data = data;
+    const uint8_t* end = data + 1;
+    char name[NBNS_NAME_LEN / 2 + 1] = {0};
+
+    int ret = netbios_validate_name_and_decode(&data, data, end, name);
+    CHECK_EQUAL(-1, ret);
+    CHECK_EQUAL(data, original_data); // Ensure data pointer is unchanged
+}
+
+TEST(netbios_parsing_tests, netbios_parse_invalid_len_wrong_position)
+{
+    const uint8_t* data = (const uint8_t*)"\xC0\xFF"; // Invalid length
+    const uint8_t* original_data = data;
+    const uint8_t* end = data + 2;
+    char name[NBNS_NAME_LEN / 2 + 1] = {0};
+
+    int ret = netbios_validate_name_and_decode(&data, data, end, name);
+    CHECK_EQUAL(-1, ret);
+    CHECK_EQUAL(original_data + sizeof(NBNSLabelPtr), data); // Check that length and flags are parsed
+}
+
+TEST(netbios_parsing_tests, netbios_parse_invalid_len_missing_position_without_decode)
+{
+    const uint8_t* data = (const uint8_t*)"\xC0"; // Invalid length
+    const uint8_t* original_data = data;
+    const uint8_t* end = data + 1;
+    char name[NBNS_NAME_LEN / 2 + 1] = {0};
+
+    int ret = netbios_validate_name(&data, data, end);
+    CHECK_EQUAL(-1, ret);
+    CHECK_EQUAL(data, original_data); // Ensure data pointer is unchanged
+}
+
+TEST(netbios_parsing_tests, netbios_parse_invalid_len_wrong_position_without_decode)
+{
+    const uint8_t* data = (const uint8_t*)"\xC0\xFF"; // Invalid length
+    const uint8_t* original_data = data;
+    const uint8_t* end = data + 2;
+    char name[NBNS_NAME_LEN / 2 + 1] = {0};
+
+    int ret = netbios_validate_name(&data, data, end);
+    CHECK_EQUAL(-1, ret);
+    CHECK_EQUAL(original_data + sizeof(NBNSLabelPtr), data); // Check that length and flags are parsed
+}
+
+int main(int argc, char** argv)
+{
+    int return_value = CommandLineTestRunner::RunAllTests(argc, argv);
+    return return_value;
+}
index d4e83c2d2cb904ef5cfbc7d2b024e0c7bfd3f780..5fae71be905d576c7b91014c8d0f49e5141e3a98 100644 (file)
 
 #ifndef SERVICE_PLUGIN_MOCK_H
 #define SERVICE_PLUGIN_MOCK_H
-#include "appid_detector.h"
-#include "appid_module.h"
-#include "appid_peg_counts.h"
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
+#include <framework/data_bus.h>
+#include <detection/detection_engine.h>
+#include <appid/appid_inspector.h>
+#include <appid/service_plugins/service_discovery.h>
+
+#include "appid_detector.h"
+#include "appid_module.h"
+#include "appid_peg_counts.h"
+
 #define APPID_UT_ID 1492
 
 namespace snort
@@ -68,15 +74,12 @@ char* snort_strdup(const char* str)
     memcpy(p, str, n);
     return p;
 }
-Module::Module(const char*, const char*) {}
-Module::Module(const char*, const char*, const Parameter*, bool)
-{}
-PegCount Module::get_global_count(char const*) const { return 0; }
-void Module::show_interval_stats(std::vector<unsigned int, std::allocator<unsigned int> >&, FILE*) {}
-void Module::show_stats(){}
-void Module::sum_stats(bool){}
-void Module::main_accumulate_stats(){}
-void Module::reset_stats() {}
+void snort::Module::sum_stats(bool) {}
+void snort::Module::show_interval_stats(std::vector<unsigned>&, FILE*) {}
+void snort::Module::show_stats() {}
+void snort::Module::init_stats(bool) {}
+void snort::Module::reset_stats() {}
+void snort::Module::main_accumulate_stats() {}
 
 AppIdSessionApi::AppIdSessionApi(const AppIdSession*, const SfIp&)
 { }
@@ -92,7 +95,6 @@ UserDataMap::~UserDataMap() { }
 CipPatternMatchers::~CipPatternMatchers() { }
 void ClientDiscovery::initialize(AppIdInspector&) {}
 void ClientDiscovery::reload() {}
-FpSMBData* smb_data = nullptr;
 
 int AppIdDetector::initialize(AppIdInspector&){return 0;}
 int AppIdDetector::data_add(AppIdSession&, AppIdFlowData*){return 0;}
@@ -112,18 +114,32 @@ void AppIdDiscovery::register_udp_pattern(AppIdDetector*, const uint8_t* const,
     int, unsigned){}
 int AppIdDiscovery::add_service_port(AppIdDetector*, const ServiceDetectorPort&){return 0;}
 void ApplicationDescriptor::set_id(const snort::Packet&, AppIdSession&, AppidSessionDirection, AppId, AppidChangeBits&){}
-int AppIdSession::add_flow_data(void*, unsigned) { return 0; }
 int dcerpc_validate(const uint8_t*, int){return 0; }
 AppIdDiscovery::~AppIdDiscovery() { }
 void show_stats(PegCount*, const PegInfo*, unsigned, const char*) { }
-void show_stats(PegCount*, const PegInfo*, const vector<unsigned>&, const char*, FILE*) { }
 AppIdConfig config;
 AppIdContext ctxt(config);
-class AppIdInspector : public snort::Inspector
-{
-public:
-    bool configure(snort::SnortConfig*) override { return true; }
-};
+ServiceDetector::ServiceDetector() {}
+int ServiceDetector::incompatible_data(AppIdSession& asd, const snort::Packet* pkt, AppidSessionDirection dir) { return 0; }
+int ServiceDetector::fail_service(AppIdSession& asd, const snort::Packet* pkt, AppidSessionDirection dir) { return 0; }
+int ServiceDetector::service_inprocess(AppIdSession& asd, const snort::Packet* pkt, AppidSessionDirection dir) { return 0; }
+int ServiceDetector::add_service_consume_subtype(AppIdSession& asd, const snort::Packet* pkt,
+    AppidSessionDirection dir, AppId appId, const char* vendor, const char* version,
+    AppIdServiceSubtype* subtype, AppidChangeBits& change_bits)
+    { return 0; }
+int ServiceDetector::add_service(AppidChangeBits& change_bits, AppIdSession& asd,
+    const snort::Packet* pkt, AppidSessionDirection dir, AppId appId, const char* vendor,
+    const char* version, AppIdServiceSubtype* subtype)
+    { return 0; }
+void ServiceDetector::register_appid(AppId appId, unsigned extractsInfo, OdpContext& odp_ctxt) {}
+
+void AppIdDebug::activate(const snort::Flow*, const AppIdSession*, bool) { active = false; }
+
+AppIdSession* AppIdSession::create_future_session(const snort::Packet* ctrlPkt, const snort::SfIp* cliIp,
+    uint16_t cliPort, const snort::SfIp* srvIp, uint16_t srvPort, IpProtocol proto,
+    SnortProtocolId snort_protocol_id, OdpContext& odp_ctxt, bool swap_app_direction,
+    bool bidirectional, bool expect_persist) { return nullptr; }
+void AppIdSession::initialize_future_session(AppIdSession& expected, uint64_t flags) {}
 
 // Stubs for modules, config
 AppIdConfig::~AppIdConfig() = default;
@@ -142,7 +158,7 @@ bool AppIdModule::end(const char*, int, snort::SnortConfig*)
     return false;
 }
 
-const Command* AppIdModule::get_commands() const
+const snort::Command* AppIdModule::get_commands() const
 {
     return nullptr;
 }
@@ -157,8 +173,8 @@ PegCount* AppIdModule::get_counts() const
     return nullptr;
 }
 
-void AppIdModule::set_trace(const Trace*) const { }
-const TraceOption* AppIdModule::get_trace_options() const { return nullptr; }
+void AppIdModule::set_trace(const snort::Trace*) const { }
+const snort::TraceOption* AppIdModule::get_trace_options() const { return nullptr; }
 
 // Stubs for inspectors
 unsigned AppIdSession::inspector_id = 0;
@@ -166,25 +182,29 @@ AppIdConfig stub_config;
 AppIdContext stub_ctxt(stub_config);
 static OdpContext stub_odp_ctxt(stub_config, nullptr);
 OdpContext* AppIdContext::odp_ctxt = &stub_odp_ctxt;
-AppIdSession::AppIdSession(IpProtocol, const SfIp* ip, uint16_t, AppIdInspector& inspector,
-    OdpContext&
+AppIdSession::AppIdSession(IpProtocol, const snort::SfIp* ip, uint16_t, AppIdInspector& inspector,
+    OdpContext& odpctxt, uint32_t
 #ifndef DISABLE_TENANT_ID
-    ,uint16_t
+    ,uint32_t
 #endif
     ) : snort::FlowData(inspector_id, (snort::Inspector*)&inspector),
-    config(stub_config), api(*(new AppIdSessionApi(this, *ip))), odp_ctxt(stub_odp_ctxt) { }
+        config(stub_config), api(*(new snort::AppIdSessionApi(this, *ip))), odp_ctxt(odpctxt)
+{ }
 AppIdSession::~AppIdSession() = default;
 DiscoveryFilter::~DiscoveryFilter(){}
 void AppIdSession::free_flow_data()
 {
-    snort_free(smb_data);
+    
+}
+AppIdFlowData* AppIdSession::get_flow_data(unsigned) const
+{
+    return nullptr;
 }
-void* AppIdSession::get_flow_data(unsigned) const { return smb_data;}
 
 // Stubs for AppIdPegCounts
-void AppIdPegCounts::inc_service_count(AppId, bool) { }
-void AppIdPegCounts::inc_client_count(AppId, bool) { }
-void AppIdPegCounts::inc_payload_count(AppId, bool) { }
+//void AppIdPegCounts::inc_service_count(AppId, bool) { }
+//void AppIdPegCounts::inc_client_count(AppId, bool) { }
+//void AppIdPegCounts::inc_payload_count(AppId, bool) { }
 
 THREAD_LOCAL AppIdStats appid_stats;
 void AppIdModule::show_dynamic_stats() { }
@@ -199,15 +219,26 @@ bool AppInfoManager::configured()
 {
     return true;
 }
-ServiceDiscoveryState* AppIdServiceState::add(SfIp const*, IpProtocol,
-    unsigned short, int16_t, uint16_t, bool, bool)
-{
-  return nullptr;
-}
 
-void ServiceDiscoveryState::set_service_id_valid(ServiceDetector*) { }
+
+void ServiceDiscovery::initialize(AppIdInspector&) {}
+void ServiceDiscovery::reload() {}
+int ServiceDiscovery::add_service_port(AppIdDetector*, const ServiceDetectorPort&) { return 0; }
 
 OdpContext::OdpContext(const AppIdConfig&, snort::SnortConfig*)
 { }
 
+void appid_log(const snort::Packet*, unsigned char, char const*, ...) { }
+int AppIdSession::add_flow_data_id(uint16_t, ServiceDetector*) { return 0; }
+AppIdHttpSession* AppIdSession::get_http_session(uint32_t) const { return nullptr; }
+AppIdHttpSession* AppIdSession::create_http_session(int64_t stream_id) { return nullptr; }
+void AppIdHttpSession::set_field(HttpFieldIds id, const std::string* str, AppidChangeBits&) { }
+
+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*) { }
+
+snort::Packet* snort::DetectionEngine::get_current_packet() { return nullptr; }
+
+unsigned AppIdInspector::get_pub_id() { return 0; }
 #endif
diff --git a/src/network_inspectors/appid/service_plugins/test/service_rtmp_test.cc b/src/network_inspectors/appid/service_plugins/test/service_rtmp_test.cc
new file mode 100644 (file)
index 0000000..a34cd1b
--- /dev/null
@@ -0,0 +1,62 @@
+//--------------------------------------------------------------------------
+// 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_rtmp_test.cc author Oleksandr Stepanov <ostepano@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "../service_rtmp.h"
+#include "../service_rtmp.cc"
+#include "service_plugin_mock.h"
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+
+TEST_GROUP(rtmp_parsing_tests)
+{
+    void setup() override
+    {
+        
+    }
+    void teardown() override
+    {
+        
+    }
+};
+
+TEST(rtmp_parsing_tests, rtmp_parse_invalid_len)
+{
+    const uint8_t* data = (const uint8_t*)"\x41\x00";
+    uint16_t size = 2;
+    uint8_t format = 0;
+    uint32_t chunk_stream_id = 0;
+
+    int ret = parse_rtmp_chunk_basic_header(&data, &size, &format, &chunk_stream_id);
+    CHECK_EQUAL(0, ret);
+    CHECK_EQUAL(2, size);
+    CHECK_EQUAL(1, chunk_stream_id);
+}
+
+int main(int argc, char** argv)
+{
+    int return_value = CommandLineTestRunner::RunAllTests(argc, argv);
+    return return_value;
+}
diff --git a/src/network_inspectors/appid/service_plugins/test/service_snmp_test.cc b/src/network_inspectors/appid/service_plugins/test/service_snmp_test.cc
new file mode 100644 (file)
index 0000000..350fcfc
--- /dev/null
@@ -0,0 +1,173 @@
+//--------------------------------------------------------------------------
+// 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_snmp_test.cc author Oleksandr Stepanov <ostepano@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <protocols/packet.h>
+#include "../service_detector.h"
+
+#include "../service_snmp.h"
+#include "../service_snmp.cc"
+
+#include "service_plugin_mock.h"
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+
+THREAD_LOCAL AppIdDebug* appidDebug = nullptr;
+THREAD_LOCAL bool appid_trace_enabled = false;
+
+
+TEST_GROUP(snmp_parsing_tests)
+{
+    void setup() override
+    {
+        
+    }
+    void teardown() override
+    {
+        
+    }
+};
+
+TEST(snmp_parsing_tests, fail_on_invalid_sequence_tag)
+{
+    const uint8_t* data = (const uint8_t*)"\x31\x02\x01\x00"; /* Invalid tag - should be 0x30 */
+    const uint8_t* end = data + 4;
+    uint8_t pdu = 0;
+    uint8_t version = 0;
+
+    int ret = snmp_verify_packet(&data, end, &pdu, &version);
+    CHECK_EQUAL(ret, -1);
+}
+
+TEST(snmp_parsing_tests, fail_on_insufficient_data)
+{
+    const uint8_t* data = (const uint8_t*)"\x30"; /* Only sequence tag, no length */
+    const uint8_t* end = data + 1;
+    uint8_t pdu = 0;
+    uint8_t version = 0;
+
+    int ret = snmp_verify_packet(&data, end, &pdu, &version);
+    CHECK_EQUAL(ret, -1);
+}
+
+TEST(snmp_parsing_tests, fail_on_invalid_version_tag)
+{
+    const uint8_t* data = (const uint8_t*)"\x30\x05\x03\x01\x00\x04\x01"; /* Wrong version tag (0x03 instead of 0x02) */
+    const uint8_t* end = data + 7;
+    uint8_t pdu = 0;
+    uint8_t version = 0;
+
+    int ret = snmp_verify_packet(&data, end, &pdu, &version);
+    CHECK_EQUAL(ret, -1);
+}
+
+TEST(snmp_parsing_tests, fail_on_invalid_version_length)
+{
+    const uint8_t* data = (const uint8_t*)"\x30\x05\x02\x02\x00\x04\x01"; /* Version length should be 1, not 2 */
+    const uint8_t* end = data + 7;
+    uint8_t pdu = 0;
+    uint8_t version = 0;
+
+    int ret = snmp_verify_packet(&data, end, &pdu, &version);
+    CHECK_EQUAL(ret, -1);
+}
+
+TEST(snmp_parsing_tests, success_snmp_v1_packet)
+{
+    const uint8_t snmp_v1[] = "\x30\x1c\x02\x01\x00\x04\x06public\xa0\x0f\x02\x01\x01\x02\x01\x00\x02\x01\x00\x30\x04\x30\x02\x06\x00";
+    const uint8_t* data = snmp_v1;
+    const uint8_t* end = data + sizeof(snmp_v1) - 1;
+    uint8_t pdu = 0;
+    uint8_t version = 0;
+
+    int ret = snmp_verify_packet(&data, end, &pdu, &version);
+    CHECK_EQUAL(ret, 0);
+    CHECK_EQUAL(version, 0); /* SNMP v1 */
+    CHECK_EQUAL(pdu, 0); /* GET request */
+}
+
+TEST(snmp_parsing_tests, success_snmp_v2c_packet)
+{
+    const uint8_t snmp_v2c[] = "\x30\x1d\x02\x01\x01\x04\x06public\xa0\x10\x02\x01\x01\x02\x01\x00\x02\x01\x00\x30\x05\x30\x03\x06\x01\x00";
+    const uint8_t* data = snmp_v2c;
+    const uint8_t* end = data + sizeof(snmp_v2c) - 1;
+    uint8_t pdu = 0;
+    uint8_t version = 0;
+
+    int ret = snmp_verify_packet(&data, end, &pdu, &version);
+    CHECK_EQUAL(ret, 0);
+    CHECK_EQUAL(version, 1); /* SNMP v2c */
+    CHECK_EQUAL(pdu, 0); /* GET request */
+}
+
+TEST(snmp_parsing_tests, fail_on_invalid_community_string)
+{
+    const uint8_t* data = (const uint8_t*)"\x30\x0b\x02\x01\x00\x04\x04\xff\xfe\xfd\xfc\xa0\x00"; /* Non-printable community */
+    const uint8_t* end = data + 13;
+    uint8_t pdu = 0;
+    uint8_t version = 0;
+
+    int ret = snmp_verify_packet(&data, end, &pdu, &version);
+    CHECK_EQUAL(ret, -1);
+}
+
+TEST(snmp_parsing_tests, fail_on_unsupported_version)
+{
+    const uint8_t* data = (const uint8_t*)"\x30\x05\x02\x01\x05\x04\x00"; /* Version 5 (unsupported) */
+    const uint8_t* end = data + 7;
+    uint8_t pdu = 0;
+    uint8_t version = 0;
+
+    int ret = snmp_verify_packet(&data, end, &pdu, &version);
+    CHECK_EQUAL(ret, -1);
+}
+
+TEST(snmp_parsing_tests, fail_on_length_overflow)
+{
+    const uint8_t* data = (const uint8_t*)"\x30\x82\xff\xff"; /* Length field indicates more data than available */
+    const uint8_t* end = data + 4;
+    uint8_t pdu = 0;
+    uint8_t version = 0;
+
+    int ret = snmp_verify_packet(&data, end, &pdu, &version);
+    CHECK_EQUAL(ret, -1);
+}
+
+TEST(snmp_parsing_tests, fail_on_wrong_packet_length)
+{
+    const uint8_t* data = (const uint8_t*)"\x30\x7F"; /* SNMP packet with packet length = 127 */
+    const uint8_t* end = data + 2;
+    uint8_t pdu = 0;
+    uint8_t version = 0;
+
+    int ret = snmp_verify_packet(&data, end, &pdu, &version);
+    CHECK_EQUAL(ret, -1);
+}
+
+int main(int argc, char** argv)
+{
+    int return_value = CommandLineTestRunner::RunAllTests(argc, argv);
+    return return_value;
+}
\ No newline at end of file
index 23f902dd984023002fdf5500eafb01ae49cd75c0..eae87c9eedceb3a4933dd6ea6df72d553f72968b 100644 (file)
@@ -711,7 +711,7 @@ bool parse_server_certificates(SSLV3ServerCertData* server_cert_data)
     int common_name_len = 0;
     int org_unit_len  = 0;
 
-    while (len > 0 and !(common_name and org_unit))
+    while (len > 2 and !(common_name and org_unit))
     {
         X509* cert = nullptr;
         X509_NAME* cert_name = nullptr;
index b0e338f652220829211f98f93e7b2a5f3f688326..ef998c2f1d9dcf8259f9121297d2248122de9dbb 100644 (file)
@@ -8,3 +8,5 @@ add_cpputest( decode_err_len_test
       ../packet.cc
       ../packet_manager.cc
 )
+
+add_cpputest( ssl_protocol_test )
\ No newline at end of file
diff --git a/src/protocols/test/ssl_protocol_test.cc b/src/protocols/test/ssl_protocol_test.cc
new file mode 100644 (file)
index 0000000..bbf0720
--- /dev/null
@@ -0,0 +1,85 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2023-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.
+//--------------------------------------------------------------------------
+// ssl_protocol_test.cc author Oleksandr Stepanov <ostepano@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <cstring>
+#include <openssl/ossl_typ.h>
+
+#include "../ssl.h"
+#include "../ssl.cc"
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+
+using namespace snort;
+
+typedef struct X509_name_entry_st X509_NAME_ENTRY;
+X509_NAME *X509_get_subject_name(const X509 *a) { return nullptr; }
+void X509_free(X509* a) { }
+int X509_NAME_get_index_by_NID(X509_NAME *name, int nid, int lastpos) { return -1; }
+X509_NAME_ENTRY *X509_NAME_get_entry(const X509_NAME *name, int loc) { return nullptr; }
+ASN1_STRING *X509_NAME_ENTRY_get_data(const X509_NAME_ENTRY *ne) { return nullptr; }
+const unsigned char *ASN1_STRING_get0_data(const ASN1_STRING *x) { return nullptr; }
+X509* d2i_X509(X509 **a, const unsigned char **in, long len)
+{
+    return nullptr;
+}
+
+namespace snort
+{
+char* snort_strdup(const char* str)
+{
+    return str ? strdup(str) : nullptr;
+}
+
+char* snort_strndup(const char* src, size_t)
+{
+    return snort_strdup(src);
+}
+}
+
+TEST_GROUP(ssl_protocol_tests)
+{
+    void setup() override
+    {
+    }
+
+    void teardown() override
+    {
+    }
+};
+
+TEST(ssl_protocol_tests, cert_data_incomplete_len_2)
+{
+    SSLV3ServerCertData test_data;
+    test_data.certs_data = new uint8_t[2] { 0x01, 0x02 }; // Incomplete length, should be at least 3 bytes
+    test_data.certs_len = 2;
+    auto result = parse_server_certificates(&test_data);
+    CHECK_EQUAL(true, result);
+    CHECK_EQUAL(nullptr, test_data.certs_data);
+    CHECK_EQUAL(0, test_data.certs_len);
+}
+
+int main(int argc, char** argv)
+{
+    return CommandLineTestRunner::RunAllTests(argc, argv);
+}
\ No newline at end of file