00001 //--------------------------------------------------------------------------
00002 // Copyright (C) 2016-2017 Cisco and/or its affiliates. All rights reserved.
00003 //
00004 // This program is free software; you can redistribute it and/or modify it
00005 // under the terms of the GNU General Public License Version 2 as published
00006 // by the Free Software Foundation. You may not use, modify or distribute
00007 // this program under any other version of the GNU General Public License.
00008 //
00009 // This program is distributed in the hope that it will be useful, but
00010 // WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00012 // General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License along
00015 // with this program; if not, write to the Free Software Foundation, Inc.,
00016 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017 //--------------------------------------------------------------------------
00018
00019 // detection_engine.h author Russ Combs <rucombs@cisco.com>
00020
00021 #ifdef HAVE_CONFIG_H
00022 #include "config.h"
00023 #endif
00024
00025 #include "detection_engine.h"
00026
00027 #include "events/sfeventq.h"
00028 #include "filters/sfthreshold.h"
00029 #include "framework/endianness.h"
00030 #include "helpers/ring.h"
00031 #include "latency/packet_latency.h"
00032 #include "main/modules.h"
00033 #include "main/snort.h"
00034 #include "main/snort_config.h"
00035 #include "main/snort_debug.h"
00036 #include "main/thread.h"
00037 #include "managers/inspector_manager.h"
00038 #include "packet_io/active.h"
00039 #include "parser/parser.h"
00040 #include "profiler/profiler_defs.h"
00041 #include "protocols/packet.h"
00042 #include "stream/stream.h"
00043 #include "utils/stats.h"
00044
00045 #include "context_switcher.h"
00046 #include "detection_util.h"
00047 #include "detect.h"
00048 #include "detect_trace.h"
00049 #include "fp_config.h"
00050 #include "fp_detect.h"
00051 #include "ips_context.h"
00052 #include "regex_offload.h"
00053
00054 static THREAD_LOCAL RegexOffload* offloader = nullptr;
00055 static THREAD_LOCAL uint64_t context_num = 0;
00056
00057 //--------------------------------------------------------------------------
00058 // basic de
00059 //--------------------------------------------------------------------------
00060
00061 void DetectionEngine::thread_init()
00062 { offloader = new RegexOffload(snort_conf->offload_threads); }
00063
00064 void DetectionEngine::thread_term()
00065 { delete offloader; }
00066
00067 DetectionEngine::DetectionEngine()
00068 {
00069 context = Snort::get_switcher()->interrupt();
00070 context->file_data = { nullptr, 0 };
00071 reset();
00072 }
00073
00074 DetectionEngine::~DetectionEngine()
00075 {
00076 finish_packet(context->packet);
00077 ContextSwitcher* sw = Snort::get_switcher();
00078
00079 if ( context == sw->get_context() )
00080 {
00081 sw->complete();
00082 }
00083 }
00084
00085 void DetectionEngine::reset()
00086 {
00087 IpsContext* c = Snort::get_switcher()->get_context();
00088 c->context_num = ++context_num;
00089 c->alt_data.len = 0; // FIXIT-H need context::reset()
00090 }
00091
00092 IpsContext* DetectionEngine::get_context()
00093 { return Snort::get_switcher()->get_context(); }
00094
00095 SF_EVENTQ* DetectionEngine::get_event_queue()
00096 { return Snort::get_switcher()->get_context()->equeue; }
00097
00098 Packet* DetectionEngine::get_current_packet()
00099 { return Snort::get_switcher()->get_context()->packet; }
00100
00101 void DetectionEngine::set_encode_packet(Packet* p)
00102 { Snort::get_switcher()->get_context()->encode_packet = p; }
00103
00104 Packet* DetectionEngine::get_encode_packet()
00105 { return Snort::get_switcher()->get_context()->encode_packet; }
00106
00107 // we need to stay in the current context until rebuild is successful
00108 // any events while rebuilding will be logged against the current packet
00109 // however, rebuild is always in the next context, not current.
00110 Packet* DetectionEngine::set_next_packet()
00111 {
00112 const IpsContext* c = Snort::get_switcher()->get_next();
00113 Packet* p = c->packet;
00114
00115 p->pkth = c->pkth;
00116 p->data = c->buf;
00117 p->pkt = c->buf;
00118
00119 p->reset();
00120 return p;
00121 }
00122
00123 void DetectionEngine::finish_packet(Packet* p)
00124 {
00125 log_events(p);
00126 clear_events(p);
00127 p->release_helpers();
00128
00129 // clean up any failed rebuilds
00130 const IpsContext* c = Snort::get_switcher()->get_next();
00131 c->packet->release_helpers();
00132 }
00133
00134 uint8_t* DetectionEngine::get_buffer(unsigned& max)
00135 {
00136 max = IpsContext::buf_size;
00137 return Snort::get_switcher()->get_context()->buf;
00138 }
00139
00140 uint8_t* DetectionEngine::get_next_buffer(unsigned& max)
00141 {
00142 max = IpsContext::buf_size;
00143 return Snort::get_switcher()->get_next()->buf;
00144 }
00145
00146 DataBuffer& DetectionEngine::get_alt_buffer(Packet* p)
00147 {
00148 assert(p);
00149 return p->context->alt_data;
00150 }
00151
00152 void DetectionEngine::set_file_data(const DataPointer& dp)
00153 { Snort::get_switcher()->get_context()->file_data = dp; }
00154
00155 void DetectionEngine::get_file_data(DataPointer& dp)
00156 { dp = Snort::get_switcher()->get_context()->file_data; }
00157
00158 void DetectionEngine::set_data(unsigned id, IpsContextData* p)
00159 { Snort::get_switcher()->get_context()->set_context_data(id, p); }
00160
00161 IpsContextData* DetectionEngine::get_data(unsigned id)
00162 { return Snort::get_switcher()->get_context()->get_context_data(id); }
00163
00164 void DetectionEngine::disable_all(Packet* p)
00165 { p->context->active_rules = IpsContext::NONE; }
00166
00167 bool DetectionEngine::all_disabled(Packet* p)
00168 { return p->context->active_rules == IpsContext::NONE; }
00169
00170 void DetectionEngine::disable_content(Packet* p)
00171 {
00172 if ( p->context->active_rules == IpsContext::CONTENT )
00173 p->context->active_rules = IpsContext::NON_CONTENT;
00174 }
00175
00176 void DetectionEngine::enable_content(Packet* p)
00177 { p->context->active_rules = IpsContext::CONTENT; }
00178
00179 bool DetectionEngine::content_enabled(Packet* p)
00180 { return p->context->active_rules == IpsContext::CONTENT; }
00181
00182 IpsContext::ActiveRules DetectionEngine::get_detects(Packet* p)
00183 { return p->context->active_rules; }
00184
00185 void DetectionEngine::set_detects(Packet* p, IpsContext::ActiveRules ar)
00186 { p->context->active_rules = ar; }
00187
00188 bool DetectionEngine::offloaded(Packet* p)
00189 { return p->flow and p->flow->is_offloaded(); }
00190
00191 void DetectionEngine::set_check_tags(bool enable)
00192 { Snort::get_switcher()->get_context()->check_tags = enable; }
00193
00194 bool DetectionEngine::get_check_tags()
00195 { return Snort::get_switcher()->get_context()->check_tags; }
00196
00197 //--------------------------------------------------------------------------
00198 // offload / onload
00199 //--------------------------------------------------------------------------
00200
00201 void DetectionEngine::idle()
00202 {
00203 if (offloader)
00204 {
00205 while ( offloader->count() )
00206 {
00207 trace_logf(detection, TRACE_DETECTION_ENGINE, "%" PRIu64 " de::sleep\n", pc.total_from_daq);
00208 const struct timespec blip = { 0, 1 };
00209 nanosleep(&blip, nullptr);
00210 onload();
00211 }
00212 trace_logf(detection, TRACE_DETECTION_ENGINE, "%" PRIu64 " de::idle (r=%d)\n", pc.total_from_daq, offloader->count());
00213 offloader->stop();
00214 }
00215 }
00216
00217 void DetectionEngine::onload(Flow* flow)
00218 {
00219 while ( flow->is_offloaded() )
00220 {
00221 const struct timespec blip = { 0, 1 };
00222 trace_logf(detection, TRACE_DETECTION_ENGINE, "%" PRIu64 " de::sleep\n", pc.total_from_daq);
00223 nanosleep(&blip, nullptr);
00224 onload();
00225 }
00226 assert(!Snort::get_switcher()->on_hold(flow));
00227 assert(!offloader->on_hold(flow));
00228 }
00229
00230 void DetectionEngine::onload()
00231 {
00232 unsigned id;
00233
00234 if ( !offloader->get(id) )
00235 return;
00236
00237 ContextSwitcher* sw = Snort::get_switcher();
00238 IpsContext* c = sw->get_context(id);
00239 assert(c);
00240
00241 trace_logf(detection, TRACE_DETECTION_ENGINE, "%" PRIu64 " de::onload %u (r=%d)\n",
00242 pc.total_from_daq, id, offloader->count());
00243
00244 Packet* p = c->packet;
00245 p->flow->clear_offloaded();
00246
00247 sw->resume(id);
00248
00249 fp_onload(p);
00250 finish_packet(p);
00251
00252 InspectorManager::clear(p);
00253 sw->complete();
00254 }
00255
00256 bool DetectionEngine::offload(Packet* p)
00257 {
00258 ContextSwitcher* sw = Snort::get_switcher();
00259
00260 if ( p->type() != PktType::PDU or (p->dsize < snort_conf->offload_limit) or !sw->can_hold() )
00261 {
00262 fp_local(p);
00263 return false;
00264 }
00265 assert(p == p->context->packet);
00266 onload(p->flow); // FIXIT-L just assert !offloaded?
00267
00268 assert(p->context == sw->get_context());
00269 unsigned id = sw->suspend();
00270
00271 trace_logf(detection, TRACE_DETECTION_ENGINE, "%" PRIu64 " de::offload %u (r=%d)\n",
00272 pc.total_from_daq, id, offloader->count());
00273
00274 p->flow->set_offloaded();
00275 p->context->conf = snort_conf;
00276
00277 offloader->put(id, p);
00278 pc.offloads++;
00279
00280 return true;
00281 }
00282
00283 //--------------------------------------------------------------------------
00284 // detection / inspection
00285 //--------------------------------------------------------------------------
00286
00287 bool DetectionEngine::detect(Packet* p, bool offload_ok)
00288 {
00289 assert(p);
00290 Profile profile(detectPerfStats);
00291
00292 if ( !p->ptrs.ip_api.is_valid() )
00293 return false;
00294
00295 if ( p->packet_flags & PKT_PASS_RULE )
00296 return false;
00297
00298 if ( PacketLatency::fastpath() )
00299 return false;
00300
00301 // FIXIT-M restrict detect to current ip layer
00302 // Currently, if a rule is found on any IP layer, we perform the detect routine
00303 // on the entire packet. Instead, we should only perform detect on that layer!!
00304 switch ( p->type() )
00305 {
00306 case PktType::PDU:
00307 if ( offload_ok )
00308 return offload(p);
00309 // fall thru
00310
00311 case PktType::IP:
00312 case PktType::TCP:
00313 case PktType::UDP:
00314 case PktType::ICMP:
00315 case PktType::FILE:
00316 fp_local(p);
00317 break;
00318
00319 default:
00320 break;
00321 }
00322 return false;
00323 }
00324
00325 void DetectionEngine::inspect(Packet* p)
00326 {
00327
00328 bool inspected = false;
00329 {
00330 PacketLatency::Context pkt_latency_ctx { p };
00331
00332 if ( p->ptrs.decode_flags & DECODE_ERR_FLAGS )
00333 {
00334
00335
00336 printf("inspect - decode error flags - %d\n", p->get_id());
00337 if ( SnortConfig::inline_mode() and
00338 SnortConfig::checksum_drop(p->ptrs.decode_flags & DECODE_ERR_CKSUM_ALL) )
00339 {
00340 Active::drop_packet(p);
00341 }
00342 }
00343 else
00344 {
00345 enable_content(p);
00346 p->alt_dsize = 0; // FIXIT-H should be redundant
00347
00348 //upload_packet(p);
00349
00350 InspectorManager::execute(p);
00351 //upload_packet(p);
00352
00353 // RAS
00354
00355 inspected = true;
00356
00357 if ( !all_disabled(p) )
00358 {
00359 if ( detect(p, true) )
00360 return;
00361 }
00362 }
00363 DetectionEngine::set_check_tags();
00364
00365 // By checking tagging here, we make sure that we log the
00366 // tagged packet whether it generates an alert or not.
00367
00368 if ( p->has_ip() )
00369 check_tags(p);
00370
00371 InspectorManager::probe(p);
00372 }
00373
00374 Profile profile(eventqPerfStats);
00375 log_events(p);
00376 Active::apply_delayed_action(p);
00377
00378 if ( offloaded(p) )
00379 return;
00380
00381 // clear closed sessions here after inspection since non-stream
00382 // inspectors may depend on flow information
00383 // this also handles block pending state
00384 Stream::check_flow_closed(p);
00385
00386 if ( inspected )
00387 InspectorManager::clear(p);
00388
00389 clear_events(p);
00390 }
00391
00392 //--------------------------------------------------------------------------
00393 // events
00394 //--------------------------------------------------------------------------
00395
00396 // Return 0 if no OTN since -1 return indicates queue limit reached.
00397 // See fpFinalSelectEvent()
00398 int DetectionEngine::queue_event(const OptTreeNode* otn)
00399 {
00400 RuleTreeNode* rtn = getRtnFromOtn(otn);
00401
00402 if ( !rtn )
00403 {
00404 // If the rule isn't in the current policy,
00405 // don't add it to the event queue.
00406 return 0;
00407 }
00408
00409 SF_EVENTQ* pq = get_event_queue();
00410 EventNode* en = (EventNode*)sfeventq_event_alloc(pq);
00411
00412 if ( !en )
00413 return -1;
00414
00415 en->otn = otn;
00416 en->rtn = rtn;
00417
00418 if ( sfeventq_add(pq, en) )
00419 return -1;
00420
00421 return 0;
00422 }
00423
00424 int DetectionEngine::queue_event(unsigned gid, unsigned sid, RuleType type)
00425 {
00426 OptTreeNode* otn = GetOTN(gid, sid);
00427
00428 if ( !otn )
00429 return 0;
00430
00431 SF_EVENTQ* pq = get_event_queue();
00432 EventNode* en = (EventNode*)sfeventq_event_alloc(pq);
00433
00434 if ( !en )
00435 return -1;
00436
00437 en->otn = otn;
00438 en->rtn = nullptr; // lookup later after ips policy selection
00439 en->type = type;
00440
00441 if ( sfeventq_add(pq, en) )
00442 return -1;
00443
00444 return 0;
00445 }
00446
00447 static int log_events(void* event, void* user)
00448 {
00449 if ( !event || !user )
00450 return 0;
00451
00452 EventNode* en = (EventNode*)event;
00453
00454 if ( !en->rtn )
00455 {
00456 en->rtn = getRtnFromOtn(en->otn);
00457
00458 if ( !en->rtn )
00459 return 0; // not enabled
00460 }
00461
00462 fpLogEvent(en->rtn, en->otn, (Packet*)user);
00463 sfthreshold_reset();
00464
00465 return 0;
00466 }
00467
00468 /*
00469 ** We return whether we logged events or not. We've add a eventq user
00470 ** structure so we can track whether the events logged were rule events
00471 ** or preprocessor/decoder events. The reason being that we don't want
00472 ** to flush a TCP stream for preprocessor/decoder events, and cause
00473 ** early flushing of the stream.
00474 */
00475 int DetectionEngine::log_events(Packet* p)
00476 {
00477 SF_EVENTQ* pq = p->context->equeue;
00478 sfeventq_action(pq, ::log_events, (void*)p);
00479 return 0;
00480 }
00481
00482 void DetectionEngine::clear_events(Packet* p)
00483 {
00484 SF_EVENTQ* pq = p->context->equeue;
00485 pc.log_limit += sfeventq_reset(pq);
00486 }
00487
END OF CODE