]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
add detection_engine.* sources
authorRuss Combs <rucombs@cisco.com>
Sat, 22 Oct 2016 09:40:46 +0000 (05:40 -0400)
committerRuss Combs <rucombs@cisco.com>
Wed, 18 Jan 2017 14:12:46 +0000 (09:12 -0500)
src/detection/detection_engine.cc [new file with mode: 0644]
src/detection/detection_engine.h [new file with mode: 0644]

diff --git a/src/detection/detection_engine.cc b/src/detection/detection_engine.cc
new file mode 100644 (file)
index 0000000..a66c695
--- /dev/null
@@ -0,0 +1,300 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2016 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.
+//--------------------------------------------------------------------------
+
+// detection_engine.h author Russ Combs <rucombs@cisco.com>
+
+#include "detection_engine.h"
+
+#include "detection/detection_engine.h"
+#include "events/sfeventq.h"
+#include "filters/sfthreshold.h"
+#include "latency/packet_latency.h"
+#include "main/snort.h"
+#include "main/snort_config.h"
+#include "main/thread.h"
+#include "managers/inspector_manager.h"
+#include "packet_io/active.h"
+#include "parser/parser.h"
+#include "profiler/profiler_defs.h"
+#include "protocols/packet.h"
+#include "stream/stream.h"
+#include "utils/stats.h"
+
+#include "context_switcher.h"
+#include "detect.h"
+#include "fp_detect.h"
+#include "ips_context.h"
+
+static THREAD_LOCAL unsigned s_events = 0;
+
+THREAD_LOCAL DetectionEngine::ActiveRules active_rules = DetectionEngine::NONE;
+
+DetectionEngine::DetectionEngine()
+{ Snort::get_switcher()->interrupt(); }
+
+DetectionEngine::~DetectionEngine()
+{ clear_packet(); }
+
+SF_EVENTQ* DetectionEngine::get_event_queue()
+{ return Snort::get_switcher()->get_context()->equeue; }
+
+Packet* DetectionEngine::get_current_packet()
+{ return Snort::get_switcher()->get_context()->packet; }
+
+Packet* DetectionEngine::get_packet()
+{ return get_current_packet(); }
+
+Packet* DetectionEngine::set_packet()
+{
+    // we need to stay in the current context until rebuild is successful
+    // any events while rebuilding will be logged against the current packet
+    // FIXIT-H bypass the interrupt / complete
+    ContextSwitcher* sw = Snort::get_switcher();
+    const IpsContext* c = sw->interrupt();
+    Packet* p = c->packet;
+    sw->complete();
+
+    p->pkth = c->pkth;
+    p->data = c->buf;
+    p->reset();
+
+    return p;
+}
+
+void DetectionEngine::clear_packet()
+{
+    ContextSwitcher* sw = Snort::get_switcher();
+    Packet* p = sw->get_context()->packet;
+
+    log_events(p);
+    reset();
+
+    if ( p->endianness )
+    {
+        delete p->endianness;
+        p->endianness = nullptr;
+    }
+
+    sw->complete();
+}
+
+DetectionEngine::ActiveRules DetectionEngine::get_detects()
+{ return active_rules; }
+
+void DetectionEngine::set_detects(ActiveRules ar)
+{ active_rules = ar; }
+
+void DetectionEngine::disable_content()
+{
+    if ( active_rules == CONTENT )
+        active_rules = NON_CONTENT;
+}
+
+void DetectionEngine::disable_all()
+{ active_rules = NONE; }
+
+bool DetectionEngine::detect(Packet* p)
+{
+    assert(p);
+    Profile profile(detectPerfStats);
+    
+    if ( !p->ptrs.ip_api.is_valid() )
+        return false;
+    
+    if ( p->packet_flags & PKT_PASS_RULE )
+        return false;
+        
+    // FIXIT-M restrict detect to current ip layer
+    // Curently, if a rule is found on any IP layer, we perform the detect routine
+    // on the entire packet. Instead, we should only perform detect on that layer!!
+    switch ( p->type() )
+    {
+    case PktType::IP:
+    case PktType::TCP:
+    case PktType::UDP:
+    case PktType::ICMP:
+    case PktType::PDU:
+    case PktType::FILE:
+        if ( PacketLatency::fastpath() )
+            return false;
+
+        return fpEvalPacket(p);
+
+    default:
+        break;
+    }
+    return false;
+}
+
+void DetectionEngine::inspect(Packet* p)
+{
+    {
+        PacketLatency::Context pkt_latency_ctx { p };
+        bool inspected = false;
+
+        if ( p->ptrs.decode_flags & DECODE_ERR_FLAGS )
+        {
+            if ( SnortConfig::inline_mode() and
+                SnortConfig::checksum_drop(p->ptrs.decode_flags & DECODE_ERR_CKSUM_ALL) )
+            {
+                Active::drop_packet(p);
+            }
+        }
+        else
+        {
+            active_rules = CONTENT;
+            p->alt_dsize = 0;  // FIXIT-H should be redundant
+
+            InspectorManager::execute(p);
+            inspected = true;
+
+            Active::apply_delayed_action(p);
+
+            if ( active_rules > NONE )
+                detect(p);
+        }
+        enable_tags();
+
+        // clear closed sessions here after inspection since non-stream
+        // inspectors may depend on flow information
+        // FIXIT-H but this result in double clearing?  should normal
+        // clear_session() calls be deleted from stream?  this is a
+        // performance hit on short-lived flows
+        Stream::check_flow_closed(p);
+
+        /*
+        ** By checking tagging here, we make sure that we log the
+        ** tagged packet whether it generates an alert or not.
+        */
+        if ( p->has_ip() )
+            check_tags(p);
+
+        if ( inspected )
+            InspectorManager::clear(p);
+    }
+
+    Profile profile(eventqPerfStats);
+    log_events(p);
+    reset();
+}
+
+// Return 0 if no OTN since -1 return indicates queue limit reached.
+// See fpFinalSelectEvent()
+int DetectionEngine::queue_event(const OptTreeNode* otn)
+{
+    RuleTreeNode* rtn = getRtnFromOtn(otn);
+
+    if ( !rtn )
+    {
+        // If the rule isn't in the current policy,
+        // don't add it to the event queue.
+        return 0;
+    }
+
+    SF_EVENTQ* pq = get_event_queue();
+    EventNode* en = (EventNode*)sfeventq_event_alloc(pq);
+
+    if ( !en )
+        return -1;
+
+    en->otn = otn;
+    en->rtn = rtn;
+
+    if ( sfeventq_add(pq, en) )
+        return -1;
+
+    s_events++;
+    return 0;
+}
+
+int DetectionEngine::queue_event(uint32_t gid, uint32_t sid, RuleType type)
+{
+    OptTreeNode* otn = GetOTN(gid, sid);
+
+    if ( !otn )
+        return 0;
+
+    SF_EVENTQ* pq = get_event_queue();
+    EventNode* en = (EventNode*)sfeventq_event_alloc(pq);
+
+    if ( !en )
+        return -1;
+
+    en->otn = otn;
+    en->rtn = nullptr;  // lookup later after ips policy selection
+    en->type = type;
+
+    if ( sfeventq_add(pq, en) )
+        return -1;
+
+    s_events++;
+    return 0;
+}
+
+static int log_events(void* event, void* user)
+{
+    if ( !event || !user )
+        return 0;
+
+    EventNode* en = (EventNode*)event;
+
+    if ( !en->rtn )
+    {
+        en->rtn = getRtnFromOtn(en->otn);
+
+        if ( !en->rtn )
+            return 0;  // not enabled
+    }
+
+    if ( s_events > 0 )
+        s_events--;
+
+    fpLogEvent(en->rtn, en->otn, (Packet*)user);
+    sfthreshold_reset();
+
+    return 0;
+}
+
+/*
+**  We return whether we logged events or not.  We've add a eventq user
+**  structure so we can track whether the events logged were rule events
+**  or preprocessor/decoder events.  The reason being that we don't want
+**  to flush a TCP stream for preprocessor/decoder events, and cause
+**  early flushing of the stream.
+*/
+int DetectionEngine::log_events(Packet* p)
+{
+    SF_EVENTQ* pq = get_event_queue();
+    sfeventq_action(pq, ::log_events, (void*)p);
+    return 0;
+}
+
+void DetectionEngine::reset_counts()
+{
+    pc.log_limit += s_events;
+    s_events = 0;
+}
+
+void DetectionEngine::reset()
+{
+    SF_EVENTQ* pq = get_event_queue();
+    sfeventq_reset(pq);
+    reset_counts();
+}
+
diff --git a/src/detection/detection_engine.h b/src/detection/detection_engine.h
new file mode 100644 (file)
index 0000000..edcb746
--- /dev/null
@@ -0,0 +1,77 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2016-2016 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.
+//--------------------------------------------------------------------------
+
+// detection_engine_h author Russ Combs <rucombs@cisco.com>
+
+#ifndef DETECTION_ENGINE_H
+#define DETECTION_ENGINE_H
+
+// DetectionEngine manages a detection context.  To detect a rebuilt
+// packet (PDU), first call set_packet().  If rebuild is successful,
+// then instantiate a new DetectionContext() to detect that packet.
+
+#include "actions/actions.h"
+#include "main/snort_types.h"
+
+struct Packet;
+
+class SO_PUBLIC DetectionEngine
+{
+public:
+    DetectionEngine();
+    ~DetectionEngine();
+
+    Packet* get_packet();
+
+public:
+    static Packet* get_current_packet();
+    static Packet* set_packet();
+    static void clear_packet();
+
+    static bool detect(Packet*);
+    static void inspect(Packet*);
+
+    static int queue_event(const struct OptTreeNode*);
+    static int queue_event(unsigned gid, unsigned sid, RuleType = RULE_TYPE__NONE);
+
+    static int log_events(struct Packet*);
+
+    static void reset();
+    static void reset_counts();
+
+    enum ActiveRules
+    { NONE, NON_CONTENT, CONTENT };
+
+    static ActiveRules get_detects();
+    static void set_detects(ActiveRules);
+
+    static void disable_content();
+    static void disable_all();
+
+    static void enable_content()
+    { set_detects(CONTENT); }
+
+    static bool content_enabled()
+    { return get_detects() == CONTENT; }
+
+private:
+    static struct SF_EVENTQ* get_event_queue();
+};
+
+#endif
+