1 /*
2 **  $Id$
3 **
4 **  pcrm.c
5 **
6 **  Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
7 **  Copyright (C) 2002-2013 Sourcefire, Inc.
8 **  Marc Norton <mnorton@sourcefire.com>
9 **  Dan Roelker <droelker@sourcefire.com>
10 **
11 **  NOTES
12 **  5.15.02   - Initial version of pcrm.c distributed. - Norton/Roelker
13 **
14 **  This program is free software; you can redistribute it and/or modify
15 **  it under the terms of the GNU General Public License Version 2 as
16 **  published by the Free Software Foundation.  You may not use, modify or
17 **  distribute this program under any other version of the GNU General
18 **  Public License.
19 **
20 **  This program is distributed in the hope that it will be useful,
21 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
22 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23 **  GNU General Public License for more details.
24 **
25 **  You should have received a copy of the GNU General Public License
26 **  along with this program; if not, write to the Free Software
27 **  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
28 */
29 
30 /*
31 **
32 **  Packet Classificationa and Rule Manager
33 **
34 **
35 **  A Fast Packet Classification method for Rule and Pattern Matching in SNORT
36 **  --------------------------------------------------------------------------
37 **
38 **  A simple method for grouping rules into lists and looking them up quickly
39 **  in realtime.
40 **
41 **  There is a natural problem when aggregating rules into pattern groups for
42 **  performing multi-pattern matching not seen with single pattern Boyer-Moore
43 **  strategies.  The problem is how to group the rules efficiently when
44 **  considering that there are multiple parameters which govern what rules to
45 **  apply to each packet or connection. The paramters, sip, dip, sport, dport,
46 **  and flags form an enormous address space of possible packets that
47 **  must be tested in realtime against a subset of rule patterns. Methods to
48 **  group patterns precisely based on all of these parameters can quickly
49 **  become complicated by both algorithmic implications and implementation
50 **  details.  The procedure described herein is quick and simple.
51 **
52 **  The methodology presented here to solve this problem is based on the
53 **  premise that we can use the source and destination ports to isolate
54 **  pattern groups for pattern matching, and rely on an event validation
55 **  procedure to authenticate other parameters such as sip, dip and flags after
56 **  a pattern match is made. An instrinsic assumption here is that most sip
57 **  and dip values will be acceptable and that the big gain in performance
58 **  is due to the fact that by isolating traffic based on services (ports)
59 **  we gain the most benefit.  Additionally, and just as important, is the
60 **  requirement that we can perform a multi-pattern recognition-inspection phase
61 **  on a large set of patterns many times quicker than we can apply a single
62 **  pattern test against many single patterns.
63 **
64 **  The current implementation assumes that for each rule the src and dst ports
65 **  each have one of 2 possible values.  Either a specific port number or the
66 **  ANYPORT designation. This does allow us to handle port ranges and NOT port
67 **  rules as well.
68 **
69 **  We make the following assumptions about classifying packets based on ports:
70 **
71 **    1) There are Unique ports which represent special services.  For example,
72 **       ports 21,25,80,110,etc.
73 **
74 **    2) Patterns can be grouped into Unique Pattern groups, and a Generic
75 **       Pattern Group
76 **       a) Unique pattern groups exist for source ports 21,25,80,110,etc.
77 **       b) Unique pattern groups exist for destination ports 21,25,80,etc.
78 **       c) A Generic pattern group exists for rules applied to every
79 **          combination of source and destination ports.
80 **
81 **  We make the following assumptions about packet traffic:
82 **
83 **    1) Well behaved traffic has one Unique port and one ephemeral port for
84 **       most packets and sometimes legitimately, as in the case of DNS, has
85 **       two unique ports that are the same. But we always determine that
86 **       packets with two different but Unique ports is bogus, and should
87 **       generate an alert.  For example, if you have traffic going from
88 **       port 80 to port 20.
89 **
90 **    2) In fact, state could tell us which side of this connection is a
91 **       service and which side is a client. Than we could handle this packet
92 **       more precisely, but this is a rare situation and is still bogus. We
93 **       can choose not to do pattern inspections on these packets or to do
94 **       complete inspections.
95 **
96 **  Rules are placed into each group as follows:
97 **
98 **    1) Src Port == Unique Service, Dst Port == ANY -> Unique Src Port Table
99 **       Src Port == Unique Service, Dst Port ==
100 **       Unique -> Unique Src & Dst Port Tables
101 **    2) Dst Port == Unqiue Service, Src Port == ANY -> Unique Dst Port Table
102 **       Dst Port == Unqiue Service, Src Port ==
103 **       Unique -> Unique Dst & Src Port Tables
104 **    3) Dst Port == ANY, Src Port == ANY -> Generic Rule Set,
105 **       And add to all Unique Src/Dst Rule Sets that have entries
106 **    4) !Dst or !Src Port is the same as ANY Dst or ANY Src port respectively
107 **    5) DstA:DstB is treated as an ANY port group, same for SrcA:SrcB
108 **
109 **  Initialization
110 **  --------------
111 **  For each rule check the dst-port, if it's specific, then add it to the
112 **  dst table.  If the dst-port is Any port, then do not add it to the dst
113 **  port table. Repeat this for the src-port.
114 **
115 **  If the rule has Any for both ports then it's added generic rule list.
116 **
117 **  Also, fill in the Unique-Conflicts array, this indicates if it's OK to have
118 **  the same Unique service port for both destination and source. This will
119 **  force an alert if it's not ok.  We optionally pattern match against this
120 **  anyway.
121 **
122 **  Processing Rules
123 **  -----------------
124 **  When packets arrive:
125 **
126 **   Categorize the Port Uniqueness:
127 **
128 **   a)Check the DstPort[DstPort] for possible rules,
129 **     if no entry,then no rules exist for this packet with this destination.
130 **
131 **   b)Check the SrcPort[SrcPort] for possible rules,
132 **     if no entry,then no rules exist for this packet with this source.
133 **
134 **   Process the Uniqueness:
135 **
136 **   If a AND !b has rules or !a AND b has rules then
137 **      match against those rules
138 **
139 **   If a AND b have rules then
140 **      if( sourcePort != DstPort )
141 **         Alert on this traffic and optionally match both rule sets
142 **      else if( SourcePort == DstPort )
143 **         Check the Unique-Conflicts array for allowable conflicts
144 **             if( NOT allowed )
145 **	       Alert on this traffic, optionally match the rules
146 **	    else
147 **	       match both sets of rules against this traffic
148 **
149 **   If( !a AND ! b )  then
150 **      Pattern Match against the Generic Rules ( these apply to all packets)
151 **
152 **
153 **  example.c
154 **  ---------
155 **
156 **   PORT_RULE_MAP * prm;
157 **   PORT_GROUP  *src, *dst, *generic;
158 **
159 **   RULE * prule; //user defined rule structure for user rules
160 **
161 **   prm = prmNewMap();
162 **
163 **   for( each rule )
164 **   {
165 **      prule = ....get a rule pointer
166 **
167 **      prmAddRule( prm, prule->dport, prule->sport, prule );
168 **   }
169 **
170 **   prmCompileGroups( prm );
171 **
172 **   while( sniff-packets )
173 **   {
174 **      ....
175 **
176 **      stat = prmFindRuleGroup( prm, dport, sport, &src, &dst, &generic );
177 **      switch( stat )
178 **      {
179 **         case 0:  // No rules at all
180 **          break;
181 **         case 1:  // Dst Rules
182 **           // pass 'dst->pgPatData', 'dst->pgPatDataUri' to the pattern engine
183 **          break;
184 **         case 2:  // Src Rules
185 **           // pass 'src->pgPatData', 'src->pgPatDataUri' to the pattern engine
186 **          break;
187 **         case 3:  // Src/Dst Rules - Both ports represent Unique service ports
188 **           // pass 'src->pgPatData' ,'src->pgPatDataUri' to the pattern engine
189 **           // pass 'dst->pgPatData'  'src->pgPatDataUri' to the pattern engine
190 **          break;
191 **         case 4:  // Generic Rules Only
192 **           // pass 'generic->pgPatData' to the pattern engine
193 **           // pass 'generic->pgPatDataUri' to the pattern engine
194 **          break;
195 **      }
196 **   }
197 **
198 */
199 
200 #ifdef HAVE_CONFIG_H
201 #include "config.h"
202 #endif
203 
204 #include <stdio.h>
205 #include <stdlib.h>
206 #include <string.h>
207 
208 #include "pcrm.h"
209 #include "util.h"
210 #include "fpcreate.h"
211 #include "snort.h"
212 
213 /*
214 **
215 **  NAME
216 **    prmNewMap::
217 **
218 **  DESCRIPTION
219 **    Allocate new PORT_RULE_MAP and return pointer.
220 **
221 **  FORMAL INPUTS
222 **    None
223 **
224 **  FORMAL OUTPUT
225 **    PORT_RULE_MAP * - NULL if failed, ptr otherwise.
226 **
227 */
prmNewMap(void)228 PORT_RULE_MAP * prmNewMap(void)
229 {
230     PORT_RULE_MAP * p;
231 
232     p = (PORT_RULE_MAP *)calloc(1, sizeof(PORT_RULE_MAP) );
233 
234     return p;
235 }
236 
237 /*
238 **
239 **  NAME
240 **    prmNewByteMap::
241 **
242 **  DESCRIPTION
243 **    Allocate new BYTE_RULE_MAP and return pointer.
244 **
245 **  FORMAL INPUTS
246 **    None
247 **
248 **  FORMAL OUTPUT
249 **    BYTE_RULE_MAP * - NULL if failed, ptr otherwise.
250 **
251 */
prmNewByteMap(void)252 BYTE_RULE_MAP * prmNewByteMap(void)
253 {
254     BYTE_RULE_MAP * p;
255 
256     p = (BYTE_RULE_MAP *)calloc(1, sizeof(BYTE_RULE_MAP) );
257 
258     return p;
259 }
260 
261 
262 /*
263 **
264 **  NAME
265 **    prmxFreeGroup::
266 **
267 **  DESCRIPTION
268 **    Frees a PORT_GROUP of it's RuleNodes.
269 **
270 **  FORMAL INPUTS
271 **    PORT_GROUP * - port group to free
272 **
273 **  FORMAL OUTPUT
274 **    None
275 **
276 */
prmxFreeGroup(PORT_GROUP * pg)277 static void prmxFreeGroup(PORT_GROUP *pg)
278 {
279      RULE_NODE * rn, *rx;
280 
281      rn = pg->pgHead;
282      while( rn )
283      {
284        rx = rn->rnNext;
285        free( rn );
286        rn = rx;
287      }
288      pg->pgHead = NULL;
289 
290      rn = pg->pgHeadNC;
291      while( rn )
292      {
293        rx = rn->rnNext;
294        free( rn );
295        rn = rx;
296      }
297      pg->pgHeadNC = NULL;
298 
299      rn = pg->pgUriHead;
300      while( rn )
301      {
302        rx = rn->rnNext;
303        free( rn );
304        rn = rx;
305      }
306      pg->pgUriHead = NULL;
307 }
308 
309 /*
310 **
311 **  NAME
312 **    prmFreeMap
313 **
314 **  DESCRIPTION
315 **    Frees the memory utilized by a PORT_RULE_MAP.
316 **
317 **  FORMAL INPUTS
318 **    PORT_RULE_MAP * - PORT_RULE_MAP to free
319 **
320 **  FORMAL OUTPUT
321 **    None
322 **
323 */
prmFreeMap(PORT_RULE_MAP * p)324 void prmFreeMap( PORT_RULE_MAP * p )
325 {
326      int i;
327 
328      if( p )
329      {
330        for(i=0;i<MAX_PORTS;i++)
331        {
332            if(p->prmSrcPort[i])
333            {
334                prmxFreeGroup( p->prmSrcPort[i] );
335                free(p->prmSrcPort[i]);
336            }
337        }
338 
339        for(i=0;i<MAX_PORTS;i++)
340        {
341            if(p->prmDstPort[i])
342            {
343                prmxFreeGroup( p->prmDstPort[i] );
344                free(p->prmDstPort[i]);
345            }
346        }
347 
348        if(p->prmGeneric)
349        {
350            prmxFreeGroup( p->prmGeneric );
351            free(p->prmGeneric);
352        }
353 
354        free( p );
355      }
356 }
357 
358 /*
359 **
360 **  NAME
361 **    prmFreeByteMap
362 **
363 **  DESCRIPTION
364 **    Frees the memory utilized by a BYTE_RULE_MAP.
365 **
366 **  FORMAL INPUTS
367 **    BYTE_RULE_MAP * - BYTE_RULE_MAP to free
368 **
369 **  FORMAL OUTPUT
370 **    None
371 **
372 */
prmFreeByteMap(BYTE_RULE_MAP * p)373 void prmFreeByteMap( BYTE_RULE_MAP * p )
374 {
375      int i;
376 
377      if( p )
378      {
379        for(i=0;i<256;i++)
380        {
381           prmxFreeGroup( &p->prmByteGroup[i] );
382        }
383 
384        prmxFreeGroup( &p->prmGeneric );
385 
386        free( p );
387      }
388 }
389 
390 /*
391 **
392 **  NAME
393 **    prmxAddPortRule::
394 **
395 **  DESCRIPTION
396 **    Adds a RULE_NODE to a PORT_GROUP.  This particular
397 **    function is specific in that it adds "content" rules.
398 **    A "content" rule is a snort rule that has a content
399 **    flag.
400 **
401 **    Each RULE_NODE in a PORT_GROUP is given a RULE_NODE
402 **    ID.  This allows us to track particulars as to what
403 **    rules have been alerted upon, and allows other neat
404 **    things like correlating events on different streams.
405 **    The RULE_NODE IDs may not be consecutive, because
406 **    we can add RULE_NODES into "content", "uri", and
407 **    "no content" lists.
408 **
409 **  FORMAL INPUTS
410 **    PORT_GROUP * - PORT_GROUP to add the rule to.
411 **    RULE_PTR - void ptr to the user information
412 **
413 **  FORMAL OUTPUT
414 **    int - 0 is successful, 1 is failure
415 **
416 */
417 //static
prmxAddPortRule(PORT_GROUP * p,RULE_PTR rd)418 int prmxAddPortRule( PORT_GROUP *p, RULE_PTR rd )
419 {
420     if( !p->pgHead )
421     {
422          p->pgHead = (RULE_NODE*) calloc( 1,sizeof(RULE_NODE) );
423          if( !p->pgHead )return 1;
424 
425          p->pgHead->rnNext      = 0;
426          p->pgHead->rnRuleData  = rd;
427          p->pgTail              = p->pgHead;
428     }
429     else
430     {
431          p->pgTail->rnNext = (RULE_NODE*)calloc( 1,sizeof(RULE_NODE) );
432          if(!p->pgTail->rnNext)return 1;
433 
434          p->pgTail             = p->pgTail->rnNext;
435          p->pgTail->rnNext     = 0;
436          p->pgTail->rnRuleData = rd;
437     }
438 
439     /*
440     **  Set RULE_NODE ID to unique identifier
441     */
442     p->pgTail->iRuleNodeID = p->pgCount;
443 
444     /*
445     **  Update the total Rule Node Count for this PORT_GROUP
446     */
447     p->pgCount++;
448 
449     p->pgContentCount++;
450 
451     return 0;
452 }
453 
454 /*
455 **
456 **  NAME
457 **    prmxAddPortRuleUri::
458 **
459 **  DESCRIPTION
460 **    Adds a RULE_NODE to a PORT_GROUP.  This particular
461 **    function is specific in that it adds "uri" rules.
462 **    A "uri" rule is a snort rule that has a uri
463 **    flag.
464 **
465 **    Each RULE_NODE in a PORT_GROUP is given a RULE_NODE
466 **    ID.  This allows us to track particulars as to what
467 **    rules have been alerted upon, and allows other neat
468 **    things like correlating events on different streams.
469 **    The RULE_NODE IDs may not be consecutive, because
470 **    we can add RULE_NODES into "content", "uri", and
471 **    "no content" lists.
472 **
473 **  FORMAL INPUTS
474 **    PORT_GROUP * - PORT_GROUP to add the rule to.
475 **    RULE_PTR - void ptr to the user information
476 **
477 **  FORMAL OUTPUT
478 **    int - 0 is successful, 1 is failure
479 **
480 */
481 //static
prmxAddPortRuleUri(PORT_GROUP * p,RULE_PTR rd)482 int prmxAddPortRuleUri( PORT_GROUP *p, RULE_PTR rd )
483 {
484     if( !p->pgUriHead )
485     {
486          p->pgUriHead = (RULE_NODE*) calloc(1, sizeof(RULE_NODE) );
487          if( !p->pgUriHead ) return 1;
488 
489          p->pgUriTail              = p->pgUriHead;
490          p->pgUriHead->rnNext      = 0;
491          p->pgUriHead->rnRuleData  = rd;
492     }
493     else
494     {
495          p->pgUriTail->rnNext = (RULE_NODE*)calloc(1, sizeof(RULE_NODE) );
496          if( !p->pgUriTail->rnNext) return 1;
497 
498          p->pgUriTail             = p->pgUriTail->rnNext;
499          p->pgUriTail->rnNext     = 0;
500          p->pgUriTail->rnRuleData = rd;
501     }
502 
503     /*
504     **  Set RULE_NODE ID to unique identifier
505     */
506     p->pgUriTail->iRuleNodeID = p->pgCount;
507 
508     /*
509     **  Update the total Rule Node Count for this PORT_GROUP
510     */
511     p->pgCount++;
512 
513     p->pgUriContentCount++;
514 
515     return 0;
516 }
517 
518 /*
519 **
520 **  NAME
521 **    prmxAddPortRuleNC::
522 **
523 **  DESCRIPTION
524 **    Adds a RULE_NODE to a PORT_GROUP.  This particular
525 **    function is specific in that it adds "no content" rules.
526 **    A "no content" rule is a snort rule that has no "content"
527 **    or "uri" flag, and hence does not need to be pattern
528 **    matched.
529 **
530 **    Each RULE_NODE in a PORT_GROUP is given a RULE_NODE
531 **    ID.  This allows us to track particulars as to what
532 **    rules have been alerted upon, and allows other neat
533 **    things like correlating events on different streams.
534 **    The RULE_NODE IDs may not be consecutive, because
535 **    we can add RULE_NODES into "content", "uri", and
536 **    "no content" lists.
537 **
538 **  FORMAL INPUTS
539 **    PORT_GROUP * - PORT_GROUP to add the rule to.
540 **    RULE_PTR - void ptr to the user information
541 **
542 **  FORMAL OUTPUT
543 **    int - 0 is successful, 1 is failure
544 **
545 */
546 //static
prmxAddPortRuleNC(PORT_GROUP * p,RULE_PTR rd)547 int prmxAddPortRuleNC( PORT_GROUP *p, RULE_PTR rd )
548 {
549     if( !p->pgHeadNC )
550     {
551          p->pgHeadNC = (RULE_NODE*) calloc( 1,sizeof(RULE_NODE) );
552          if( !p->pgHeadNC )return 1;
553 
554          p->pgTailNC             = p->pgHeadNC;
555          p->pgHeadNC->rnNext     = 0;
556          p->pgHeadNC->rnRuleData = rd;
557     }
558     else
559     {
560          p->pgTailNC->rnNext = (RULE_NODE*)calloc( 1,sizeof(RULE_NODE) );
561          if(!p->pgTailNC->rnNext)return 1;
562 
563          p->pgTailNC             = p->pgTailNC->rnNext;
564          p->pgTailNC->rnNext     = 0;
565          p->pgTailNC->rnRuleData = rd;
566     }
567 
568     /*
569     **  Set RULE_NODE ID to unique identifier
570     */
571     p->pgTailNC->iRuleNodeID = p->pgCount;
572 
573     /*
574     **  Update the Total Rule Node Count for this PORT_GROUP
575     */
576     p->pgCount++;
577 
578     p->pgNoContentCount++;
579 
580     return 0;
581 }
582 
583 /*
584 **
585 **  NAME
586 **    prmAddNotNode::
587 **
588 **  DESCRIPTION
589 **    NOT SUPPORTED YET.  Build a list of pur NOT nodes i.e. content !"this"
590 **    content:!"that".
591 **
592 */
prmAddNotNode(PORT_GROUP * pg,int id)593 void prmAddNotNode( PORT_GROUP * pg, int id )
594 {
595     NOT_RULE_NODE * p = calloc(1,sizeof( NOT_RULE_NODE));
596 
597     if( !p ) return ;
598 
599     p->iPos = id;
600 
601     if( !pg->pgNotRuleList )
602     {
603        pg->pgNotRuleList = p;
604        p->next = 0;
605     }
606     else
607     {
608        p->next = pg->pgNotRuleList;
609        pg->pgNotRuleList = p;
610     }
611 }
612 
613 
614 /*
615 **
616 **  NAME
617 **    prmGetFirstRule::
618 **
619 **  DESCRIPTION
620 **    This function returns the first rule user data in
621 **    the "content" list of a PORT_GROUP.
622 **
623 **  FORMAL INPUTS
624 **    PORT_GROUP * - PORT_GROUP to retrieve data from.
625 **
626 **  FORMAL OUTPUT
627 **    RULE_PTR - the ptr to the user data.
628 **
629 */
prmGetFirstRule(PORT_GROUP * pg)630 RULE_PTR prmGetFirstRule( PORT_GROUP * pg )
631 {
632     pg->pgCur = pg->pgHead;
633 
634     if( !pg->pgCur )
635         return 0;
636 
637     return pg->pgCur->rnRuleData;
638 }
639 
640 /*
641 **
642 **  NAME
643 **    prmGetNextRule::
644 **
645 **  DESCRIPTION
646 **    Gets the next "content" rule.  This function allows easy
647 **    walking of the "content" rule list.
648 **
649 **  FORMAL INPUTS
650 **    PORT_GROUP * - PORT_GROUP to retrieve data from.
651 **
652 **  FORMAL OUTPUT
653 **    RULE_PTR - ptr to the user data
654 **
655 */
prmGetNextRule(PORT_GROUP * pg)656 RULE_PTR prmGetNextRule( PORT_GROUP * pg )
657 {
658     if( pg->pgCur )
659         pg->pgCur = pg->pgCur->rnNext;
660 
661     if( !pg->pgCur )
662         return 0;
663 
664     return pg->pgCur->rnRuleData;
665 }
666 
667 /*
668 **
669 **  NAME
670 **    prmGetFirstRuleUri::
671 **
672 **  DESCRIPTION
673 **    This function returns the first rule user data in
674 **    the "uri" list of a PORT_GROUP.
675 **
676 **  FORMAL INPUTS
677 **    PORT_GROUP * - PORT_GROUP to retrieve data from.
678 **
679 **  FORMAL OUTPUT
680 **    RULE_PTR - the ptr to the user data.
681 **
682 */
prmGetFirstRuleUri(PORT_GROUP * pg)683 RULE_PTR prmGetFirstRuleUri( PORT_GROUP * pg )
684 {
685     pg->pgUriCur = pg->pgUriHead;
686 
687     if( !pg->pgUriCur )
688         return 0;
689 
690     return pg->pgUriCur->rnRuleData;
691 }
692 
693 /*
694 **
695 **  NAME
696 **    prmGetNextRuleUri::
697 **
698 **  DESCRIPTION
699 **    Gets the next "uri" rule.  This function allows easy
700 **    walking of the "uri" rule list.
701 **
702 **  FORMAL INPUTS
703 **    PORT_GROUP * - PORT_GROUP to retrieve data from.
704 **
705 **  FORMAL OUTPUT
706 **    RULE_PTR - ptr to the user data
707 **
708 */
prmGetNextRuleUri(PORT_GROUP * pg)709 RULE_PTR prmGetNextRuleUri( PORT_GROUP * pg )
710 {
711     if( pg->pgUriCur )
712         pg->pgUriCur = pg->pgUriCur->rnNext;
713 
714     if( !pg->pgUriCur )
715         return 0;
716 
717     return pg->pgUriCur->rnRuleData;
718 }
719 
720 /*
721 **
722 **  NAME
723 **    prmGetFirstRuleNC::
724 **
725 **  DESCRIPTION
726 **    This function returns the first rule user data in
727 **    the "no content" list of a PORT_GROUP.
728 **
729 **  FORMAL INPUTS
730 **    PORT_GROUP * - PORT_GROUP to retrieve data from.
731 **
732 **  FORMAL OUTPUT
733 **    RULE_PTR - the ptr to the user data.
734 **
735 */
prmGetFirstRuleNC(PORT_GROUP * pg)736 RULE_PTR prmGetFirstRuleNC( PORT_GROUP * pg )
737 {
738     pg->pgCurNC = pg->pgHeadNC;
739 
740     if( !pg->pgCurNC )
741         return 0;
742 
743     return pg->pgCurNC->rnRuleData;
744 }
745 
746 /*
747 **
748 **  NAME
749 **    prmGetNextRuleNC::
750 **
751 **  DESCRIPTION
752 **    Gets the next "no content" rule.  This function allows easy
753 **    walking of the "no content" rule list.
754 **
755 **  FORMAL INPUTS
756 **    PORT_GROUP * - PORT_GROUP to retrieve data from.
757 **
758 **  FORMAL OUTPUT
759 **    RULE_PTR - ptr to the user data
760 **
761 */
prmGetNextRuleNC(PORT_GROUP * pg)762 RULE_PTR prmGetNextRuleNC( PORT_GROUP * pg )
763 {
764     if( pg->pgCurNC )
765         pg->pgCurNC = pg->pgCurNC->rnNext;
766 
767     if( !pg->pgCurNC )
768         return 0;
769 
770     return pg->pgCurNC->rnRuleData;
771 }
772 
773 /*
774 **
775 **  NAME
776 **    prmAddRule::
777 **
778 **  DESCRIPTION
779 **    This function adds a rule to a PORT_RULE_MAP.  Depending on the
780 **    values of the sport and dport, the rule gets added in different
781 **    groups (src,dst,generic).  The values for dport and sport
782 **    can be: 0 -> 64K or -1 for generic (meaning that the rule applies
783 **    to all values.
784 **
785 **    Warning: Consider this carefully.
786 **    Some rules use 6000:6005 -> any  for a port designation, we could
787 **    add each rule to it's own group, in this case Src=6000 to 6005.
788 **    But we opt to add them as ANY rules for now, to reduce groups.
789 **
790 **    IMPORTANT:
791 **    This function adds a rule to the "content" list of rules.
792 **
793 **  FORMAL INPUTS
794 **    PORT_RULE_MAP * - PORT_RULE_MAP to add rule to.
795 **    int - the dst port value.
796 **    int - the src port value.
797 **    RULE_PTR - the ptr to the user data for the rule.
798 **
799 **  FORMAL OUTPUT
800 **    int - 0 is successful, 1 is failure.
801 **
802 */
prmAddRule(PORT_RULE_MAP * p,int dport,int sport,RULE_PTR rd)803 int prmAddRule( PORT_RULE_MAP * p, int dport, int sport, RULE_PTR rd )
804 {
805     if( dport != ANYPORT && dport < MAX_PORTS )  /* dst=21,25,80,110,139 */
806     {
807        p->prmNumDstRules++;
808 
809        /*
810        **  Check to see if this PORT_GROUP has been initialized
811        */
812        if(p->prmDstPort[dport] == NULL)
813        {
814            p->prmDstPort[dport] = (PORT_GROUP *)calloc(1, sizeof(PORT_GROUP));
815            if(p->prmDstPort[dport] == NULL)
816            {
817                return 1;
818            }
819        }
820 
821        if(p->prmDstPort[dport]->pgCount==0) p->prmNumDstGroups++;
822 
823        prmxAddPortRule( p->prmDstPort[ dport ], rd );
824     }
825 
826     if( sport != ANYPORT && sport < MAX_PORTS) /* src=ANY, SRC=80,21,25,etc. */
827     {
828        p->prmNumSrcRules++;
829 
830        /*
831        **  Check to see if this PORT_GROUP has been initialized
832        */
833        if(p->prmSrcPort[sport] == NULL)
834        {
835            p->prmSrcPort[sport] = (PORT_GROUP *)calloc(1, sizeof(PORT_GROUP));
836            if(p->prmSrcPort[sport] == NULL)
837            {
838                return 1;
839            }
840        }
841 
842        if(p->prmSrcPort[sport]->pgCount==0) p->prmNumSrcGroups++;
843 
844        prmxAddPortRule( p->prmSrcPort[ sport ], rd );
845     }
846 
847     if( sport == ANYPORT && dport == ANYPORT) /* dst=ANY, src=ANY */
848     {
849        p->prmNumGenericRules++;
850 
851        /*
852        **  Check to see if this PORT_GROUP has been initialized
853        */
854        if(p->prmGeneric == NULL)
855        {
856            p->prmGeneric = (PORT_GROUP *)calloc(1, sizeof(PORT_GROUP));
857            if(p->prmGeneric == NULL)
858            {
859                return 1;
860            }
861        }
862 
863        prmxAddPortRule( p->prmGeneric, rd );
864     }
865 
866   return 0;
867 }
868 
prmAddByteRule(BYTE_RULE_MAP * p,int dport,RULE_PTR rd)869 int prmAddByteRule( BYTE_RULE_MAP * p, int dport, RULE_PTR rd )
870 {
871     if( dport != ANYPORT && dport < 256 )  /* dst=21,25,80,110,139 */
872     {
873        p->prmNumRules++;
874        if( p->prmByteGroup[dport].pgCount==0 ) p->prmNumGroups++;
875 
876        prmxAddPortRule( &(p->prmByteGroup[ dport ]), rd );
877     }
878 
879     else if( dport == ANYPORT ) /* dst=ANY, src=ANY */
880     {
881        p->prmNumGenericRules++;
882 
883        prmxAddPortRule( &(p->prmGeneric), rd );
884     }
885 
886   return 0;
887 }
888 
889 /*
890 **
891 **  NAME
892 **    prmAddRuleUri::
893 **
894 **  DESCRIPTION
895 **    This function adds a rule to a PORT_RULE_MAP.  Depending on the
896 **    values of the sport and dport, the rule gets added in different
897 **    groups (src,dst,generic).  The values for dport and sport
898 **    can be: 0 -> 64K or -1 for generic (meaning that the rule applies
899 **    to all values.
900 **
901 **    Warning: Consider this carefully.
902 **    Some rules use 6000:6005 -> any  for a port designation, we could
903 **    add each rule to it's own group, in this case Src=6000 to 6005.
904 **    But we opt to add them as ANY rules for now, to reduce groups.
905 **
906 **    IMPORTANT:
907 **    This function adds a rule to the "uri" list of rules.
908 **
909 **  FORMAL INPUTS
910 **    PORT_RULE_MAP * - PORT_RULE_MAP to add rule to.
911 **    int - the dst port value.
912 **    int - the src port value.
913 **    RULE_PTR - the ptr to the user data for the rule.
914 **
915 **  FORMAL OUTPUT
916 **    int - 0 is successful, 1 is failure.
917 **
918 */
prmAddRuleUri(PORT_RULE_MAP * p,int dport,int sport,RULE_PTR rd)919 int prmAddRuleUri( PORT_RULE_MAP * p, int dport, int sport, RULE_PTR rd )
920 {
921     if( dport != ANYPORT && dport < MAX_PORTS )  /* dst=21,25,80,110,139 */
922     {
923        p->prmNumDstRules++;
924 
925        /*
926        **  Check to see if this PORT_GROUP has been initialized
927        */
928        if(p->prmDstPort[dport] == NULL)
929        {
930            p->prmDstPort[dport] = (PORT_GROUP *)calloc(1, sizeof(PORT_GROUP));
931            if(p->prmDstPort[dport] == NULL)
932            {
933                return 1;
934            }
935        }
936 
937        if(p->prmDstPort[dport]->pgCount==0) p->prmNumDstGroups++;
938 
939        prmxAddPortRuleUri( p->prmDstPort[ dport ], rd );
940     }
941 
942     if( sport != ANYPORT && sport < MAX_PORTS) /* src=ANY, SRC=80,21,25,etc. */
943     {
944        p->prmNumSrcRules++;
945 
946        /*
947        **  Check to see if this PORT_GROUP has been initialized
948        */
949        if(p->prmSrcPort[sport] == NULL)
950        {
951            p->prmSrcPort[sport] = (PORT_GROUP *)calloc(1, sizeof(PORT_GROUP));
952            if(p->prmSrcPort[sport] == NULL)
953            {
954                return 1;
955            }
956        }
957 
958        if(p->prmSrcPort[sport]->pgCount==0) p->prmNumSrcGroups++;
959 
960        prmxAddPortRuleUri( p->prmSrcPort[ sport ], rd );
961     }
962 
963     if( sport == ANYPORT && dport == ANYPORT) /* dst=ANY, src=ANY */
964     {
965        p->prmNumGenericRules++;
966 
967        /*
968        **  Check to see if this PORT_GROUP has been initialized
969        */
970        if(p->prmGeneric == NULL)
971        {
972            p->prmGeneric = (PORT_GROUP *)calloc(1, sizeof(PORT_GROUP));
973            if(p->prmGeneric == NULL)
974            {
975                return 1;
976            }
977        }
978 
979        prmxAddPortRuleUri( p->prmGeneric, rd );
980     }
981 
982   return 0;
983 }
984 
985 /*
986 **
987 **  NAME
988 **    prmAddRuleNC::
989 **
990 **  DESCRIPTION
991 **    This function adds a rule to a PORT_RULE_MAP.  Depending on the
992 **    values of the sport and dport, the rule gets added in different
993 **    groups (src,dst,generic).  The values for dport and sport
994 **    can be: 0 -> 64K or -1 for generic (meaning that the rule applies
995 **    to all values.
996 **
997 **    Warning: Consider this carefully.
998 **    Some rules use 6000:6005 -> any  for a port designation, we could
999 **    add each rule to it's own group, in this case Src=6000 to 6005.
1000 **    But we opt to add them as ANY rules for now, to reduce groups.
1001 **
1002 **    IMPORTANT:
1003 **    This function adds a rule to the "no content" list of rules.
1004 **
1005 **  FORMAL INPUTS
1006 **    PORT_RULE_MAP * - PORT_RULE_MAP to add rule to.
1007 **    int - the dst port value.
1008 **    int - the src port value.
1009 **    RULE_PTR - the ptr to the user data for the rule.
1010 **
1011 **  FORMAL OUTPUT
1012 **    int - 0 is successful, 1 is failure.
1013 **
1014 */
prmAddRuleNC(PORT_RULE_MAP * p,int dport,int sport,RULE_PTR rd)1015 int prmAddRuleNC( PORT_RULE_MAP * p, int dport, int sport, RULE_PTR rd )
1016 {
1017     if( dport != ANYPORT && dport < MAX_PORTS )  /* dst=21,25,80,110,139 */
1018     {
1019        p->prmNumDstRules++;
1020 
1021        /*
1022        **  Check to see if this PORT_GROUP has been initialized
1023        */
1024        if(p->prmDstPort[dport] == NULL)
1025        {
1026            p->prmDstPort[dport] = (PORT_GROUP *)calloc(1, sizeof(PORT_GROUP));
1027            if(p->prmDstPort[dport] == NULL)
1028            {
1029                return 1;
1030            }
1031        }
1032 
1033        if(p->prmDstPort[dport]->pgCount==0) p->prmNumDstGroups++;
1034 
1035        prmxAddPortRuleNC( p->prmDstPort[ dport ], rd );
1036     }
1037 
1038     if( sport != ANYPORT && sport < MAX_PORTS) /* src=ANY, SRC=80,21,25,etc. */
1039     {
1040        p->prmNumSrcRules++;
1041 
1042        /*
1043        **  Check to see if this PORT_GROUP has been initialized
1044        */
1045        if(p->prmSrcPort[sport] == NULL)
1046        {
1047            p->prmSrcPort[sport] = (PORT_GROUP *)calloc(1, sizeof(PORT_GROUP));
1048            if(p->prmSrcPort[sport] == NULL)
1049            {
1050                return 1;
1051            }
1052        }
1053 
1054        if(p->prmSrcPort[sport]->pgCount==0) p->prmNumSrcGroups++;
1055 
1056        prmxAddPortRuleNC( p->prmSrcPort[ sport ], rd );
1057     }
1058 
1059     if( sport == ANYPORT && dport == ANYPORT) /* dst=ANY, src=ANY */
1060     {
1061        p->prmNumGenericRules++;
1062 
1063        /*
1064        **  Check to see if this PORT_GROUP has been initialized
1065        */
1066        if(p->prmGeneric == NULL)
1067        {
1068            p->prmGeneric = (PORT_GROUP *)calloc(1, sizeof(PORT_GROUP));
1069            if(p->prmGeneric == NULL)
1070            {
1071                return 1;
1072            }
1073        }
1074 
1075        prmxAddPortRuleNC( p->prmGeneric, rd );
1076     }
1077 
1078   return 0;
1079 }
1080 
1081 
prmAddByteRuleNC(BYTE_RULE_MAP * p,int dport,RULE_PTR rd)1082 int prmAddByteRuleNC( BYTE_RULE_MAP * p, int dport, RULE_PTR rd )
1083 {
1084     if( dport != ANYPORT && dport < 256 )  /* dst=21,25,80,110,139 */
1085     {
1086        p->prmNumRules++;
1087        if(p->prmByteGroup[dport].pgCount==0) p->prmNumGroups++;
1088 
1089        prmxAddPortRuleNC( &(p->prmByteGroup[ dport ]), rd );
1090     }
1091 
1092     else if( dport == ANYPORT) /* dst=ANY, src=ANY */
1093     {
1094        p->prmNumGenericRules++;
1095 
1096        prmxAddPortRuleNC( &(p->prmGeneric), rd );
1097     }
1098 
1099   return 0;
1100 }
1101 
1102 /*
1103 **
1104 **  NAME
1105 **    prmFindRuleGroup::
1106 **
1107 **  DESCRIPTION
1108 **    Given a PORT_RULE_MAP, this function selects the PORT_GROUP or
1109 **    PORT_GROUPs necessary to fully match a given dport, sport pair.
1110 **    The selection logic looks at both the dport and sport and
1111 **    determines if one or both are unique.  If one is unique, then
1112 **    the appropriate PORT_GROUP ptr is set.  If both are unique, then
1113 **    both th src and dst PORT_GROUP ptrs are set.  If neither of the
1114 **    ports are unique, then the gen PORT_GROUP ptr is set.
1115 **
1116 **  FORMAL INPUTS
1117 **    PORT_RULE_MAP * - the PORT_RULE_MAP to pick PORT_GROUPs from.
1118 **    int             - the dst port value (0->64K or -1 for generic)
1119 **    int             - the src port value (0->64K or -1 for generic)
1120 **    PORT_GROUP **   - the src PORT_GROUP ptr to set.
1121 **    PORT_GROUP **   - the dst PORT_GROUP ptr to set.
1122 **    PORT_GROUP **   - the generic PORT_GROUP ptr to set.
1123 **
1124 **  FORMAL OUTPUT
1125 **    int -  0: Don't evaluate
1126 **           1: There are port groups to evaluate
1127 **
1128 **  NOTES
1129 **    Currently, if there is a "unique conflict", we return both the src
1130 **    and dst PORT_GROUPs.  This conflict forces us to do two searches, one
1131 **    for the src and one for the dst.  So we are taking twice the time to
1132 **    inspect a packet then usual.  Obviously, this is not good.  There
1133 **    are several options that we have to deal with unique conflicts, but
1134 **    have not implemented any currently.  The optimum solution will be to
1135 **    incorporate streaming and protocol analysis to a session so we know
1136 **    what to match against.
1137 **
1138 */
1139 int
prmFindRuleGroup(PORT_RULE_MAP * p,int dport,int sport,PORT_GROUP ** src,PORT_GROUP ** dst,PORT_GROUP ** ns_src,PORT_GROUP ** ns_dst,PORT_GROUP ** gen)1140 prmFindRuleGroup(
1141         PORT_RULE_MAP *p,
1142         int dport,
1143         int sport,
1144         PORT_GROUP **src,
1145         PORT_GROUP **dst,
1146 #ifdef TARGET_BASED
1147         PORT_GROUP **ns_src,
1148         PORT_GROUP **ns_dst,
1149 #endif
1150         PORT_GROUP **gen
1151         )
1152 {
1153     if (!p || !src || !dst || !gen)
1154         return 0;
1155 
1156     *src = NULL;
1157     *dst = NULL;
1158     *gen = NULL;
1159 
1160 #ifdef TARGET_BASED
1161     if ( !ns_src || !ns_dst )
1162         return 0;
1163 
1164     *ns_src = NULL;
1165     *ns_dst = NULL;
1166 #endif
1167 
1168     if (dport != ANYPORT && dport < MAX_PORTS)
1169     {
1170         *dst = p->prmDstPort[dport];
1171 #ifdef TARGET_BASED
1172         *ns_dst = p->prmNoServiceDstPort[dport];
1173 #endif
1174     }
1175 
1176     if (sport != ANYPORT && sport < MAX_PORTS)
1177     {
1178         *src = p->prmSrcPort[sport];
1179 #ifdef TARGET_BASED
1180         *ns_src = p->prmNoServiceSrcPort[sport];
1181 #endif
1182 
1183     }
1184 
1185     /* If no Src/Dst rules - use the generic set, if any exist  */
1186     if (p->prmGeneric != NULL && p->prmGeneric->pgCount > 0)
1187     {
1188         if (fpDetectSplitAnyAny(snort_conf->fast_pattern_config) || (!*src && !*dst))
1189         {
1190             *gen = p->prmGeneric;
1191         }
1192     }
1193 
1194     if (*src == NULL && *dst == NULL && *gen == NULL)
1195     {
1196 #ifdef TARGET_BASED
1197         if (*ns_src == NULL && *ns_dst == NULL)
1198 #endif
1199         {
1200             return 0;
1201         }
1202     }
1203 
1204     return 1;
1205 }
1206 
1207 #ifdef TARGET_BASED
prmFindNoServiceRuleGroup(PORT_RULE_MAP * p,int dport,int sport,PORT_GROUP ** src,PORT_GROUP ** dst,PORT_GROUP ** gen)1208 int prmFindNoServiceRuleGroup (
1209         PORT_RULE_MAP *p,
1210         int dport,
1211         int sport,
1212         PORT_GROUP ** src,
1213         PORT_GROUP ** dst,
1214         PORT_GROUP ** gen )
1215 {
1216     if (!p || !src || !dst)
1217         return 0;
1218 
1219     *src = NULL;
1220     *dst = NULL;
1221     *gen = NULL;
1222 
1223     if (dport != ANYPORT && dport < MAX_PORTS)
1224         *dst = p->prmNoServiceDstPort[dport];
1225 
1226     if (sport != ANYPORT && sport < MAX_PORTS)
1227         *src = p->prmNoServiceSrcPort[sport];
1228 
1229     if (p->prmGeneric != NULL && p->prmGeneric->pgCount > 0)
1230     {
1231         if (fpDetectSplitAnyAny(snort_conf->fast_pattern_config) || (!*src && !*dst))
1232         {
1233             *gen = p->prmGeneric;
1234         }
1235     }
1236 
1237     if (*src || *dst || *gen)
1238         return 1;
1239 
1240     return 0;
1241 }
1242 #endif
1243 
prmFindGenericRuleGroup(PORT_RULE_MAP * p,PORT_GROUP ** gen)1244 int prmFindGenericRuleGroup(PORT_RULE_MAP *p, PORT_GROUP ** gen)
1245 {
1246     if (gen == NULL)
1247     {
1248         return 0;
1249     }
1250 
1251     *gen = NULL;
1252     if ((p->prmGeneric != NULL) && (p->prmGeneric->pgCount > 0))
1253     {
1254         if (fpDetectSplitAnyAny(snort_conf->fast_pattern_config))
1255         {
1256             *gen = p->prmGeneric;
1257             return 1;
1258         }
1259     }
1260     return 0;
1261 }
1262 
1263 /*
1264 *
1265 */
prmFindByteRuleGroup(BYTE_RULE_MAP * p,int dport,PORT_GROUP ** dst,PORT_GROUP ** gen)1266 int prmFindByteRuleGroup( BYTE_RULE_MAP * p, int dport, PORT_GROUP **dst , PORT_GROUP ** gen)
1267 {
1268     int stat= 0;
1269 
1270     if( (dport != ANYPORT && dport < 256 ) && p->prmByteGroup[dport].pgCount  )
1271     {
1272          *dst  = &p->prmByteGroup[dport];
1273          stat = 1;
1274 
1275     }else{
1276 
1277        *dst=0;
1278     }
1279 
1280     /* If no Src/Dst rules - use the generic set, if any exist  */
1281     if( !stat &&  (p->prmGeneric.pgCount > 0) )
1282     {
1283        *gen  = &p->prmGeneric;
1284         stat = 4;
1285 
1286     }else{
1287 
1288       *gen = 0;
1289     }
1290 
1291 
1292     return stat;
1293 }
1294 
1295 /*
1296 ** Access each Rule group by index (0-MAX_PORTS)
1297 */
prmFindDstRuleGroup(PORT_RULE_MAP * p,int port)1298 PORT_GROUP * prmFindDstRuleGroup( PORT_RULE_MAP * p, int port )
1299 {
1300     if( port < 0 || port >= MAX_PORTS ) return 0;
1301 
1302     if( p->prmDstPort[port])
1303         return p->prmDstPort[port];
1304 
1305     return 0;
1306 }
1307 
1308 /*
1309 ** Access each Rule group by index (0-MAX_PORTS)
1310 */
prmFindSrcRuleGroup(PORT_RULE_MAP * p,int port)1311 PORT_GROUP * prmFindSrcRuleGroup( PORT_RULE_MAP * p, int port )
1312 {
1313     if( port < 0 || port >= MAX_PORTS ) return 0;
1314 
1315     if( p->prmSrcPort[port])
1316       return p->prmSrcPort[port];
1317 
1318     return 0;
1319 }
1320 
1321 
1322 /*
1323 ** Assign the pattern matching data to this group
1324 */
prmSetGroupPatData(PORT_GROUP * pg,void * data)1325 int prmSetGroupPatData( PORT_GROUP * pg, void * data )
1326 {
1327     pg->pgPms[PM_TYPE__CONTENT] = data;
1328     return 0;
1329 }
1330 
1331 /*
1332 ** Get the patttern matching data for this group
1333 */
prmGetGroupPatData(PORT_GROUP * pg)1334 void * prmGetGroupPatData( PORT_GROUP * pg )
1335 {
1336     return pg->pgPms[PM_TYPE__CONTENT];
1337 }
1338 
1339 /*
1340 **
1341 **  NAME
1342 **    prmCompileGroups::
1343 **
1344 **  DESCRIPTION
1345 **    Add Generic rules to each Unique rule group, this could be
1346 **    optimized a bit, right now we will process generic rules
1347 **    twice when packets have 2 unique ports, but this will not
1348 **    occur often.
1349 **
1350 **    The generic rules are added to the Unique rule groups, so that
1351 **    the setwise methodology can be taking advantage of.
1352 **
1353 **  FORMAL INPUTS
1354 **    PORT_RULE_MAP * - the PORT_RULE_MAP to compile generice rules.
1355 **
1356 **  FORMAL OUTPUT
1357 **    int - 0 is successful;
1358 **
1359 */
prmCompileGroups(PORT_RULE_MAP * p)1360 int prmCompileGroups( PORT_RULE_MAP * p )
1361 {
1362    PORT_GROUP *pgGen, *pgSrc, *pgDst;
1363    RULE_PTR   *prule;
1364    int  i;
1365 
1366    /*
1367    **  Add Generic to Src and Dst groups
1368    */
1369    pgGen = p->prmGeneric;
1370 
1371    if(!pgGen)
1372         return 0;
1373 
1374    for(i=0;i<MAX_PORTS;i++)
1375    {
1376      /* Add to the Unique Src and Dst Groups as well,
1377      ** but don't inc thier prmNUMxxx counts, we want these to be true Unique counts
1378      ** we can add the Generic numbers if we want these, besides
1379      ** each group has it's own count.
1380      */
1381 
1382      if(p->prmSrcPort[i])
1383      {
1384         pgSrc = p->prmSrcPort[i];
1385 
1386         prule = prmGetFirstRule( pgGen );
1387         while( prule )
1388         {
1389            prmxAddPortRule( pgSrc, prule );
1390            prule = prmGetNextRule( pgGen );
1391         }
1392 
1393         prule = prmGetFirstRuleUri( pgGen );
1394         while( prule )
1395         {
1396            prmxAddPortRuleUri( pgSrc, prule );
1397            prule = prmGetNextRuleUri( pgGen );
1398         }
1399 
1400         prule = prmGetFirstRuleNC( pgGen );
1401         while( prule )
1402         {
1403            prmxAddPortRuleNC( pgSrc, prule );
1404            prule = prmGetNextRuleNC( pgGen );
1405         }
1406      }
1407 
1408      if(p->prmDstPort[i])
1409      {
1410         pgDst = p->prmDstPort[i];
1411 
1412         prule = prmGetFirstRule( pgGen );
1413         while( prule )
1414         {
1415            prmxAddPortRule( pgDst, prule );
1416            prule = prmGetNextRule( pgGen );
1417         }
1418 
1419         prule = prmGetFirstRuleUri( pgGen );
1420         while( prule )
1421         {
1422            prmxAddPortRuleUri( pgDst, prule );
1423            prule = prmGetNextRuleUri( pgGen );
1424         }
1425 
1426         prule = prmGetFirstRuleNC( pgGen );
1427         while( prule )
1428         {
1429            prmxAddPortRuleNC( pgDst, prule );
1430            prule = prmGetNextRuleNC( pgGen );
1431         }
1432      }
1433 
1434 #ifdef TARGET_BASED
1435      if(p->prmNoServiceDstPort[i])
1436      {
1437          pgDst = p->prmNoServiceDstPort [i];
1438 
1439          for (prule = prmGetFirstRule (pgGen); prule; prule = prmGetNextRule (pgGen))
1440              prmxAddPortRule (pgDst, prule);
1441          for (prule = prmGetFirstRuleUri (pgGen); prule; prule = prmGetNextRuleUri (pgGen))
1442              prmxAddPortRuleUri (pgDst, prule);
1443          for (prule = prmGetFirstRuleNC (pgGen); prule; prule = prmGetNextRuleNC (pgGen))
1444              prmxAddPortRuleNC (pgDst, prule);
1445      }
1446 
1447      if(p->prmNoServiceSrcPort[i])
1448      {
1449          pgSrc = p->prmNoServiceSrcPort [i];
1450 
1451          for (prule = prmGetFirstRule (pgGen); prule; prule = prmGetNextRule (pgGen))
1452              prmxAddPortRule (pgSrc, prule);
1453          for (prule = prmGetFirstRuleUri (pgGen); prule; prule = prmGetNextRuleUri (pgGen))
1454              prmxAddPortRuleUri (pgSrc, prule);
1455          for (prule = prmGetFirstRuleNC (pgGen); prule; prule = prmGetNextRuleNC (pgGen))
1456              prmxAddPortRuleNC (pgSrc, prule);
1457      }
1458 #endif // TARGET_BASED
1459 
1460 
1461    }
1462 
1463    return 0;
1464 }
1465 
1466 
1467 /*
1468 *
1469 *
1470 */
prmCompileByteGroups(BYTE_RULE_MAP * p)1471 int prmCompileByteGroups( BYTE_RULE_MAP * p )
1472 {
1473    PORT_GROUP *pgGen, *pgByte;
1474    RULE_PTR   *prule;
1475    int  i;
1476 
1477    /*
1478    **  Add Generic to Unique groups
1479    */
1480    pgGen = &p->prmGeneric;
1481 
1482    if( !pgGen->pgCount )
1483         return 0;
1484 
1485    for(i=0;i<256;i++)
1486    {
1487       if(p->prmByteGroup[i].pgCount)
1488       {
1489         pgByte = &p->prmByteGroup[i];
1490 
1491         prule = prmGetFirstRule( pgGen );
1492         while( prule )
1493         {
1494            prmxAddPortRule( pgByte, prule );
1495            prule = prmGetNextRule( pgGen );
1496         }
1497 
1498         prule = prmGetFirstRuleNC( pgGen );
1499         while( prule )
1500         {
1501            prmxAddPortRuleNC( pgByte, prule );
1502            prule = prmGetNextRuleNC( pgGen );
1503         }
1504      }
1505    }
1506 
1507    return 0;
1508 }
1509 
1510 /*
1511 **
1512 **  NAME
1513 **    prmShowStats::
1514 **
1515 **  DESCRIPTION
1516 **    This function shows some basic stats on the fast packet
1517 **    classification.  It show the the number of PORT_GROUPS
1518 **    for a PORT_RULE_MAP, and the break down of the different
1519 **    rule types (content, uri, no content).
1520 **
1521 **  FORMAL INPUTS
1522 **    PORT_RULE_MAP * - the PORT_RULE_MAP to show stats on.
1523 **
1524 **  FORMAL OUTPUT
1525 **    int - 0 is successful.
1526 **
1527 */
prmShowStats(PORT_RULE_MAP * p)1528 int prmShowStats( PORT_RULE_MAP * p )
1529 {
1530    int i;
1531    PORT_GROUP * pg;
1532 
1533    LogMessage("Packet Classification Rule Manager Stats ----\n");
1534    LogMessage("NumDstGroups   : %d\n",p->prmNumDstGroups);
1535    LogMessage("NumSrcGroups   : %d\n",p->prmNumSrcGroups);
1536    LogMessage("\n");
1537    LogMessage("NumDstRules    : %d\n",p->prmNumDstRules);
1538    LogMessage("NumSrcRules    : %d\n",p->prmNumSrcRules);
1539    LogMessage("NumGenericRules: %d\n",p->prmNumGenericRules);
1540    LogMessage("\n");
1541 
1542    LogMessage("%d Dst Groups In Use, %d Unique Rules, includes generic\n",p->prmNumDstGroups,p->prmNumDstRules);
1543    for(i=0;i<MAX_PORTS;i++)
1544    {
1545      pg = prmFindDstRuleGroup( p, i );
1546      if(pg)
1547      {
1548        LogMessage("  Dst Port %5d : %d uricontent, %d content, %d nocontent \n",i,
1549                  pg->pgUriContentCount,pg->pgContentCount,pg->pgNoContentCount);
1550        if( pg->avgLen )
1551        {
1552          LogMessage("MinLen=%d MaxLen=%d AvgLen=%d",pg->minLen,pg->maxLen,pg->avgLen);
1553          if(pg->c1)LogMessage(" [1]=%d",pg->c1);
1554          if(pg->c2)LogMessage(" [2]=%d",pg->c2);
1555          if(pg->c3)LogMessage(" [3]=%d",pg->c3);
1556          if(pg->c4)LogMessage(" [4]=%d",pg->c4);
1557          LogMessage("\n");
1558        }
1559      }
1560    }
1561 
1562    LogMessage("%d Src Groups In Use, %d Unique Rules, includes generic\n",p->prmNumSrcGroups,p->prmNumSrcRules);
1563    for(i=0;i<MAX_PORTS;i++)
1564    {
1565      pg = prmFindSrcRuleGroup( p, i );
1566      if(pg){
1567         LogMessage("  Src Port %5d : %d uricontent, %d content, %d nocontent \n",i,
1568                  pg->pgUriContentCount,pg->pgContentCount,pg->pgNoContentCount);
1569         if( pg->avgLen )
1570 	{
1571 	   LogMessage("MinLen=%d MaxLen=%d AvgLen=%d",pg->minLen,pg->maxLen,pg->avgLen);
1572           if(pg->c1)LogMessage(" [1]=%d",pg->c1);
1573           if(pg->c2)LogMessage(" [2]=%d",pg->c2);
1574           if(pg->c3)LogMessage(" [3]=%d",pg->c3);
1575           if(pg->c4)LogMessage(" [4]=%d",pg->c4);
1576           LogMessage("\n");
1577 	}
1578      }
1579    }
1580 
1581    pg = p->prmGeneric;
1582      if(pg){
1583         LogMessage("   Generic Rules : %d uricontent, %d content, %d nocontent \n",
1584                  pg->pgUriContentCount,pg->pgContentCount,pg->pgNoContentCount);
1585         if( pg->avgLen )
1586 	{
1587 	  LogMessage("MinLen=%d MaxLen=%d AvgLen=%d",pg->minLen,pg->maxLen,pg->avgLen);
1588           if(pg->c1)LogMessage(" [1]=%d",pg->c1);
1589           if(pg->c2)LogMessage(" [2]=%d",pg->c2);
1590           if(pg->c3)LogMessage(" [3]=%d",pg->c3);
1591           if(pg->c4)LogMessage(" [4]=%d",pg->c4);
1592           LogMessage("\n");
1593 	}
1594      }
1595 
1596    return 0;
1597 }
1598 
1599 
1600 /*
1601 **
1602 **  NAME
1603 **    prmShowEventStats::
1604 **
1605 **  DESCRIPTION
1606 **    This function is used at the close of the Fast Packet
1607 **    inspection.  It tells how many non-qualified and qualified
1608 **    hits occurred for each PORT_GROUP.  A non-qualified hit
1609 **    is defined by an initial match against a packet, but upon
1610 **    further inspection a hit was not validated.  Non-qualified
1611 **    hits occur because we can match on the most unique aspect
1612 **    of a packet, this is the content.  Snort has other flags
1613 **    then content though, so once we hit a content match we must
1614 **    verify these additional flags.  Sometimes these flags do
1615 **    not pass the validation.  A qualified hit is an event that
1616 **    has been fully qualified, and has been put in the event
1617 **    cache for event selection.  Qualified hits are not a subset
1618 **    of non-qualified hits.  Ideally, non-qualified hits should
1619 **    be zero.  The reason for these stats is that it allows
1620 **    users to trouble shoot PORT_GROUPs.  A poorly written rule
1621 **    may cause many non-qualified events, and these stats
1622 **    allow the user to track this down.
1623 **
1624 **  FORMAL INPUTS
1625 **    PORT_RULE_MAP * -  the PORT_RULE_MAP to show stats on.
1626 **
1627 **  FORMAL OUTPUT
1628 **    int - 0 is successful.
1629 **
1630 */
prmShowEventStats(PORT_RULE_MAP * p)1631 int prmShowEventStats( PORT_RULE_MAP * p )
1632 {
1633    int i;
1634    PORT_GROUP * pg;
1635 
1636    int NQEvents = 0;
1637    int QEvents = 0;
1638 
1639    LogMessage("Packet Classification Rule Manager Stats ----\n");
1640    LogMessage("NumDstGroups   : %d\n",p->prmNumDstGroups);
1641    LogMessage("NumSrcGroups   : %d\n",p->prmNumSrcGroups);
1642    LogMessage("\n");
1643    LogMessage("NumDstRules    : %d\n",p->prmNumDstRules);
1644    LogMessage("NumSrcRules    : %d\n",p->prmNumSrcRules);
1645    LogMessage("NumGenericRules: %d\n",p->prmNumGenericRules);
1646    LogMessage("\n");
1647 
1648    LogMessage("%d Dst Groups In Use, %d Unique Rules, includes generic\n",p->prmNumDstGroups,p->prmNumDstRules);
1649    for(i=0;i<MAX_PORTS;i++)
1650    {
1651      pg = prmFindDstRuleGroup( p, i );
1652      if(pg)
1653      {
1654        NQEvents += pg->pgNQEvents;
1655        QEvents  += pg->pgQEvents;
1656 
1657        if( pg->pgNQEvents + pg->pgQEvents )
1658        {
1659           LogMessage("  Dst Port %5d : %d group entries \n",i, pg->pgCount);
1660           LogMessage("    NQ Events  : %d\n", pg->pgNQEvents);
1661           LogMessage("     Q Events  : %d\n", pg->pgQEvents);
1662        }
1663      }
1664    }
1665 
1666    LogMessage("%d Src Groups In Use, %d Unique Rules, includes generic\n",p->prmNumSrcGroups,p->prmNumSrcRules);
1667    for(i=0;i<MAX_PORTS;i++)
1668    {
1669      pg = prmFindSrcRuleGroup( p, i );
1670      if(pg)
1671      {
1672 
1673         NQEvents += pg->pgNQEvents;
1674         QEvents += pg->pgQEvents;
1675 
1676         if( pg->pgNQEvents + pg->pgQEvents )
1677         {
1678           LogMessage("  Src Port %5d : %d group entries \n",i, pg->pgCount);
1679           LogMessage("    NQ Events  : %d\n", pg->pgNQEvents);
1680           LogMessage("     Q Events  : %d\n", pg->pgQEvents);
1681         }
1682      }
1683    }
1684 
1685    pg = p->prmGeneric;
1686    if(pg)
1687    {
1688       NQEvents += pg->pgNQEvents;
1689       QEvents += pg->pgQEvents;
1690 
1691       if( pg->pgNQEvents + pg->pgQEvents )
1692       {
1693         LogMessage("  Generic Rules : %d group entries\n", pg->pgCount);
1694         LogMessage("    NQ Events   : %d\n", pg->pgNQEvents);
1695         LogMessage("     Q Events   : %d\n", pg->pgQEvents);
1696       }
1697    }
1698 
1699    LogMessage("Total NQ Events : %d\n", NQEvents);
1700    LogMessage("Total  Q Events  : %d\n", QEvents);
1701 
1702    return 0;
1703 }
1704 
1705