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