1 /*
2 ** $Id$
3 **
4 ** fpdetect.c
5 **
6 ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
7 ** Copyright (C) 2002-2013 Sourcefire, Inc.
8 ** Author(s): Dan Roelker <droelker@sourcefire.com>
9 ** Marc Norton <mnorton@sourcefire.com>
10 ** Andrew R. Baker <andrewb@snort.org>
11 ** Andrew J. Mullican <amullican@sourcefire.com>
12 ** Steven Sturges <ssturges@sourcefire.com>
13 ** NOTES
14 ** 5.15.02 - Initial Source Code. Norton/Roelker
15 ** 2002-12-06 - Modify event selection logic to fix broken custom rule types
16 ** arbitrary rule type ordering (ARB)
17 ** 2005-02-08 - Track alerts per session so that they aren't double reported
18 ** for rebuilt packets. AJM.
19 ** 2005-02-17 - Track alerts per IP frag tracker so that they aren't double
20 ** reported for rebuilt frags. SAS (code similar to AJM's for
21 ** per session tracking).
22 **
23 **
24 ** This program is free software; you can redistribute it and/or modify
25 ** it under the terms of the GNU General Public License Version 2 as
26 ** published by the Free Software Foundation. You may not use, modify or
27 ** distribute this program under any other version of the GNU General
28 ** Public License.
29 **
30 ** This program is distributed in the hope that it will be useful,
31 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
32 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33 ** GNU General Public License for more details.
34 **
35 ** You should have received a copy of the GNU General Public License
36 ** along with this program; if not, write to the Free Software
37 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
38 **
39 */
40 # ifdef HAVE_CONFIG_H
41 # include "config.h"
42 # endif
43
44 #include "snort.h"
45 #include "detect.h"
46 #include "snort_debug.h"
47 #include "util.h"
48 #include "tag.h"
49 #include "rules.h"
50 #include "treenodes.h"
51 #include "pcrm.h"
52 #include "fpcreate.h"
53 #include "fpdetect.h"
54 #include "mpse.h"
55 #include "bitop.h"
56 #include "perf-event.h"
57 #include "sfthreshold.h"
58 #include "rate_filter.h"
59 #include "event_queue.h"
60 #include "event_wrapper.h"
61 #include "active.h"
62 #include "encode.h"
63 #include "sfPolicy.h"
64 #include "sfPolicyData.h"
65
66 #include "sp_pattern_match.h"
67 #include "spp_frag3.h"
68 #include "stream_api.h"
69
70 # ifdef TARGET_BASED
71 # include "target-based/sftarget_protocol_reference.h"
72 # include "target-based/sftarget_reader.h"
73 # endif
74
75 #include "ppm.h"
76 #include "generators.h"
77 #include "detection_util.h"
78
79 /*
80 ** This define enables set-wise signature detection for
81 ** IP and ICMP packets. During early testing, the old
82 ** method of detection seemed faster for ICMP and IP
83 ** signatures, but with modifications to the set-wise engine
84 ** performance became much better. This define could be
85 ** taken out, but is still in for regression testing.
86 */
87
88 /*
89 ** GLOBALS
90 ** These variables are local to this file and deal with
91 ** configuration issues that are set in snort.conf through
92 ** variables.
93 */
94
95 /*
96 ** Assorted global variables from the old detection engine
97 ** for backwards compatibility.
98 */
99 extern OptTreeNode *otn_tmp;
100 extern SFEVENT sfEvent;
101
102 /*
103 ** Static function prototypes
104 */
105 int fpEvalRTN(RuleTreeNode *rtn, Packet *p, int check_ports);
106 static inline int fpEvalHeaderIp(Packet *p, int ip_proto, OTNX_MATCH_DATA *);
107 static inline int fpEvalHeaderIcmp(Packet *p, OTNX_MATCH_DATA *);
108 static inline int fpEvalHeaderTcp(Packet *p, OTNX_MATCH_DATA *);
109 static inline int fpEvalHeaderUdp(Packet *p, OTNX_MATCH_DATA *);
110 static inline int fpEvalHeaderSW(PORT_GROUP *port_group, Packet *p,
111 int check_ports, char ip_rule, OTNX_MATCH_DATA *);
112 static int rule_tree_match (void* id, void * tree, int index, void * data, void *neg_list );
113 static inline int fpAddSessionAlert(Packet *p, OptTreeNode *otn);
114 static inline int fpSessionAlerted(Packet *p, OptTreeNode *otn);
115
116 //static inline int fpLogEvent(RuleTreeNode *rtn, OptTreeNode *otn, Packet *p);
117
118 #ifdef PERF_PROFILING
119 PreprocStats rulePerfStats;
120 PreprocStats ncrulePerfStats;
121 PreprocStats ruleRTNEvalPerfStats;
122 PreprocStats ruleOTNEvalPerfStats;
123 #endif
124
125 /* initialize the global OTNX_MATCH_DATA variable */
OtnXMatchDataNew(int num_rule_types)126 OTNX_MATCH_DATA * OtnXMatchDataNew(int num_rule_types)
127 {
128 OTNX_MATCH_DATA *omd = (OTNX_MATCH_DATA *)SnortAlloc(sizeof(OTNX_MATCH_DATA));
129
130 omd->iMatchInfoArraySize = num_rule_types;
131 omd->matchInfo = (MATCH_INFO *)SnortAlloc(num_rule_types * sizeof(MATCH_INFO));
132
133 return omd;
134 }
135
136 /*
137 **
138 ** NAME
139 ** InitMatchInfo::
140 **
141 ** DESCRIPTION
142 ** Initialize the OTNX_MATCH_DATA structure. We do this for
143 ** every packet so calloc is not used as this would zero the
144 ** whole space and this only sets the necessary counters to
145 ** zero, and saves us time.
146 **
147 ** FORMAL INPUTS
148 ** OTNX_MATCH_DATA * - pointer to structure to init.
149 **
150 ** FORMAL OUTPUT
151 ** None
152 **
153 */
InitMatchInfo(OTNX_MATCH_DATA * o)154 static inline void InitMatchInfo(OTNX_MATCH_DATA *o)
155 {
156 int i = 0;
157
158 for(i = 0; i < o->iMatchInfoArraySize; i++)
159 {
160 o->matchInfo[i].iMatchCount = 0;
161 o->matchInfo[i].iMatchIndex = 0;
162 o->matchInfo[i].iMatchMaxLen = 0;
163 }
164 }
165
OtnxMatchDataFree(OTNX_MATCH_DATA * omd)166 void OtnxMatchDataFree(OTNX_MATCH_DATA *omd)
167 {
168 if (omd == NULL)
169 return;
170
171 if (omd->matchInfo != NULL)
172 free(omd->matchInfo);
173
174 free(omd);
175 }
176
177 // called by fpLogEvent(), which does the filtering etc.
178 // this handles the non-rule-actions (responses).
fpLogOther(Packet * p,OptTreeNode * otn,int action)179 static inline void fpLogOther (Packet* p, OptTreeNode* otn, int action)
180 {
181 TriggerResponses(p, otn);
182
183 if ( !EventTrace_IsEnabled() )
184 return;
185
186 EventTrace_Log(p, otn, action);
187 }
188
189 /*
190 **
191 ** NAME
192 ** fpLogEvent::
193 **
194 ** DESCRIPTION
195 ** This function takes the corresponding RTN and OTN for a snort rule
196 ** and logs the event and packet that was alerted upon. This
197 ** function was pulled out of fpEvalSomething, so now we can log an
198 ** event no matter where we are.
199 **
200 ** FORMAL INPUTS
201 ** RuleTreeNode * - rtn for snort rule
202 ** OptTreeNode * - otn for snort rule
203 ** Packet * - packet that elicited event.
204 */
fpLogEvent(RuleTreeNode * rtn,OptTreeNode * otn,Packet * p)205 int fpLogEvent(RuleTreeNode *rtn, OptTreeNode *otn, Packet *p)
206 {
207 int action = -1,
208 rateAction = -1,
209 filterEvent = 0;
210
211 if (!rtn || !otn)
212 {
213 return 1;
214 }
215
216 DEBUG_WRAP(DebugMessage(DEBUG_DETECT,
217 " => Got rule match, rtn type = %d, evalIndex = %d, passIndex = %d\n",
218 rtn->type,ScGetEvalIndex(rtn->type), ScGetEvalIndex(RULE_TYPE__PASS)););
219
220 if (RULE_TYPE__PASS == rtn->type)
221 {
222 p->packet_flags |= PKT_PASS_RULE;
223 }
224
225 if (otn->stateless)
226 {
227 /* Stateless rule, set the stateless bit */
228 p->packet_flags |= PKT_STATELESS;
229 }
230 else
231 {
232 /* Not stateless, clear the stateless bit if it was set
233 * from a previous rule.
234 */
235 p->packet_flags &= ~PKT_STATELESS;
236 }
237
238 if ((p->packet_flags & PKT_STREAM_UNEST_UNI) &&
239 ScAssureEstablished() &&
240 (!(p->packet_flags & PKT_REBUILT_STREAM)) &&
241 (otn->stateless == 0))
242 {
243 // We still want to drop packets that are drop rules.
244 // We just don't want to see the alert.
245 if ((rtn->type == RULE_TYPE__DROP) ||
246 (rtn->type == RULE_TYPE__SDROP) ||
247 (rtn->type == RULE_TYPE__REJECT))
248 {
249 Active_DropSession(p);
250 if (pkt_trace_enabled)
251 {
252 addPktTraceData(VERDICT_REASON_SNORT, snprintf(trace_line, MAX_TRACE_LINE,
253 "Snort fpdetect: gid %u, sid %u, %s\n", otn->sigInfo.generator, otn->sigInfo.id, getPktTraceActMsg()));
254 }
255 else addPktTraceData(VERDICT_REASON_SNORT, 0);
256 }
257 fpLogOther(p, otn, rtn->type);
258 return 1;
259 }
260
261 // perform rate filtering tests - impacts action taken
262 rateAction = RateFilter_Test(otn, p);
263
264 if (rateAction < 0)
265 {
266 // internal events are no-ops
267 if (EventIsInternal(otn->sigInfo.generator))
268 return 1;
269 else
270 action = (int) rtn->type;
271 }
272 else
273 {
274 if (rateAction >= RULE_TYPE__MAX)
275 action = rateAction - RULE_TYPE__MAX;
276 else
277 action = rateAction;
278 }
279
280 // When rate filters kick in, event filters are still processed.
281 // perform event filtering tests - impacts logging
282 if ( IPH_IS_VALID(p) )
283 {
284 filterEvent = sfthreshold_test(
285 otn->event_data.sig_generator,
286 otn->event_data.sig_id,
287 GET_SRC_IP(p), GET_DST_IP(p),
288 p->pkth->ts.tv_sec);
289 }
290 else
291 {
292 sfaddr_t cleared;
293 IP_CLEAR(cleared);
294
295 filterEvent = sfthreshold_test(
296 otn->event_data.sig_generator,
297 otn->event_data.sig_id,
298 IP_ARG(cleared), IP_ARG(cleared),
299 p->pkth->ts.tv_sec);
300 }
301
302 if ( (filterEvent < 0) || (filterEvent > 0 && (rateAction < RULE_TYPE__MAX)) )
303 {
304 /*
305 ** If InlineMode is on, then we still want to drop packets
306 ** that are drop rules. We just don't want to see the alert.
307 */
308 if ( (action == RULE_TYPE__DROP) ||
309 (action == RULE_TYPE__SDROP) ||
310 (action == RULE_TYPE__REJECT) )
311 {
312 Active_DropSession(p);
313 if (pkt_trace_enabled)
314 {
315 addPktTraceData(VERDICT_REASON_SNORT, snprintf(trace_line, MAX_TRACE_LINE,
316 "Snort fpdetect_filter: gid %u, sid %u, %s\n", otn->sigInfo.generator, otn->sigInfo.id, getPktTraceActMsg()));
317 }
318 else addPktTraceData(VERDICT_REASON_SNORT, 0);
319 }
320 pc.event_limit++;
321 fpLogOther(p, otn, action);
322 return 1;
323 }
324
325 /* If this packet has been passed based on detection rules,
326 * check the decoder/preprocessor events (they have been added to Event queue already).
327 * If its order is lower than 'pass', it should have been passed.
328 * This is consistent with other detection rules */
329 if ( (p->packet_flags & PKT_PASS_RULE)
330 &&(ScGetEvalIndex(rtn->type) > ScGetEvalIndex(RULE_TYPE__PASS)))
331 {
332 fpLogOther(p, otn, rtn->type);
333 return 1;
334 }
335 // Set the ref_time to 0 so we make the logging work right.
336 otn->event_data.ref_time.tv_sec = 0;
337
338 /* Set otn_tmp because log.c uses it to log details
339 ** of the event. Maybe we should look into making this
340 ** part of the log routines and not a global variable.
341 ** This way we could support multiple events per packet.
342 */
343 otn_tmp = otn;
344 OTN_PROFILE_ALERT(otn);
345
346 event_id++;
347
348 switch (action)
349 {
350 case RULE_TYPE__PASS:
351 PassAction();
352 SetTags(p, otn, rtn, event_id);
353 break;
354
355 case RULE_TYPE__ALERT:
356 AlertAction(p, otn, rtn, &otn->event_data);
357 SetTags(p, otn, rtn, event_id);
358 break;
359
360 case RULE_TYPE__LOG:
361 LogAction(p, otn, rtn, &otn->event_data);
362 SetTags(p, otn, rtn, event_id);
363 break;
364
365 case RULE_TYPE__DROP:
366 DropAction(p, otn, rtn, &otn->event_data);
367 SetTags(p, otn, rtn, event_id);
368 break;
369
370 case RULE_TYPE__SDROP:
371 SDropAction(p, otn, &otn->event_data);
372 break;
373
374 case RULE_TYPE__REJECT:
375 DropAction(p, otn, rtn, &otn->event_data);
376 #ifdef ACTIVE_RESPONSE
377 Active_QueueReject();
378 #endif
379 SetTags(p, otn, rtn, event_id);
380 break;
381
382 default:
383 break;
384 }
385
386 otn_tmp = NULL;
387 fpLogOther(p, otn, action);
388 return 0;
389 }
390
391 /*
392 **
393 ** NAME
394 ** fpAddMatch::
395 **
396 ** DESCRIPTION
397 ** Add and Event to the appropriate Match Queue: Alert, Pass, or Log.
398 ** This allows us to find multiple events per packet and pick the 'best'
399 ** one. This function also allows us to change the order of alert,
400 ** pass, and log signatures by cacheing them for decision later.
401 **
402 ** IMPORTANT NOTE:
403 ** fpAddMatch must be called even when the queue has been maxed
404 ** out. This is because there are three different queues (alert,
405 ** pass, log) and unless all three are filled (or at least the
406 ** queue that is in the highest priority), events must be looked
407 ** at to see if they are members of a queue that is not maxed out.
408 **
409 ** FORMAL INPUTS
410 ** OTNX_MATCH_DATA * - the omd to add the event to.
411 ** int pLen - length of pattern that matched, 0 for no content
412 ** OptTreeNode * - the otn to add.
413 **
414 ** FORMAL OUTPUTS
415 ** int - 1 max_events variable hit, 0 successful.
416 **
417 */
fpAddMatch(OTNX_MATCH_DATA * omd_local,int pLen,OptTreeNode * otn)418 int fpAddMatch(OTNX_MATCH_DATA *omd_local, int pLen, OptTreeNode *otn)
419 {
420 MATCH_INFO * pmi;
421 int evalIndex;
422 int i;
423 RuleTreeNode *rtn = getRuntimeRtnFromOtn(otn);
424
425 evalIndex = rtn->listhead->ruleListNode->evalIndex;
426
427 /* bounds check index */
428 if( evalIndex >= omd_local->iMatchInfoArraySize )
429 {
430 pc.match_limit++;
431 return 1;
432 }
433 pmi = &omd_local->matchInfo[evalIndex];
434
435 /*
436 ** If we hit the max number of unique events for any rule type alert,
437 ** log or pass, then we don't add it to the list.
438 */
439 if( pmi->iMatchCount >= (int)snort_conf->fast_pattern_config->max_queue_events ||
440 pmi->iMatchCount >= MAX_EVENT_MATCH)
441 {
442 pc.match_limit++;
443 return 1;
444 }
445
446 /* Check that we are not storing the same otn again */
447 for( i=0; i< pmi->iMatchCount;i++ )
448 {
449 if( pmi->MatchArray[ i ] == otn )
450 {
451 //LogMessage("fpAddMatch: storing the same otn...\n");
452 return 0;
453 }
454 }
455
456 /*
457 ** Add the event to the appropriate list
458 */
459 pmi->MatchArray[ pmi->iMatchCount ] = otn;
460
461 /*
462 ** This means that we are adding a NC rule
463 ** and we only set the index to this rule
464 ** if there is no content rules in the
465 ** same array.
466 */
467 if(pLen > 0)
468 {
469 /*
470 ** Event Comparison Function
471 ** Here the largest content match is the
472 ** priority
473 */
474 if( pmi->iMatchMaxLen < pLen )
475 {
476 pmi->iMatchMaxLen = pLen;
477 pmi->iMatchIndex = pmi->iMatchCount;
478 }
479 }
480
481 pmi->iMatchCount++;
482
483 return 0;
484 }
485
486 /*
487 **
488 ** NAME
489 ** fpEvalRTN::
490 **
491 ** DESCRIPTION
492 ** Evaluates an RTN against a packet. We can probably get rid of
493 ** the check_ports variable, but it's in there for good luck. :)
494 **
495 ** FORMAL INPUTS
496 ** RuleTreeNode * - RTN to check packet against.
497 ** Packet * - Packet to evaluate
498 ** int - whether to do a quick enhancement against ports.
499 **
500 ** FORMAL OUTPUT
501 ** int - 1 if match, 0 if match failed.
502 **
503 */
fpEvalRTN(RuleTreeNode * rtn,Packet * p,int check_ports)504 int fpEvalRTN(RuleTreeNode *rtn, Packet *p, int check_ports)
505 {
506 PROFILE_VARS;
507
508 PREPROC_PROFILE_START(ruleRTNEvalPerfStats);
509
510 if(rtn == NULL)
511 {
512 PREPROC_PROFILE_END(ruleRTNEvalPerfStats);
513 return 0;
514 }
515
516 /* TODO: maybe add a port test here ... */
517
518
519 DEBUG_WRAP(DebugMessage(DEBUG_DETECT, "[*] Rule Head %d\n",
520 rtn->head_node_number);)
521
522 if(!rtn->rule_func->RuleHeadFunc(p, rtn, rtn->rule_func, check_ports))
523 {
524 DEBUG_WRAP(DebugMessage(DEBUG_DETECT,
525 " => Header check failed, checking next node\n"););
526 DEBUG_WRAP(DebugMessage(DEBUG_DETECT,
527 " => returned from next node check\n"););
528 PREPROC_PROFILE_END(ruleRTNEvalPerfStats);
529 return 0;
530 }
531
532 DEBUG_WRAP(DebugMessage(DEBUG_DETECT,
533 "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"););
534 DEBUG_WRAP(DebugMessage(DEBUG_DETECT, " => RTN %d Matched!\n",
535 rtn->head_node_number););
536 DEBUG_WRAP(DebugMessage(DEBUG_DETECT,
537 "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n"););
538 /*
539 ** Return that there is a rule match and log the event outside
540 ** of this routine.
541 */
542 PREPROC_PROFILE_END(ruleRTNEvalPerfStats);
543 return 1;
544 }
545
detection_option_tree_evaluate(detection_option_tree_root_t * root,detection_option_eval_data_t * eval_data)546 static int detection_option_tree_evaluate(detection_option_tree_root_t *root, detection_option_eval_data_t *eval_data)
547 {
548 int i, rval = 0;
549 PROFILE_VARS;
550
551 if (!root)
552 return 0;
553
554 PREPROC_PROFILE_START(ruleOTNEvalPerfStats); /* Not really OTN, but close */
555
556 #ifdef PPM_MGR
557 /* Start Rule Timer */
558 if( PPM_RULES_ENABLED() )
559 {
560 PPM_GET_TIME();
561 PPM_INIT_RULE_TIMER();
562
563 if (root->tree_state == RULE_STATE_DISABLED)
564 {
565 PPM_REENABLE_TREE(root, eval_data->p);
566
567 if (root->tree_state == RULE_STATE_DISABLED)
568 {
569 PPM_END_RULE_TIMER();
570 return 0;
571 }
572 }
573 }
574 #endif
575
576 for ( i = 0; i< root->num_children; i++)
577 {
578 /* New tree, reset doe_ptr for safety */
579 UpdateDoePtr(NULL, 0);
580
581 /* Increment number of events generated from that child */
582 rval += detection_option_node_evaluate(root->children[i], eval_data);
583 }
584
585 #ifdef PPM_MGR
586 if( PPM_ENABLED() )
587 {
588 PPM_GET_TIME();
589
590 /* Rule test */
591 if( PPM_RULES_ENABLED() )
592 {
593 if( PPM_PKTS_ENABLED() )
594 PPM_INC_PKT_RULE_TESTS();
595
596 PPM_RULE_TEST(root, eval_data->p);
597 PPM_ACCUM_RULE_TIME();
598 PPM_END_RULE_TIMER();
599 }
600 }
601 #endif
602
603 PREPROC_PROFILE_END(ruleOTNEvalPerfStats);
604 return rval;
605 }
606
rule_tree_match(void * id,void * tree,int index,void * data,void * neg_list)607 static int rule_tree_match( void * id, void *tree, int index, void * data, void * neg_list)
608 {
609 OTNX_MATCH_DATA *pomd = (OTNX_MATCH_DATA *)data;
610 PMX *pmx = (PMX*)id;
611 PatternMatchData *pmd = (PatternMatchData*)pmx->PatternMatchData;
612 detection_option_tree_root_t *root = (detection_option_tree_root_t *)tree;
613 detection_option_eval_data_t eval_data;
614 NCListNode *ncl;
615 int rval=0;
616 PROFILE_VARS;
617
618 eval_data.pomd = pomd;
619 eval_data.p = pomd->p;
620 eval_data.pmd = pmd;
621 eval_data.flowbit_failed = 0;
622 eval_data.flowbit_noalert = 0;
623 eval_data.detection_filter_count = 0;
624
625 PREPROC_PROFILE_START(rulePerfStats);
626
627 /* NOTE: The otn will be the first one in the match state. If there are
628 * multiple rules associated with a match state, mucking with the otn
629 * may muck with an unintended rule */
630
631 /* Set flag for not contents so they aren't evaluated */
632 for (ncl = (NCListNode *)neg_list; ncl != NULL; ncl = ncl->next)
633 {
634 PMX *neg_pmx = (PMX *)ncl->pmx;
635 PatternMatchData *neg_pmd = (PatternMatchData *)neg_pmx->PatternMatchData;
636
637 neg_pmd->last_check.ts.tv_sec = eval_data.p->pkth->ts.tv_sec;
638 neg_pmd->last_check.ts.tv_usec = eval_data.p->pkth->ts.tv_usec;
639 neg_pmd->last_check.packet_number = (rule_eval_pkt_count + (GetRebuiltPktCount()));
640 neg_pmd->last_check.rebuild_flag = (eval_data.p->packet_flags & PKT_REBUILT_STREAM);
641 }
642
643 rval = detection_option_tree_evaluate(root, &eval_data);
644 if (rval)
645 {
646 /*
647 ** We have a qualified event from this tree
648 */
649 pomd->pg->pgQEvents++;
650 UpdateQEvents(&sfEvent);
651 }
652 else
653 {
654 /*
655 ** This means that the event is non-qualified.
656 */
657 pomd->pg->pgNQEvents++;
658 UpdateNQEvents(&sfEvent);
659 }
660
661 PREPROC_PROFILE_END(rulePerfStats);
662 if (eval_data.flowbit_failed)
663 {
664 return -1;
665 }
666
667 #ifdef GRE
668 /* If this is for an IP rule set, evalute the rules from
669 * the inner IP offset as well */
670 if (eval_data.p->packet_flags & PKT_IP_RULE)
671 {
672 if (eval_data.p->outer_ip_data)
673 {
674 const uint8_t *tmp_data = eval_data.p->data;
675 uint16_t tmp_dsize = eval_data.p->dsize;
676 const IPHdr *tmp_iph = eval_data.p->iph;
677 IP4Hdr *tmp_ip4h = eval_data.p->ip4h;
678 IP6Hdr *tmp_ip6h = eval_data.p->ip6h;
679 eval_data.p->iph = eval_data.p->inner_iph;
680 eval_data.p->ip4h = &eval_data.p->inner_ip4h;
681 eval_data.p->ip6h = &eval_data.p->inner_ip6h;
682 eval_data.p->data = eval_data.p->ip_data;
683 eval_data.p->dsize = eval_data.p->ip_dsize;
684
685 /* clear so we dont keep recursing */
686 eval_data.p->packet_flags &= ~PKT_IP_RULE;
687 eval_data.p->packet_flags |= PKT_IP_RULE_2ND;
688
689 /* Recurse, and evaluate with the inner IP */
690 rval = rule_tree_match(id, tree, index, data, NULL);
691
692 eval_data.p->packet_flags &= ~PKT_IP_RULE_2ND;
693 eval_data.p->packet_flags |= PKT_IP_RULE;
694
695 /* restore original data & dsize */
696 eval_data.p->iph = tmp_iph;
697 eval_data.p->ip4h = tmp_ip4h;
698 eval_data.p->ip6h = tmp_ip6h;
699 eval_data.p->data = tmp_data;
700 eval_data.p->dsize = tmp_dsize;
701 }
702 }
703 #endif
704 return 0;
705 }
706
sortOrderByPriority(const void * e1,const void * e2)707 static int sortOrderByPriority(const void *e1, const void *e2)
708 {
709 OptTreeNode *otn1;
710 OptTreeNode *otn2;
711
712 if (!e1 || !e2)
713 return 0;
714
715 otn1 = *(OptTreeNode **)e1;
716 otn2 = *(OptTreeNode **)e2;
717
718 if( otn1->sigInfo.priority < otn2->sigInfo.priority )
719 return -1;
720
721 if( otn1->sigInfo.priority > otn2->sigInfo.priority )
722 return +1;
723
724 /* This improves stability of repeated tests */
725 if( otn1->sigInfo.id < otn2->sigInfo.id )
726 return -1;
727
728 if( otn1->sigInfo.id > otn2->sigInfo.id )
729 return +1;
730
731 return 0;
732 }
733
sortOrderByContentLength(const void * e1,const void * e2)734 static int sortOrderByContentLength(const void *e1, const void *e2)
735 {
736 OptTreeNode *otn1;
737 OptTreeNode *otn2;
738
739 if (!e1 || !e2)
740 return 0;
741
742 otn1 = *(OptTreeNode **)e1;
743 otn2 = *(OptTreeNode **)e2;
744
745 if (otn1->longestPatternLen < otn2->longestPatternLen)
746 return +1;
747
748 if (otn1->longestPatternLen > otn2->longestPatternLen)
749 return -1;
750
751 /* This improves stability of repeated tests */
752 if( otn1->sigInfo.id < otn2->sigInfo.id )
753 return +1;
754
755 if( otn1->sigInfo.id > otn2->sigInfo.id )
756 return -1;
757
758 return 0;
759 }
760
761
762 /*
763 **
764 ** NAME
765 ** fpFinalSelectEvent::
766 **
767 ** DESCRIPTION
768 ** fpFinalSelectEvent is called at the end of packet processing
769 ** to decide, if there hasn't already been a selection, to decide
770 ** what event to select. This function is different from
771 ** fpSelectEvent by the fact that fpSelectEvent only selects an
772 ** event if it is the first priority setting (drop/pass/alert...).
773 **
774 ** We also loop through the events we log, so that we don't log the
775 ** same event twice. This can happen with unique conflicts some
776 ** of the time.
777 **
778 ** IMPORTANT NOTE:
779 ** We call fpFinalSelectEvent() after all processing of the packet
780 ** has been completed. The reason this must be called afterwards is
781 ** because of unique rule group conflicts for a packet. If there is
782 ** a unique conflict, then we inspect both rule groups and do the final
783 ** event select after both rule groups have been inspected. The
784 ** problem came up with bi-directional rules with pass rule ordering
785 ** as the first type of rule. Before we would detect a alert rule in
786 ** the first rule group, and since there was no pass rules we would
787 ** log that alert rule. However, if we had inspected the second rule
788 ** group, we would have found a pass rule and that should have taken
789 ** precedence. We now inspect both rule groups before doing a final
790 ** event select.
791 **
792 ** NOTES
793 ** Jan 2006 : marc norton
794 ** Previously it was possible to not log all desired events, if for
795 ** instance the rule order was alert->drop in inline mode we would
796 ** alert but no drop. The default ordering of 'drop alert pass log ...'
797 ** normally handles this, however, it could happen. Also, in the
798 ** default ordering alerts on the same packet a drop was applied to
799 ** did not get logged. To be more flexible and handle all manners of
800 ** subjective rule ordering and logging desired by the whole farm we've
801 ** changed things a bit.
802 **
803 ** Now, each actions event list is processed in order, based on the rule
804 ** order. We process all events up to the log limit specified via the
805 ** 'config event_queue: ...' as you might expect. Pass rules are
806 ** handled a bit differently. As soon as a pass rule based event is
807 ** processed in the event queue, we stop processing any further events
808 ** on the packet if the pass event is the 1st ordering that sees an
809 ** event. Otherwise if the ordering has it that pass rule events are
810 ** processed after a drop or alert you will see the drops and alerts,
811 ** and the pass event just causes us to stop processing any more events
812 ** on the packet, but the packet does not pass. Also, the --alert-on-drop
813 ** flag causes any drop/sdrop/reject rules to be loaded as alert rules.
814 ** The default has been to ignore them on parsing.
815 **
816 ** If this is less than clear, herese the $.02 version:
817 ** default order -> pass drop alert log ( --alert-before-pass reverts
818 ** to -> drop alert pass log ) the 1st action-type of events in the rule
819 ** ordering to be seen gets logged by default the --flush-all-events
820 ** flag will cause secondary and tertiary action-events to be logged.
821 ** the -o flag is useless, but accepted, for now.
822 ** the max_events and log fields are reduced to only needing the log
823 ** events field. max_fields is harmless.
824 ** ( drop rules may be honored as alerts in IDS mode (no -Q) by using
825 ** the --alert-on-drop flag )
826 **
827 ** FORMAL INPUTS
828 ** OTNX_MATCH_DATA * - omd to select event from.
829 ** Packet * - pointer to packet to log.
830 **
831 ** FORMAL OUTPUT
832 ** int - return 0 if no match, 1 if match.
833 **
834 */
fpFinalSelectEvent(OTNX_MATCH_DATA * o,Packet * p)835 static inline int fpFinalSelectEvent(OTNX_MATCH_DATA *o, Packet *p)
836 {
837 int i;
838 int j;
839 int k;
840 OptTreeNode *otn;
841 int tcnt = 0;
842 EventQueueConfig *eq = snort_conf->event_queue_config;
843 RuleTreeNode *rtn;
844
845 for( i = 0; i < o->iMatchInfoArraySize; i++ )
846 {
847 /* bail if were not dumping events in all the action groups,
848 * and we've alresady got some events */
849 if (!ScProcessAllEvents() && (tcnt > 0))
850 return 1;
851
852 if(o->matchInfo[i].iMatchCount)
853 {
854 /*
855 * We must always sort so if we que 8 and log 3 and they are
856 * all from the same action group we want them sorted so we get
857 * the highest 3 in priority, priority and lenght sort do NOT
858 * take precedence over 'alert drop pass ...' ordering. If
859 * order is 'drop alert', and we log 3 for drop alertsdo not
860 * get logged. IF order is 'alert drop', and we log 3 for
861 * alert, than no drops are logged. So, there should be a
862 * built in drop/sdrop/reject comes before alert/pass/log as
863 * part of the natural ordering....Jan '06..
864 */
865 /* Sort the rules in this action group */
866 if (eq->order == SNORT_EVENTQ_PRIORITY)
867 {
868 qsort(o->matchInfo[i].MatchArray, o->matchInfo[i].iMatchCount,
869 sizeof(void *), sortOrderByPriority);
870 }
871 else if (eq->order == SNORT_EVENTQ_CONTENT_LEN)
872 {
873 qsort(o->matchInfo[i].MatchArray, o->matchInfo[i].iMatchCount,
874 sizeof(void*), sortOrderByContentLength);
875 }
876 else
877 {
878 FatalError("fpdetect: Order function for event queue is invalid.\n");
879 }
880
881 /* Process each event in the action (alert,drop,log,...) groups */
882 for(j=0; j < o->matchInfo[i].iMatchCount; j++)
883 {
884 otn = o->matchInfo[i].MatchArray[j];
885 rtn = getRtnFromOtn(otn, getIpsRuntimePolicy());
886
887 if ((otn != NULL) && (rtn != NULL) && (rtn->type == RULE_TYPE__PASS))
888 {
889 /* Already acted on rules, so just don't act on anymore */
890 if( tcnt > 0 )
891 return 1;
892 }
893
894 /*
895 ** Loop here so we don't log the same event
896 ** multiple times.
897 */
898 for(k = 0; k < j; k++)
899 {
900 if(o->matchInfo[i].MatchArray[k] == otn)
901 {
902 otn = NULL;
903 break;
904 }
905 }
906
907 if( otn && !fpSessionAlerted(p, otn) &&
908 !fpFragAlerted(p, otn))
909 {
910 /*
911 ** QueueEvent
912 */
913 int err = SnortEventqAdd(
914 otn->sigInfo.generator,
915 otn->sigInfo.id,
916 otn->sigInfo.rev,
917 otn->sigInfo.class_id,
918 otn->sigInfo.priority,
919 otn->sigInfo.message,
920 (void *)otn);
921 if ( err )
922 pc.queue_limit++;
923
924 tcnt++;
925 }
926 else
927 pc.alert_limit++;
928
929 /* Only count it if we're going to log it */
930 if (tcnt <= eq->log_events)
931 {
932 if ( p->ssnptr )
933 fpAddSessionAlert(p, otn);
934
935 if ( p->fragtracker )
936 fpAddFragAlert(p, otn);
937 }
938
939 if (tcnt >= eq->max_events)
940 {
941 pc.queue_limit++;
942 return 1;
943 }
944
945 /* only log/count one pass */
946 if ((otn != NULL) && (rtn != NULL) && (rtn->type == RULE_TYPE__PASS))
947 {
948 p->packet_flags |= PKT_PASS_RULE;
949 return 1;
950 }
951 }
952 }
953 }
954
955 return 0;
956 }
957
958 /*
959 **
960 ** NAME
961 ** fpAddSessionAlert::
962 **
963 ** DESCRIPTION
964 ** This function flags an alert per session.
965 **
966 ** FORMAL INPUTS
967 ** Packet * - the packet to inspect
968 ** OptTreeNode * - the rule that generated the alert
969 **
970 ** FORMAL OUTPUTS
971 ** int - 0 if not flagged
972 ** 1 if flagged
973 **
974 */
fpAddSessionAlert(Packet * p,OptTreeNode * otn)975 static inline int fpAddSessionAlert(Packet *p, OptTreeNode *otn)
976 {
977 if ( !p->ssnptr )
978 return 0;
979
980 if ( !otn )
981 return 0;
982
983 /* Only track a certain number of alerts per session */
984 if (stream_api)
985 return !stream_api->add_session_alert(
986 p->ssnptr, p, otn->sigInfo.generator, otn->sigInfo.id);
987 return 0;
988 }
989
990 /*
991 **
992 ** NAME
993 ** fpSessionAlerted::
994 **
995 ** DESCRIPTION
996 ** This function indicates whether or not an alert has been generated previously
997 ** in this session, but only if this is a rebuilt packet.
998 **
999 ** FORMAL INPUTS
1000 ** Packet * - the packet to inspect
1001 ** OptTreeNode * - the rule that generated the alert
1002 **
1003 ** FORMAL OUTPUTS
1004 ** int - 0 if alert NOT previously generated
1005 ** 1 if alert previously generated
1006 **
1007 */
fpSessionAlerted(Packet * p,OptTreeNode * otn)1008 static inline int fpSessionAlerted(Packet *p, OptTreeNode *otn)
1009 {
1010 SigInfo *si = &otn->sigInfo;
1011
1012 if ( !stream_api )
1013 return 0;
1014
1015 if (!stream_api->check_session_alerted(p->ssnptr, p, si->generator, si->id))
1016 return 0;
1017 else
1018 return 1;
1019
1020 }
1021
1022 #if 0
1023 Not currently used
1024 /*
1025 * Prints an OTN in a simple format with:
1026 *
1027 * rule proto: # gid: # sid: # sp: # dp # \n
1028 */
1029 void printRuleFmt1( SnortConfig *sc, OptTreeNode * otn )
1030 {
1031 RuleTreeNode *rtn = getParserRtnFromOtn(otn);
1032
1033 LogMessage("rule proto: ");
1034
1035 if( rtn->proto== IPPROTO_TCP )LogMessage("tcp ");
1036 else if( rtn->proto== IPPROTO_UDP )LogMessage("udp ");
1037 else if( rtn->proto== IPPROTO_ICMP )LogMessage("icmp ");
1038 else if( rtn->proto== ETHERNET_TYPE_IP)LogMessage("ip ");
1039
1040 LogMessage("gid:%u sid:%5u ", otn->sigInfo.generator,otn->sigInfo.id);
1041
1042 LogMessage(" sp:");
1043
1044 fflush(stdout);fflush(stderr);
1045 PortObjectPrintPortsRaw(rtn->src_portobject);
1046 fflush(stdout);fflush(stderr);
1047
1048 LogMessage(" dp:");
1049
1050 PortObjectPrintPortsRaw(rtn->dst_portobject);
1051 printf("\n");
1052 fflush(stdout);fflush(stderr);
1053 }
1054 #endif
1055
1056 /*
1057 **
1058 ** NAME
1059 ** fpEvalHeaderSW::
1060 **
1061 ** DESCRIPTION
1062 ** This function does a set-wise match on content, and walks an otn list
1063 ** for non-content. The otn list search will eventually be redone for
1064 ** for performance purposes.
1065 **
1066 ** FORMAL INPUTS
1067 ** PORT_GROUP * - the port group to inspect
1068 ** Packet * - the packet to inspect
1069 ** int - whether src/dst ports should be checked (udp/tcp or icmp)
1070 ** char - whether the rule is an IP rule (change the packet payload pointer)
1071 **
1072 ** FORMAL OUTPUTS
1073 ** int - 0 for failed pattern match
1074 ** 1 for sucessful pattern match
1075 **
1076 */
fpEvalHeaderSW(PORT_GROUP * port_group,Packet * p,int check_ports,char ip_rule,OTNX_MATCH_DATA * omd)1077 static inline int fpEvalHeaderSW(PORT_GROUP *port_group, Packet *p,
1078 int check_ports, char ip_rule, OTNX_MATCH_DATA *omd)
1079 {
1080 void * so;
1081 int start_state;
1082 const uint8_t *tmp_payload = NULL;
1083 uint16_t tmp_dsize = 0;
1084 IPHdr *tmp_iph = NULL;
1085 IP6Hdr *tmp_ip6h = NULL;
1086 IP4Hdr *tmp_ip4h = NULL;
1087 IPH_API *tmp_api = NULL;
1088 char repeat = 0;
1089 FastPatternConfig *fp = snort_conf->fast_pattern_config;
1090 PROFILE_VARS;
1091
1092 if (ip_rule)
1093 {
1094 tmp_iph = (void *)p->iph;
1095 tmp_ip6h = (void *)p->ip6h;
1096 tmp_ip4h = (void *)p->ip4h;
1097 tmp_payload = p->data;
1098 tmp_dsize = p->dsize;
1099 tmp_api = p->iph_api;
1100
1101 /* Set the packet payload pointers to that of IP,
1102 ** since this is an IP rule. */
1103 #ifdef GRE
1104 if (p->outer_ip_data)
1105 {
1106 p->iph = p->outer_iph;
1107 p->ip6h = &p->outer_ip6h;
1108 p->ip4h = &p->outer_ip4h;
1109 p->data = p->outer_ip_data;
1110 p->dsize = p->outer_ip_dsize;
1111 p->iph_api = p->outer_iph_api;
1112 p->packet_flags |= PKT_IP_RULE;
1113 repeat = 2;
1114 }
1115 else
1116 #endif /* GRE */
1117 {
1118 if (p->ip_data)
1119 {
1120 p->data = p->ip_data;
1121 p->dsize = p->ip_dsize;
1122 p->packet_flags |= PKT_IP_RULE;
1123 }
1124 }
1125 }
1126 else
1127 {
1128 p->packet_flags &= ~PKT_IP_RULE;
1129 }
1130
1131 /*
1132 ** Init the info for rule ordering selection
1133 */
1134 //InitMatchInfo(omd);
1135
1136 if (do_detect_content)
1137 {
1138 /*
1139 ** PKT_STREAM_INSERT packets are being rebuilt and re-injected
1140 ** through this detection engine. So in order to avoid pattern
1141 ** matching bytes twice, we wait until the PKT_STREAM_INSERT
1142 ** packets are rebuilt and injected through the detection engine.
1143 **
1144 ** PROBLEM:
1145 ** If a stream gets stomped on before it gets re-injected, an attack
1146 ** would be missed. So before a connection gets stomped, we
1147 ** re-inject the stream we have.
1148 */
1149
1150 /*
1151 ** First evaluate the detection functions. Namely those things
1152 ** that are between a preprocessor and rules.
1153 */
1154 {
1155 tSfPolicyId policy_id = getIpsRuntimePolicy();
1156 SnortPolicy *policy = snort_conf->targeted_policies[policy_id];
1157 /* safe to assume policy is non NULL here because of check in
1158 * Preprocess() */
1159 DetectionEvalFuncNode *idx = policy->detect_eval_funcs;
1160
1161 for (; (idx != NULL) && !(p->packet_flags & PKT_PASS_RULE); idx = idx->next)
1162 {
1163 if ( p->proto_bits & idx->proto_mask )
1164 //IsDetectBitSet(p, idx->preproc_bit))
1165 {
1166 idx->func(p, idx->context);
1167 }
1168 }
1169 }
1170
1171 if ( fp->inspect_stream_insert || !(p->packet_flags & PKT_STREAM_INSERT) )
1172 {
1173 const HttpBuffer* hb;
1174
1175 omd->pg = port_group;
1176 omd->p = p;
1177 omd->check_ports = check_ports;
1178
1179 if ( GetHttpBufferMask() )
1180 {
1181 if ( (hb = GetHttpBuffer(HTTP_BUFFER_URI)) )
1182 {
1183 so = (void *)port_group->pgPms[PM_TYPE__HTTP_URI_CONTENT];
1184
1185 if ( so && mpseGetPatternCount(so) > 0 )
1186 {
1187 start_state = 0;
1188
1189 mpseSearch(so, hb->buf, hb->length,
1190 rule_tree_match, omd, &start_state);
1191 #ifdef PPM_MGR
1192 /* Bail if we spent too much time already */
1193 if (PPM_PACKET_ABORT_FLAG())
1194 goto fp_eval_header_sw_reset_ip;
1195 #endif
1196 }
1197 }
1198 if ( (hb = GetHttpBuffer(HTTP_BUFFER_HEADER)) )
1199 {
1200 so = (void *)port_group->pgPms[PM_TYPE__HTTP_HEADER_CONTENT];
1201
1202 if ( so && mpseGetPatternCount(so) > 0 )
1203 {
1204 start_state = 0;
1205
1206 mpseSearch(so, hb->buf, hb->length,
1207 rule_tree_match, omd, &start_state);
1208 #ifdef PPM_MGR
1209 /* Bail if we spent too much time already */
1210 if (PPM_PACKET_ABORT_FLAG())
1211 goto fp_eval_header_sw_reset_ip;
1212 #endif
1213 }
1214 }
1215 if ( (hb = GetHttpBuffer(HTTP_BUFFER_CLIENT_BODY)) )
1216 {
1217 so = (void *)port_group->pgPms[PM_TYPE__HTTP_CLIENT_BODY_CONTENT];
1218
1219 if ( so && mpseGetPatternCount(so) > 0 )
1220 {
1221 start_state = 0;
1222
1223 mpseSearch(so, hb->buf, hb->length,
1224 rule_tree_match, omd, &start_state);
1225 #ifdef PPM_MGR
1226 /* Bail if we spent too much time already */
1227 if (PPM_PACKET_ABORT_FLAG())
1228 goto fp_eval_header_sw_reset_ip;
1229 #endif
1230 }
1231 }
1232 }
1233 /*
1234 ** Decode Content Match
1235 ** We check to see if the packet has been normalized into
1236 ** the global (decode.c) DecodeBuffer. Currently, only
1237 ** telnet normalization writes to this buffer. So, if
1238 ** it is set, we do this the match against the normalized
1239 ** buffer and we do the check against the original
1240 ** payload, in case any of the rules have the
1241 ** 'rawbytes' option.
1242 */
1243 so = (void *)port_group->pgPms[PM_TYPE__CONTENT];
1244 if ((so != NULL) && (mpseGetPatternCount(so) > 0))
1245 {
1246 if (Is_DetectFlag(FLAG_ALT_DECODE) && DecodeBuffer.len)
1247 {
1248 start_state = 0;
1249 mpseSearch(so, DecodeBuffer.data, DecodeBuffer.len,
1250 rule_tree_match, omd, &start_state);
1251 #ifdef PPM_MGR
1252 /* Bail if we spent too much time already */
1253 if (PPM_PACKET_ABORT_FLAG())
1254 goto fp_eval_header_sw_reset_ip;
1255 #endif
1256 }
1257
1258 /* Adding this extra search on file data since we no more use DecodeBuffer to decode now*/
1259 if(file_data_ptr.len)
1260 {
1261 start_state = 0;
1262 mpseSearch(so, file_data_ptr.data, file_data_ptr.len,
1263 rule_tree_match, omd, &start_state);
1264 #ifdef PPM_MGR
1265 /* Bail if we spent too much time already */
1266 if (PPM_PACKET_ABORT_FLAG())
1267 goto fp_eval_header_sw_reset_ip;
1268 #endif
1269 }
1270
1271 /*
1272 ** Content-Match - If no Uri-Content matches, than do a Content search
1273 **
1274 ** NOTE:
1275 ** We may want to bail after the Content search if there
1276 ** has been a successful match.
1277 */
1278 if (p->data && p->dsize)
1279 {
1280 uint16_t pattern_match_size = p->dsize;
1281
1282 if ( IsLimitedDetect(p) && (p->alt_dsize < p->dsize) )
1283 pattern_match_size = p->alt_dsize;
1284
1285 start_state = 0;
1286 mpseSearch(so, p->data, pattern_match_size,
1287 rule_tree_match, omd, &start_state);
1288 #ifdef PPM_MGR
1289 /* Bail if we spent too much time already */
1290 if (PPM_PACKET_ABORT_FLAG())
1291 goto fp_eval_header_sw_reset_ip;
1292 #endif
1293 }
1294 }
1295 }
1296 }
1297
1298 /*
1299 ** PKT_REBUILT_STREAM packets are re-injected streams. This means
1300 ** that the "packet headers" are completely bogus and only the
1301 ** content matches are important. So for PKT_REBUILT_STREAMs, we
1302 ** don't inspect against no-content OTNs since these deal with
1303 ** packet headers, packet sizes, etc.
1304 **
1305 ** NOTE:
1306 ** This has been changed when evaluating no-content rules because
1307 ** it was interfering with the pass->alert ordering. We still
1308 ** need to check no-contents against rebuilt packets, because of
1309 ** this problem. Immediate solution is to have the detection plugins
1310 ** bail if the rule should only be inspected against packets, a.k.a
1311 ** dsize checks.
1312 **
1313 ** NOTE 2:
1314 ** PKT_REBUILT_STREAM packets are now cooked (encoded by Snort)
1315 ** and have the same encapsulations as the raw packets. The
1316 ** headers are "good enough" for detection (valid TCP sequence
1317 ** numbers, but zero checksums) but packet sizes are different.
1318 ** Given that TCP segmentation is arbitrary to start with, the
1319 ** use of dsize in a rule is questionable for raw or rebuilt.
1320 */
1321
1322 /*
1323 ** Walk and test the non-content OTNs
1324 */
1325 if (fpDetectGetDebugPrintNcRules(fp))
1326 LogMessage("NC-testing %u rules\n", port_group->pgNoContentCount);
1327
1328 #ifdef PPM_MGR
1329 if( PPM_ENABLED() )
1330 PPM_GET_TIME();
1331 #endif
1332
1333 do
1334 {
1335 if (port_group->pgHeadNC)
1336 {
1337 detection_option_eval_data_t eval_data;
1338 int rval;
1339
1340 eval_data.pomd = omd;
1341 eval_data.p = p;
1342 eval_data.pmd = NULL;
1343 eval_data.flowbit_failed = 0;
1344 eval_data.flowbit_noalert = 0;
1345 eval_data.detection_filter_count = 0;
1346
1347 PREPROC_PROFILE_START(ncrulePerfStats);
1348 rval = detection_option_tree_evaluate(port_group->pgNonContentTree, &eval_data);
1349 PREPROC_PROFILE_END(ncrulePerfStats);
1350
1351 if (rval)
1352 {
1353 /* We have a qualified event from this tree */
1354 port_group->pgQEvents++;
1355 UpdateQEvents(&sfEvent);
1356 }
1357 else
1358 {
1359 /* This means that the event is non-qualified. */
1360 port_group->pgNQEvents++;
1361 UpdateNQEvents(&sfEvent);
1362 }
1363 }
1364
1365 #ifdef GRE
1366 if (ip_rule && p->outer_ip_data)
1367 {
1368 /* Evaluate again with the inner IPs */
1369 p->iph = p->inner_iph;
1370 p->ip6h = &p->inner_ip6h;
1371 p->ip4h = &p->inner_ip4h;
1372 p->data = p->ip_data;
1373 p->dsize = p->ip_dsize;
1374 p->iph_api = tmp_api;
1375 p->packet_flags |= PKT_IP_RULE_2ND | PKT_IP_RULE;
1376 repeat--;
1377 }
1378 #else
1379 repeat = 0;
1380 #endif /* GRE */
1381 }
1382 while(repeat != 0);
1383
1384 #ifdef PPM_MGR /* Tag only used with PPM right now */
1385 fp_eval_header_sw_reset_ip:
1386 #endif
1387 if (ip_rule)
1388 {
1389 /* Set the data & dsize back to original values. */
1390 p->iph = tmp_iph;
1391 p->ip6h = tmp_ip6h;
1392 p->ip4h = tmp_ip4h;
1393 p->data = tmp_payload;
1394 p->dsize = tmp_dsize;
1395 p->iph_api = tmp_api;
1396 p->packet_flags &= ~(PKT_IP_RULE| PKT_IP_RULE_2ND);
1397 }
1398
1399 return 0;
1400 }
1401
1402 /*
1403 ** fpEvalHeaderUdp::
1404 */
fpEvalHeaderUdp(Packet * p,OTNX_MATCH_DATA * omd)1405 static inline int fpEvalHeaderUdp(Packet *p, OTNX_MATCH_DATA *omd)
1406 {
1407 PORT_GROUP *src = NULL, *dst = NULL, *gen = NULL;
1408
1409 #ifdef TARGET_BASED
1410 PORT_GROUP *nssrc = NULL, *nsdst = NULL;
1411
1412 if (IsAdaptiveConfigured())
1413 {
1414 /* Check for a service/protocol ordinal for this packet */
1415 int16_t proto_ordinal = GetProtocolReference(p);
1416 if (proto_ordinal > 0 && proto_ordinal != SFTARGET_UNKNOWN_PROTOCOL)
1417 {
1418 prmFindGenericRuleGroup(snort_conf->prmUdpRTNX, &gen);
1419
1420 /* TODO: To From Server ?, else we apply */
1421 dst = fpGetServicePortGroupByOrdinal(snort_conf->sopgTable, IPPROTO_UDP, TO_SERVER, proto_ordinal);
1422 src = fpGetServicePortGroupByOrdinal(snort_conf->sopgTable, IPPROTO_UDP, TO_CLIENT, proto_ordinal);
1423 }
1424
1425 // Find non-service based rule groups and the generic rule groups
1426 prmFindNoServiceRuleGroup(snort_conf->prmUdpRTNX, p->dp, p->sp, &nssrc, &nsdst, &gen);
1427 }
1428
1429 if ( src == NULL && dst == NULL )
1430 {
1431 if(!prmFindRuleGroupUdp(snort_conf->prmUdpRTNX, p->dp, p->sp, &src, &dst, &nssrc, &nsdst, &gen))
1432 return 0;
1433 }
1434 else
1435 {
1436 prmFindNoServiceRuleGroup(snort_conf->prmUdpRTNX, p->dp, p->sp, &nssrc, &nsdst, &gen);
1437 }
1438 #else
1439 if (!prmFindRuleGroupUdp(snort_conf->prmUdpRTNX, p->dp, p->sp, &src, &dst, &gen))
1440 return 0;
1441 #endif
1442
1443 if (fpDetectGetDebugPrintNcRules(snort_conf->fast_pattern_config))
1444 {
1445 LogMessage(
1446 "fpEvalHeaderUdp: sport=%d, dport=%d, src:%p, dst:%p, gen:%p\n",
1447 p->sp, p->dp, (void*)src, (void*)dst, (void*)gen);
1448 }
1449
1450 InitMatchInfo(omd);
1451
1452 if ( dst )
1453 fpEvalHeaderSW(dst, p, 1, 0, omd);
1454 if ( src )
1455 fpEvalHeaderSW(src, p, 1, 0, omd);
1456 #ifdef TARGET_BASED
1457 if ( nsdst )
1458 fpEvalHeaderSW(nsdst, p, 1, 0, omd);
1459 if ( nssrc )
1460 fpEvalHeaderSW(nssrc, p, 1, 0, omd);
1461 #endif
1462 if ( gen )
1463 fpEvalHeaderSW(gen, p, 1, 0, omd);
1464
1465 return fpFinalSelectEvent(omd, p);
1466 }
1467
1468 /*
1469 ** fpEvalHeaderTcp::
1470 */
fpEvalHeaderTcp(Packet * p,OTNX_MATCH_DATA * omd)1471 static inline int fpEvalHeaderTcp(Packet *p, OTNX_MATCH_DATA *omd)
1472 {
1473 PORT_GROUP *src = NULL, *dst = NULL, *gen = NULL;
1474
1475 #ifdef TARGET_BASED
1476 PORT_GROUP *nssrc = NULL, *nsdst = NULL;
1477
1478 if (IsAdaptiveConfigured())
1479 {
1480 int16_t proto_ordinal = GetProtocolReference(p);
1481 if (proto_ordinal > 0 && proto_ordinal != SFTARGET_UNKNOWN_PROTOCOL)
1482 {
1483 prmFindGenericRuleGroup(snort_conf->prmTcpRTNX, &gen);
1484
1485 if (p->packet_flags & PKT_FROM_SERVER)
1486 src = fpGetServicePortGroupByOrdinal(snort_conf->sopgTable, IPPROTO_TCP, TO_CLIENT, proto_ordinal);
1487
1488 if (p->packet_flags & PKT_FROM_CLIENT)
1489 dst = fpGetServicePortGroupByOrdinal(snort_conf->sopgTable, IPPROTO_TCP, TO_SERVER, proto_ordinal);
1490 }
1491 }
1492
1493 if ( src == NULL && dst == NULL )
1494 {
1495 if(!prmFindRuleGroupTcp(snort_conf->prmTcpRTNX, p->dp, p->sp, &src, &dst, &nssrc, &nsdst, &gen))
1496 return 0;
1497 }
1498 else
1499 {
1500 prmFindNoServiceRuleGroup(snort_conf->prmTcpRTNX, p->dp, p->sp, &nssrc, &nsdst, &gen);
1501 }
1502 #else
1503 if (!prmFindRuleGroupTcp(snort_conf->prmTcpRTNX, p->dp, p->sp, &src, &dst, &gen))
1504 return 0;
1505 #endif
1506
1507 InitMatchInfo(omd);
1508
1509 if ( dst )
1510 fpEvalHeaderSW(dst, p, 1, 0, omd);
1511 if ( src )
1512 fpEvalHeaderSW(src, p, 1, 0, omd);
1513 #ifdef TARGET_BASED
1514 if ( nsdst )
1515 fpEvalHeaderSW(nsdst, p, 1, 0, omd);
1516 if ( nssrc )
1517 fpEvalHeaderSW(nssrc, p, 1, 0, omd);
1518 #endif
1519 if ( gen )
1520 fpEvalHeaderSW(gen, p, 1, 0, omd);
1521
1522 return fpFinalSelectEvent(omd, p);
1523 }
1524
1525 /*
1526 ** fpEvalHeaderICMP::
1527 */
fpEvalHeaderIcmp(Packet * p,OTNX_MATCH_DATA * omd)1528 static inline int fpEvalHeaderIcmp(Packet *p, OTNX_MATCH_DATA *omd)
1529 {
1530 PORT_GROUP *gen = NULL, *type = NULL;
1531
1532 if (!prmFindRuleGroupIcmp(snort_conf->prmIcmpRTNX, p->icmph->type, &type, &gen))
1533 return 0;
1534
1535 if (fpDetectGetDebugPrintNcRules(snort_conf->fast_pattern_config))
1536 {
1537 LogMessage(
1538 "fpEvalHeaderIcmp: icmp->type=%d type=%p gen=%p\n",
1539 p->icmph->type, (void*)type, (void*)gen);
1540 }
1541
1542 InitMatchInfo(omd);
1543
1544 if (type != NULL)
1545 {
1546 if (fpEvalHeaderSW(type, p, 0, 0, omd))
1547 return 1;
1548 }
1549
1550 if (gen != NULL)
1551 {
1552 if (fpEvalHeaderSW(gen, p, 0, 0, omd))
1553 return 1;
1554 }
1555
1556 return fpFinalSelectEvent(omd, p);
1557 }
1558
1559 /*
1560 ** fpEvalHeaderIP::
1561 */
fpEvalHeaderIp(Packet * p,int ip_proto,OTNX_MATCH_DATA * omd)1562 static inline int fpEvalHeaderIp(Packet *p, int ip_proto, OTNX_MATCH_DATA *omd)
1563 {
1564 PORT_GROUP *gen = NULL, *ip_group = NULL;
1565
1566 if (!prmFindRuleGroupIp(snort_conf->prmIpRTNX, ip_proto, &ip_group, &gen))
1567 return 0;
1568
1569 if(fpDetectGetDebugPrintNcRules(snort_conf->fast_pattern_config))
1570 LogMessage("fpEvalHeaderIp: ip_group=%p, gen=%p\n", (void*)ip_group, (void*)gen);
1571
1572 InitMatchInfo(omd);
1573
1574 if (ip_group != NULL)
1575 {
1576 if (fpEvalHeaderSW(ip_group, p, 0, 1, omd))
1577 return 1;
1578 }
1579
1580 if (gen != NULL)
1581 {
1582 if (fpEvalHeaderSW(gen, p, 0, 1, omd))
1583 return 1;
1584 }
1585
1586 return fpFinalSelectEvent(omd, p);
1587 }
1588
1589 /*
1590 **
1591 ** NAME
1592 ** fpEvalPacket::
1593 **
1594 ** DESCRIPTION
1595 ** This function is the interface to the Detect() routine. Here
1596 ** the IP protocol is processed. If it is TCP, UDP, or ICMP, we
1597 ** process the both that particular ruleset and the IP ruleset
1598 ** with in the fpEvalHeader for that protocol. If the protocol
1599 ** is not TCP, UDP, or ICMP, we just process the packet against
1600 ** the IP rules at the end of the fpEvalPacket routine. Since
1601 ** we are using a setwise methodology for snort rules, both the
1602 ** network layer rules and the transport layer rules are done
1603 ** at the same time. While this is not the best for modularity,
1604 ** it is the best for performance, which is what we are working
1605 ** on currently.
1606 **
1607 ** FORMAL INPUTS
1608 ** Packet * - the packet to inspect
1609 **
1610 ** FORMAL OUTPUT
1611 ** int - 0 means that packet has been processed.
1612 **
1613 */
fpEvalPacket(Packet * p)1614 int fpEvalPacket(Packet *p)
1615 {
1616 int ip_proto = GET_IPH_PROTO(p);
1617 OTNX_MATCH_DATA *omd = snort_conf->omd;
1618
1619 /* Run UDP rules against the UDP header of Teredo packets */
1620 if ( p->udph && (p->proto_bits & (PROTO_BIT__TEREDO | PROTO_BIT__GTP)) )
1621 {
1622 uint16_t tmp_sp = p->sp;
1623 uint16_t tmp_dp = p->dp;
1624 const UDPHdr *tmp_udph = p->udph;
1625 const uint8_t *tmp_data = p->data;
1626 int tmp_do_detect_content = do_detect_content;
1627 uint16_t tmp_dsize = p->dsize;
1628
1629 if (p->outer_udph)
1630 {
1631 p->udph = p->outer_udph;
1632 }
1633 p->sp = ntohs(p->udph->uh_sport);
1634 p->dp = ntohs(p->udph->uh_dport);
1635 p->data = (const uint8_t *)p->udph + UDP_HEADER_LEN;
1636 if (p->outer_ip_dsize > UDP_HEADER_LEN)
1637 p->dsize = p->outer_ip_dsize - UDP_HEADER_LEN;
1638 if (p->dsize)
1639 do_detect_content = 1;
1640
1641 fpEvalHeaderUdp(p, omd);
1642
1643 p->sp = tmp_sp;
1644 p->dp = tmp_dp;
1645 p->udph = tmp_udph;
1646 p->data = tmp_data;
1647 p->dsize = tmp_dsize;
1648 do_detect_content = tmp_do_detect_content;
1649 }
1650
1651 switch(ip_proto)
1652 {
1653 case IPPROTO_TCP:
1654 DEBUG_WRAP(DebugMessage(DEBUG_DETECT,
1655 "Detecting on TcpList\n"););
1656
1657 if(p->tcph == NULL)
1658 {
1659 ip_proto = -1;
1660 break;
1661 }
1662
1663 return fpEvalHeaderTcp(p, omd);
1664
1665 case IPPROTO_UDP:
1666 DEBUG_WRAP(DebugMessage(DEBUG_DETECT,
1667 "Detecting on UdpList\n"););
1668
1669 if(p->udph == NULL)
1670 {
1671 ip_proto = -1;
1672 break;
1673 }
1674
1675 return fpEvalHeaderUdp(p, omd);
1676
1677 case IPPROTO_ICMPV6:
1678 case IPPROTO_ICMP:
1679 DEBUG_WRAP(DebugMessage(DEBUG_DETECT,
1680 "Detecting on IcmpList\n"););
1681
1682 if(p->icmph == NULL)
1683 {
1684 ip_proto = -1;
1685 break;
1686 }
1687
1688 return fpEvalHeaderIcmp(p, omd);
1689
1690 default:
1691 break;
1692 }
1693
1694 /*
1695 ** No Match on TCP/UDP, Do IP
1696 */
1697 return fpEvalHeaderIp(p, ip_proto, omd);
1698 }
1699
fpEvalIpProtoOnlyRules(SF_LIST ** ip_proto_only_lists,Packet * p)1700 void fpEvalIpProtoOnlyRules(SF_LIST **ip_proto_only_lists, Packet *p)
1701 {
1702 if ((p != NULL) && IPH_IS_VALID(p))
1703 {
1704 SF_LIST *l = ip_proto_only_lists[GET_IPH_PROTO(p)];
1705 OptTreeNode *otn;
1706
1707 /* If list is NULL, sflist_first returns NULL */
1708 for (otn = (OptTreeNode *)sflist_first(l);
1709 otn != NULL;
1710 otn = (OptTreeNode *)sflist_next(l))
1711 {
1712 if (fpEvalRTN(getRuntimeRtnFromOtn(otn), p, 0))
1713 {
1714 SnortEventqAdd(otn->sigInfo.generator,
1715 otn->sigInfo.id,
1716 otn->sigInfo.rev,
1717 otn->sigInfo.class_id,
1718 otn->sigInfo.priority,
1719 otn->sigInfo.message,
1720 (void *)otn);
1721 if (RULE_TYPE__PASS == getRuntimeRtnFromOtn(otn)->type)
1722 {
1723 p->packet_flags |= PKT_PASS_RULE;
1724 }
1725 }
1726 }
1727 }
1728 }
1729
1730
CreateOtnForPolicy(uint32_t gid,uint32_t sid,uint32_t rev,uint32_t classification,uint32_t priority,const char * msg,tSfPolicyId policy_id)1731 static inline OptTreeNode *CreateOtnForPolicy(
1732 uint32_t gid,
1733 uint32_t sid,
1734 uint32_t rev,
1735 uint32_t classification,
1736 uint32_t priority,
1737 const char * msg,
1738 tSfPolicyId policy_id
1739 )
1740 {
1741 OptTreeNode *otn = otnCreate(
1742 gid,
1743 sid,
1744 rev,
1745 classification,
1746 priority,
1747 msg
1748 );
1749
1750 if (otn)
1751 {
1752 if (GenerateSnortEventRtn(otn, policy_id))
1753 {
1754 OtnLookupAdd(snort_conf->otn_map, otn);
1755 }
1756 else
1757 {
1758 free(otn);
1759 otn = NULL;
1760 }
1761 }
1762
1763 return otn;
1764 }
1765
1766
GetOtnForPolicy(uint32_t gid,uint32_t sid,uint32_t rev,uint32_t classification,uint32_t priority,const char * msg,tSfPolicyId policy_id)1767 OptTreeNode *GetOtnForPolicy(
1768 uint32_t gid,
1769 uint32_t sid,
1770 uint32_t rev,
1771 uint32_t classification,
1772 uint32_t priority,
1773 const char *msg,
1774 tSfPolicyId policy_id
1775 )
1776 {
1777 OptTreeNode *otn = OtnLookup(snort_conf->otn_map, gid, sid);
1778
1779 if (!getRtnFromOtn(otn, policy_id))
1780 {
1781 if (ScAutoGenPreprocDecoderOtns())
1782 {
1783 if (!otn)
1784 {
1785 return CreateOtnForPolicy(
1786 gid,
1787 sid,
1788 rev,
1789 classification,
1790 priority,
1791 msg,
1792 policy_id
1793 );
1794 }
1795 else if (otn->generated && GenerateSnortEventRtn(otn, policy_id))
1796 {
1797 return otn;
1798 }
1799 }
1800
1801 return NULL;
1802 }
1803
1804 return otn;
1805 }
1806
1807
GetApplicableOtn(uint32_t gid,uint32_t sid,uint32_t rev,uint32_t classification,uint32_t priority,const char * msg)1808 OptTreeNode *GetApplicableOtn(
1809 uint32_t gid,
1810 uint32_t sid,
1811 uint32_t rev,
1812 uint32_t classification,
1813 uint32_t priority,
1814 const char * msg
1815 )
1816 {
1817 return GetOtnForPolicy(
1818 gid,
1819 sid,
1820 rev,
1821 classification,
1822 priority,
1823 msg,
1824 getApplicableRuntimePolicy(gid)
1825 );
1826 }
1827