From: Russ Combs Date: Sat, 22 Oct 2016 09:40:46 +0000 (-0400) Subject: add detection_engine.* sources X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ba6c519b04d7f6c0f5e3a80b14dc8e3d53954f55;p=thirdparty%2Fsnort3.git add detection_engine.* sources --- diff --git a/src/detection/detection_engine.cc b/src/detection/detection_engine.cc new file mode 100644 index 000000000..a66c69519 --- /dev/null +++ b/src/detection/detection_engine.cc @@ -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 + +#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 index 000000000..edcb74674 --- /dev/null +++ b/src/detection/detection_engine.h @@ -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 + +#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 +