00001 //--------------------------------------------------------------------------
00002 // Copyright (C) 2014-2017 Cisco and/or its affiliates. All rights reserved.
00003 // Copyright (C) 2002-2013 Sourcefire, Inc.
00004 //
00005 // This program is free software; you can redistribute it and/or modify it
00006 // under the terms of the GNU General Public License Version 2 as published
00007 // by the Free Software Foundation. You may not use, modify or distribute
00008 // this program under any other version of the GNU General Public License.
00009 //
00010 // This program is distributed in the hope that it will be useful, but
00011 // WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00013 // General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License along
00016 // with this program; if not, write to the Free Software Foundation, Inc.,
00017 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018 //--------------------------------------------------------------------------
00019 /*
00020 ** Author(s): Dan Roelker <droelker@sourcefire.com>
00021 ** Marc Norton <mnorton@sourcefire.com>
00022 ** Andrew R. Baker <andrewb@snort.org>
00023 ** Andrew J. Mullican <amullican@sourcefire.com>
00024 ** Steven Sturges <ssturges@sourcefire.com>
00025 ** NOTES
00026 ** 5.15.02 - Initial Source Code. Norton/Roelker
00027 ** 2002-12-06 - Modify event selection logic to fix broken custom rule types
00028 ** arbitrary rule type ordering (ARB)
00029 ** 2005-02-08 - Track alerts per session so that they aren't double reported
00030 ** for rebuilt packets. AJM.
00031 ** 2005-02-17 - Track alerts per IP frag tracker so that they aren't double
00032 ** reported for rebuilt frags. SAS (code similar to AJM's for
00033 ** per session tracking).
00034 */
00035
00036 #ifdef HAVE_CONFIG_H
00037 #include "config.h"
00038 #endif
00039
00040 #include "fp_detect.h"
00041
00042 #include "events/event.h"
00043 #include "filters/rate_filter.h"
00044 #include "filters/sfthreshold.h"
00045 #include "framework/cursor.h"
00046 #include "framework/mpse.h"
00047 #include "latency/packet_latency.h"
00048 #include "latency/rule_latency.h"
00049 #include "log/messages.h"
00050 #include "log/packet_tracer.h"
00051 #include "main/modules.h"
00052 #include "main/snort.h"
00053 #include "main/snort_config.h"
00054 #include "main/snort_debug.h"
00055 #include "managers/action_manager.h"
00056 #include "parser/parser.h"
00057 #include "profiler/profiler_defs.h"
00058 #include "protocols/icmp4.h"
00059 #include "protocols/packet_manager.h"
00060 #include "protocols/udp.h"
00061 #include "search_engines/pat_stats.h"
00062 #include "stream/stream.h"
00063 #include "utils/stats.h"
00064 #include "utils/util.h"
00065
00066 #include "context_switcher.h"
00067 #include "detect.h"
00068 #include "detect_trace.h"
00069 #include "detection_util.h"
00070 #include "detection_engine.h"
00071 #include "detection_options.h"
00072 #include "fp_config.h"
00073 #include "fp_create.h"
00074 #include "ips_context.h"
00075 #include "pattern_match_data.h"
00076 #include "pcrm.h"
00077 #include "rules.h"
00078 #include "service_map.h"
00079 #include "tag.h"
00080 #include "treenodes.h"
00081
00082 THREAD_LOCAL ProfileStats rulePerfStats;
00083 THREAD_LOCAL ProfileStats ruleRTNEvalPerfStats;
00084 THREAD_LOCAL ProfileStats ruleOTNEvalPerfStats;
00085 THREAD_LOCAL ProfileStats ruleNFPEvalPerfStats;
00086
00087 // Initialize the OtnxMatchData structure. We do this for
00088 // every packet so this only sets the necessary counters to
00089 // zero which saves us time.
00090
00091 static inline void init_match_info(OtnxMatchData* o, bool do_fp)
00092 {
00093 for ( int i = 0; i < o->iMatchInfoArraySize; i++ )
00094 o->matchInfo[i].iMatchCount = 0;
00095
00096 o->have_match = false;
00097 o->do_fp = do_fp;
00098 }
00099
00100 // called by fpLogEvent(), which does the filtering etc.
00101 // this handles the non-rule-actions (responses).
00102 static inline void fpLogOther(
00103 Packet* p, const RuleTreeNode* rtn, const OptTreeNode* otn, int action)
00104 {
00105 if ( EventTrace_IsEnabled() )
00106 EventTrace_Log(p, otn, action);
00107
00108 PacketTracer::log("Event: %u:%u:%u, Action %s\n",
00109 otn->sigInfo.gid, otn->sigInfo.sid, otn->sigInfo.rev,
00110 get_action_string((RuleType)action));
00111
00112 // rule option actions are queued here (eg replace)
00113 otn_trigger_actions(otn, p);
00114
00115 // rule actions are queued here (eg reject)
00116 if ( rtn->listhead->action )
00117 ActionManager::queue(rtn->listhead->action);
00118 }
00119
00120 /*
00121 ** This function takes the corresponding RTN and OTN for a snort rule
00122 ** and logs the event and packet that was alerted upon. This
00123 ** function was pulled out of fpEvalSomething, so now we can log an
00124 ** event no matter where we are.
00125 */
00126 int fpLogEvent(const RuleTreeNode* rtn, const OptTreeNode* otn, Packet* p)
00127 {
00128 int action = -1, rateAction = -1;
00129 int override, filterEvent = 0;
00130
00131 if ( pass_action(rtn->type) )
00132 p->packet_flags |= PKT_PASS_RULE;
00133
00134 if ( otn->stateless )
00135 {
00136 /* Stateless rule, set the stateless bit */
00137 p->packet_flags |= PKT_STATELESS;
00138 }
00139 else
00140 {
00141 /* Not stateless, clear the stateless bit if it was set
00142 * from a previous rule.
00143 */
00144 p->packet_flags &= ~PKT_STATELESS;
00145 }
00146
00147 if ((p->packet_flags & PKT_STREAM_UNEST_UNI) &&
00148 SnortConfig::assure_established() &&
00149 (!(p->packet_flags & PKT_REBUILT_STREAM)) &&
00150 (otn->stateless == 0))
00151 {
00152 // We still want to drop packets that are drop rules.
00153 // We just don't want to see the alert.
00154 action_apply(rtn->type, p);
00155 fpLogOther(p, rtn, otn, rtn->type);
00156 return 1;
00157 }
00158
00159 // perform rate filtering tests - impacts action taken
00160 rateAction = RateFilter_Test(otn, p);
00161 override = ( rateAction >= RULE_TYPE__MAX );
00162 if ( override )
00163 rateAction -= RULE_TYPE__MAX;
00164
00165 // internal events are no-ops
00166 if ( (rateAction < 0) && EventIsInternal(otn->sigInfo.gid) )
00167 {
00168 return 1;
00169 }
00170 action = (rateAction < 0) ? (int)rtn->type : rateAction;
00171
00172 // When rate filters kick in, event filters are still processed.
00173 // perform event filtering tests - impacts logging
00174 if ( p->ptrs.ip_api.is_valid() )
00175 {
00176 filterEvent = sfthreshold_test(
00177 otn->sigInfo.gid, otn->sigInfo.sid,
00178 p->ptrs.ip_api.get_src(), p->ptrs.ip_api.get_dst(),
00179 p->pkth->ts.tv_sec);
00180 }
00181 else
00182 {
00183 SfIp cleared;
00184 cleared.clear();
00185
00186 filterEvent = sfthreshold_test(
00187 otn->sigInfo.gid, otn->sigInfo.sid,
00188 &cleared, &cleared, p->pkth->ts.tv_sec);
00189 }
00190
00191 if ( (filterEvent < 0) || (filterEvent > 0 && !override) )
00192 {
00193 /*
00194 ** If InlineMode is on, then we still want to drop packets
00195 ** that are drop rules. We just don't want to see the alert.
00196 */
00197 action_apply((RuleType)action, p);
00198 fpLogOther(p, rtn, otn, action);
00199 pc.event_limit++;
00200 return 1;
00201 }
00202
00203 /* If this packet has been passed based on detection rules,
00204 * check the decoder/preprocessor events (they have been added to Event queue already).
00205 * If its order is lower than 'pass', it should have been passed.
00206 * This is consistent with other detection rules */
00207 if ( (p->packet_flags & PKT_PASS_RULE)
00208 &&(SnortConfig::get_eval_index(rtn->type) > SnortConfig::get_eval_index(RULE_TYPE__PASS)))
00209 {
00210 fpLogOther(p, rtn, otn, rtn->type);
00211 return 1;
00212 }
00213
00214 otn->state[get_instance_id()].alerts++;
00215
00216 event_id++;
00217 action_execute((RuleType)action, p, otn, event_id);
00218 fpLogOther(p, rtn, otn, action);
00219
00220 return 0;
00221 }
00222
00223 /*
00224 ** DESCRIPTION
00225 ** Add and Event to the appropriate Match Queue: Alert, Pass, or Log.
00226 ** This allows us to find multiple events per packet and pick the 'best'
00227 ** one. This function also allows us to change the order of alert,
00228 ** pass, and log signatures by caching them for decision later.
00229 **
00230 ** IMPORTANT NOTE:
00231 ** fpAddMatch must be called even when the queue has been maxed
00232 ** out. This is because there are three different queues (alert,
00233 ** pass, log) and unless all three are filled (or at least the
00234 ** queue that is in the highest priority), events must be looked
00235 ** at to see if they are members of a queue that is not maxed out.
00236 **
00237 ** FORMAL INPUTS
00238 ** OtnxMatchData * - the omd to add the event to.
00239 ** int pLen - length of pattern that matched, 0 for no content
00240 ** OptTreeNode * - the otn to add.
00241 **
00242 ** FORMAL OUTPUTS
00243 ** int - 1 max_events variable hit, 0 successful.
00244 **
00245 */
00246 int fpAddMatch(OtnxMatchData* omd_local, int /*pLen*/, const OptTreeNode* otn)
00247 {
00248 RuleTreeNode* rtn = getRuntimeRtnFromOtn(otn);
00249 int evalIndex = rtn->listhead->ruleListNode->evalIndex;
00250
00251 /* bounds check index */
00252 if ( evalIndex >= omd_local->iMatchInfoArraySize )
00253 {
00254 pc.match_limit++;
00255 return 1;
00256 }
00257 MatchInfo* pmi = &omd_local->matchInfo[evalIndex];
00258
00259 /*
00260 ** If we hit the max number of unique events for any rule type alert,
00261 ** log or pass, then we don't add it to the list.
00262 */
00263 if ( pmi->iMatchCount >= (int)snort_conf->fast_pattern_config->get_max_queue_events() ||
00264 pmi->iMatchCount >= MAX_EVENT_MATCH)
00265 {
00266 pc.match_limit++;
00267 return 1;
00268 }
00269
00270 // don't store the same otn again
00271 for ( int i=0; i< pmi->iMatchCount; i++ )
00272 {
00273 if ( pmi->MatchArray[ i ] == otn )
00274 return 0;
00275 }
00276
00277 // add the event to the appropriate list
00278 pmi->MatchArray[ pmi->iMatchCount ] = otn;
00279
00280 pmi->iMatchCount++;
00281 omd_local->have_match = true;
00282 return 0;
00283 }
00284
00285 /*
00286 ** DESCRIPTION
00287 ** Evaluates an RTN against a packet. We can probably get rid of
00288 ** the check_ports variable, but it's in there for good luck. :)
00289 **
00290 ** FORMAL INPUTS
00291 ** RuleTreeNode * - RTN to check packet against.
00292 ** Packet * - Packet to evaluate
00293 ** int - whether to do a quick enhancement against ports.
00294 **
00295 ** FORMAL OUTPUT
00296 ** int - 1 if match, 0 if match failed.
00297 */
00298 int fpEvalRTN(RuleTreeNode* rtn, Packet* p, int check_ports)
00299 {
00300 Profile rule_profile(rulePerfStats);
00301 Profile rule_rtn_eval_profile(ruleRTNEvalPerfStats);
00302
00303 if ( !rtn )
00304 return 0;
00305
00306 // FIXIT-L maybe add a port test here ...
00307
00308 DebugFormat(DEBUG_DETECT, "[*] Rule Head %p\n", (void*)rtn);
00309
00310 if (!rtn->rule_func->RuleHeadFunc(p, rtn, rtn->rule_func, check_ports))
00311 {
00312 DebugMessage(DEBUG_DETECT,
00313 " => Header check failed, checking next node\n");
00314 DebugMessage(DEBUG_DETECT,
00315 " => returned from next node check\n");
00316 return 0;
00317 }
00318
00319 /*
00320 ** Return that there is a rule match and log the event outside
00321 ** of this routine.
00322 */
00323 return 1;
00324 }
00325
00326 static int detection_option_tree_evaluate(detection_option_tree_root_t* root,
00327 detection_option_eval_data_t* eval_data)
00328 {
00329 if ( !root )
00330 return 0;
00331
00332 RuleLatency::Context rule_latency_ctx(root, eval_data->p);
00333
00334 if ( RuleLatency::suspended() )
00335 return 0;
00336
00337 Cursor c(eval_data->p);
00338 int rval = 0;
00339
00340 trace_log(detection, TRACE_RULE_EVAL, "Starting tree eval\n");
00341
00342 for ( int i = 0; i < root->num_children; ++i )
00343 {
00344 // Increment number of events generated from that child
00345 rval += detection_option_node_evaluate(root->children[i], eval_data, c);
00346 }
00347 clear_trace_cursor_info();
00348
00349 return rval;
00350 }
00351
00352 static int rule_tree_match(
00353 void* user, void* tree, int index, void* context, void* neg_list)
00354 {
00355 PMX* pmx = (PMX*)user;
00356 OtnxMatchData* pomd = (OtnxMatchData*)context;
00357
00358 detection_option_tree_root_t* root = (detection_option_tree_root_t*)tree;
00359 detection_option_eval_data_t eval_data;
00360 NCListNode* ncl;
00361
00362 eval_data.pomd = pomd;
00363 eval_data.p = pomd->p;
00364 eval_data.pmd = pmx->pmd;
00365 eval_data.flowbit_failed = 0;
00366 eval_data.flowbit_noalert = 0;
00367
00368 print_pattern(pmx->pmd);
00369
00370 {
00371 Profile rule_profile(rulePerfStats);
00372 /* NOTE: The otn will be the first one in the match state. If there are
00373 * multiple rules associated with a match state, mucking with the otn
00374 * may muck with an unintended rule */
00375
00376 /* Set flag for not contents so they aren't evaluated */
00377 for (ncl = (NCListNode*)neg_list; ncl != nullptr; ncl = ncl->next)
00378 {
00379 PMX* neg_pmx = (PMX*)ncl->pmx;
00380 assert(neg_pmx->pmd->last_check);
00381
00382 PmdLastCheck* last_check =
00383 neg_pmx->pmd->last_check + get_instance_id();
00384
00385 last_check->ts.tv_sec = eval_data.p->pkth->ts.tv_sec;
00386 last_check->ts.tv_usec = eval_data.p->pkth->ts.tv_usec;
00387 last_check->run_num = get_run_num();
00388 last_check->context_num = eval_data.p->context->context_num;
00389 last_check->rebuild_flag = (eval_data.p->packet_flags & PKT_REBUILT_STREAM);
00390 }
00391
00392 int ret = 0;
00393 {
00394 Profile rule_otn_eval_profile(ruleOTNEvalPerfStats);
00395 ret = detection_option_tree_evaluate(root, &eval_data);
00396 }
00397
00398 if ( ret )
00399 pmqs.qualified_events++;
00400 else
00401 pmqs.non_qualified_events++;
00402 }
00403
00404 if (eval_data.flowbit_failed)
00405 return -1;
00406
00407 /* If this is for an IP rule set, evaluate the rules from
00408 * the inner IP offset as well */
00409 if (eval_data.p->packet_flags & PKT_IP_RULE)
00410 {
00411 ip::IpApi tmp_api = eval_data.p->ptrs.ip_api;
00412 int8_t curr_layer = eval_data.p->num_layers - 1;
00413
00414 if (layer::set_inner_ip_api(eval_data.p,
00415 eval_data.p->ptrs.ip_api,
00416 curr_layer) &&
00417 (eval_data.p->ptrs.ip_api != tmp_api))
00418 {
00419 const uint8_t* tmp_data = eval_data.p->data;
00420 uint16_t tmp_dsize = eval_data.p->dsize;
00421
00422 /* clear so we don't keep recursing */
00423 eval_data.p->packet_flags &= ~PKT_IP_RULE;
00424 eval_data.p->packet_flags |= PKT_IP_RULE_2ND;
00425
00426 do
00427 {
00428 eval_data.p->data = eval_data.p->ptrs.ip_api.ip_data();
00429 eval_data.p->dsize = eval_data.p->ptrs.ip_api.pay_len();
00430
00431 /* Recurse, and evaluate with the inner IP */
00432 rule_tree_match(user, tree, index, context, nullptr);
00433 }
00434 while (layer::set_inner_ip_api(eval_data.p,
00435 eval_data.p->ptrs.ip_api,
00436 curr_layer) &&
00437 (eval_data.p->ptrs.ip_api != tmp_api));
00438
00439 /* cleanup restore original data & dsize */
00440 eval_data.p->packet_flags &= ~PKT_IP_RULE_2ND;
00441 eval_data.p->packet_flags |= PKT_IP_RULE;
00442
00443 eval_data.p->data = tmp_data;
00444 eval_data.p->dsize = tmp_dsize;
00445 }
00446 }
00447 return 0;
00448 }
00449
00450 static int sortOrderByPriority(const void* e1, const void* e2)
00451 {
00452 const OptTreeNode* otn1;
00453 const OptTreeNode* otn2;
00454
00455 if (!e1 || !e2)
00456 return 0;
00457
00458 otn1 = *(OptTreeNode* const*)e1;
00459 otn2 = *(OptTreeNode* const*)e2;
00460
00461 if ( otn1->sigInfo.priority < otn2->sigInfo.priority )
00462 return -1;
00463
00464 if ( otn1->sigInfo.priority > otn2->sigInfo.priority )
00465 return +1;
00466
00467 /* This improves stability of repeated tests */
00468 if ( otn1->sigInfo.sid < otn2->sigInfo.sid )
00469 return -1;
00470
00471 if ( otn1->sigInfo.sid > otn2->sigInfo.sid )
00472 return +1;
00473
00474 return 0;
00475 }
00476
00477 // FIXIT-L pattern length is not a valid event sort criterion for
00478 // non-literals
00479 static int sortOrderByContentLength(const void* e1, const void* e2)
00480 {
00481 const OptTreeNode* otn1;
00482 const OptTreeNode* otn2;
00483
00484 if (!e1 || !e2)
00485 return 0;
00486
00487 otn1 = *(OptTreeNode* const*)e1;
00488 otn2 = *(OptTreeNode* const*)e2;
00489
00490 if (otn1->longestPatternLen < otn2->longestPatternLen)
00491 return +1;
00492
00493 if (otn1->longestPatternLen > otn2->longestPatternLen)
00494 return -1;
00495
00496 /* This improves stability of repeated tests */
00497 if ( otn1->sigInfo.sid < otn2->sigInfo.sid )
00498 return +1;
00499
00500 if ( otn1->sigInfo.sid > otn2->sigInfo.sid )
00501 return -1;
00502
00503 return 0;
00504 }
00505
00506 /*
00507 ** DESCRIPTION
00508 ** This function flags an alert per session.
00509 **
00510 ** FORMAL INPUTS
00511 ** Packet * - the packet to inspect
00512 ** OptTreeNode * - the rule that generated the alert
00513 **
00514 ** FORMAL OUTPUTS
00515 ** int - 0 if not flagged
00516 ** 1 if flagged
00517 */
00518 static inline int fpAddSessionAlert(Packet* p, const OptTreeNode* otn)
00519 {
00520 if ( !p->flow )
00521 return 0;
00522
00523 if ( !otn )
00524 return 0;
00525
00526 return !Stream::add_flow_alert(p->flow, p, otn->sigInfo.gid, otn->sigInfo.sid);
00527 }
00528
00529 /*
00530 ** DESCRIPTION
00531 ** This function indicates whether or not an alert has been generated previously
00532 ** in this session, but only if this is a rebuilt packet.
00533 **
00534 ** FORMAL INPUTS
00535 ** Packet * - the packet to inspect
00536 ** OptTreeNode * - the rule that generated the alert
00537 **
00538 ** FORMAL OUTPUTS
00539 ** int - 0 if alert NOT previously generated
00540 ** 1 if alert previously generated
00541 */
00542 static inline int fpSessionAlerted(Packet* p, const OptTreeNode* otn)
00543 {
00544 const SigInfo* si = &otn->sigInfo;
00545
00546 if (!Stream::check_flow_alerted(p->flow, p, si->gid, si->sid))
00547 return 0;
00548 else
00549 return 1;
00550 }
00551
00552 /*
00553 ** DESCRIPTION
00554 ** fpFinalSelectEvent is called at the end of packet processing
00555 ** to decide, if there hasn't already been a selection, to decide
00556 ** what event to select. This function is different from
00557 ** fpSelectEvent by the fact that fpSelectEvent only selects an
00558 ** event if it is the first priority setting (drop/pass/alert...).
00559 **
00560 ** We also loop through the events we log, so that we don't log the
00561 ** same event twice. This can happen with unique conflicts some
00562 ** of the time.
00563 **
00564 ** IMPORTANT NOTE:
00565 ** We call fpFinalSelectEvent() after all processing of the packet
00566 ** has been completed. The reason this must be called afterwards is
00567 ** because of unique rule group conflicts for a packet. If there is
00568 ** a unique conflict, then we inspect both rule groups and do the final
00569 ** event select after both rule groups have been inspected. The
00570 ** problem came up with bi-directional rules with pass rule ordering
00571 ** as the first type of rule. Before we would detect a alert rule in
00572 ** the first rule group, and since there was no pass rules we would
00573 ** log that alert rule. However, if we had inspected the second rule
00574 ** group, we would have found a pass rule and that should have taken
00575 ** precedence. We now inspect both rule groups before doing a final
00576 ** event select.
00577 **
00578 ** MORE NOTES
00579 ** Jan 2006 : marc norton
00580 ** Previously it was possible to not log all desired events, if for
00581 ** instance the rule order was alert->drop in inline mode we would
00582 ** alert but no drop. The default ordering of 'drop alert pass log ...'
00583 ** normally handles this, however, it could happen. Also, in the
00584 ** default ordering alerts on the same packet a drop was applied to
00585 ** did not get logged. To be more flexible and handle all manners of
00586 ** subjective rule ordering and logging desired by the whole farm we've
00587 ** changed things a bit.
00588 **
00589 ** Now, each actions event list is processed in order, based on the rule
00590 ** order. We process all events up to the log limit specified via the
00591 ** 'config event_queue: ...' as you might expect. Pass rules are
00592 ** handled a bit differently. As soon as a pass rule based event is
00593 ** processed in the event queue, we stop processing any further events
00594 ** on the packet if the pass event is the 1st ordering that sees an
00595 ** event. Otherwise if the ordering has it that pass rule events are
00596 ** processed after a drop or alert you will see the drops and alerts,
00597 ** and the pass event just causes us to stop processing any more events
00598 ** on the packet, but the packet does not pass. Also, the --alert-on-drop
00599 ** flag causes any drop/sdrop/reject rules to be loaded as alert rules.
00600 ** The default has been to ignore them on parsing.
00601 **
00602 ** If this is less than clear, here's the $.02 version:
00603 ** default order -> pass drop alert log ( --alert-before-pass reverts
00604 ** to -> drop alert pass log ) the 1st action-type of events in the rule
00605 ** ordering to be seen gets logged by default the --flush-all-events
00606 ** flag will cause secondary and tertiary action-events to be logged.
00607 ** the -o flag is useless, but accepted, for now.
00608 ** the max_events and log fields are reduced to only needing the log
00609 ** events field. max_fields is harmless.
00610 ** ( drop rules may be honored as alerts in IDS mode (no -Q) by using
00611 ** the --alert-on-drop flag )
00612 **
00613 ** FORMAL INPUTS
00614 ** OtnxMatchData * - omd to select event from.
00615 ** Packet * - pointer to packet to log.
00616 **
00617 ** FORMAL OUTPUT
00618 ** int - return 0 if no match, 1 if match.
00619 */
00620 static inline int fpFinalSelectEvent(OtnxMatchData* o, Packet* p)
00621 {
00622 if ( !o->have_match )
00623 return 0;
00624
00625 int i;
00626 int j;
00627 int k;
00628 const OptTreeNode* otn;
00629 int tcnt = 0;
00630 EventQueueConfig* eq = snort_conf->event_queue_config;
00631 RuleTreeNode* rtn;
00632
00633 for ( i = 0; i < o->iMatchInfoArraySize; i++ )
00634 {
00635 /* bail if were not dumping events in all the action groups,
00636 * and we've already got some events */
00637 if (!SnortConfig::process_all_events() && (tcnt > 0))
00638 return 1;
00639
00640 if (o->matchInfo[i].iMatchCount)
00641 {
00642 /*
00643 * We must always sort so if we que 8 and log 3 and they are
00644 * all from the same action group we want them sorted so we get
00645 * the highest 3 in priority, priority and length sort do NOT
00646 * take precedence over 'alert drop pass ...' ordering. If
00647 * order is 'drop alert', and we log 3 for drop alerts do not
00648 * get logged. IF order is 'alert drop', and we log 3 for
00649 * alert, then no drops are logged. So, there should be a
00650 * built in drop/sdrop/reject comes before alert/pass/log as
00651 * part of the natural ordering....Jan '06..
00652 */
00653 /* Sort the rules in this action group */
00654 if (eq->order == SNORT_EVENTQ_PRIORITY)
00655 {
00656 qsort(o->matchInfo[i].MatchArray, o->matchInfo[i].iMatchCount,
00657 sizeof(void*), sortOrderByPriority);
00658 }
00659 else if (eq->order == SNORT_EVENTQ_CONTENT_LEN)
00660 {
00661 qsort(o->matchInfo[i].MatchArray, o->matchInfo[i].iMatchCount,
00662 sizeof(void*), sortOrderByContentLength);
00663 }
00664 else
00665 {
00666 FatalError("fpdetect: Order function for event queue is invalid.\n");
00667 }
00668
00669 /* Process each event in the action (alert,drop,log,...) groups */
00670 for (j=0; j < o->matchInfo[i].iMatchCount; j++)
00671 {
00672 otn = o->matchInfo[i].MatchArray[j];
00673 rtn = getRtnFromOtn(otn);
00674
00675 if (otn && rtn && pass_action(rtn->type))
00676 {
00677 /* Already acted on rules, so just don't act on anymore */
00678 if ( tcnt > 0 )
00679 return 1;
00680 }
00681
00682 // Loop here so we don't log the same event multiple times.
00683 for (k = 0; k < j; k++)
00684 {
00685 if (o->matchInfo[i].MatchArray[k] == otn)
00686 {
00687 otn = nullptr;
00688 break;
00689 }
00690 }
00691
00692 if ( otn && !fpSessionAlerted(p, otn) )
00693 {
00694 if ( DetectionEngine::queue_event(otn) )
00695 pc.queue_limit++;
00696
00697 tcnt++;
00698 }
00699 else
00700 pc.alert_limit++;
00701
00702 /* Only count it if we're going to log it */
00703 if (tcnt <= eq->log_events)
00704 {
00705 if ( p->flow )
00706 fpAddSessionAlert(p, otn);
00707 }
00708
00709 if (tcnt >= eq->max_events)
00710 {
00711 pc.queue_limit++;
00712 return 1;
00713 }
00714
00715 /* only log/count one pass */
00716 if ( otn && rtn && pass_action(rtn->type))
00717 {
00718 p->packet_flags |= PKT_PASS_RULE;
00719 return 1;
00720 }
00721 }
00722 }
00723 }
00724
00725 return 0;
00726 }
00727
00728 class MpseStash
00729 {
00730 public:
00731 // FIXIT-H use max = n * k, at most k per group
00732 // need n >= 4 for src+dst+gen+svc
00733 static const unsigned max = 32;
00734
00735 void init()
00736 { if ( enable ) { count = flushed = 0; } }
00737
00738 // this is done in the offload thread
00739 bool push(void* user, void* tree, int index, void* list);
00740
00741 // this is done in the packet thread
00742 bool process(MpseMatch, void*);
00743
00744 void disable_process()
00745 { enable = false; }
00746
00747 void enable_process()
00748 { enable = true; }
00749
00750 private:
00751 bool enable;
00752 unsigned count;
00753 unsigned flushed;
00754
00755 struct Node
00756 {
00757 void* user;
00758 void* tree;
00759 void* list;
00760 int index;
00761 } queue[max];
00762 };
00763
00764 // uniquely insert into q, should splay elements for performance
00765 // return true if maxed out to trigger a flush
00766 bool MpseStash::push(void* user, void* tree, int index, void* list)
00767 {
00768 pmqs.tot_inq_inserts++;
00769
00770 for ( int i = (int)(count) - 1; i >= 0; --i )
00771 {
00772 if ( tree == queue[i].tree )
00773 return false;
00774 }
00775
00776 if ( count < max )
00777 {
00778 Node& node = queue[count++];
00779 node.user = user;
00780 node.tree = tree;
00781 node.index = index;
00782 node.list = list;
00783 pmqs.tot_inq_uinserts++;
00784 }
00785
00786 if ( count == max )
00787 {
00788 flushed++;
00789 return true;
00790 }
00791
00792 return false;
00793 }
00794
00795 bool MpseStash::process(MpseMatch match, void* context)
00796 {
00797 if ( !enable )
00798 return true; // maxed out - quit, FIXIT-H count this condition
00799
00800 if ( count > pmqs.max_inq )
00801 pmqs.max_inq = count;
00802
00803 pmqs.tot_inq_flush += flushed;
00804
00805 #ifdef DEBUG_MSGS
00806 if (count == 0)
00807 trace_log(detection, TRACE_RULE_EVAL, "Fast pattern processing - no matches found\n");
00808 #endif
00809
00810 for ( unsigned i = 0; i < count; ++i )
00811 {
00812 Node& node = queue[i];
00813
00814 // process a pattern - case is handled by otn processing
00815 trace_logf(detection, TRACE_RULE_EVAL,"Processing pattern match #%d\n", i+1);
00816 int res = match(node.user, node.tree, node.index, context, node.list);
00817
00818 if ( res > 0 )
00819 {
00820 /* terminate matching */
00821 count = 0;
00822 return true;
00823 }
00824 }
00825 count = 0;
00826 return false;
00827 }
00828
00829 void fp_set_context(IpsContext& c)
00830 {
00831 c.stash = new MpseStash;
00832
00833 c.otnx = (OtnxMatchData*)snort_calloc(sizeof(OtnxMatchData));
00834 c.otnx->iMatchInfoArraySize = snort_conf->num_rule_types;
00835
00836 c.otnx->matchInfo = (MatchInfo*)snort_calloc(
00837 snort_conf->num_rule_types, sizeof(MatchInfo));
00838
00839 c.context_num = 0;
00840 }
00841
00842 void fp_clear_context(IpsContext& c)
00843 {
00844 delete c.stash;
00845 snort_free(c.otnx->matchInfo);
00846 snort_free(c.otnx);
00847 }
00848
00849 // rule_tree_match() could be used instead to bypass the queuing
00850 static int rule_tree_queue(
00851 void* user, void* tree, int index, void* context, void* list)
00852 {
00853 OtnxMatchData* pomd = (OtnxMatchData*)context;
00854 MpseStash* stash = pomd->p->context->stash;
00855
00856 if ( stash->push(user, tree, index, list) )
00857 {
00858 if ( stash->process(rule_tree_match, context) )
00859 return 1;
00860 }
00861 return 0;
00862 }
00863
00864 static inline int search_data(
00865 Mpse* so, OtnxMatchData* omd, const uint8_t* buf, unsigned len, PegCount& cnt)
00866 {
00867 assert(so->get_pattern_count() > 0);
00868 int start_state = 0;
00869 cnt++;
00870 omd->data = buf; omd->size = len;
00871 MpseStash* stash = omd->p->context->stash;
00872 stash->init();
00873 dump_buffer(buf, len);
00874 so->search(buf, len, rule_tree_queue, omd, &start_state);
00875 stash->process(rule_tree_match, omd);
00876 if ( PacketLatency::fastpath() )
00877 return 1;
00878 return 0;
00879 }
00880
00881 static inline int search_buffer(
00882 Inspector* gadget, OtnxMatchData* omd, InspectionBuffer& buf,
00883 InspectionBuffer::Type ibt, PmType pmt, PegCount& cnt)
00884 {
00885 if ( gadget->get_fp_buf(ibt, omd->p, buf) )
00886 {
00887 if ( Mpse* so = omd->pg->mpse[pmt] )
00888 {
00889 trace_logf(detection, TRACE_RULE_EVAL,
00890 "inspector %s, buffer type %s\n",
00891 gadget->get_name(),pm_type_strings[pmt]);
00892
00893
00894 add_gadget_buffer(omd->p, buf.data, buf.len, gadget->get_name());
00895
00896 search_data(so, omd, buf.data, buf.len, cnt);
00897 }
00898 }
00899 return 0;
00900 }
00901
00902 static int fp_search(
00903 PortGroup* port_group, Packet* p, int check_ports, int type, OtnxMatchData* omd)
00904 {
00905 Inspector* gadget = p->flow ? p->flow->gadget : nullptr;
00906 InspectionBuffer buf;
00907
00908 omd->pg = port_group;
00909 omd->p = p;
00910 omd->check_ports = check_ports;
00911
00912 bool user_mode = snort_conf->sopgTable->user_mode;
00913
00914 trace_log(detection, TRACE_RULE_EVAL, "Fast pattern search\n");
00915
00916 if ( (!user_mode or type < 2) and p->data and p->dsize )
00917 {
00918 // ports search raw packet only
00919 if ( Mpse* so = port_group->mpse[PM_TYPE_PKT] )
00920 {
00921 uint16_t pattern_match_size = p->dsize;
00922
00923 if ( IsLimitedDetect(p) && (p->alt_dsize < p->dsize) )
00924 pattern_match_size = p->alt_dsize;
00925
00926 if ( pattern_match_size )
00927 search_data(so, omd, p->data, pattern_match_size, pc.pkt_searches);
00928
00929 if ( pattern_match_size )
00930 p->is_cooked() ? pc.cooked_searches++ : pc.raw_searches++;
00931 }
00932 }
00933
00934 if ( (!user_mode or type == 1) and gadget )
00935 {
00936 // service searches PDU buffers and file
00937 if ( search_buffer(gadget, omd, buf, buf.IBT_KEY, PM_TYPE_KEY, pc.key_searches) )
00938 return 1;
00939
00940 if ( search_buffer(gadget, omd, buf, buf.IBT_HEADER, PM_TYPE_HEADER, pc.header_searches) )
00941 return 1;
00942
00943 if ( search_buffer(gadget, omd, buf, buf.IBT_BODY, PM_TYPE_BODY, pc.body_searches) )
00944 return 1;
00945
00946 // FIXIT-L PM_TYPE_ALT will never be set unless we add
00947 // norm_data keyword or telnet, rpc_decode, smtp keywords
00948 // until then we must use the standard packet mpse
00949 if ( search_buffer(gadget, omd, buf, buf.IBT_ALT, PM_TYPE_PKT, pc.alt_searches) )
00950 return 1;
00951 }
00952
00953 if ( !user_mode or type > 0 )
00954 {
00955 // file searches file only
00956 if ( Mpse* so = port_group->mpse[PM_TYPE_FILE] )
00957 {
00958 // FIXIT-M file data should be obtained from
00959 // inspector gadget as is done with search_buffer
00960 DataPointer file_data = p->context->file_data;
00961
00962 if ( file_data.len )
00963 {
00964 trace_log(detection, TRACE_RULE_EVAL, "Searching file data\n");
00965 search_data(so, omd, file_data.data, file_data.len, pc.file_searches);
00966 }
00967 }
00968 }
00969 return 0;
00970 }
00971
00972 /*
00973 ** DESCRIPTION
00974 ** This function does a set-wise match on content, and walks an otn list
00975 ** for non-content. The otn list search will eventually be redone for
00976 ** for performance purposes.
00977 **
00978 ** FORMAL INPUTS
00979 ** PortGroup * - the port group to inspect
00980 ** Packet * - the packet to inspect
00981 ** int - whether src/dst ports should be checked (udp/tcp or icmp)
00982 ** char - whether the rule is an IP rule (change the packet payload pointer)
00983 **
00984 ** FORMAL OUTPUTS
00985 ** int - 0 for failed pattern match
00986 ** 1 for successful pattern match
00987 */
00988 static inline int fpEvalHeaderSW(PortGroup* port_group, Packet* p,
00989 int check_ports, char ip_rule, int type, OtnxMatchData* omd)
00990 {
00991 const uint8_t* tmp_payload = nullptr;
00992 int8_t curr_ip_layer = 0;
00993 bool repeat = false;
00994 uint16_t tmp_dsize = 0;
00995 FastPatternConfig* fp = snort_conf->fast_pattern_config;
00996
00997 print_pkt_info(p);
00998
00999 if (ip_rule)
01000 {
01001 tmp_payload = p->data;
01002 tmp_dsize = p->dsize;
01003
01004 if (layer::set_outer_ip_api(p, p->ptrs.ip_api, curr_ip_layer))
01005 {
01006 p->data = p->ptrs.ip_api.ip_data();
01007 p->dsize = p->ptrs.ip_api.pay_len();
01008 p->packet_flags |= PKT_IP_RULE;
01009 repeat = true;
01010 }
01011 }
01012 else
01013 {
01014 p->packet_flags &= ~PKT_IP_RULE;
01015 }
01016
01017 if ( omd->do_fp and DetectionEngine::content_enabled(p) )
01018 {
01019 if ( fp->get_stream_insert() || !(p->packet_flags & PKT_STREAM_INSERT) )
01020 if ( fp_search(port_group, p, check_ports, type, omd) )
01021 return 0;
01022 }
01023
01024 if ( DetectionEngine::offloaded(p) )
01025 return 0;
01026
01027 do
01028 {
01029 if (port_group->nfp_rule_count)
01030 {
01031 // walk and test the nfp OTNs
01032 if ( fp->get_debug_print_nc_rules() )
01033 LogMessage("NC-testing %u rules\n", port_group->nfp_rule_count);
01034
01035 detection_option_eval_data_t eval_data;
01036
01037 eval_data.pomd = omd;
01038 eval_data.p = p;
01039 eval_data.pmd = nullptr;
01040 eval_data.flowbit_failed = 0;
01041 eval_data.flowbit_noalert = 0;
01042
01043 int rval = 0;
01044 {
01045 Profile rule_profile(rulePerfStats);
01046 Profile rule_nfp_eval_profile(ruleNFPEvalPerfStats);
01047 trace_log(detection, TRACE_RULE_EVAL, "Testing non-content rules\n");
01048 rval = detection_option_tree_evaluate(
01049 (detection_option_tree_root_t*)port_group->nfp_tree, &eval_data);
01050 }
01051
01052 if (rval)
01053 pmqs.qualified_events++;
01054 else
01055 pmqs.non_qualified_events++;
01056
01057 pc.hard_evals++;
01058 }
01059
01060 // FIXIT-L need to eval all IP layers, etc.
01061 // FIXIT-L why run only nfp rules?
01062 if (ip_rule)
01063 {
01064 /* Evaluate again with the next IP layer */
01065 if (layer::set_outer_ip_api(p, p->ptrs.ip_api, curr_ip_layer))
01066 {
01067 p->data = p->ptrs.ip_api.ip_data();
01068 p->dsize = p->ptrs.ip_api.pay_len();
01069 p->packet_flags |= PKT_IP_RULE_2ND | PKT_IP_RULE;
01070 }
01071 else
01072 {
01073 /* Set the data & dsize back to original values. */
01074 p->data = tmp_payload;
01075 p->dsize = tmp_dsize;
01076 p->packet_flags &= ~(PKT_IP_RULE| PKT_IP_RULE_2ND);
01077 repeat = false;
01078 }
01079 }
01080 }
01081 while (repeat);
01082
01083 return 0;
01084 }
01085
01086 static inline void fpEvalHeaderIp(Packet* p, OtnxMatchData* omd)
01087 {
01088 PortGroup* any = nullptr, * ip_group = nullptr;
01089
01090 if ( !prmFindRuleGroupIp(snort_conf->prmIpRTNX, ANYPORT, &ip_group, &any) )
01091 return;
01092
01093 if ( snort_conf->fast_pattern_config->get_debug_print_nc_rules() )
01094 LogMessage("fpEvalHeaderIp: ip_group=%p, any=%p\n", (void*)ip_group, (void*)any);
01095
01096 if ( ip_group )
01097 fpEvalHeaderSW(ip_group, p, 0, 1, 0, omd);
01098
01099 if (any )
01100 fpEvalHeaderSW(any, p, 0, 1, 0, omd);
01101 }
01102
01103 static inline void fpEvalHeaderIcmp(Packet* p, OtnxMatchData* omd)
01104 {
01105 PortGroup* any = nullptr, * type = nullptr;
01106
01107 if ( !prmFindRuleGroupIcmp(snort_conf->prmIcmpRTNX, p->ptrs.icmph->type, &type, &any) )
01108 return;
01109
01110 if ( type )
01111 fpEvalHeaderSW(type, p, 0, 0, 0, omd);
01112
01113 if ( any )
01114 fpEvalHeaderSW(any, p, 0, 0, 0, omd);
01115 }
01116
01117 static inline void fpEvalHeaderTcp(Packet* p, OtnxMatchData* omd)
01118 {
01119 PortGroup* src = nullptr, * dst = nullptr, * any = nullptr;
01120
01121 if ( !prmFindRuleGroupTcp(snort_conf->prmTcpRTNX, p->ptrs.dp, p->ptrs.sp, &src, &dst, &any) )
01122 return;
01123
01124 DebugFormat(DEBUG_ATTRIBUTE,
01125 "fpEvalHeaderTcp: sport=%d, dport=%d, src:%p, dst:%p, any:%p\n",
01126 p->ptrs.sp,p->ptrs.dp,(void*)src,(void*)dst,(void*)any);
01127
01128 if ( dst )
01129 fpEvalHeaderSW(dst, p, 1, 0, 0, omd);
01130
01131 if ( src )
01132 fpEvalHeaderSW(src, p, 1, 0, 0, omd);
01133
01134 if ( any )
01135 fpEvalHeaderSW(any, p, 1, 0, 0, omd);
01136 }
01137
01138 static inline void fpEvalHeaderUdp(Packet* p, OtnxMatchData* omd)
01139 {
01140 PortGroup* src = nullptr, * dst = nullptr, * any = nullptr;
01141
01142 if ( !prmFindRuleGroupUdp(snort_conf->prmUdpRTNX, p->ptrs.dp, p->ptrs.sp, &src, &dst, &any) )
01143 return;
01144
01145 DebugFormat(DEBUG_ATTRIBUTE,
01146 "fpEvalHeaderUdp: sport=%d, dport=%d, src:%p, dst:%p, any:%p\n",
01147 p->ptrs.sp,p->ptrs.dp,(void*)src,(void*)dst,(void*)any);
01148
01149 if ( dst )
01150 fpEvalHeaderSW(dst, p, 1, 0, 0, omd);
01151
01152 if ( src )
01153 fpEvalHeaderSW(src, p, 1, 0, 0, omd);
01154
01155 if ( any )
01156 fpEvalHeaderSW(any, p, 1, 0, 0, omd);
01157 }
01158
01159 static inline bool fpEvalHeaderSvc(Packet* p, OtnxMatchData* omd, int proto)
01160 {
01161 PortGroup* svc = nullptr, * file = nullptr;
01162
01163 int16_t proto_ordinal = p->get_application_protocol();
01164
01165 DebugFormat(DEBUG_ATTRIBUTE, "proto_ordinal=%d\n", proto_ordinal);
01166
01167 if (proto_ordinal > 0)
01168 {
01169 if (p->is_from_server()) /* to cli */
01170 {
01171 DebugMessage(DEBUG_ATTRIBUTE, "pkt_from_server\n");
01172
01173 svc = snort_conf->sopgTable->get_port_group(proto, false, proto_ordinal);
01174 file = snort_conf->sopgTable->get_port_group(proto, false, SNORT_PROTO_FILE);
01175 }
01176
01177 if (p->is_from_client()) /* to srv */
01178 {
01179 DebugMessage(DEBUG_ATTRIBUTE, "pkt_from_client\n");
01180
01181 svc = snort_conf->sopgTable->get_port_group(proto, true, proto_ordinal);
01182 file = snort_conf->sopgTable->get_port_group(proto, true, SNORT_PROTO_FILE);
01183 }
01184
01185 DebugFormat(DEBUG_ATTRIBUTE,
01186 "fpEvalHeaderSvc:targetbased-ordinal-lookup: "
01187 "sport=%d, dport=%d, proto_ordinal=%d, proto=%d, src:%p, "
01188 "file:%p\n",p->ptrs.sp,p->ptrs.dp,proto_ordinal,proto,(void*)svc,(void*)file);
01189 }
01190 // FIXIT-P put alert service rules with file data fp in alert file group and
01191 // verify ports and service during rule eval to avoid searching file data 2x.
01192 int check_ports = (proto == SNORT_PROTO_USER) ? 2 : 1;
01193
01194 if ( file )
01195 fpEvalHeaderSW(file, p, check_ports, 0, 2, omd);
01196
01197 if ( svc )
01198 fpEvalHeaderSW(svc, p, check_ports, 0, 1, omd);
01199
01200 return svc != nullptr;
01201 }
01202
01203 static void fpEvalPacketUdp(Packet* p, OtnxMatchData* omd)
01204 {
01205 uint16_t tmp_sp = p->ptrs.sp;
01206 uint16_t tmp_dp = p->ptrs.dp;
01207 const udp::UDPHdr* tmp_udph = p->ptrs.udph;
01208 const uint8_t* tmp_data = p->data;
01209 uint16_t tmp_dsize = p->dsize;
01210
01211 const udp::UDPHdr* udph = layer::get_outer_udp_lyr(p);
01212
01213 p->ptrs.udph = udph;
01214 p->ptrs.sp = ntohs(udph->uh_sport);
01215 p->ptrs.dp = ntohs(udph->uh_dport);
01216 p->data = (const uint8_t*)udph + udp::UDP_HEADER_LEN;
01217
01218 ip::IpApi tmp_api;
01219 int8_t curr_layer = 0;
01220 layer::set_outer_ip_api(p, tmp_api, curr_layer);
01221
01222 if (tmp_api.pay_len() > udp::UDP_HEADER_LEN)
01223 p->dsize = tmp_api.pay_len() - udp::UDP_HEADER_LEN;
01224
01225 auto save_detect = DetectionEngine::get_detects(p);
01226
01227 if ( p->dsize )
01228 DetectionEngine::enable_content(p);
01229
01230 fpEvalHeaderUdp(p, omd);
01231
01232 p->ptrs.sp = tmp_sp;
01233 p->ptrs.dp = tmp_dp;
01234 p->ptrs.udph = tmp_udph;
01235 p->data = tmp_data;
01236 p->dsize = tmp_dsize;
01237
01238 DetectionEngine::set_detects(p, save_detect);
01239 }
01240
01241 /*
01242 ** the IP protocol is processed. If it is TCP, UDP, or ICMP, we
01243 ** process the both that particular ruleset and the IP ruleset
01244 ** with in the fpEvalHeader for that protocol. If the protocol
01245 ** is not TCP, UDP, or ICMP, we just process the packet against
01246 ** the IP rules at the end of the fpEvalPacket routine. Since
01247 ** we are using a setwise methodology for snort rules, both the
01248 ** network layer rules and the transport layer rules are done
01249 ** at the same time. While this is not the best for modularity,
01250 ** it is the best for performance, which is what we are working
01251 ** on currently.
01252 */
01253 static int fpEvalPacket(Packet* p)
01254 {
01255 OtnxMatchData* omd = p->context->otnx;
01256
01257 /* Run UDP rules against the UDP header of Teredo packets */
01258 // FIXIT-L udph is always inner; need to check for outer
01259 if ( p->ptrs.udph && (p->proto_bits & (PROTO_BIT__TEREDO | PROTO_BIT__GTP)) )
01260 fpEvalPacketUdp(p, omd);
01261
01262 switch (p->type())
01263 {
01264 case PktType::IP:
01265 fpEvalHeaderIp(p, omd);
01266 fpEvalHeaderSvc(p, omd, SNORT_PROTO_IP);
01267 break;
01268
01269 case PktType::ICMP:
01270 fpEvalHeaderIcmp(p, omd);
01271 fpEvalHeaderSvc(p, omd, SNORT_PROTO_ICMP);
01272 break;
01273
01274 case PktType::TCP:
01275 fpEvalHeaderTcp(p, omd);
01276 fpEvalHeaderSvc(p, omd, SNORT_PROTO_TCP);
01277 break;
01278
01279 case PktType::UDP:
01280 fpEvalHeaderUdp(p, omd);
01281 fpEvalHeaderSvc(p, omd, SNORT_PROTO_UDP);
01282 break;
01283
01284 case PktType::PDU:
01285 if ( snort_conf->sopgTable->user_mode )
01286 fpEvalHeaderSvc(p, omd, SNORT_PROTO_USER);
01287
01288 // use ports if we don't know service or don't have rules
01289 else if ( p->proto_bits & PROTO_BIT__TCP )
01290 {
01291 if ( !p->get_application_protocol() or !fpEvalHeaderSvc(p, omd, SNORT_PROTO_TCP) )
01292 fpEvalHeaderTcp(p, omd);
01293 }
01294 else if ( p->proto_bits & PROTO_BIT__UDP )
01295 {
01296 if ( !p->get_application_protocol() or !fpEvalHeaderSvc(p, omd, SNORT_PROTO_UDP) )
01297 fpEvalHeaderUdp(p, omd);
01298 }
01299 break;
01300
01301 case PktType::FILE:
01302 fpEvalHeaderSvc(p, omd, SNORT_PROTO_USER);
01303 break;
01304
01305 default:
01306 break;
01307 }
01308
01309 return 0;
01310 }
01311
01312 void fp_local(Packet* p)
01313 {
01314 IpsContext* c = p->context;
01315 MpseStash* stash = c->stash;
01316 stash->enable_process();
01317 stash->init();
01318 init_match_info(c->otnx, true);
01319 fpEvalPacket(p);
01320 fpFinalSelectEvent(c->otnx, p);
01321 }
01322
01323 void fp_offload(Packet* p)
01324 {
01325 IpsContext* c = p->context;
01326 MpseStash* stash = c->stash;
01327 stash->init();
01328 stash->disable_process();
01329 init_match_info(c->otnx, true);
01330 fpEvalPacket(p);
01331 }
01332
01333 void fp_onload(Packet* p)
01334 {
01335 IpsContext* c = p->context;
01336 MpseStash* stash = c->stash;
01337 stash->enable_process();
01338 stash->process(rule_tree_match, c->otnx);
01339 fpEvalPacket(p);
01340 fpFinalSelectEvent(c->otnx, p);
01341 }
01342
END OF CODE