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