]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #1703 in SNORT/snort3 from ~MASHASAN/snort3:rna_unified_log to...
authorMike Stepanek (mstepane) <mstepane@cisco.com>
Mon, 26 Aug 2019 17:05:41 +0000 (13:05 -0400)
committerMike Stepanek (mstepane) <mstepane@cisco.com>
Mon, 26 Aug 2019 17:05:41 +0000 (13:05 -0400)
Squashed commit of the following:

commit 35a9980eefe2fe7848bd936e77a66d90e8a603a3
Author: Masud Hasan <mashasan@cisco.com>
Date:   Tue Aug 6 09:30:45 2019 -0400

    rna: Support for rna unified2 logging

22 files changed:
src/hash/lru_cache_shared.h
src/host_tracker/CMakeLists.txt
src/host_tracker/host_cache.h
src/host_tracker/host_tracker.cc
src/host_tracker/host_tracker.h
src/host_tracker/host_tracker_module.h
src/host_tracker/test/host_cache_module_test.cc
src/host_tracker/test/host_cache_test.cc
src/host_tracker/test/host_tracker_module_test.cc
src/host_tracker/test/host_tracker_test.cc
src/network_inspectors/rna/CMakeLists.txt
src/network_inspectors/rna/dev_notes.txt
src/network_inspectors/rna/rna_config.h
src/network_inspectors/rna/rna_event_handler.cc
src/network_inspectors/rna/rna_inspector.cc
src/network_inspectors/rna/rna_inspector.h
src/network_inspectors/rna/rna_logger.cc [new file with mode: 0644]
src/network_inspectors/rna/rna_logger.h [new file with mode: 0644]
src/network_inspectors/rna/rna_logger_common.h [new file with mode: 0644]
src/network_inspectors/rna/rna_module.cc
src/network_inspectors/rna/rna_pnd.cc
src/network_inspectors/rna/rna_pnd.h

index d621b1bdbe6c3db5cdbbd035a8f0538bb9f90eb6..2ffd1a84cbc1289edf6fbf88d565ae00ab4f1b1a 100644 (file)
@@ -67,6 +67,9 @@ public:
     // Return data entry associated with key. If doesn't exist, create a new entry.
     Data operator[](const Key& key);
 
+    // Same as operator[]; additionally, sets the boolean if a new entry is created.
+    Data find_else_create(const Key& key, bool* new_data);
+
     // Return all data from the LruCache in order (most recently used to least)
     std::vector<std::pair<Key, Data> > get_all_data();
 
@@ -183,6 +186,13 @@ std::shared_ptr<Value> LruCacheShared<Key, Value, Hash>::find(const Key& key)
 
 template<typename Key, typename Value, typename Hash>
 std::shared_ptr<Value> LruCacheShared<Key, Value, Hash>::operator[](const Key& key)
+{
+    return find_else_create(key, nullptr);
+}
+
+template<typename Key, typename Value, typename Hash>
+std::shared_ptr<Value> LruCacheShared<Key, Value, Hash>::
+find_else_create(const Key& key, bool* new_data)
 {
     LruMapIter map_iter;
     std::lock_guard<std::mutex> cache_lock(cache_mutex);
@@ -197,6 +207,8 @@ std::shared_ptr<Value> LruCacheShared<Key, Value, Hash>::operator[](const Key& k
 
     stats.find_misses++;
     stats.adds++;
+    if ( new_data )
+        *new_data = true;
     Data data = Data(new Value);
 
     //  Add key/data pair to front of list.
index 881c277401131d00bbad3d6e61c76ccbb57ecb47..917afdee5890deb42305647c348456f4f170ff69 100644 (file)
@@ -1,12 +1,20 @@
+set (HOST_TRACKER_INCLUDES
+    host_cache.h
+    host_tracker.h
+)
+
 add_library( host_tracker OBJECT
+    ${HOST_TRACKER_INCLUDES}
     host_cache.cc
-    host_cache.h
     host_cache_module.cc
     host_cache_module.h
     host_tracker_module.cc
     host_tracker_module.h
     host_tracker.cc
-    host_tracker.h
 )
 
 add_subdirectory ( test )
+
+install(FILES ${HOST_TRACKER_INCLUDES}
+    DESTINATION "${INCLUDE_INSTALL_PATH}/host_tracker"
+)
index 725146acde234b5bdba35a4ecc59a97fa759ccaf..ac3e9a095d2524d0febdfd226e171384a6612edf 100644 (file)
@@ -39,7 +39,7 @@ struct HashIp
     }
 };
 
-extern SO_PUBLIC LruCacheShared<snort::SfIp, HostTracker, HashIp> host_cache;
+extern SO_PUBLIC LruCacheShared<snort::SfIp, snort::HostTracker, HashIp> host_cache;
 
 #endif
 
index d0911ab4be8a4b280772c4ba44bd39e8ba2d18f1..179b629784ffe0b7353f675c628f763d1327438a 100644 (file)
 
 #include "host_tracker.h"
 
+#include "utils/util.h"
+
 using namespace snort;
 using namespace std;
 
 THREAD_LOCAL struct HostTrackerStats host_tracker_stats;
 
+const uint8_t snort::zero_mac[MAC_SIZE] = {0, 0, 0, 0, 0, 0};
+
+void HostTracker::update_last_seen()
+{
+    std::lock_guard<std::mutex> lck(host_tracker_lock);
+    last_seen = (uint32_t) packet_time();
+}
+
+bool HostTracker::add_mac(const u_int8_t* mac, u_int8_t ttl, u_int8_t primary)
+{
+    if ( !mac or !memcmp(mac, zero_mac, MAC_SIZE) )
+        return false;
+
+    std::lock_guard<std::mutex> lck(host_tracker_lock);
+
+    for ( auto& hm : macs )
+        if ( !memcmp(mac, hm.mac, MAC_SIZE) )
+            return false;
+
+    if ( primary )
+    {
+        // only one primary mac (e.g., from ARP) is maintained at the front
+        if ( !macs.empty() )
+            macs.front().primary = 0;
+        macs.emplace_front(ttl, mac, primary, last_seen);
+    }
+    else
+        macs.emplace_back(ttl, mac, primary, last_seen);
+    return true;
+}
+
+void HostTracker::copy_data(uint8_t& p_hops, uint32_t& p_last_seen, list<HostMac>*& p_macs)
+{
+    std::lock_guard<std::mutex> lck(host_tracker_lock);
+
+    p_hops = hops;
+    p_last_seen = last_seen;
+    if ( !macs.empty() )
+        p_macs = new list<HostMac>(macs.begin(), macs.end());
+}
+
 bool HostTracker::add_service(Port port, IpProtocol proto, AppId appid, bool inferred_appid)
 {
     host_tracker_stats.service_adds++;
@@ -66,8 +109,41 @@ AppId HostTracker::get_appid(Port port, IpProtocol proto, bool inferred_only)
     return APP_ID_NONE;
 }
 
+static inline string to_time_string(uint32_t p_time)
+{
+    time_t raw_time = (time_t) p_time;
+    struct tm* timeinfo = gmtime(&raw_time);
+    char buffer[30];
+    strftime(buffer, 30, "%F %T", timeinfo);
+    return buffer;
+}
+
+static inline string to_mac_string(const u_int8_t* mac)
+{
+    char mac_addr[18];
+    snprintf(mac_addr, 18, "%02X:%02X:%02X:%02X:%02X:%02X",
+        mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+    return mac_addr;
+}
+
 void HostTracker::stringify(string& str)
 {
+    std::lock_guard<std::mutex> lck(host_tracker_lock);
+
+    str += "\n    hops: " + to_string(hops) + ", time: " + to_time_string(last_seen);
+
+    if ( !macs.empty() )
+    {
+        str += "\nmacs size: " + to_string(macs.size());
+        for ( const auto& m : macs )
+        {
+            str += "\n    mac: " + to_mac_string(m.mac)
+                + ", ttl: " + to_string(m.ttl)
+                + ", primary: " + to_string(m.primary)
+                + ", time: " + to_time_string(m.last_seen);
+        }
+    }
+
     if ( !services.empty() )
     {
         str += "\nservices size: " + to_string(services.size());
index 0c22509bec9f3c7d05bf35601d62e751eb71388e..9e032e6bf676733bdae904017cfb7436ba7864fb 100644 (file)
@@ -25,7 +25,9 @@
 // configuration or dynamic discovery).  It provides a thread-safe API to
 // set/get the host data.
 
+#include <cstring>
 #include <mutex>
+#include <list>
 #include <vector>
 
 #include "framework/counts.h"
@@ -33,6 +35,7 @@
 #include "main/thread.h"
 #include "network_inspectors/appid/application_ids.h"
 #include "protocols/protocol_ids.h"
+#include "time/packet_time.h"
 
 struct HostTrackerStats
 {
@@ -42,6 +45,23 @@ struct HostTrackerStats
 
 extern THREAD_LOCAL struct HostTrackerStats host_tracker_stats;
 
+namespace snort
+{
+#define MAC_SIZE 6
+extern const uint8_t zero_mac[MAC_SIZE];
+
+struct HostMac
+{
+    HostMac(u_int8_t p_ttl, const u_int8_t* p_mac, u_int8_t p_primary, uint32_t p_last_seen)
+        : ttl(p_ttl), primary(p_primary), last_seen (p_last_seen) { memcpy(mac, p_mac, MAC_SIZE); }
+
+    // the type and order below should match logger's serialization
+    u_int8_t ttl;
+    u_int8_t mac[MAC_SIZE];
+    u_int8_t primary;
+    uint32_t last_seen;
+};
+
 struct HostApplication
 {
     Port port;
@@ -53,6 +73,17 @@ struct HostApplication
 class SO_PUBLIC HostTracker
 {
 public:
+    HostTracker() : hops(-1)
+    { last_seen = (uint32_t) packet_time(); }
+
+    void update_last_seen();
+
+    // Returns true if a new mac entry is added, false otherwise
+    bool add_mac(const u_int8_t* mac, u_int8_t ttl, u_int8_t primary);
+
+    // The caller owns and deletes the copied list of mac addresses
+    void copy_data(uint8_t& p_hops, uint32_t& p_last_seen, std::list<HostMac>*& p_macs);
+
     // Appid may not be identified always. Inferred means dynamic/runtime
     // appid detected from one flow to another flow such as BitTorrent.
     bool add_service(Port port, IpProtocol proto,
@@ -64,11 +95,11 @@ public:
     void stringify(std::string& str);
 
 private:
-    //  Ensure that updates to a shared object are safe
-    std::mutex host_tracker_lock;
-
+    std::mutex host_tracker_lock; // ensure that updates to a shared object are safe
+    uint8_t hops;                 // hops from the snort inspector, e.g., zero for ARP
+    uint32_t last_seen;           // the last time this host was seen
+    std::list<HostMac> macs;
     std::vector<HostApplication> services;
 };
-
+} // namespace snort
 #endif
-
index 00f400030a54fc0cebe60cdfd1f623d3296e3ea4..fffa99a837bdd0e73c8aba45941c04d315e9ec10 100644 (file)
@@ -55,7 +55,7 @@ private:
     static const snort::Parameter host_tracker_params[];
     static const snort::Parameter service_params[];
 
-    HostApplication app;
+    snort::HostApplication app;
     snort::SfIp addr;
 };
 
index 7c2f6587e18afda34cbb740d3e93fafc3b276cfc..501b94d0ccf785444df3fdb1fe842365a75393b9 100644 (file)
@@ -57,6 +57,7 @@ void LogMessage(const char* format,...)
     va_end(args);
     logged_message[LOG_MAX] = '\0';
 }
+time_t packet_time() { return 0; }
 }
 
 extern "C"
index f177349ac694fc228dfa3d8e0cb22b279ec959ea..f83f0f773800f434c9307ecb6fe03e5c916c1af8 100644 (file)
@@ -40,6 +40,7 @@ char* snort_strdup(const char* str)
 {
     return strdup(str);
 }
+time_t packet_time() { return 0; }
 }
 
 TEST_GROUP(host_cache)
index 33e9da5a1ba5ab3b82045a5d7cd329e6011be11d..8ba0b2c74f62bc02181545e9d6801faf433f76bd 100644 (file)
@@ -39,6 +39,7 @@ namespace snort
 {
 char* snort_strdup(const char* s)
 { return strdup(s); }
+time_t packet_time() { return 0; }
 }
 
 //  Fake show_stats to avoid bringing in a ton of dependencies.
index ae6eb4400c18af6799a2f0620523bacb21484802..dcc52ce89e5da0d2831f1e45696c91c0d7aab5db 100644 (file)
 using namespace snort;
 using namespace std;
 
+static time_t test_time = 0;
 namespace snort
 {
 // Fake snort_strdup() because sfutil dependencies suck
 char* snort_strdup(const char* str)
 { return strdup(str); }
+time_t packet_time() { return test_time; }
 }
 
 TEST_GROUP(host_tracker)
@@ -66,15 +68,59 @@ TEST(host_tracker, add_find_service_test)
     CHECK(APP_ID_NONE == ht.get_appid(8080, IpProtocol::UDP));
 }
 
+//  Test copying data and deleting copied list
+TEST(host_tracker, copy_data_test)
+{
+    test_time = 1562198400;
+    HostTracker ht;
+    u_int8_t mac[6] = {254, 237, 222, 173, 190, 239};
+    ht.add_mac(mac, 50, 1);
+
+    uint8_t p_hops = 0;
+    uint32_t p_last_seen = 0;
+    list<HostMac>* p_macs = nullptr;
+    ht.copy_data(p_hops, p_last_seen, p_macs);
+
+    CHECK(p_hops == 255);
+    CHECK(p_last_seen == 1562198400);
+    CHECK(p_macs != nullptr);
+    CHECK(p_macs->size() == 1);
+    auto& copied_data = p_macs->front();
+    CHECK(copied_data.ttl == 50);
+    CHECK(copied_data.primary == 1);
+    CHECK(copied_data.last_seen == 1562198400);
+    CHECK(memcmp(copied_data.mac, mac, MAC_SIZE) == 0);
+
+    delete p_macs;
+}
+
 TEST(host_tracker, stringify)
 {
+    test_time = 1562198400; // this time will be updated and should not be seen in stringify
     HostTracker ht;
+
+    u_int8_t mac1[6] = {254, 237, 222, 173, 190, 239};
+    u_int8_t mac2[6] = {202, 254, 192, 255, 238, 0};
+    test_time = 1562198404; // this time should be the time of the first mac address
+    ht.update_last_seen();
+    ht.add_mac(mac1, 9, 0);
+    test_time = 1562198407; // this time should be the time of the second mac address
+    ht.update_last_seen();
+    ht.add_mac(mac2, 3, 1); // this primary mac should go to the front of the list
+
     ht.add_service(80, IpProtocol::TCP, 676, true);
+    test_time = 1562198409; // this time should be the last seen time of the host
+    ht.update_last_seen();
     ht.add_service(443, IpProtocol::TCP, 1122);
-    string host_tracker_string;
 
+    string host_tracker_string;
     ht.stringify(host_tracker_string);
+
     STRCMP_EQUAL(host_tracker_string.c_str(),
+        "\n    hops: 255, time: 2019-07-04 00:00:09"
+        "\nmacs size: 2"
+        "\n    mac: CA:FE:C0:FF:EE:00, ttl: 3, primary: 1, time: 2019-07-04 00:00:07"
+        "\n    mac: FE:ED:DE:AD:BE:EF, ttl: 9, primary: 0, time: 2019-07-04 00:00:04"
         "\nservices size: 2"
         "\n    port: 80, proto: 6, appid: 676, inferred"
         "\n    port: 443, proto: 6, appid: 1122");
index 1091697317d6fb3f3c48dd3202e15a2ee3328e1c..56b56b54d399ad92dc044c3e14c7ec63e7633cf1 100644 (file)
@@ -1,9 +1,15 @@
+set (RNA_INCLUDES
+    rna_logger.h
+)
 
 set ( RNA_SOURCES
+    ${RNA_INCLUDES}
     rna_event_handler.cc
     rna_event_handler.h
     rna_inspector.cc
     rna_inspector.h
+    rna_logger.cc
+    rna_logger_common.h
     rna_module.cc
     rna_module.h
     rna_pnd.cc
@@ -19,3 +25,7 @@ add_library( rna OBJECT
 #       ${RNA_SOURCES}
 #   )
 #endif (STATIC_INSPECTORS)
+
+install(FILES ${RNA_INCLUDES}
+    DESTINATION "${INCLUDE_INSTALL_PATH}/network_inspectors/rna"
+)
\ No newline at end of file
index bd1896d11529964ff33a4a49df6a9d02fc24729c..3e1bc2d28576937d883ee91927fddeac4f37ec09 100644 (file)
@@ -1,23 +1,23 @@
 This inspector is still in experimental (work-in-progress) state.
 
-The Real-time Network Awareness (RNA) inspector provides visibility into
-a network using Passive Network Discovery (PND). RNA analyzes traffic
-to discover hosts on the network, and detect operating systems, protocols and
-applications running on these hosts. It does not generate or alter traffic on its own.
+The Real-time Network Awareness (RNA) inspector provides visibility into a network using
+Passive Network Discovery (PND). RNA analyzes traffic to discover hosts on the network
+and to detect operating system (OS) running on a host. It uses fingerprints for OS detection.
+It logs ip/mac addresses, ports, protocols, OS, and other information about traffic running
+on these hosts. It does not generate or alter traffic on its own.
 
-RNA generates events for the information it discovers by parsing
-TCP/UDP/IP/Link-layer protocols and analyzing data found by other
-inspectors (e.g., monitoring application IDs, client versions, user-agents from stash).
-Operating systems have different signatures which are apparent in different parameters
-in the packets that it sends. These parameters include things like TCP window sizes,
-TCP options, segment sizes, etc. Such fingerprinting information is provided to RNA
-as input so that RNA can analyze traffic.
+RNA logs information it discovers by parsing TCP/UDP/IP/Link-layer protocols and observing
+data found by other inspectors (e.g., monitoring application IDs, client versions,
+user-agents found by appid or http inspectors). Operating systems have different signatures
+which are apparent in different parameters in the packets that it sends. These parameters
+include things like TCP window sizes, TCP options, segment sizes, etc. Such fingerprinting
+information is provided to RNA as input so that RNA can analyze traffic.
 
-RNA discoveries will be stored globally in host_tracker objects and to be shared among
-multiple threads. RNA memory and discovery are bounded by the memcap in host_tracker.
+RNA discoveries is stored in host tracker objects, which are saved globally in an LRU cache
+and shared among threads. RNA memory and discovery are bounded by the memcap of cache.
 
 Packets from untracked sessions (e.g., non-IP) are processed via the eval method as per
 proto-bit registrations. Packets from tracked sessions (e.g., IP, TCP, UDP, and ICMP)
 are processed via events as per subscriptions. Since RNA needs to see the first packet
-of a session published from stream trackers, these modules (e.g., stream, stream_ip,
-stream_tcp, and stream_udp) should be enabled whenever RNA module is enabled.
+of a session published from stream trackers, these modules (e.g., stream, stream_icmp,
+stream_ip, stream_tcp, and stream_udp) should be enabled whenever RNA module is enabled.
index ff6da49b8185e1485fe548a21a2de3728426ea4d..791b4f5b35aba76d493d6246b2e6e22e0a77ef90 100644 (file)
@@ -27,6 +27,7 @@ struct RnaModuleConfig
     std::string rna_util_lib_path;
     std::string fingerprint_dir;
     std::string custom_fingerprint_dir;
+    bool enable_logger;
 };
 
 // Give default values so that RNA can work even if rna_conf_path is not provided
index 8607c5e8d122a9456ca83c065f9fe8b09264641a..4e021abcd2346d169b35614783116c94dc782cf2 100644 (file)
@@ -44,21 +44,21 @@ void RnaTcpSynEventHandler::handle(DataEvent& event, Flow*)
 {
     Profile profile(rna_perf_stats);
     ++rna_stats.tcp_syn;
-    pnd.analyze_flow_tcp(event.get_packet(), false);
+    pnd.analyze_flow_tcp(event.get_packet(), TcpPacketType::SYN);
 }
 
 void RnaTcpSynAckEventHandler::handle(DataEvent& event, Flow*)
 {
     Profile profile(rna_perf_stats);
     ++rna_stats.tcp_syn_ack;
-    pnd.analyze_flow_tcp(event.get_packet(), false);
+    pnd.analyze_flow_tcp(event.get_packet(), TcpPacketType::SYN_ACK);
 }
 
 void RnaTcpMidstreamEventHandler::handle(DataEvent& event, Flow*)
 {
     Profile profile(rna_perf_stats);
     ++rna_stats.tcp_midstream;
-    pnd.analyze_flow_tcp(event.get_packet(), true);
+    pnd.analyze_flow_tcp(event.get_packet(), TcpPacketType::MIDSTREAM);
 }
 
 void RnaUdpEventHandler::handle(DataEvent& event, Flow*)
index 1b3629e769bb7864fc18e1ada782e876362867df..31f06c5e9c912a19750583ba56d929ed9c2da883 100644 (file)
@@ -52,24 +52,25 @@ THREAD_LOCAL ProfileStats rna_perf_stats;
 RnaInspector::RnaInspector(RnaModule* mod)
 {
     mod_conf = mod->get_config();
-    if (!load_rna_conf())
-        WarningMessage("RNA: Failed to load configurations from file! Using defaults.\n");
+    load_rna_conf();
+    pnd = new RnaPnd(mod_conf? mod_conf->enable_logger : false);
 }
 
 RnaInspector::~RnaInspector()
 {
-    delete mod_conf;
+    delete pnd;
     delete rna_conf;
+    delete mod_conf;
 }
 
 bool RnaInspector::configure(SnortConfig*)
 {
-    DataBus::subscribe( STREAM_ICMP_NEW_FLOW_EVENT, new RnaIcmpEventHandler(pnd) );
-    DataBus::subscribe( STREAM_IP_NEW_FLOW_EVENT, new RnaIpEventHandler(pnd) );
-    DataBus::subscribe( STREAM_UDP_NEW_FLOW_EVENT, new RnaUdpEventHandler(pnd) );
-    DataBus::subscribe( STREAM_TCP_SYN_EVENT, new RnaTcpSynEventHandler(pnd) );
-    DataBus::subscribe( STREAM_TCP_SYN_ACK_EVENT, new RnaTcpSynAckEventHandler(pnd) );
-    DataBus::subscribe( STREAM_TCP_MIDSTREAM_EVENT, new RnaTcpMidstreamEventHandler(pnd) );
+    DataBus::subscribe( STREAM_ICMP_NEW_FLOW_EVENT, new RnaIcmpEventHandler(*pnd) );
+    DataBus::subscribe( STREAM_IP_NEW_FLOW_EVENT, new RnaIpEventHandler(*pnd) );
+    DataBus::subscribe( STREAM_UDP_NEW_FLOW_EVENT, new RnaUdpEventHandler(*pnd) );
+    DataBus::subscribe( STREAM_TCP_SYN_EVENT, new RnaTcpSynEventHandler(*pnd) );
+    DataBus::subscribe( STREAM_TCP_SYN_ACK_EVENT, new RnaTcpSynAckEventHandler(*pnd) );
+    DataBus::subscribe( STREAM_TCP_MIDSTREAM_EVENT, new RnaTcpMidstreamEventHandler(*pnd) );
 
     return true;
 }
@@ -83,7 +84,7 @@ void RnaInspector::eval(Packet* p)
     assert( !(BIT((unsigned)p->type()) & PROTO_BIT__ANY_SSN) );
 
     // Handling untracked sessions, e.g., non-IP packets
-    // pnd.analyze_flow_non_ip(p);
+    // pnd->analyze_flow_non_ip(p);
     UNUSED(p);
 }
 
@@ -102,6 +103,7 @@ void RnaInspector::show(SnortConfig*)
         if (!mod_conf->custom_fingerprint_dir.empty())
             LogMessage("    Custom fingerprint dir: %s\n",
                 mod_conf->custom_fingerprint_dir.c_str());
+        LogMessage("    Enable logger:          %d\n", mod_conf->enable_logger);
     }
 
     if (rna_conf)
@@ -127,18 +129,18 @@ void RnaInspector::tterm()
     // thread local cleanup
 }
 
-bool RnaInspector::load_rna_conf()
+void RnaInspector::load_rna_conf()
 {
     if (rna_conf)
         delete rna_conf;
     rna_conf = new RnaConfig; // initialize with defaults
 
     if (!mod_conf)
-        return false;
+        return;
 
     ifstream in_stream(mod_conf->rna_conf_path);
     if (!in_stream)
-        return false;
+        return;
 
     uint32_t line_num = 0;
 
@@ -178,7 +180,6 @@ bool RnaInspector::load_rna_conf()
     }
 
     in_stream.close();
-    return true;
 }
 
 //-------------------------------------------------------------------------
index 7e2c435400ba404b8a11a34e7f9e69708f388fce..53f0b409423c2fd2eed8f3380ea042fa60c6bc52 100644 (file)
@@ -44,10 +44,10 @@ public:
     void tterm() override;
 
 private:
-    bool load_rna_conf();
+    void load_rna_conf();
     const RnaModuleConfig* mod_conf = nullptr;
     RnaConfig* rna_conf = nullptr;
-    RnaPnd pnd;
+    RnaPnd* pnd = nullptr;
 };
 
 #endif
diff --git a/src/network_inspectors/rna/rna_logger.cc b/src/network_inspectors/rna/rna_logger.cc
new file mode 100644 (file)
index 0000000..ccc0cd7
--- /dev/null
@@ -0,0 +1,65 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2014-2019 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2003-2013 Sourcefire, Inc.
+//
+// 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.
+//--------------------------------------------------------------------------
+
+// rna_logger.h author Masud Hasan <mashasan@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "rna_logger.h"
+
+#include "managers/event_manager.h"
+#include "protocols/packet.h"
+
+#ifdef UNIT_TEST
+#include "catch/snort_catch.h"
+#endif
+
+using namespace snort;
+
+bool RnaLogger::log(uint16_t type, uint16_t subtype, const Packet* p, const RnaTracker* ht,
+    const struct in6_addr* src_ip, const u_int8_t* src_mac)
+{
+    if ( !enabled )
+        return false;
+
+    RnaLoggerEvent rle(type, subtype, ht, src_mac);
+    if ( src_ip and (!IN6_IS_ADDR_V4MAPPED(src_ip) or src_ip->s6_addr32[3]) )
+        rle.ip = src_ip;
+    else
+        rle.ip = nullptr;
+
+    EventManager::call_loggers(nullptr, const_cast<Packet*>(p), "RNA", &rle);
+    return true;
+}
+
+#ifdef UNIT_TEST
+TEST_CASE("RNA logger", "[rna_logger]")
+{
+    SECTION("Checking enabled flag")
+    {
+        RnaLogger logger1(false);
+        CHECK(logger1.log(0, 0, 0, 0, 0, 0) == false);
+
+        RnaLogger logger2(true);
+        CHECK(logger2.log(0, 0, 0, 0, 0, 0) == true);
+    }
+}
+#endif
diff --git a/src/network_inspectors/rna/rna_logger.h b/src/network_inspectors/rna/rna_logger.h
new file mode 100644 (file)
index 0000000..24091e2
--- /dev/null
@@ -0,0 +1,56 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2014-2019 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2003-2013 Sourcefire, Inc.
+//
+// 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.
+//--------------------------------------------------------------------------
+
+#ifndef RNA_LOGGER_H
+#define RNA_LOGGER_H
+
+#include "events/event.h"
+#include "host_tracker/host_cache.h"
+
+namespace snort
+{
+class Flow;
+struct Packet;
+}
+
+using RnaTracker = std::shared_ptr<snort::HostTracker>;
+
+struct RnaLoggerEvent : public Event
+{
+    RnaLoggerEvent(uint16_t p_type, uint16_t p_subtype, const RnaTracker* p_ht,
+        const u_int8_t* p_mac) : type(p_type), subtype(p_subtype), ht(p_ht), mac(p_mac) { }
+    uint16_t type;
+    uint16_t subtype;
+    const RnaTracker* ht;
+    const u_int8_t* mac;
+    const struct in6_addr* ip;
+};
+
+class RnaLogger
+{
+public:
+    RnaLogger(const bool enable) : enabled(enable) { }
+    bool log(uint16_t type, uint16_t subtype, const snort::Packet* p, const RnaTracker* ht,
+        const struct in6_addr* src_ip, const u_int8_t* src_mac);
+
+private:
+    const bool enabled;
+};
+
+#endif
diff --git a/src/network_inspectors/rna/rna_logger_common.h b/src/network_inspectors/rna/rna_logger_common.h
new file mode 100644 (file)
index 0000000..bcdf273
--- /dev/null
@@ -0,0 +1,27 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2014-2019 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2003-2013 Sourcefire, Inc.
+//
+// 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.
+//--------------------------------------------------------------------------
+
+#ifndef RNA_LOGGER_COMMON_H
+#define RNA_LOGGER_COMMON_H
+
+// Common definitions between rna logger and pnd modules
+#define RNA_EVENT_NEW       1000
+    #define NEW_HOST            1
+
+#endif
index 1bbf064e92f799f7ca1dc4377c7b7f4ed8df083f..98cebdbff290a8eca43f3d94d31e23ddd15bca41 100644 (file)
@@ -53,6 +53,9 @@ static const Parameter rna_params[] =
     { "custom_fingerprint_dir", Parameter::PT_STRING, nullptr, nullptr,
       "directory to custom fingerprint patterns" },
 
+    { "enable_logger", Parameter::PT_BOOL, nullptr, "true",
+      "enable or disable writing discovery events into logger" },
+
     { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
 };
 
@@ -99,6 +102,8 @@ bool RnaModule::set(const char*, Value& v, SnortConfig*)
         mod_conf->fingerprint_dir = std::string(v.get_string());
     else if (v.is("custom_fingerprint_dir"))
         mod_conf->custom_fingerprint_dir = std::string(v.get_string());
+    else if (v.is("enable_logger"))
+        mod_conf->enable_logger = v.get_bool();
     else
         return false;
 
index 10d004065256b4aaf3ae078a737342f4f3c4675d..834be46298db5c5ad92ac3ea3cbf6af84c943064 100644 (file)
 
 #include "rna_pnd.h"
 
-#include "host_tracker/host_cache.h"
+#include "protocols/eth.h"
+#include "protocols/icmp4.h"
+#include "protocols/packet.h"
+#include "protocols/tcp.h"
 
-using namespace snort;
+#include "rna_logger_common.h"
+
+#ifdef UNIT_TEST
+#include "catch/snort_catch.h"
+#endif
 
-static const uint8_t zeromac[6] = {0, 0, 0, 0, 0, 0};
+using namespace snort;
 
-static inline bool is_eligible_packet(const snort::Packet* p)
+static inline bool is_eligible_packet(const Packet* p)
 {
     if ( p->has_ip() or
-        memcmp(snort::layer::get_eth_layer(p)->ether_src, zeromac, sizeof(zeromac)) )
+        memcmp(snort::layer::get_eth_layer(p)->ether_src, zero_mac, MAC_SIZE) )
         return true;
     return false;
 }
 
-static inline bool is_eligible_ip(const snort::Packet* p)
+static inline bool is_eligible_ip(const Packet* p)
 {
     // If payload needs to be inspected ever, allow rebuilt packet when is_proxied
-    if ( !is_eligible_packet(p) or p->is_rebuilt() or !p->flow )
+    if ( !p->has_ip() or p->is_rebuilt() or !p->flow )
         return false;
     return true;
 }
 
-static inline bool is_eligible_tcp(const snort::Packet* p)
+static inline bool is_eligible_tcp(const Packet* p)
 {
     if ( !is_eligible_ip(p) or p->ptrs.tcph->is_rst() )
         return false;
     return true;
 }
 
-static inline bool is_eligible_udp(const snort::Packet* p)
+static inline bool is_eligible_udp(const Packet* p)
 {
     if ( !is_eligible_ip(p) )
         return false;
@@ -88,13 +95,13 @@ void RnaPnd::analyze_flow_non_ip(const Packet* p)
         discover_network_non_ip(p);
 }
 
-void RnaPnd::analyze_flow_tcp(const Packet* p, bool is_midstream)
+void RnaPnd::analyze_flow_tcp(const Packet* p, TcpPacketType type)
 {
     // If and when flow stores rna state, process the flow data here before global cache access
     if ( is_eligible_tcp(p) )
         discover_network_tcp(p);
 
-    UNUSED(is_midstream);
+    UNUSED(type);
 }
 
 void RnaPnd::analyze_flow_udp(const Packet* p)
@@ -105,18 +112,12 @@ void RnaPnd::analyze_flow_udp(const Packet* p)
 
 void RnaPnd::discover_network_icmp(const Packet* p)
 {
-    if ( !(host_cache[p->flow->client_ip]->
-        add_service(p->flow->client_port, p->get_ip_proto_next())) )
-        return;
-    // process rna discovery for icmp
+    discover_network(p, 0);
 }
 
 void RnaPnd::discover_network_ip(const Packet* p)
 {
-    if ( !(host_cache[p->flow->client_ip]->
-        add_service(p->flow->client_port, p->get_ip_proto_next())) )
-        return;
-    // process rna discovery for ip
+    discover_network(p, p->ptrs.ip_api.ttl());
 }
 
 void RnaPnd::discover_network_non_ip(const Packet* p)
@@ -127,20 +128,52 @@ void RnaPnd::discover_network_non_ip(const Packet* p)
 
 void RnaPnd::discover_network_tcp(const Packet* p)
 {
-    // Track from initiator direction, if not already seen
-    if ( !(host_cache[p->flow->client_ip]->
-        add_service(p->flow->client_port, p->get_ip_proto_next())) )
-        return;
-
-    // Add mac address to ht list, ttl, last_seen, etc.
-    // Generate new host events
+    // once fingerprints and other stuff are supported, the discovery code will evolve
+    discover_network(p, p->ptrs.ip_api.ttl());
 }
 
 void RnaPnd::discover_network_udp(const Packet* p)
 {
-    if ( !(host_cache[p->flow->client_ip]->
-        add_service(p->flow->client_port, p->get_ip_proto_next())) )
-        return;
-    // process rna discovery for udp
+    const auto& ip_api = p->ptrs.ip_api;
+    if ( IN6_IS_ADDR_MULTICAST(ip_api.get_dst()->get_ip6_ptr()) )
+        discover_network(p, 0);
+    else
+        discover_network(p, ip_api.ttl());
 }
 
+void RnaPnd::discover_network(const Packet* p, u_int8_t ttl)
+{
+    bool new_host = false;
+    const auto& src_ip = p->ptrs.ip_api.get_src();
+    auto ht = host_cache.find_else_create(*src_ip, &new_host);
+    if ( !new_host )
+        ht->update_last_seen(); // this should be done always and foremost
+
+    const auto& src_mac = layer::get_eth_layer(p)->ether_src;
+    ht->add_mac(src_mac, ttl, 0);
+
+    if ( new_host )
+        logger.log(RNA_EVENT_NEW, NEW_HOST, p, &ht,
+            (const struct in6_addr*) src_ip->get_ip6_ptr(), src_mac);
+}
+
+#ifdef UNIT_TEST
+TEST_CASE("RNA pnd", "[non-ip]")
+{
+    SECTION("Testing eligible packet")
+    {
+        Packet p;
+        eth::EtherHdr eh;
+        memcpy(eh.ether_src, zero_mac, MAC_SIZE);
+        p.num_layers = 1;
+        p.layers[0].start = (const uint8_t*) &eh;
+        CHECK(is_eligible_packet(&p) == false);
+
+        ip::IP4Hdr h4;
+        p.ptrs.ip_api.set(&h4);
+        RnaPnd pnd(false);
+        pnd.analyze_flow_non_ip(&p);
+        CHECK(is_eligible_packet(&p) == true);
+    }
+}
+#endif
index b19beb408006138d7d329b351dcc27b0c5ba9690..e7be2d71481d64d7f19ae7fd9d9567897c1562d1 100644 (file)
 #ifndef RNA_PND_H
 #define RNA_PND_H
 
-#include "protocols/eth.h"
-#include "protocols/packet.h"
-#include "protocols/tcp.h"
+#include "rna_logger.h"
 
 namespace snort
 {
 struct Packet;
 }
 
+enum class TcpPacketType
+{
+    SYN, SYN_ACK, MIDSTREAM
+};
+
 class RnaPnd
 {
 public:
+    RnaPnd(const bool en) : logger(RnaLogger(en)) { }
+
     void analyze_flow_icmp(const snort::Packet* p);
     void analyze_flow_ip(const snort::Packet* p);
     void analyze_flow_non_ip(const snort::Packet* p);
-    void analyze_flow_tcp(const snort::Packet* p, bool is_midstream);
+    void analyze_flow_tcp(const snort::Packet* p, TcpPacketType type);
     void analyze_flow_udp(const snort::Packet* p);
 
 private:
@@ -45,6 +50,9 @@ private:
     void discover_network_non_ip(const snort::Packet* p);
     void discover_network_tcp(const snort::Packet* p);
     void discover_network_udp(const snort::Packet* p);
+    void discover_network(const snort::Packet* p, u_int8_t ttl);
+
+    RnaLogger logger;
 };
 
 #endif