]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #206 in SNORT/snort3 from host_tracker_start2 to master
authorRuss Combs (rucombs) <rucombs@cisco.com>
Fri, 15 Jan 2016 21:42:41 +0000 (16:42 -0500)
committerRuss Combs (rucombs) <rucombs@cisco.com>
Fri, 15 Jan 2016 21:42:41 +0000 (16:42 -0500)
Squashed commit of the following:

commit f924eda1ee598c71cc72da4ac6a29288e1cff200
Author: Steve Chew <stechew@cisco.com>
Date:   Fri Jan 15 16:13:05 2016 -0500

    Avoid memory leak.

commit 1d10f9896c70dbb33c071acaa011599f9fc0d2c1
Author: Steve Chew <stechew@cisco.com>
Date:   Fri Jan 15 13:27:43 2016 -0500

    Updates based on Russ' comments.

commit 52be6a49a0823c730f0b13b16496141a7a3f6b0b
Author: Steve Chew <stechew@cisco.com>
Date:   Thu Jan 14 17:50:54 2016 -0500

    Added UNKNOWN_PROTOCOL const.

commit b39ce69b8beccf48c2851652b2a59ab16020e315
Author: Steve Chew <stechew@cisco.com>
Date:   Thu Jan 14 14:40:42 2016 -0500

    Updated based on review.

commit 6b5d0c54bc0b4c1699ae739a096c47ab6a4e4709
Author: Steve Chew <stechew@cisco.com>
Date:   Tue Jan 12 15:29:24 2016 -0500

    Added HostTracker object to allow thread-safe get/set of host data.

configure.ac
src/main/modules.cc
src/target_based/CMakeLists.txt
src/target_based/Makefile.am
src/target_based/host_tracker.h [new file with mode: 0644]
src/target_based/test/Makefile.am [new file with mode: 0644]
src/target_based/test/host_tracker_test.cc [new file with mode: 0644]

index 0b6ab4d85e29f2dd35fca0bfc541dd134dbf3da6..d4e6c2099eec3b0ce106bf5ffb384d5a8e2f75ae 100644 (file)
@@ -1078,6 +1078,7 @@ src/search_engines/test/Makefile \
 src/sfip/Makefile \
 src/sfrt/Makefile \
 src/target_based/Makefile \
+src/target_based/test/Makefile \
 src/catch/Makefile \
 src/time/Makefile \
 src/ppm/Makefile \
index e8b1197cd45ee7f2151948bc22e771c91c2592ad..adffb9135df704e8965550d049b5c63db1a9d97a 100644 (file)
@@ -28,6 +28,7 @@
 #include <string.h>
 
 #include <string>
+#include <memory>
 using namespace std;
 
 #include "framework/module.h"
@@ -60,11 +61,13 @@ using namespace std;
 #include "stream/stream_api.h"
 #include "utils/stats.h"
 #include "target_based/snort_protocols.h"
+#include "target_based/host_tracker.h"
 
 //-------------------------------------------------------------------------
 // detection module
 //-------------------------------------------------------------------------
 
+/* *INDENT-OFF* */   //  Uncrustify handles this section incorrectly.
 static const Parameter detection_params[] =
 {
     { "asn1", Parameter::PT_INT, "1:", "256",
@@ -81,6 +84,7 @@ static const Parameter detection_params[] =
 
     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
 };
+/* *INDENT-ON* */
 
 #define detection_help \
     "configure general IPS rule processing parameters"
@@ -1340,7 +1344,7 @@ static const Parameter file_rule_params[] =
       "file type version" },
 
     { "magic", Parameter::PT_LIST, file_magic_params, nullptr,
-        "list of file magic rules" },
+      "list of file magic rules" },
 
     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
 };
@@ -1417,10 +1421,10 @@ static const Parameter file_id_params[] =
       "print this many octets" },
 
     { "file_rules", Parameter::PT_LIST, file_rule_params, nullptr,
-        "list of file magic rules" },
+      "list of file magic rules" },
 
     { "file_policy", Parameter::PT_LIST, file_policy_rule_params, nullptr,
-        "list of file rules" },
+      "list of file rules" },
 
     { "trace_type", Parameter::PT_BOOL, nullptr, "false",
       "enable runtime dump of type info" },
@@ -1444,6 +1448,7 @@ public:
     bool set(const char*, Value&, SnortConfig*) override;
     bool begin(const char*, int, SnortConfig*) override;
     bool end(const char*, int, SnortConfig*) override;
+
 private:
     FileMagicRule rule;
     FileMagicData magic;
@@ -1576,18 +1581,15 @@ bool FileIdModule::begin(const char* fqn, int idx, SnortConfig*)
     {
         rule.clear();
     }
-
     else if ( !strcmp(fqn, "file_id.file_rules.magic") )
     {
         magic.clear();
     }
-
     else if ( !strcmp(fqn, "file_id.file_policy") )
     {
         file_rule.clear();
     }
 
-
     return true;
 }
 
@@ -1602,13 +1604,11 @@ bool FileIdModule::end(const char* fqn, int idx, SnortConfig* sc)
     {
         fc.process_file_rule(rule);
     }
-
     else if ( !strcmp(fqn, "file_id.file_rules.magic") )
     {
         fc.process_file_magic(magic);
         rule.file_magics.push_back(magic);
     }
-
     else if ( !strcmp(fqn, "file_id.file_policy") )
     {
         fc.process_file_policy_rule(file_rule);
@@ -1616,6 +1616,7 @@ bool FileIdModule::end(const char* fqn, int idx, SnortConfig* sc)
 
     return true;
 }
+
 //-------------------------------------------------------------------------
 // suppress module
 //-------------------------------------------------------------------------
@@ -2052,6 +2053,94 @@ bool HostsModule::end(const char* fqn, int idx, SnortConfig*)
     return true;
 }
 
+//-------------------------------------------------------------------------
+// HostTracker module
+//-------------------------------------------------------------------------
+
+//  FIXIT-M - Temporarily create new HostTracker module to test new
+//            HostTracker object.  May eventually replace old Hosts
+//            module with this one.
+
+class HostTrackerModule : public Module
+{
+public:
+    HostTrackerModule() : Module("host_tracker", hosts_help, hosts_params, true)
+    {
+        host = nullptr;
+    }
+
+    ~HostTrackerModule()
+    {
+        //  FIXIT-H: Change this back to an assert once we hand off the
+        //           host to a cache.
+        if (host)
+            delete host;
+    }
+
+    bool set(const char*, Value&, SnortConfig*) override;
+    bool begin(const char*, int, SnortConfig*) override;
+    bool end(const char*, int, SnortConfig*) override;
+
+private:
+    HostApplicationEntry app;
+    HostTracker* host;
+};
+
+bool HostTrackerModule::set(const char*, Value& v, SnortConfig*)
+{
+    if ( host and v.is("ip") )
+    {
+        sfip_t addr;
+        v.get_addr(addr);
+        host->set_ip_addr(addr);
+    }
+    else if ( host and v.is("frag_policy") )
+        host->set_frag_policy(v.get_long() + 1);
+
+    else if ( host and v.is("tcp_policy") )
+        host->set_stream_policy(v.get_long() + 1);
+
+    else if ( v.is("name") )
+        app.protocol = AddProtocolReference(v.get_string());
+
+    else if ( v.is("proto") )
+        app.ipproto = AddProtocolReference(v.get_string());
+
+    else if ( v.is("port") )
+        app.port = v.get_long();
+
+    else
+        return false;
+
+    return true;
+}
+
+bool HostTrackerModule::begin(const char* fqn, int idx, SnortConfig*)
+{
+    if ( idx && !strcmp(fqn, "host_tracker") )
+        host = new HostTracker;
+
+    return true;
+}
+
+bool HostTrackerModule::end(const char* fqn, int idx, SnortConfig*)
+{
+    if ( idx && !strcmp(fqn, "host_tracker.services") )
+    {
+        host->add_service(app);
+        memset(&app, 0, sizeof(app));
+    }
+    else if ( idx && !strcmp(fqn, "host_tracker") )
+    {
+        //  FIXIT-H: Next step will be to add the HostTracker object to
+        //  a cache.  For now just delete in the destructor.
+        //SFAT_AddHost(host);
+        //host = nullptr;
+    }
+
+    return true;
+}
+
 #if 0
 //-------------------------------------------------------------------------
 // xxx module - used as copy/paste template
@@ -2157,5 +2246,6 @@ void module_init()
     // these modules replace config and hosts.xml
     ModuleManager::add_module(new AttributeTableModule);
     ModuleManager::add_module(new HostsModule);
+    ModuleManager::add_module(new HostTrackerModule);
 }
 
index 40ec021411d590f8ad3e172172cd6a84352cc32c..e8fcddf8a6c90577194b31c25468b62022d54dcb 100644 (file)
@@ -7,4 +7,5 @@ add_library( target_based STATIC
     sftarget_data.h
     snort_protocols.cc
     snort_protocols.h
+    host_tracker.h
 )
index bdd5b364f8b57a745dbf2bfe567f1d7ef0ca2b62..3b78e77da312f330f4681d98f1f69c78c000d657 100644 (file)
@@ -7,6 +7,12 @@ sftarget_reader.h \
 sftarget_hostentry.cc \
 sftarget_hostentry.h \
 sftarget_data.h \
+host_tracker.h \
 snort_protocols.cc \
 snort_protocols.h
 
+if BUILD_UNIT_TESTS
+SUBDIRS = test
+endif
+
+
diff --git a/src/target_based/host_tracker.h b/src/target_based/host_tracker.h
new file mode 100644 (file)
index 0000000..9f112e4
--- /dev/null
@@ -0,0 +1,191 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2015 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.
+//--------------------------------------------------------------------------
+
+// host_tracker.h author Steve Chew <stechew@cisco.com>
+
+#ifndef HOST_TRACKER_H
+#define HOST_TRACKER_H
+
+// The HostTracker class holds information known about a host (may be from
+// configuration or dynamic discovery).  It provides a thread-safe API to
+// set/get the host data.
+
+#include <mutex>
+#include <memory>
+#include <cstring>
+#include <list>
+#include <algorithm>
+
+#include "sfip/sfip_t.h"
+
+//  FIXIT-H -- For now this emulates the Snort++ attribute table. Need
+//             to add in sfrnaincludes/host_tracker.h data eventually.
+
+typedef uint16_t Port;
+typedef uint16_t Protocol;
+typedef uint8_t Policy;
+
+struct HostApplicationEntry
+{
+    Port port = 0;
+    Protocol ipproto = 0;
+    Protocol protocol = 0;
+
+    static const Protocol UNKNOWN_PROTOCOL = 0;
+
+    HostApplicationEntry()
+    {
+    }
+
+    HostApplicationEntry(Protocol ipproto_param, Port port_param, Protocol protocol_param) :
+        port(port_param),
+        ipproto(ipproto_param),
+        protocol(protocol_param)
+    {
+    }
+
+    inline bool operator==(const HostApplicationEntry& rhs) const
+    {
+        return ipproto == rhs.ipproto and port == rhs.port;
+    }
+};
+
+class HostTracker
+{
+private:
+    std::mutex host_tracker_lock;     //  Ensure that updates to a
+                                      //  shared object are safe.
+
+    //  FIXIT-H - Do we need to use a host_id instead of sfip_t as in sfrna?
+    sfip_t ip_addr;
+
+    //  Policies to apply to this host.
+    Policy stream_policy = 0;
+    Policy frag_policy = 0;
+
+    std::list<HostApplicationEntry> services;
+    std::list<HostApplicationEntry> clients;
+
+public:
+    HostTracker(void)
+    {
+        memset(&ip_addr, 0, sizeof(ip_addr));
+    }
+
+    sfip_t get_ip_addr(void)
+    {
+        std::lock_guard<std::mutex> lck(host_tracker_lock);
+        return ip_addr;
+    }
+
+    void set_ip_addr(const sfip_t& new_ip_addr)
+    {
+        std::lock_guard<std::mutex> lck(host_tracker_lock);
+        std::memcpy(&ip_addr, &new_ip_addr, sizeof(ip_addr));
+    }
+
+    Policy get_stream_policy(void)
+    {
+        std::lock_guard<std::mutex> lck(host_tracker_lock);
+        return stream_policy;
+    }
+
+    void set_stream_policy(const Policy& policy)
+    {
+        std::lock_guard<std::mutex> lck(host_tracker_lock);
+        stream_policy = policy;
+    }
+
+    Policy get_frag_policy(void)
+    {
+        std::lock_guard<std::mutex> lck(host_tracker_lock);
+        return frag_policy;
+    }
+
+    void set_frag_policy(const Policy& policy)
+    {
+        std::lock_guard<std::mutex> lck(host_tracker_lock);
+        frag_policy = policy;
+    }
+
+    //  Add host service data only if it doesn't already exist.  Returns
+    //  false if entry exists already, and true if entry was added.
+    bool add_service(const HostApplicationEntry& app_entry)
+    {
+        std::lock_guard<std::mutex> lck(host_tracker_lock);
+
+        auto iter = std::find(services.begin(), services.end(), app_entry);
+        if (iter != services.end())
+            return false;   //  Already exists.
+
+        services.push_front(app_entry);
+        return true;
+    }
+
+    //  Add host service data if it doesn't already exist.  If it does exist
+    //  replace the previous entry with the new entry.
+    void add_or_replace_service(const HostApplicationEntry& app_entry)
+    {
+        std::lock_guard<std::mutex> lck(host_tracker_lock);
+
+        auto iter = std::find(services.begin(), services.end(), app_entry);
+        if (iter != services.end())
+            services.erase(iter);
+
+        services.push_front(app_entry);
+    }
+
+    //  Returns true and fills in copy of HostApplicationEntry when found.
+    //  Returns false when not found.
+    bool find_service(Protocol ipproto, Port port, HostApplicationEntry& app_entry)
+    {
+        HostApplicationEntry tmp_entry(ipproto, port, HostApplicationEntry::UNKNOWN_PROTOCOL);
+
+        std::lock_guard<std::mutex> lck(host_tracker_lock);
+
+        auto iter = std::find(services.begin(), services.end(), tmp_entry);
+        if (iter != services.end())
+        {
+            app_entry = *iter;
+            return true;
+        }
+
+        return false;
+    }
+
+    //  Removes HostApplicationEntry object associated with ipproto and port.
+    //  Returns true if entry existed.  False otherwise.
+    bool remove_service(Protocol ipproto, Port port)
+    {
+        HostApplicationEntry tmp_entry(ipproto, port, HostApplicationEntry::UNKNOWN_PROTOCOL);
+
+        std::lock_guard<std::mutex> lck(host_tracker_lock);
+
+        auto iter = std::find(services.begin(), services.end(), tmp_entry);
+        if (iter != services.end())
+        {
+            services.erase(iter);
+            return true;   //  Assumes only one matching entry.
+        }
+
+        return false;
+    }
+};
+
+#endif
+
diff --git a/src/target_based/test/Makefile.am b/src/target_based/test/Makefile.am
new file mode 100644 (file)
index 0000000..5e2cead
--- /dev/null
@@ -0,0 +1,13 @@
+
+AM_DEFAULT_SOURCE_EXT = .cc
+
+check_PROGRAMS = \
+host_tracker_test
+
+TESTS = $(check_PROGRAMS)
+
+host_tracker_test_CPPFLAGS = @AM_CPPFLAGS@ @CPPUTEST_CPPFLAGS@
+
+host_tracker_test_LDADD = \
+@CPPUTEST_LDFLAGS@
+
diff --git a/src/target_based/test/host_tracker_test.cc b/src/target_based/test/host_tracker_test.cc
new file mode 100644 (file)
index 0000000..03de793
--- /dev/null
@@ -0,0 +1,136 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2015 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.
+//--------------------------------------------------------------------------
+
+// host_tracker_test.cc author Steve Chew <stechew@cisco.com>
+// unit tests for HostTracker class
+
+#include "target_based/host_tracker.h"
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+
+TEST_GROUP(host_tracker)
+{
+};
+
+//  Test HostTracker ipaddr get/set functions.
+TEST(host_tracker, ipaddr_test)
+{
+    HostTracker ht;
+    sfip_t zeroed_sfip;
+    sfip_t expected_ip_addr = { 0xde,0xad,0xbe,0xef,0xab,0xcd,0xef,0x01,0x23, };
+    sfip_t actual_ip_addr;
+
+    //  Test IP prior to set.
+    memset(&zeroed_sfip, 0, sizeof(zeroed_sfip));
+    actual_ip_addr = ht.get_ip_addr();
+    CHECK(0 == memcmp(&zeroed_sfip, &actual_ip_addr, sizeof(zeroed_sfip)));
+
+    ht.set_ip_addr(expected_ip_addr);
+    actual_ip_addr = ht.get_ip_addr();
+    CHECK(0 == memcmp(&expected_ip_addr, &actual_ip_addr, sizeof(expected_ip_addr)));
+}
+
+//  Test HostTracker policy get/set functions.
+TEST(host_tracker, policy_test)
+{
+    HostTracker ht;
+    Policy expected_policy = 23;
+    Policy actual_policy;
+
+    actual_policy = ht.get_stream_policy();
+    CHECK(0 == actual_policy);
+
+    actual_policy = ht.get_frag_policy();
+    CHECK(0 == actual_policy);
+
+    ht.set_stream_policy(expected_policy);
+    actual_policy = ht.get_stream_policy();
+    CHECK(expected_policy == actual_policy);
+
+    expected_policy = 77;
+    ht.set_frag_policy(expected_policy);
+    actual_policy = ht.get_frag_policy();
+    CHECK(expected_policy == actual_policy);
+}
+
+//  Test HostTracker add and find service functions.
+TEST(host_tracker, add_find_service_test)
+{
+    bool ret;
+    HostTracker ht;
+    HostApplicationEntry actual_entry;
+    HostApplicationEntry app_entry1(6, 2112, 3);
+    HostApplicationEntry app_entry2(17, 7777, 10);
+
+    //  Try a find on an empty list.
+    ret = ht.find_service(3,1000, actual_entry);
+    CHECK(false == ret);
+
+    //  Test add and find.
+    ret = ht.add_service(app_entry1);
+    CHECK(true == ret);
+
+    ret = ht.find_service(6, 2112, actual_entry);
+    CHECK(true == ret);
+    CHECK(actual_entry.port == 2112);
+    CHECK(actual_entry.ipproto == 6);
+    CHECK(actual_entry.protocol == 3);
+
+    ht.add_service(app_entry2);
+    ret = ht.find_service(6, 2112, actual_entry);
+    CHECK(true == ret);
+    CHECK(actual_entry.port == 2112);
+    CHECK(actual_entry.ipproto == 6);
+    CHECK(actual_entry.protocol == 3);
+
+    ret = ht.find_service(17, 7777, actual_entry);
+    CHECK(true == ret);
+    CHECK(actual_entry.port == 7777);
+    CHECK(actual_entry.ipproto == 17);
+    CHECK(actual_entry.protocol == 10);
+
+    //  Try adding an entry that exists already.
+    ret = ht.add_service(app_entry1);
+    CHECK(false == ret);
+
+    // Try a find on a port that isn't in the list.
+    ret = ht.find_service(6, 100, actual_entry);
+    CHECK(false == ret);
+
+    // Try a find on an ipproto that isn't in the list.
+    ret = ht.find_service(17, 2112, actual_entry);
+    CHECK(false == ret);
+
+    //  Try to remove an entry that's not in the list.
+    ret = ht.remove_service(6,100);
+    CHECK(false == ret);
+
+    ret = ht.remove_service(17,2112);
+    CHECK(false == ret);
+
+    //  Actually remove an entry.
+    ret = ht.remove_service(6,2112);
+    CHECK(true == ret);
+}
+
+int main(int argc, char** argv)
+{
+    return CommandLineTestRunner::RunAllTests(argc, argv);
+}
+