1 /****************************************************************************
2 *
3 * Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
4 * Copyright (C) 2005-2013 Sourcefire, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License Version 2 as
8 * published by the Free Software Foundation. You may not use, modify or
9 * distribute this program under any other version of the GNU General
10 * Public License.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 ****************************************************************************/
22
23 /*
24 sfportobject.c
25
26 author: marc norton
27 date: 11/05/2005
28
29 description:
30
31 Port objects provides support for generic ports lists comprised of
32 individual ports, port ranges, and negation of ports and port ranges.
33
34 Port lists require a somewhat more complex scheme to determine the proper
35 grouping of rules for each port while minimizing the number of rule groups
36 created. We can use a single group of rules in the multi-pattern detection phase,
37 however that can have a huge impact on performance. Instead we try to create
38 a smaller grouping of rules that might be applicable to each port.
39
40 As rules are defined using port ranges, and port lists there will be port
41 overlapps between rules. This requires us to determine whether we should
42 create one larger rule group to apply to all relevant ports, or to
43 create multiple rule groups and apply the smallest applicable one to
44 each port. In practice snort has some rules which span almost all 64K ports
45 which might cause all rules in all port-rule groups to be merged into one set
46 unless we apply a more complex logic than simply merging rule-port groups
47 with common ports. This is the problem addressed by the sfportobject
48 module.
49
50 port list examples of acceptable usage:
51
52 - var has been overloaded, if it includes _port we add as a port-object also.
53 var http_ports 80
54 var http_range_ports 80:81
55 var http_list_ports [80,8080,8138]
56
57 - portvar has been added to indicate portvariables, this form does not require _port
58 portvar http 80
59 portvar http_range 80:81
60 portvar http_list [80,8080,8138]
61
62 80
63 $http
64 !90
65 80:81
66 $http_range
67 !90:91
68 [80,8080,8138]
69 $http_list
70 [$http,$http_list]
71 [2001,2008,20022,8100:8150,!8121,!8123]
72 [!any] - uhhh, why do people ask about this ?
73
74 Rules are defined using a port, a port-range or a list of these, we call
75 these port objects.
76
77 As rules are loaded we generate some large rule counts on some ports, and
78 small rule counts on most ports. If for each port you build a list of
79 rules on that port, we may end up with some ports with a large rule set that
80 differs by the addition of a few rules on each port (relative to the group sizes)
81 we don't want to generate compeletely different rule groups for these as that
82 would than generate multiple large state machines for the multi-pattern matching
83 phase of the detection engine which in turn could use a lot of memory.
84
85 It turns out that one scheme, the one used herein, provides some blending
86 of rule groups to minimize memory, and tries to minimize large group sizes
87 to keep performance more optimal - although this is at the expense of memory.
88
89 --- Port variables
90 Var - has been overloaded. If it's name includes _port as part of the var name it is
91 added to the PortVarTable.
92 PortVar - has been added. These are always added to the PortVarTable.
93
94 --- Loading Port lists and rules
95 PortTables - we support src and dst tables for tcp/udp/icmp/ip/arp rules.
96 PortVar References - we dup the PortVar entries as needed into each table if referenced,
97 so HTTP_PORTS for tcp and udp contain different rules. If a rule references a PortVar
98 we look it up in the table, if its not present we dup it from the PortVarTable, otherwise
99 we just add the rule index to the PortVar HTTP_PORTS in the proper table. If a PortVar
100 is not used to specify a Port entry in a rule we create a temp port-object, and check if
101 it's port-list is already in the table. If it's not we make the temp port-object the
102 permanent entry in the table. If it is, we just add the rule index to the existing entry,
103 and delete the temp port-object. When the rules are done loading we should have a set of
104 port-objects with port-lists that differ by at least one port. The next step handles the
105 cases where we have multiple port-objects with at least one common port.
106
107 --- Merging Ports and Rules
108 We maintain for each port a list of port objects and their rules that apply
109 to it. This allows us to view combining the rules associated with each port
110 object using a few heuristics. A list of port objects applicable to each port
111 presents rules in one of four catagories:
112
113 1) a single port object, and all rules associated with it.
114 2) multiple port objects each with a small set of rules associated with it.
115 3) one port object with a large rule set, and one or more port objects
116 with a small set of rules associated with each.
117 4) multiple port objects with large rule sets, and zero or more port objects
118 each with a small set of rules associated with it.
119
120 We process these four categories as follows:
121
122 1) -a single port object (large or small)
123 do nothing, each port referencing this port object is complete.
124 2) -multiple small port objects
125 merge the rules for all port objects into one virtual object,
126 for each port in this category lookup it's combined port object
127 to see if it's already defined, if not create one. This way
128 all ports that have the same port groups point to the same virtual
129 port object.
130 3) -one large port object, and one or more small port objects
131 add the small rule groups into the large rule set, using the existing
132 port object.
133 4) -multiple large port objects and zero or more small port objects
134 merge the large port objects into a virtual port object and
135 add all rules from both large and small sets into it's rule set.
136 we use the combined large group ports to form a key, so any ports
137 referencing just these large rule groups, and some small ones
138 will be recognized as the same. This handles cases where we have
139 2,3,4.etc large rule groups combined. Any time we see a 'n' grouping
140 of the same large rule sets we'll look it up and point to it for that
141 port.
142
143 To determine when a port object has a large rule set or a small one we use
144 a simple threshold value. In theory the larger this value is the more
145 merging of rules in category 2 and 3 will occur. When this value is
146 small category 4 should become a more prevalent situation. However,
147 the behavior of groupings for a given threshold can change as more rules
148 are added to port groups. Therefore generous statistics are printed after
149 the rules and port objects are compiled into their final groupings.
150
151
152 Procedure for using PortLists
153
154 1) Process Var's as PortVar's and standard Var's (for now). This allows
155 existing snort features to work, with the Var's. Add in the PortVar support
156 to parse the Var input into PortObjects, and add these to the PortVartable.
157
158 2) Read Rules
159 a) Read port numbers and lists
160 1) Dereference PortVar/Var Names if any are referenced.
161 b) Create a Port Object
162 c) Test if this Port object exists already,
163 1) If so, add the sid to it.
164 2) If not add it ....
165
166
167
168 Notes:
169
170 All any-any port rules are managed separately, and added in to the final
171 rules lists of each port group after this analysis. Rules defined with
172 ranges are no longer considered any-any rules for the purpose of organizing
173 port-rule groupings. This should help prevent some cross fertilization of
174 rule groups with rules that are unneccessary, this causes rule group
175 sizes to bloat and performance to slow.
176
177 Hierarchy:
178
179 PortTable -> PortObject's
180
181 PortVar -> PortObject ( These are pure, and are dup'ed for use in the PortTables )
182
183 PortObject -> PortObjectItems (port or port range)
184
185 */
186
187
188 #include <stdlib.h>
189 #include <string.h>
190 #include <sys/types.h>
191 #include <ctype.h>
192
193 #ifdef HAVE_CONFIG_H
194 #include "config.h"
195 #endif
196
197 #include "sf_types.h"
198
199 #include "snort.h"
200 #include "snort_bounds.h"
201 #include "snort_debug.h"
202 #include "sfportobject.h"
203 #include "sfrim.h"
204 #include "util.h"
205
206 #define PO_EXTRA_RULE_CNT 25
207 #define PTBL_LRC_DEFAULT 10
208 #define PO_INIT_ID 1000000
209 #define PO_HASH_TBL_ROWS 10000
210
211 /*
212 Hash Key Comparisons for treating PortObjects as Keys
213
214 return values memcmp style
215 */
216 static
PortObject_keycmp(const void * a,const void * b,size_t n)217 int PortObject_keycmp( const void *a , const void *b, size_t n )
218 {
219 #ifdef WIN32
220 n = n;
221 #endif
222 return !PortObjectEqual( *(PortObject**)a, *(PortObject**)b );
223 }
224
225 /*
226 * plx_t is a variable sized array of pointers
227 */
228 typedef struct {
229 int n;
230 void ** p;
231 }plx_t;
232
233 static
plx_new(void * pv_array[],int n)234 plx_t * plx_new( void * pv_array[], int n )
235 {
236 plx_t * p;
237 int i;
238
239 if(!pv_array || n < 0)
240 return NULL;
241
242 p = SnortAlloc(sizeof(plx_t));
243
244 p->p = SnortAlloc(n * sizeof(void*));
245
246 p->n = n;
247 for(i=0;i<n;i++)
248 {
249 p->p[i] = pv_array[i];
250 }
251 return p;
252 }
253
plx_free(void * p)254 static void plx_free(void * p )
255 {
256 plx_t * plx=(plx_t*)p;
257
258 if( !plx ) return;
259 if( plx->p ) free(plx->p);
260 free( p );
261 }
262
263 #ifdef DEBUG_MSGS
264 static
plx_print(plx_t * p)265 void plx_print(plx_t * p)
266 {
267 DEBUG_WRAP(
268 int i;
269 DebugMessage(DEBUG_PORTLISTS, "plx-n=%d\n", p->n);
270 for(i=0;i<p->n;i++)
271 DebugMessage(DEBUG_PORTLISTS, "plx[%d]=%lu\n", i, p->p[i]);
272 );
273 }
274 #endif
275
276 /*
277 * hash function for plx_t types
278 */
279 static
plx_hash(SFHASHFCN * p,unsigned char * d,int n)280 unsigned plx_hash( SFHASHFCN * p, unsigned char *d, int n )
281 {
282 unsigned k, hash = p->seed;
283 int i;
284 plx_t* plx;
285
286 #ifdef WIN32
287 n = n; /* To silence a Win32 warning */
288 #endif
289
290 plx = *(plx_t**)d;
291
292 for(i=0;i<plx->n;i++)
293 {
294 unsigned char * pc_ptr = (unsigned char*)&plx->p[i];
295 for(k=0;k<sizeof(void*);k++)
296 {
297 hash *= p->scale;
298 hash += pc_ptr[k];
299 }
300 }
301 return hash ^ p->hardener;
302 }
303
304
305 /* for sorting an array of pointers */
306 static inline
p_keycmp(const void * a,const void * b)307 int p_keycmp( const void *a , const void *b )
308 {
309 if( *(unsigned long**)a < *(unsigned long**)b ) return -1;
310 if( *(unsigned long**)a > *(unsigned long**)b ) return 1;
311
312 return 0; /* they are equal */
313 }
314
315
316 /*
317 Hash Key Comparisons for treating plx_t types as Keys
318
319 return values memcmp style
320
321 this only needs to produce 0 => exact match, otherwise not.
322 -1, and +1 are not strictly needed, they could both return
323 a non zero value for the purposes of hashing and searching.
324 */
325 static
plx_keycmp(const void * a,const void * b,size_t n)326 int plx_keycmp( const void *a , const void *b, size_t n )
327 {
328 int i, cmp;
329 plx_t * pla = *(plx_t**)a;
330 plx_t * plb = *(plx_t**)b;
331
332 #ifdef WIN32
333 n = n; /* To silence a Win32 warning */
334 #endif
335
336 if( pla->n < plb->n ) return -1;
337
338 if( pla->n > plb->n ) return 1;
339
340 for(i=0;i<pla->n;i++)
341 {
342 if((cmp = p_keycmp(&pla->p[i], &plb->p[i])) != 0)
343 return cmp;
344 }
345
346 return 0; /* they are equal */
347 }
348
349
350 /* global for printing so we don't put so many bytes
351 * on the stack */
352 static char po_print_buf[MAXPORTS];
353
354 /*
355 PORT OBJECT FUNCTIONS
356 */
357
358 /*
359 Create a new PortObject
360 */
PortObjectNew(void)361 PortObject * PortObjectNew(void)
362 {
363 PortObject *po = (PortObject *)SnortAlloc(sizeof(PortObject));
364
365 po->item_list =(SF_LIST*) sflist_new();
366
367 if( !po->item_list )
368 {
369 free( po );
370 return 0;
371 }
372
373 po->rule_list =(SF_LIST*) sflist_new();
374 if( !po->rule_list )
375 {
376 sflist_free_all( po->item_list, free );
377 free( po );
378 return 0;
379 }
380
381 return po;
382 }
383
384 /* This is the opposite of ntohl/htonl defines, and does the
385 * swap on big endian hardware */
386 #ifdef WORDS_BIGENDIAN
387 #define SWAP_BYTES(a) \
388 ((((uint32_t)(a) & 0xFF000000) >> 24) | \
389 (((uint32_t)(a) & 0x00FF0000) >> 8) | \
390 (((uint32_t)(a) & 0x0000FF00) << 8) | \
391 (((uint32_t)(a) & 0x000000FF) << 24))
392 #else
393 #define SWAP_BYTES(a) (a)
394 #endif
po_rule_hash_func(SFHASHFCN * p,unsigned char * k,int n)395 static unsigned po_rule_hash_func(SFHASHFCN *p, unsigned char *k, int n)
396 {
397 unsigned char *key;
398 int ikey = *(int*)k;
399
400 /* Since the input is really an int, put the bytes into a normalized
401 * order so that the hash function returns consistent results across
402 * on BE & LE hardware. */
403 ikey = SWAP_BYTES(ikey);
404
405 /* Set a pointer to the key to pass to the hashing function */
406 key = (unsigned char *)&ikey;
407
408 return sfhashfcn_hash(p, key, n);
409 }
410
411 /*
412 Create a new PortObject2
413 */
PortObject2New(int nrules)414 PortObject2 * PortObject2New(int nrules)
415 {
416 PortObject2 *po = (PortObject2 *)SnortAlloc(sizeof(PortObject2));
417
418 po->item_list =(SF_LIST*) sflist_new();
419
420 if( !po->item_list )
421 {
422 free( po );
423 return 0;
424 }
425
426 po->rule_hash =(SFGHASH*) sfghash_new(nrules,sizeof(int),0,free /* frees data - should be rule id ptrs == (int*) */);
427 if( !po->rule_hash )
428 {
429 sflist_free_all( po->item_list, free );
430 free( po );
431 return 0;
432 }
433
434 /* Use hash function defined above for hashing the key as an int. */
435 sfghash_set_keyops(po->rule_hash, po_rule_hash_func, memcmp);
436
437 //sfhashfcn_static( po->rule_hash->sfhashfcn ); /* TODO: Leave this in, else we get different events */
438
439 return po;
440 }
441 /*
442 * Set the name of the Port Object
443 */
PortObjectSetName(PortObject * po,char * name)444 int PortObjectSetName(PortObject * po, char * name)
445 {
446 if( !po )
447 return -1;
448
449 if( !name )
450 return -1;
451
452 /* free the old name */
453 if(po->name)
454 free(po->name);
455
456 /* alloc a new name */
457 po->name = SnortStrdup(name);
458 if( !po->name )
459 return -1;
460
461 return 0;
462 }
463
464 /*
465 * Free a PortObjectItem
466 */
PortObjectItemFree(PortObjectItem * poi)467 void PortObjectItemFree (PortObjectItem * poi)
468 {
469 if(poi) free(poi);
470 }
471
472 /*
473 * Free the PortObject
474 */
PortObjectFree(void * pvoid)475 void PortObjectFree( void * pvoid )
476 {
477 PortObject * po = (PortObject *)pvoid;
478 DEBUG_WRAP(static int pof_cnt = 0; pof_cnt++;);
479
480 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"PortObjectFree-Cnt: %d ptr=%p\n",pof_cnt,pvoid););
481
482 if( !po ) return ;
483
484 if( po->name ) free (po->name );
485 if( po->item_list) sflist_free_all( po->item_list, free );
486 if( po->rule_list) sflist_free_all( po->rule_list, free );
487
488 if (po->data && po->data_free)
489 {
490 po->data_free(po->data);
491 }
492
493 free( po );
494 }
495 /*
496 * Free the PortObject2
497 */
PortObject2Free(void * pvoid)498 void PortObject2Free( void * pvoid )
499 {
500 PortObject2 * po = (PortObject2 *)pvoid;
501 DEBUG_WRAP(static int pof2_cnt = 0; pof2_cnt++;);
502
503 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"PortObjectFree2-Cnt: %d ptr=%p\n",pof2_cnt,pvoid););
504
505 if( !po ) return;
506
507 if( po->name ) free (po->name );
508 if( po->item_list) sflist_free_all( po->item_list, free );
509 if( po->rule_hash) sfghash_delete( po->rule_hash );
510 if (po->bitop)
511 {
512 boFreeBITOP(po->bitop);
513 free(po->bitop);
514 }
515
516 if (po->data && po->data_free)
517 {
518 po->data_free(po->data);
519 }
520
521 free( po );
522 }
523
524 /*
525 * Create a new PortObjectItem
526 */
PortObjectItemNew(void)527 PortObjectItem * PortObjectItemNew(void)
528 {
529 PortObjectItem *poi = (PortObjectItem *)SnortAlloc(sizeof(PortObjectItem));
530
531 return poi;
532 }
533
534 /*
535 * Add a PortObjectItem to a PortObject
536 */
PortObjectAddItem(PortObject * po,PortObjectItem * poi,int * errflag)537 int PortObjectAddItem( PortObject * po, PortObjectItem * poi, int *errflag)
538 {
539 PortObjectItem *p;
540 SF_LNODE *pos = NULL;
541
542 if(!po || !poi) return 0;
543
544 if(errflag) *errflag = 0;
545
546 /* Make sure this is not a duplicate */
547 for(p=(PortObjectItem*)sflist_firstpos(po->item_list,&pos);
548 p != 0;
549 p=(PortObjectItem*)sflist_nextpos(po->item_list,&pos) )
550 {
551 if((p->lport == poi->lport) && (p->hport == poi->hport))
552 {
553 if(errflag) *errflag = POPERR_DUPLICATE_ENTRY;
554 return -1; /* -1 chosen for consistency with sflist_add_tail */
555 }
556 }
557
558 return sflist_add_tail( po->item_list, poi );
559 }
560
561 /*
562 * Add a PortObjectItem to a PortObject
563 */
PortObjectAddPortObject(PortObject * podst,PortObject * posrc,int * errflag)564 int PortObjectAddPortObject(PortObject * podst, PortObject * posrc, int *errflag)
565 {
566 PortObjectItem *po;
567 SF_LNODE *pos = NULL;
568 int ret = 0;
569
570 if(errflag) *errflag = 0;
571
572 for(po=(PortObjectItem*)sflist_firstpos(posrc->item_list, &pos);
573 po != 0;
574 po=(PortObjectItem*)sflist_nextpos(posrc->item_list, &pos) )
575 {
576 PortObjectItem *poi = PortObjectItemDup(po);
577 if((ret = PortObjectAddItem(podst, poi, errflag)) != 0)
578 return ret;
579 }
580
581 return ret;
582 }
583
584
585 /*
586 Dup a PortObjectItem
587 */
PortObjectItemDup(PortObjectItem * poi)588 PortObjectItem * PortObjectItemDup( PortObjectItem * poi)
589 {
590 PortObjectItem * poinew;
591
592 if( !poi )
593 return 0;
594
595 poinew = PortObjectItemNew();
596 if( !poinew )
597 return 0;
598
599 memcpy(poinew,poi,sizeof(PortObjectItem));
600
601 return poinew;
602 }
603
604 /*
605 * Dup the PortObjects Item List, RuleList, and Name
606 */
PortObjectDup(PortObject * po)607 PortObject * PortObjectDup( PortObject * po )
608 {
609 PortObject * ponew = NULL;
610 PortObjectItem * poi = NULL;
611 PortObjectItem * poinew = NULL;
612 SF_LNODE * lpos = NULL;
613 int * prid = NULL;
614 int * prule = NULL;
615
616 ponew = PortObjectNew();
617 if( !ponew )
618 return 0;
619
620 /* Dup the Name */
621 if( po->name )
622 ponew->name = strdup(po->name);
623 else
624 ponew->name = strdup("dup");
625
626 if( !ponew->name )
627 {
628 free( ponew );
629 return NULL;
630 }
631
632 /* Dup the Item List */
633 if( po->item_list )
634 {
635 for(poi =(PortObjectItem*)sflist_firstpos(po->item_list,&lpos);
636 poi != NULL;
637 poi =(PortObjectItem*)sflist_nextpos(po->item_list,&lpos) )
638 {
639 poinew = PortObjectItemDup( poi );
640 if(!poinew)
641 {
642 free( ponew->name );
643 free( ponew );
644 return 0;
645 }
646
647 PortObjectAddItem( ponew, poinew, NULL );
648 }
649 }
650
651 /* Dup the input rule list */
652 if( po->rule_list )
653 {
654 for(prid = (int*)sflist_firstpos(po->rule_list,&lpos);
655 prid != 0;
656 prid = (int*)sflist_nextpos(po->rule_list,&lpos) )
657 {
658 prule = calloc(1,sizeof(int));
659 if(!prule)
660 {
661 free( poinew );
662 free( ponew->name );
663 free( ponew );
664 return NULL;
665 }
666 *prule = *prid;
667 sflist_add_tail(ponew->rule_list,prule);
668 }
669 }
670
671 return ponew;
672 }
673 /*
674 * Dup the PortObjects Item List, and Name
675 */
PortObjectDupPorts(PortObject * po)676 PortObject * PortObjectDupPorts( PortObject * po )
677 {
678 PortObject * ponew = NULL;
679 PortObjectItem * poi = NULL;
680 PortObjectItem * poinew = NULL;
681 SF_LNODE * lpos = NULL;
682
683 ponew = PortObjectNew();
684 if( !ponew )
685 return 0;
686
687 /* Dup the Name */
688 if( po->name )
689 ponew->name = strdup(po->name);
690 else
691 ponew->name = strdup("dup");
692
693 if( !ponew->name )
694 {
695 free( ponew );
696 return NULL;
697 }
698
699 /* Dup the Item List */
700 if( po->item_list )
701 {
702 for(poi =(PortObjectItem*)sflist_firstpos(po->item_list,&lpos);
703 poi != NULL;
704 poi =(PortObjectItem*)sflist_nextpos(po->item_list,&lpos) )
705 {
706 poinew = PortObjectItemDup( poi );
707 if(!poinew)
708 {
709 free (ponew->name);
710 free (ponew);
711 return NULL;
712 }
713 PortObjectAddItem( ponew, poinew, NULL );
714 }
715 }
716 return ponew;
717 }
718
719 /*
720 * Dup the PortObjects Item List, Name, and RuleList->RuleHash
721 */
PortObject2Dup(PortObject * po)722 PortObject2 * PortObject2Dup( PortObject * po )
723 {
724 PortObject2 * ponew = NULL;
725 PortObjectItem * poi = NULL;
726 PortObjectItem * poinew = NULL;
727 SF_LNODE * lpos = NULL;
728 int * prid = NULL;
729 int * prule = NULL;
730
731 if( !po )
732 return NULL;
733
734 if( !po->rule_list )
735 return NULL;
736
737 ponew = PortObject2New(po->rule_list->count + PO_EXTRA_RULE_CNT);
738 if( !ponew )
739 return NULL;
740
741 /* Dup the Name */
742 if( po->name )
743 ponew->name = strdup(po->name);
744 else
745 ponew->name = strdup("dup");
746
747 if( !ponew->name )
748 {
749 PortObject2Free(ponew);
750 return NULL;
751 }
752
753 /* Dup the Item List */
754 if( po->item_list )
755 {
756 for(poi =(PortObjectItem*)sflist_firstpos(po->item_list,&lpos);
757 poi != NULL;
758 poi =(PortObjectItem*)sflist_nextpos(po->item_list,&lpos) )
759 {
760 poinew = PortObjectItemDup( poi );
761 if(!poinew)
762 {
763 PortObject2Free(ponew);
764 return 0;
765 }
766
767 PortObjectAddItem( (PortObject*)ponew, poinew, NULL );
768 }
769 }
770
771 /* Dup the input rule list */
772 if( po->rule_list )
773 {
774 for(prid = (int*)sflist_firstpos(po->rule_list,&lpos);
775 prid != 0;
776 prid = (int*)sflist_nextpos(po->rule_list,&lpos) )
777 {
778 prule = calloc(1,sizeof(int));
779 if(!prule)
780 {
781 PortObject2Free(ponew);
782 return NULL;
783 }
784 *prule = *prid;
785 if( sfghash_add( ponew->rule_hash, prule, prule ) != SFGHASH_OK )
786 {
787 free( prule );
788 }
789 }
790 }
791
792 return ponew;
793 }
794
795 /*
796 Add a Port to a PortObject
797 */
PortObjectAddPort(PortObject * po,int port,int not_flag)798 int PortObjectAddPort( PortObject * po, int port, int not_flag )
799 {
800 PortObjectItem * poi;
801
802 poi = PortObjectItemNew();
803 if( !poi )
804 return -1;
805
806 poi->type = PORT_OBJECT_PORT;
807
808 if( not_flag )
809 poi->flags = PORT_OBJECT_NOT_FLAG;
810
811 poi->lport = (unsigned short)port;
812 poi->hport = (unsigned short)port;
813
814 return sflist_add_tail( po->item_list, poi );
815 }
816
817 /*
818 Add a Port Range to a PortObject
819 */
PortObjectAddRange(PortObject * po,int lport,int hport,int not_flag)820 int PortObjectAddRange( PortObject * po, int lport, int hport, int not_flag )
821 {
822 PortObjectItem * poi;
823
824 poi = PortObjectItemNew();
825 if( !poi )
826 return -1;
827
828 poi->type = PORT_OBJECT_RANGE;
829
830 if( not_flag )
831 poi->flags = PORT_OBJECT_NOT_FLAG;
832
833 poi->lport = (unsigned short)lport;
834 poi->hport = (unsigned short)hport;
835
836 return sflist_add_tail( po->item_list, poi );
837 }
838 /*
839 Add ANY port
840 */
PortObjectAddPortAny(PortObject * po)841 int PortObjectAddPortAny( PortObject * po )
842 {
843 PortObjectItem * poi;
844
845 if(!po)
846 return -1 ;
847
848 poi = PortObjectItemNew();
849 if( !poi )
850 return -1;
851
852 poi->type = PORT_OBJECT_ANY;
853
854 poi->lport = 0;
855 poi->hport = MAXPORTS-1;
856
857 if(!po->name)
858 po->name = strdup("any");
859
860 if(!po->name)
861 {
862 free(poi);
863 return -1;
864 }
865 return sflist_add_tail( po->item_list, poi );
866 }
867
868 /*
869 * Check if we have any ANY ports
870 */
PortObjectHasAny(PortObject * po)871 int PortObjectHasAny (PortObject * po )
872 {
873 PortObjectItem *poi;
874
875 if( !po )
876 return 0;
877
878 for(poi=(PortObjectItem*)sflist_first(po->item_list);
879 poi != 0;
880 poi=(PortObjectItem*)sflist_next(po->item_list) )
881 {
882 if( poi->type == PORT_OBJECT_ANY )
883 return 1;
884 }
885 return 0;
886 }
PortObjectHasNot(PortObject * po)887 int PortObjectHasNot (PortObject * po )
888 {
889 PortObjectItem *poi;
890
891 if( !po )
892 return 0;
893
894 for(poi=(PortObjectItem*)sflist_first(po->item_list);
895 poi != 0;
896 poi=(PortObjectItem*)sflist_next(po->item_list) )
897 {
898 if ( poi->flags== PORT_OBJECT_NOT_FLAG) return 1;
899 }
900 return 0;
901 }
PortObjectIsPureNot(PortObject * po)902 int PortObjectIsPureNot (PortObject * po )
903 {
904 PortObjectItem *poi;
905 int cnt=0;
906
907 if( !po )
908 return 0;
909
910 for(poi=(PortObjectItem*)sflist_first(po->item_list);
911 poi != 0;
912 poi=(PortObjectItem*)sflist_next(po->item_list) )
913 {
914 cnt++;
915 if ( poi->flags != PORT_OBJECT_NOT_FLAG)
916 return 0;
917 }
918
919 if( cnt == 0 ) return 0;
920
921 return 1;
922 }
923
924 /*
925 * This does NOT return true if the object is an ANY port
926 */
PortObjectHasPort(PortObject * po,int port)927 int PortObjectHasPort (PortObject * po, int port )
928 {
929 PortObjectItem *poi;
930
931 if( !po )
932 return 0;
933
934 for(poi=(PortObjectItem*)sflist_first(po->item_list);
935 poi != 0;
936 poi=(PortObjectItem*)sflist_next(po->item_list) )
937 {
938 switch( poi->type )
939 {
940 case PORT_OBJECT_ANY:
941 return 0;
942
943 case PORT_OBJECT_PORT:
944 if( poi->lport == (uint16_t)(port&0xffff) )
945 return 1;
946 if( poi->flags & PORT_OBJECT_NOT_FLAG )
947 return 1;
948 break;
949
950 case PORT_OBJECT_RANGE:
951 if( (uint16_t)port >= poi->lport &&
952 (uint16_t)port <= poi->hport )
953 return 1;
954 if( poi->flags & PORT_OBJECT_NOT_FLAG )
955 return 1;
956 break;
957 }
958 }
959 return 0;
960 }
961 /*
962 * This returns true if the object is an ANY port
963 */
PortObjectIncludesPort(PortObject * po,int port)964 int PortObjectIncludesPort (PortObject * po, int port )
965 {
966 PortObjectItem *poi;
967
968 if( !po )
969 return 0;
970
971 for(poi=(PortObjectItem*)sflist_first(po->item_list);
972 poi != 0;
973 poi=(PortObjectItem*)sflist_next(po->item_list) )
974 {
975 switch( poi->type )
976 {
977 case PORT_OBJECT_ANY:
978 return 1;
979
980 case PORT_OBJECT_PORT:
981 if( poi->lport == (uint16_t)port )
982 return 1;
983 if( poi->flags & PORT_OBJECT_NOT_FLAG )
984 return 1;
985 break;
986
987 case PORT_OBJECT_RANGE:
988 if( (uint16_t)port >= poi->lport &&
989 (uint16_t)port <= poi->hport )
990 return 1;
991 if( poi->flags & PORT_OBJECT_NOT_FLAG )
992 return 1;
993 break;
994 }
995 }
996 return 0;
997 }
998
999 /*
1000 * Locate a PortObject by Port number , this only locates the 1st one
1001 * This was a hack for testing....
1002 */
PortTableFindPortObjectByPort(PortTable * p,int port)1003 PortObject * PortTableFindPortObjectByPort( PortTable * p , int port )
1004 {
1005 PortObject * po;
1006 SF_LNODE * pos;
1007
1008 for(po =(PortObject*)sflist_firstpos(p->pt_polist,&pos);
1009 po != NULL;
1010 po =(PortObject*)sflist_nextpos(p->pt_polist,&pos) )
1011 {
1012 if( PortObjectHasPort ( po, port ) )
1013 {
1014 return po;
1015 }
1016 }
1017
1018 return 0;
1019 }
1020
1021 /*
1022 * Calcs number of ports in this object,
1023 * object do not have to be normalized,
1024 * but if the same ports are referenced
1025 * twice, the count will be off.
1026 *
1027 * returns:
1028 * any = -1
1029 * 0 = none/empty
1030 * >0 = number of ports
1031 */
PortObjectPortCount(PortObject * po)1032 int PortObjectPortCount (PortObject * po )
1033 {
1034 PortObjectItem *poi;
1035 int cnt=0;
1036 int nports;
1037
1038 if( !po )
1039 return 0;
1040
1041 for(poi=(PortObjectItem*)sflist_first(po->item_list);
1042 poi != 0;
1043 poi=(PortObjectItem*)sflist_next(po->item_list) )
1044 {
1045 switch( poi->type )
1046 {
1047 case PORT_OBJECT_ANY:
1048 return -1;
1049
1050 case PORT_OBJECT_PORT:
1051 if( poi->flags & PORT_OBJECT_NOT_FLAG )
1052 {
1053 cnt--;
1054 }
1055 else
1056 {
1057 cnt++;
1058 }
1059 break;
1060
1061 case PORT_OBJECT_RANGE:
1062 nports = poi->hport - poi->lport + 1;
1063 if( poi->flags & PORT_OBJECT_NOT_FLAG )
1064 {
1065 cnt-=nports;
1066 }
1067 else
1068 {
1069 cnt+=nports;
1070 }
1071 }
1072 }
1073
1074 if( cnt < 0 )
1075 {
1076 /* we have a pure not port or port range
1077 *
1078 * !80 = -1, add 64K (65535 -1 = 65534)
1079 * !80:81 = -2, (65535 - 2 = 65533)
1080 *
1081 * [:1023,!80] = 1024 - 1 = 1023 ports
1082 *
1083 */
1084 cnt += SFPO_MAX_PORTS; /* add back in the acceptable ports */
1085 }
1086
1087 return cnt;
1088 }
1089
1090 /*
1091 * Build a PortMap Char Array
1092 * returns: 0 if an ANY port.
1093 * n number of unique ports.
1094 */
PortObjectCharPortArray(char * parray,PortObject * po,int * nports)1095 char * PortObjectCharPortArray ( char * parray, PortObject * po, int * nports )
1096 {
1097 int cnt = 0;
1098 unsigned not_cnt=0;
1099 PortObjectItem * poi;
1100 SF_LNODE * pos;
1101
1102 if( !po || PortObjectHasAny ( po ) )
1103 {
1104 return 0; /* ANY =64K */
1105 }
1106
1107 if( !parray )
1108 {
1109 parray = (char*) calloc(1,SFPO_MAX_PORTS);
1110 if( !parray )
1111 return 0;
1112 }
1113
1114 for(poi=(PortObjectItem*)sflist_firstpos(po->item_list,&pos);
1115 poi != 0;
1116 poi=(PortObjectItem*)sflist_nextpos(po->item_list,&pos) )
1117 {
1118 /* Add ports that are not NOT'd */
1119 if( poi->flags & PORT_OBJECT_NOT_FLAG )
1120 {
1121 not_cnt++;
1122 continue;
1123 }
1124
1125 if( poi->type == PORT_OBJECT_PORT )
1126 {
1127 if( !parray[poi->lport] )
1128 cnt++;
1129
1130 parray[poi->lport] = 1;
1131 }
1132
1133 else if( poi->type == PORT_OBJECT_RANGE )
1134 {
1135 int i;
1136 for(i=poi->lport;i<=poi->hport;i++)
1137 {
1138 if( !parray[i] )
1139 cnt++;
1140 parray[i] = 1;
1141 }
1142 }
1143 }
1144
1145 /* Remove any NOT'd ports that may have been added above */
1146 for(poi=(PortObjectItem*)sflist_firstpos(po->item_list,&pos);
1147 poi != 0;
1148 poi=(PortObjectItem*)sflist_nextpos(po->item_list,&pos) )
1149 {
1150 if( !( poi->flags & PORT_OBJECT_NOT_FLAG) )
1151 continue;
1152
1153 if( poi->type == PORT_OBJECT_PORT )
1154 {
1155 if( parray[poi->lport] )
1156 cnt--;
1157
1158 parray[poi->lport] =0;
1159 }
1160 else if( poi->type == PORT_OBJECT_RANGE )
1161 {
1162 int i;
1163
1164 for(i=poi->lport;i<=poi->hport;i++)
1165 {
1166 if( parray[i] )
1167 cnt--;
1168 parray[i] = 0;
1169 }
1170 }
1171 }
1172
1173
1174 /* A pure Not list */
1175 if( po->item_list->count == not_cnt )
1176 {
1177 int i;
1178
1179 /* enable all of the ports */
1180 for(i=0;i<SFPO_MAX_PORTS;i++)
1181 {
1182 parray[i] =1;
1183 cnt++;
1184 }
1185
1186 /* disable the NOT'd ports */
1187 for(poi=(PortObjectItem*)sflist_firstpos(po->item_list,&pos);
1188 poi != 0;
1189 poi=(PortObjectItem*)sflist_nextpos(po->item_list,&pos) )
1190 {
1191 if( !( poi->flags & PORT_OBJECT_NOT_FLAG) )
1192 continue; /* should not happen */
1193
1194 if( poi->type == PORT_OBJECT_PORT )
1195 {
1196 if( parray[poi->lport] )
1197 cnt--;
1198 parray[poi->lport] =0;
1199 }
1200
1201 else if( poi->type == PORT_OBJECT_RANGE )
1202 {
1203 int k;
1204
1205 for(k=poi->lport;k<=poi->hport;k++)
1206 {
1207 if( parray[k] )
1208 cnt--;
1209 parray[k] = 0;
1210 }
1211 }
1212 }
1213 }
1214
1215 *nports = cnt;
1216
1217 return parray;
1218 }
1219
1220 /*
1221 * Make a list of ports form the char array, each char is either
1222 * on or off.
1223 */
1224 static
PortObjectItemListFromCharPortArray(char * parray,int n,int nports)1225 SF_LIST * PortObjectItemListFromCharPortArray( char * parray, int n, int nports )
1226 {
1227 int i, lport ,hport;
1228 SF_LIST * plist;
1229 PortObjectItem * poi;
1230
1231 plist = sflist_new();
1232 if( !plist )
1233 return 0;
1234
1235 for(i=0; (i<n) && (nports > 0); i++)
1236 {
1237 if( parray[i] == 0 ) continue;
1238
1239 /* Either a port or the start of a range */
1240 lport = hport = i;
1241 nports--;
1242
1243 for(i++;i<n;i++)
1244 {
1245 if( parray[i] )
1246 {
1247 hport = i;
1248 nports--;
1249 continue;
1250 }
1251 break;
1252 }
1253
1254 poi = PortObjectItemNew();
1255 if( !poi )
1256 {
1257 sflist_free_all(plist,free);
1258 return 0;
1259 }
1260
1261 if( hport == lport )
1262 {
1263 poi->type = PORT_OBJECT_PORT;
1264 poi->lport = (unsigned short)lport;
1265 }
1266 else
1267 {
1268 poi->type = PORT_OBJECT_RANGE;
1269 poi->lport =(unsigned short)lport;
1270 poi->hport =(unsigned short)hport;
1271 }
1272
1273 if( sflist_add_tail( plist, poi ) )
1274 {
1275 sflist_free_all( plist, free );
1276 return 0;
1277 }
1278 }
1279
1280 return plist;
1281 }
1282
1283 /*
1284 * Removes Ports in B from A ... A = A - B
1285 */
PortObjectRemovePorts(PortObject * a,PortObject * b)1286 int PortObjectRemovePorts( PortObject * a, PortObject * b )
1287 {
1288 int i;
1289 int nportsa;
1290 int nportsb;
1291 SF_LIST * plist;
1292 static char pA[SFPO_MAX_PORTS];
1293 static char pB[SFPO_MAX_PORTS];
1294
1295 memset(pA,0,SFPO_MAX_PORTS);
1296 memset(pB,0,SFPO_MAX_PORTS);
1297
1298 /* Create a char array of ports */
1299 PortObjectCharPortArray ( pA, a, &nportsa );
1300
1301 /* Create a char array of ports */
1302 PortObjectCharPortArray ( pB, b, &nportsb );
1303
1304 for(i=0;i<SFPO_MAX_PORTS;i++)
1305 {
1306 if( pB[i] )
1307 {
1308 pA[i] = 0; /* remove portB from A */
1309 nportsa--;
1310 }
1311 }
1312
1313 /* Convert the array into a Port Object list */
1314 plist = PortObjectItemListFromCharPortArray( pA, SFPO_MAX_PORTS, nportsa );
1315
1316 /* Release the old port list */
1317 sflist_free_all( a->item_list, free );
1318
1319 /* Replace the old PortObject list */
1320 a->item_list = plist;
1321
1322 return 0;
1323 }
1324
1325 /*
1326 * Normalize a port object
1327 *
1328 * The reduces multiple references to a given port to a single unique reference
1329 * This function should be used on each PortObject, once it's completed. After
1330 * the normalized PortObject is created, the input PortObject may be deleted.
1331 */
PortObjectNormalize(PortObject * po)1332 int PortObjectNormalize (PortObject * po )
1333 {
1334 SF_LIST * plist;
1335 int nports = 0;
1336
1337 static char parray[SFPO_MAX_PORTS];
1338
1339 if( PortObjectHasAny ( po ) )
1340 {
1341 return 0; /* ANY =65K */
1342 }
1343
1344 memset(parray,0,SFPO_MAX_PORTS);
1345
1346 /* Create a char array of ports */
1347 PortObjectCharPortArray ( parray, po, &nports );
1348
1349 /* Convert the array into a Port Object list */
1350 plist = PortObjectItemListFromCharPortArray( parray, SFPO_MAX_PORTS, nports );
1351 if( !plist )
1352 return -1;
1353
1354 /* Release the old port list */
1355 sflist_free_all( po->item_list, free );
1356
1357 /* Replace the old PortObject list */
1358 po->item_list = plist;
1359
1360 return nports;
1361 }
1362
1363 /*
1364 * Negate an entire PortObject
1365 */
PortObjectNegate(PortObject * po)1366 int PortObjectNegate (PortObject * po )
1367 {
1368 int i;
1369 SF_LIST * plist;
1370 int nports = 0;
1371
1372 static char parray[SFPO_MAX_PORTS];
1373
1374 if( PortObjectHasAny ( po ) )
1375 {
1376 return 0; /* ANY =65K */
1377 }
1378
1379 memset(parray,0,SFPO_MAX_PORTS);
1380
1381 /* Create a char array of ports */
1382 PortObjectCharPortArray ( parray, po, &nports );
1383
1384 for(i=0;i<SFPO_MAX_PORTS;i++)
1385 {
1386 if( parray[i] ) /* negate */
1387 parray[i] = 0;
1388 else
1389 parray[i] = 1;
1390 }
1391
1392 /* Convert the array into a Port Object list */
1393 plist = PortObjectItemListFromCharPortArray( parray, SFPO_MAX_PORTS,
1394 SFPO_MAX_PORTS - nports );
1395
1396 /* Release the old port list */
1397 sflist_free_all( po->item_list, free );
1398
1399 /* Replace the old PortObject list */
1400 po->item_list = plist;
1401
1402 return nports;
1403 }
1404
1405
1406 /*
1407 PortObjects should be normalized, prior to testing
1408 */
1409 static
PortObjectItemsEqual(PortObjectItem * a,PortObjectItem * b)1410 int PortObjectItemsEqual(PortObjectItem * a, PortObjectItem * b )
1411 {
1412 if( a->type != b->type )
1413 return 0;
1414
1415 switch( a->type )
1416 {
1417 case PORT_OBJECT_ANY:
1418 return 1;
1419 case PORT_OBJECT_PORT:
1420 if( a->lport == b->lport )
1421 return 1;
1422 break;
1423 case PORT_OBJECT_RANGE:
1424 if( a->lport == b->lport && a->hport == b->hport )
1425 return 1;
1426 break;
1427 }
1428
1429 return 0;
1430 }
1431
1432 /*
1433 PortObjects should be normalized, prior to testing
1434 */
PortObjectEqual(PortObject * a,PortObject * b)1435 int PortObjectEqual( PortObject * a, PortObject *b )
1436 {
1437 PortObjectItem *pa;
1438 PortObjectItem *pb;
1439 SF_LNODE * posa;
1440 SF_LNODE * posb;
1441
1442 if( a->item_list->count != b->item_list->count )
1443 return 0;
1444
1445 pa = (PortObjectItem*)sflist_firstpos(a->item_list,&posa);
1446 pb = (PortObjectItem*)sflist_firstpos(b->item_list,&posb);
1447
1448 while( pa && pb )
1449 {
1450 if( !PortObjectItemsEqual( pa, pb) )
1451 return 0;
1452
1453 pa = (PortObjectItem*)sflist_nextpos(a->item_list,&posa);
1454 pb = (PortObjectItem*)sflist_nextpos(b->item_list,&posb);
1455 }
1456
1457 if( pa || pb ) /* both are not done - cannot match */
1458 return 0;
1459
1460 return 1; /* match */
1461 }
1462
1463 /*
1464 Dup and Append PortObjectItems from pob to poa
1465 */
PortObjectAppend(PortObject * poa,PortObject * pob)1466 PortObject * PortObjectAppend(PortObject * poa, PortObject * pob )
1467 {
1468 PortObjectItem * poia;
1469 PortObjectItem * poib;
1470
1471 for( poib = (PortObjectItem*) sflist_first(pob->item_list);
1472 poib!= 0;
1473 poib = (PortObjectItem*)sflist_next(pob->item_list) )
1474 {
1475 poia = PortObjectItemNew();
1476
1477 if(!poia)
1478 return 0;
1479
1480 memcpy(poia,poib,sizeof(PortObjectItem));
1481
1482 sflist_add_tail(poa->item_list,poia);
1483 }
1484 return poa;
1485 }
1486 /* Dup and append rule list numbers from pob to poa */
PortObjectAppendPortObject(PortObject * poa,PortObject * pob)1487 PortObject * PortObjectAppendPortObject(PortObject * poa, PortObject * pob )
1488 {
1489 int * prid;
1490 int * prid2;
1491 SF_LNODE * lpos;
1492
1493 for( prid = (int*) sflist_firstpos(pob->rule_list,&lpos);
1494 prid!= 0;
1495 prid = (int*)sflist_nextpos(pob->rule_list,&lpos) )
1496 {
1497 prid2 = calloc( 1, sizeof(int));
1498 if( !prid2 )
1499 return 0;
1500 *prid2 = *prid;
1501 sflist_add_tail(poa->rule_list,prid2);
1502 }
1503 return poa;
1504 }
1505 /* Dup and append rule list numbers from pob to poa */
PortObject2AppendPortObject(PortObject2 * poa,PortObject * pob)1506 PortObject2 * PortObject2AppendPortObject(PortObject2 * poa, PortObject * pob )
1507 {
1508 int * prid;
1509 int * prid2;
1510 SF_LNODE * lpos;
1511
1512 for( prid = (int*) sflist_firstpos(pob->rule_list,&lpos);
1513 prid!= 0;
1514 prid = (int*)sflist_nextpos(pob->rule_list,&lpos) )
1515 {
1516 prid2 = calloc( 1, sizeof(int));
1517 if( !prid2 )
1518 return 0;
1519 *prid2 = *prid;
1520 if( sfghash_add(poa->rule_hash,prid2,prid2) != SFGHASH_OK )
1521 {
1522 free(prid2);
1523 }
1524 }
1525 return poa;
1526 }
1527 /* Dup and append rule list numbers from pob to poa */
PortObject2AppendPortObject2(PortObject2 * poa,PortObject2 * pob)1528 PortObject2 * PortObject2AppendPortObject2(PortObject2 * poa, PortObject2 * pob )
1529 {
1530 int * prid;
1531 int * prid2;
1532 SFGHASH_NODE * node;
1533
1534 for( node = sfghash_findfirst(pob->rule_hash);
1535 node!= NULL;
1536 node = sfghash_findnext(pob->rule_hash) )
1537 {
1538 prid = node->data;
1539 if( !prid )
1540 continue;
1541
1542 prid2 = calloc( 1, sizeof(int));
1543 if( !prid2 )
1544 return 0;
1545
1546 *prid2 = *prid;
1547 if( sfghash_add(poa->rule_hash,prid2,prid2) != SFGHASH_OK )
1548 {
1549 free( prid2 );
1550 }
1551 }
1552 return poa;
1553 }
1554 /*
1555 * Append Ports and Rules from pob to poa
1556 */
PortObjectAppendEx(PortObject * poa,PortObject * pob)1557 PortObject * PortObjectAppendEx(PortObject * poa, PortObject * pob )
1558 {
1559 // LogMessage("PortObjectAppendEx: appending ports\n");
1560 if( !PortObjectAppend( poa, pob ) ) return 0;
1561
1562 //LogMessage("PortObjectAppendEx: appending rules\n");
1563 if( !PortObjectAppendPortObject( poa, pob ) ) return 0;
1564
1565 return poa;
1566 }
1567 /*
1568 * Append Ports and Rules from pob to poa
1569 */
PortObjectAppendEx2(PortObject2 * poa,PortObject * pob)1570 PortObject2 * PortObjectAppendEx2(PortObject2 * poa, PortObject * pob )
1571 {
1572 // LogMessage("PortObjectAppendEx: appending ports\n");
1573 if( !PortObjectAppend((PortObject*) poa, pob ) ) return 0;
1574
1575 // LogMessage("PortObjectAppendEx: appending rules\n");
1576 if( !PortObject2AppendPortObject( poa, pob ) ) return 0;
1577
1578 return poa;
1579 }
1580
1581 /*
1582 PORT TABLE FUNCTIONS
1583 */
1584
1585 /*
1586 Create a new table
1587 */
PortTableNew(void)1588 PortTable * PortTableNew(void)
1589 {
1590 PortTable * p;
1591
1592 p = (PortTable*) calloc(1,sizeof(PortTable));
1593 if(!p)
1594 return 0;
1595
1596 p->pt_polist = sflist_new();
1597 if(!p->pt_polist )
1598 {
1599 free(p);
1600 return 0;
1601 }
1602
1603 p->pt_lrc = PTBL_LRC_DEFAULT; /* 10 rules, user should really control these */
1604 p->pt_optimize = 1; /* if disabled, only one merged rule group is used */
1605
1606 return p;
1607 }
1608
PortTableFree(PortTable * p)1609 void PortTableFree(PortTable *p)
1610 {
1611 int i;
1612 SFGHASH_NODE *node;
1613
1614 if (!p)
1615 return;
1616
1617 if (p->pt_polist)
1618 {
1619 sflist_free_all(p->pt_polist, PortObjectFree );
1620 }
1621 if (p->pt_mpo_hash)
1622 {
1623 PortObject2 *po;
1624 for (node = sfghash_findfirst(p->pt_mpo_hash);
1625 node;
1626 node = sfghash_findnext(p->pt_mpo_hash))
1627 {
1628 po = node->data;
1629 /* Free the data from this entry */
1630 PortObject2Free(po);
1631 }
1632 sfghash_delete(p->pt_mpo_hash);
1633 }
1634 if (p->pt_plx_list)
1635 {
1636 sflist_free_all(p->pt_plx_list, plx_free);
1637 }
1638 if (p->pt_mpxo_hash)
1639 {
1640 #if 0
1641 PortObject2 *po;
1642 for (node = sfghash_findfirst(p->pt_mpxo_hash);
1643 node;
1644 node = sfghash_findnext(p->pt_mpxo_hash))
1645 {
1646 po = node->data;
1647 /* Free the data from this entry */
1648 //PortObject2Free(po);
1649 }
1650 #endif
1651 sfghash_delete(p->pt_mpxo_hash);
1652 }
1653 for (i=0;i<SFPO_MAX_PORTS;i++)
1654 {
1655 #if 0
1656 if (p->pt_port_object[i])
1657 {
1658 PortObject2Free(p->pt_port_object[i]);
1659 }
1660 #endif
1661 }
1662
1663 free(p);
1664 }
1665
PortTableFindInputPortObjectName(PortTable * pt,char * po_name)1666 PortObject * PortTableFindInputPortObjectName(PortTable * pt, char * po_name)
1667 {
1668 SF_LNODE * lpos;
1669 PortObject * po;
1670
1671 if( !pt ) return NULL;
1672 if( !po_name ) return NULL;
1673
1674 /* Normalize each of the input port objects */
1675 for(po =(PortObject*)sflist_firstpos(pt->pt_polist,&lpos);
1676 po!=0;
1677 po =(PortObject*)sflist_nextpos(pt->pt_polist,&lpos) )
1678 {
1679 if( po->name )
1680 {
1681 if( strcmp(po->name,po_name)==0 )
1682 {
1683 return po;
1684 }
1685 }
1686 }
1687 return NULL;
1688 }
1689
1690 /*
1691 * Find PortObject by PortItem Info
1692 */
PortTableFindInputPortObjectPorts(PortTable * pt,PortObject * pox)1693 PortObject * PortTableFindInputPortObjectPorts( PortTable * pt, PortObject * pox )
1694 {
1695 SF_LNODE * lpos;
1696 PortObject * po;
1697
1698 if( !pt ) return NULL;
1699 if( !pox ) return NULL;
1700
1701 for(po =(PortObject*)sflist_firstpos(pt->pt_polist,&lpos);
1702 po!=0;
1703 po =(PortObject*)sflist_nextpos(pt->pt_polist,&lpos) )
1704 {
1705 if( PortObjectEqual( po, pox ) )
1706 {
1707 return po;
1708 }
1709 }
1710 return NULL;
1711 }
1712
1713
PortTableNormalizeInputPortObjects(PortTable * p)1714 int PortTableNormalizeInputPortObjects( PortTable *p )
1715 {
1716 SF_LNODE * lpos;
1717 PortObject * po;
1718
1719 /* Normalize each of the input port objects */
1720 for(po =(PortObject*)sflist_firstpos(p->pt_polist,&lpos);
1721 po!=0;
1722 po =(PortObject*)sflist_nextpos(p->pt_polist,&lpos) )
1723 {
1724 PortObjectNormalize(po);
1725 }
1726 return 0;
1727 }
1728
PortObjectAddRule(PortObject * po,int rule)1729 int PortObjectAddRule( PortObject * po , int rule )
1730 {
1731 int * pruleid;
1732
1733 //LogMessage("Adding Rule %d to Port Object '%s'\n",rule,po->name);
1734 if( !po )
1735 return -1;
1736
1737 if( !po->rule_list )
1738 return -1;
1739
1740 /* Add rule index to rule list */
1741 pruleid = calloc(1,sizeof(int));
1742 if( !pruleid )
1743 {
1744 return -1;
1745 }
1746
1747 *pruleid = rule;
1748
1749 sflist_add_tail( po->rule_list, pruleid );
1750
1751 return 0;
1752 }
1753
1754 /*
1755 Add Users PortObjects to the Table
1756
1757 We save the users port object, so it's no longer the users.
1758 */
PortTableAddObject(PortTable * p,PortObject * po)1759 int PortTableAddObject( PortTable *p, PortObject * po )
1760 {
1761 SF_LNODE * lpos;
1762 PortObject * pox;
1763
1764
1765 /* Search for the Port Object in the input list, by address */
1766 for(pox =(PortObject*)sflist_firstpos(p->pt_polist,&lpos);
1767 pox!=0;
1768 pox =(PortObject*)sflist_nextpos(p->pt_polist,&lpos) )
1769 {
1770 if( pox == po )
1771 {
1772 /* already in list - just return */
1773 return 0;
1774 }
1775 }
1776
1777 /* Save the users port object, if not already in the list */
1778 if( sflist_add_tail(p->pt_polist,po) )
1779 return -1;
1780
1781 return 0;
1782 }
1783
1784
1785
1786 /*
1787 Hash routine for hashing PortObjects as Keys
1788
1789 p - SFHASHFCN *
1790 d - PortObject *
1791 n = 4 bytes (sizeof*) - not used
1792
1793 Don't use this for type=ANY port objects
1794 */
1795 static
PortObject_hash(SFHASHFCN * p,unsigned char * d,int n)1796 unsigned PortObject_hash( SFHASHFCN * p, unsigned char *d, int n )
1797 {
1798 unsigned hash = p->seed;
1799 PortObjectItem * poi;
1800 PortObject * po;
1801 SF_LNODE * pos;
1802
1803 #ifdef WIN32
1804 n = n; /* This quiets a Win32 warning */
1805 #endif
1806
1807 po = *(PortObject**) d;
1808
1809 /* hash up each item */
1810 for(poi =(PortObjectItem*)sflist_firstpos(po->item_list,&pos);
1811 poi != NULL;
1812 poi =(PortObjectItem*)sflist_nextpos(po->item_list,&pos) )
1813 {
1814 switch(poi->type)
1815 {
1816 case PORT_OBJECT_PORT:
1817 hash *= p->scale;
1818 hash += poi->lport & 0xff;
1819 hash *= p->scale;
1820 hash += (poi->lport >> 8) & 0xff;
1821 break;
1822
1823 case PORT_OBJECT_RANGE:
1824 hash *= p->scale;
1825 hash += poi->lport & 0xff;
1826 hash *= p->scale;
1827 hash += (poi->lport >> 8) & 0xff;
1828
1829 hash *= p->scale;
1830 hash += poi->hport & 0xff;
1831 hash *= p->scale;
1832 hash += (poi->hport >> 8) & 0xff;
1833 break;
1834 }
1835 }
1836 return hash ^ p->hardener;
1837 }
1838
1839 /*
1840 * Merge multiple PortObjects into a final PortObject2,
1841 * this merges ports and rules.
1842 *
1843 * merge po's in pol, find a previous instance add it.
1844 *
1845 * This is done as follows:
1846 * 1) check if it's in the plx table-mhashx, this uses the list of
1847 * addresses of the Input PortObjects as it's key, not the ports.
1848 * This is quick and does not require assembling/merging the port
1849 * objects intoa PortObject2 1st.
1850 * 2) if found were done, otherwise
1851 * 3) make a merged PortObject2
1852 * 4) Try adding the PortObject2 to it's table - mhash
1853 * a) if it adds go on, else
1854 * b) if it's already in the table
1855 * 1) get the one in the table
1856 * 2) add any ports in the just created one
1857 * 3) free the one just created
1858 * 5) Create a plx object
1859 * 6) Add the plx object to the plx Table
1860 * 1) if it's already in the object - fail this contradicts 1)
1861 * 7) return the create PortObject2, or the one retrived from the
1862 * PortObject table.
1863 *
1864 * pol - list of input PortObject pointers
1865 * pol_cnt- count in 'pol'
1866 * mhash - stores the merged ports, using the merged port objects port list as a key.
1867 * mhashx - stores plx keys, and PortObject2 *'s as data for the final merged port objects,
1868 * the plx keys provide a quicker way to compare port lists to ensure if two ports
1869 * are using the same set of rules (port objects).
1870 * mhash and mhashx reference the same port objects as data, but use different keys for lookup
1871 * purposes. Once we perform a merge we store the results, using the 'plx' as the key for future lookup.
1872 * plx - key to use to lookup and store the merged port object
1873 *
1874 *
1875 */
1876 static
_merge_N_pol(SFGHASH * mhash,SFGHASH * mhashx,SF_LIST * plx_list,void ** pol,int pol_cnt,plx_t * plx)1877 PortObject2 * _merge_N_pol( SFGHASH * mhash, SFGHASH * mhashx,
1878 SF_LIST * plx_list, void ** pol,
1879 int pol_cnt, plx_t * plx )
1880 {
1881 PortObject2 * ponew;
1882 PortObject2 * pox;
1883 plx_t * plx_tmp;
1884 int stat;
1885 int i;
1886
1887 /*
1888 * Check for the merged port object in the plx table
1889 */
1890 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
1891 "++++n=%d sfghash_find-mhashx\n",pol_cnt););
1892 ponew = sfghash_find( mhashx, &plx );
1893 if( ponew )
1894 {
1895 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
1896 "n=%d ponew found in mhashx\n",pol_cnt););
1897 return ponew;
1898 }
1899 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
1900 "n=%d posnew not found in mhashx\n",pol_cnt););
1901
1902 /*
1903 * Merge the port objects together - ports and rules
1904 */
1905
1906
1907 /* Dup the 1st port objects rules and ports */
1908 ponew = PortObject2Dup( (PortObject *)pol[0] );
1909 if( !ponew )
1910 {
1911 FatalError("Could not Dup2\n");
1912 }
1913
1914 /* Merge in all the other port object rules and ports */
1915 if( pol_cnt > 1 )
1916 {
1917 for(i=1;i<pol_cnt;i++)
1918 {
1919 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"*** %d rules in object %d\n",
1920 ((PortObject *)pol[i])->rule_list->count,i););
1921 PortObjectAppendEx2( ponew, (PortObject *)pol[i] );
1922 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
1923 "*** merged port-object[%d], %d rules\n",
1924 i,ponew->rule_hash->count););
1925 }
1926 PortObjectNormalize( (PortObject*)ponew );
1927 }
1928
1929 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
1930 "*** merged %d port objects, %d rules\n",
1931 pol_cnt,ponew->rule_hash->count););
1932 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"*** merged ponew - follows: \n"););
1933 // PortObjectPrint2(ponew);
1934
1935 /*
1936 * Add the Merged PortObject2 to the PortObject2 hash table
1937 * keyed by ports.
1938 */
1939 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"n=%d sfghash_add-mhash\n",pol_cnt););
1940 stat =sfghash_add( mhash, &ponew, ponew );
1941 if( stat != SFGHASH_OK )
1942 {
1943 /* This is possible since PLX hash on a different key */
1944 if( stat == SFGHASH_INTABLE )
1945 {
1946 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"n=%d sfghash_add-mhash ponew in table\n",pol_cnt););
1947 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"n=%d sfghash_find-mhash ponew\n",pol_cnt););
1948 pox = sfghash_find(mhash,&ponew);
1949 if( pox )
1950 {
1951 PortObject2AppendPortObject2(pox,ponew);
1952 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"sfportobject.c: merge_N_pol() line=%d SFGHASH_INTABLE\n",__LINE__););
1953 PortObject2Free( ponew );
1954 ponew = pox;
1955 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"n=%d sfghash_find-mhash ponew found, new rules merged\n",pol_cnt););
1956 }
1957 else
1958 {
1959 FatalError("mhash add/find error n=%d\n", pol_cnt);
1960 }
1961 }
1962 else
1963 {
1964 FatalError("Could not add ponew to hash table- error\n");
1965 }
1966 }
1967
1968 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"***%d ports merged object added to mhash table\n",pol_cnt););
1969
1970 /*
1971 * Create a plx node and add it to plx table
1972 * as the key with the merged port object as the data
1973 */
1974 plx_tmp = plx_new( pol, pol_cnt);
1975 if(!plx_tmp)
1976 {
1977 FatalError("plx_new: memory alloc error\n");
1978 }
1979 sflist_add_head(plx_list, (void *)plx_tmp);
1980
1981 /*
1982 * Add the plx node to the PLX hash table
1983 */
1984 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"n=%d sfghash_add-mhashx\n",pol_cnt););
1985 stat = sfghash_add( mhashx, &plx_tmp, ponew );
1986 if( stat != SFGHASH_OK )
1987 {
1988 if( stat == SFGHASH_INTABLE )
1989 {
1990 FatalError("Could not add merged plx to PLX HASH table-INTABLE\n");
1991 }
1992 else
1993 {
1994 FatalError("Could not add merged plx to PLX HASH table\n");
1995 }
1996 }
1997
1998 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"Added-%d Merged Rule Groups to PLX HASH\n",pol_cnt););
1999
2000 /*
2001 * Validate hash table entry
2002 */
2003 if( sfghash_find( mhashx, &plx_tmp ) != ponew )
2004 {
2005 FatalError("Find after add failed on PLX HASH table key\n");
2006 }
2007
2008 return ponew;
2009 }
2010 /*
2011 * Merge Input Port Objects into rule collections that are particular to
2012 * each port. We store the results as objects and point to these in the
2013 * pt_port_object[MAX_PORTS] array.
2014 *
2015 * We use plx_t types to manage tracking and testing for merged large
2016 * rule groups, and merged small port groups.
2017 *
2018 * mhash - table of merged port objects ( built and used here )
2019 * mhashx - table of plx_t objects ( built and used here )
2020 * pol - list of input port objects touching the current port
2021 * pol_cnt - number of port objects in port list
2022 * lcnt - large rule count
2023 *
2024 */
2025 static
PortTableCompileMergePortObjectList2(SFGHASH * mhash,SFGHASH * mhashx,SF_LIST * plx_list,PortObject * pol[],int pol_cnt,unsigned int lcnt)2026 PortObject2 * PortTableCompileMergePortObjectList2(SFGHASH * mhash,
2027 SFGHASH * mhashx,
2028 SF_LIST * plx_list,
2029 PortObject * pol[],
2030 int pol_cnt,
2031 unsigned int lcnt )
2032 {
2033 PortObject2 * ponew = NULL;
2034 PortObject2 * posnew = NULL;
2035 static void * polarge[SFPO_MAX_LPORTS];
2036 static void * posmall[SFPO_MAX_LPORTS];
2037 int nlarge = 0;
2038 int nsmall = 0;
2039 plx_t plx_small;
2040 plx_t plx_large;
2041 unsigned largest;
2042 int i;
2043
2044 /*
2045 * Find the largest rule count of all of the port objects
2046 */
2047 largest = 0;
2048 for(i=0;i<pol_cnt;i++)
2049 {
2050 if( pol[i]->rule_list->count >= (unsigned)lcnt )
2051 {
2052 if( pol[i]->rule_list->count > largest )
2053 largest = pol[i]->rule_list->count;
2054 }
2055 }
2056
2057 /*
2058 * Classify PortObjects as large or small based on rule set size
2059 * and copy them into separate lists
2060 */
2061 for(i=0;i<pol_cnt;i++)
2062 {
2063 if( pol[i]->rule_list->count >= (unsigned)lcnt )
2064 {
2065 if( nlarge < SFPO_MAX_LPORTS )
2066 polarge[ nlarge++ ] = (void *)pol[i];
2067 }
2068 else
2069 {
2070 if( nsmall < SFPO_MAX_LPORTS )
2071 posmall[ nsmall++ ] = (void *)pol[i];
2072 }
2073 }
2074
2075 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"*** %d small rule groups, %d large rule groups\n",nsmall,nlarge););
2076
2077 /*
2078 * Sort the pointers to the input port objects so
2079 * we always get them in the same order for key comparisons
2080 */
2081 if( nlarge > 1 )
2082 qsort( polarge, nlarge, sizeof(void*), p_keycmp );
2083 if( nsmall > 1 )
2084 qsort( posmall, nsmall, sizeof(void*), p_keycmp );
2085
2086 DEBUG_WRAP(
2087 for(i=0;i<nsmall;i++) DebugMessage(DEBUG_PORTLISTS, "posmall[%d]=%lu\n",i,posmall[i]);
2088 for(i=0;i<nlarge;i++) DebugMessage(DEBUG_PORTLISTS, "polarge[%d]=%lu\n",i,polarge[i]);
2089 );
2090
2091 /*
2092 * Setup plx_t representation of port list pointers
2093 */
2094 plx_small.n = nsmall;
2095 plx_small.p = (void**)&posmall[0];
2096
2097 plx_large.n = nlarge;
2098 plx_large.p = (void**)&polarge[0];
2099
2100 #ifdef DEBUG_MSGS
2101 if( nlarge )
2102 {
2103 DebugMessage(DEBUG_PORTLISTS, "large "); plx_print(&plx_large);
2104 }
2105 if( nsmall )
2106 {
2107 DebugMessage(DEBUG_PORTLISTS, "small "); plx_print(&plx_small);
2108 }
2109 #endif
2110
2111 /*
2112 * Merge Large PortObjects
2113 */
2114 if( nlarge )
2115 {
2116 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"***nlarge=%d \n",nlarge););
2117 ponew = _merge_N_pol( mhash, mhashx, plx_list, polarge, nlarge, &plx_large);
2118 }
2119
2120 /*
2121 * Merge Small PortObjects
2122 */
2123 if( nsmall )
2124 {
2125 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"***nsmall=%d \n",nsmall););
2126 posnew = _merge_N_pol( mhash, mhashx, plx_list, posmall, nsmall, &plx_small);
2127 }
2128 /*
2129 * Merge Large and Small (rule groups) PortObject2's together
2130 * append small port object rule sets to the large port objects,
2131 * remove the large port objects ports from the smaller port objects
2132 */
2133 if( nlarge && nsmall )
2134 {
2135 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"*** appending small rules to larger rule group\n"););
2136 if (ponew != posnew)
2137 {
2138
2139 /* Append small port object, just the rules */
2140 PortObject2AppendPortObject2( ponew, posnew );
2141
2142 /* Remove Ports in ponew from posnew */
2143 PortObjectRemovePorts( (PortObject*)posnew, (PortObject*)ponew );
2144 }
2145
2146 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"*** final - using small+large rule group \n"););
2147 }
2148 else if( nsmall )
2149 {
2150 /* Only a small port object */
2151 ponew = posnew;
2152
2153 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"*** final - using small rule group only \n"););
2154 }
2155 else if( nlarge )
2156 {
2157 /*
2158 * The large rule group port object is already set to ponew
2159 */
2160 }
2161
2162 return ponew;
2163 }
2164
add_port_object(SF_LIST ** parray,int port,PortObject * po)2165 static inline void add_port_object(SF_LIST **parray, int port, PortObject *po)
2166 {
2167 if (!parray[port])
2168 {
2169 parray [port] = (SF_LIST*) sflist_new();
2170 if ( !parray[port] )
2171 return;
2172 }
2173
2174 if (parray[port]->tail && (parray[port]->tail->ndata == po))
2175 return;
2176
2177 sflist_add_tail( parray [port], po );
2178 }
2179
2180 // Update port object lists
update_port_lists(SF_LIST ** parray,PortObject * po)2181 static inline void update_port_lists(SF_LIST **parray, PortObject *po)
2182 {
2183 PortObjectItem *poi;
2184 int port;
2185 bool not_flag_set = FALSE;
2186
2187 for(poi=(PortObjectItem*)sflist_first(po->item_list);
2188 poi != 0;
2189 poi=(PortObjectItem*)sflist_next(po->item_list) )
2190 {
2191 if( poi->type == PORT_OBJECT_ANY)
2192 return;
2193
2194 else if( poi->type == PORT_OBJECT_PORT)
2195 {
2196 if (poi->flags & PORT_OBJECT_NOT_FLAG)
2197 {
2198 not_flag_set = TRUE;
2199 break;
2200 }
2201
2202 add_port_object(parray, poi->lport, po);
2203
2204 }
2205 else if( poi->type == PORT_OBJECT_RANGE)
2206 {
2207 if (poi->flags & PORT_OBJECT_NOT_FLAG)
2208 {
2209 not_flag_set = TRUE;
2210 break;
2211 }
2212
2213 for( port = poi->lport; port <= poi->hport; port++ )
2214 {
2215 add_port_object(parray, port, po);
2216 }
2217
2218 }
2219 }
2220
2221 if (not_flag_set)
2222 {
2223 for( port = 0; port < SFPO_MAX_PORTS; port++ )
2224 {
2225 add_port_object(parray, port, po);
2226 }
2227 }
2228 }
2229
2230 // Create optimized port lists per port
create_port_lists(PortTable * p)2231 static inline SF_LIST **create_port_lists(PortTable * p)
2232 {
2233 PortObject *po;
2234 SF_LNODE *lpos;
2235
2236 SF_LIST **parray = calloc(sizeof(SF_LIST *),SFPO_MAX_PORTS);
2237
2238 if(!parray)
2239 return NULL;
2240
2241 /* Build a list of port objects touching port 'i' */
2242 for(po=sflist_firstpos(p->pt_polist,&lpos);
2243 po;
2244 po=sflist_nextpos(p->pt_polist,&lpos) )
2245 {
2246 update_port_lists(parray, po);
2247 }
2248
2249 return parray;
2250 }
2251
delete_port_lists(SF_LIST ** parray)2252 static inline void delete_port_lists(SF_LIST **parray)
2253 {
2254 int port;
2255
2256 for( port = 0; port < SFPO_MAX_PORTS; port++ )
2257 {
2258 SF_LIST *list = (SF_LIST *) parray[port];
2259 if (list)
2260 sflist_free(list);
2261 }
2262 }
2263
2264 /*
2265 *
2266 *
2267 * mhash
2268 * mhashx
2269 data structure used: p->pt_polist
2270 */
PortTableCompileMergePortObjects(PortTable * p)2271 int PortTableCompileMergePortObjects( PortTable * p )
2272 {
2273 SF_LNODE * lpos;
2274 SFGHASH * mhash;
2275 SFGHASH * mhashx;
2276 SFGHASH_NODE * node;
2277 SF_LIST * plx_list;
2278 int id = PO_INIT_ID;
2279 static PortObject * pol[SFPO_MAX_LPORTS]; // TODO: dynamically allocate
2280 int pol_cnt;
2281 char * parray = NULL;
2282 int i;
2283 SF_LIST **optimized_pl;
2284
2285 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"***\n***Merging PortObjects->PortObjects2\n***\n"););
2286
2287 /* Create a Merged Port Object Table - hash by ports */
2288 mhash = sfghash_new(PO_HASH_TBL_ROWS, sizeof(PortObject *), 0 /*userkeys-no*/, 0 /*free data-don't*/);
2289 if( !mhash )
2290 return -1;
2291
2292 /* Setup hashing function and key comparison function */
2293 sfhashfcn_set_keyops( mhash->sfhashfcn, PortObject_hash, PortObject_keycmp );
2294
2295 /* remove randomness */
2296 if (ScStaticHash())
2297 sfhashfcn_static( mhash->sfhashfcn );
2298
2299 p->pt_mpo_hash = mhash;
2300
2301 /* Create a Merged Port Object Table - hash by ports */
2302 mhashx = sfghash_new(PO_HASH_TBL_ROWS, sizeof(plx_t *), 0/*userkeys-no*/, 0/*freedata()-don't*/);
2303 if( !mhashx )
2304 return -1;
2305 /* Setup hashing function and key comparison function */
2306 sfhashfcn_set_keyops( mhashx->sfhashfcn,plx_hash,plx_keycmp );
2307
2308 /* remove randomness */
2309 if (ScStaticHash())
2310 sfhashfcn_static( mhashx->sfhashfcn );
2311
2312 p->pt_mpxo_hash = mhashx;
2313
2314 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"***\n*** PortList-Merging, Large Rule groups must have %d rules\n",p->pt_lrc););
2315
2316 plx_list = sflist_new();
2317 sflist_init(plx_list);
2318
2319 p->pt_plx_list = plx_list;
2320
2321 optimized_pl = create_port_lists(p);
2322 if(!optimized_pl)
2323 {
2324 FatalError("Memory error in PortTableCompile()\n");
2325 }
2326 /*
2327 * For each port, merge rules from all port objects that touch the port
2328 * into an optimal object, that may be shared with other ports.
2329 */
2330 for(i=0;i<SFPO_MAX_PORTS;i++)
2331 {
2332 PortObject * po;
2333
2334 /* Build a list of port objects touching port 'i' */
2335 pol_cnt = 0;
2336 for(po=sflist_firstpos(optimized_pl[i],&lpos);
2337 po;
2338 po=sflist_nextpos(optimized_pl[i],&lpos) )
2339 {
2340 if( pol_cnt < SFPO_MAX_LPORTS )
2341 {
2342 pol[ pol_cnt++ ] = po;
2343 }
2344 }
2345
2346 p->pt_port_object[i] = 0;
2347
2348 if( !pol_cnt )
2349 {
2350 //port not contained in any PortObject
2351 continue;
2352 }
2353
2354 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"*** merging list for port[%d] \n",i);fflush(stdout););
2355
2356 /* merge the rules into an optimal port object */
2357 p->pt_port_object[i] =
2358 PortTableCompileMergePortObjectList2( mhash, mhashx, plx_list, pol, pol_cnt, p->pt_lrc );
2359 if( !p->pt_port_object[i] )
2360 {
2361 FatalError(" Could not merge PorObjectList on port %d\n",i);
2362 }
2363
2364 /* give the new compiled port object an id of its own */
2365 p->pt_port_object[i]->id = id++;
2366
2367 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"\n");fflush(stdout););
2368 }
2369
2370 delete_port_lists(optimized_pl);
2371 free(optimized_pl);
2372 /*
2373 * Normalize the Ports so they indicate only the ports that
2374 * reference the composite port object
2375 */
2376
2377 /* 1st- Setup bitmasks for collecting ports */
2378 for(node=sfghash_findfirst(mhashx);
2379 node;
2380 node=sfghash_findnext(mhashx) )
2381 {
2382 unsigned char * buf;
2383 PortObject2 * poa;
2384
2385 poa = (PortObject2*)node->data;
2386 if( !poa )
2387 continue;
2388
2389 if (!poa->bitop)
2390 {
2391 poa->bitop = calloc(1,sizeof(BITOP));
2392 if( !poa->bitop)
2393 {
2394 FatalError("Memory error in PortTableCompile\n");
2395 }
2396 buf = calloc(1,8192);
2397 if( !buf )
2398 {
2399 FatalError("Memory alloc error in PortObjectCompile()\n");
2400 }
2401 if( boInitStaticBITOP(poa->bitop,8192,buf) )
2402 {
2403 FatalError("BitOp error in PortObjectCompile()\n");
2404 }
2405 }
2406 }
2407
2408 /* Count how many ports each final port-object is used on */
2409 for(i=0;i<SFPO_MAX_PORTS;i++)
2410 {
2411 PortObject2 * poa;
2412 poa = p->pt_port_object[i];
2413 if(poa)
2414 {
2415 poa->port_cnt++;
2416 if( poa->bitop )
2417 {
2418 if( boSetBit(poa->bitop, (unsigned int) i ) )
2419 {
2420 FatalError("BitOp-Set error\n");
2421 }
2422 }
2423 else
2424 {
2425 FatalError("NULL po->bitop in po on port %d\n",i);
2426 }
2427 }
2428 }
2429
2430 /* get a port array 64K bytes */
2431 parray = calloc(1,SFPO_MAX_PORTS);
2432 if(!parray)
2433 {
2434 FatalError("Memory error in PortTableCompile()\n");
2435 }
2436
2437 /* Process Port-Bitop map and print final port-object usage stats */
2438 for(node=sfghash_findfirst(mhashx);
2439 node;
2440 node=sfghash_findnext(mhashx) )
2441 {
2442 SF_LIST * plist;
2443 PortObject2 * po;
2444 int nports;
2445
2446 po = (PortObject2*)node->data;
2447 if( !po )
2448 {
2449 FatalError("MergePortOBject-NormalizePorts -NULL po\n");
2450 }
2451
2452 if( !po->port_cnt )/* port object is not used ignore it */
2453 continue;
2454
2455 if( !po->bitop )
2456 {
2457 //FatalError("MergePortOBject-NormalizePorts -NULL po->bitop\n");
2458 continue;
2459 }
2460
2461 /* Convert the bitop bits to a char array */
2462 memset(parray,0,SFPO_MAX_PORTS);
2463 nports = 0;
2464 for(i=0;i<SFPO_MAX_PORTS;i++)
2465 {
2466 if( boIsBitSet(po->bitop, i ) )
2467 {
2468 parray[ i ] = 1;
2469 nports++;
2470 }
2471 }
2472
2473 /* Release bit buffer for each port object */
2474 if( po->bitop )
2475 {
2476 //if( po->bitop->pucBitBuffer )
2477 //{
2478 // free( po->bitop->pucBitBuffer );
2479 // po->bitop->pucBitBuffer = NULL;
2480 //}
2481 boFreeBITOP(po->bitop);
2482 free( po->bitop );
2483 po->bitop=NULL;
2484 }
2485
2486 /* Build a PortObjectItem list from the char array */
2487 plist = PortObjectItemListFromCharPortArray( parray, SFPO_MAX_PORTS, nports);
2488 if( !plist )
2489 {
2490 FatalError("MergePortObjects: No PortObjectItems in portobject\n");
2491 }
2492
2493 /* free the original list */
2494 sflist_free_all( po->item_list, free );
2495
2496 /* set the new list - this is a list of port itmes for this port object */
2497 po->item_list = plist;
2498
2499 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"port-object id = %d, port cnt = %d\n",po->id,po->port_cnt););
2500 }
2501
2502 if(parray) free(parray);
2503
2504 return 0;
2505 }
2506 /*
2507 *
2508 * Verify all rules in 'po' list are in 'po2' hash
2509 *
2510 * return 0 - OK
2511 * !0 - a rule in po is not in po2
2512 */
2513 static
_po2_include_po_rules(PortObject2 * po2,PortObject * po)2514 int _po2_include_po_rules( PortObject2 * po2, PortObject * po )
2515 {
2516 //SFGHASH_NODE * node;
2517 int * pid;
2518 int * id;
2519 SF_LNODE * rpos;
2520
2521 /* get each rule in po */
2522 for(pid=sflist_firstpos(po->rule_list,&rpos);
2523 pid;
2524 pid=sflist_nextpos(po->rule_list,&rpos) )
2525 {
2526 /* find it in po2 */
2527 id =(int*) sfghash_find(po2->rule_hash,pid);
2528
2529 /* make sure it's in po2 */
2530 if(!id )
2531 {
2532 return 1; /* error */
2533 }
2534 }
2535
2536 return 0;
2537 }
2538
2539 /*
2540 * Perform a consistency check on the final port+rule objects
2541 *
2542 * Walk the rules
2543 */
PortTableConsistencyCheck(PortTable * p)2544 int PortTableConsistencyCheck( PortTable *p )
2545 {
2546 char * parray = 0;
2547 SFGHASH_NODE * node;
2548 int i;
2549 SF_LNODE * pos;
2550 SF_LNODE * ipos;
2551 PortObject * ipo;
2552 PortObject2 * lastpo = NULL;
2553 PortObjectItem * poi;
2554
2555 parray = calloc(1,SFPO_MAX_PORTS);
2556 if(!parray)
2557 {
2558 FatalError("Memory eror in PortTableComopile\n");
2559 }
2560
2561 /* Make sure each port is only in one composite port object */
2562 for(node=sfghash_findfirst(p->pt_mpo_hash);
2563 node;
2564 node=sfghash_findnext(p->pt_mpo_hash) )
2565 {
2566 PortObject2 * po;
2567 po = (PortObject2*)node->data;
2568
2569 if( !po )
2570 {
2571 FatalError("PortObject consistency Check failed, hash table problem\n");
2572 }
2573
2574 if( !po->port_cnt )/* port object is not used ignore it */
2575 continue;
2576
2577 for(i=0;i<SFPO_MAX_PORTS;i++)
2578 {
2579 if( PortObjectHasPort( (PortObject*)po, i ) )
2580 {
2581 if( parray[i] )
2582 {
2583 FatalError("PortTableCompile: failed consistency check, multiple objects reference port %d\n",i);
2584 }
2585 parray[i]=1;
2586 }
2587 }
2588 }
2589
2590 if( parray ) free(parray);
2591
2592 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"***\n***Port Table Compiler Consistency Check Phase-I Passed !\n"););
2593
2594
2595 /*
2596 * This phase checks the Input port object rules/ports against
2597 * the composite port objects.
2598 *
2599 * For each input object
2600 * check that each port it reference has all of the rules
2601 * referenced to that port in the composit object
2602 */
2603 for(ipo=sflist_firstpos(p->pt_polist,&pos);
2604 ipo;
2605 ipo=sflist_nextpos(p->pt_polist,&pos) )
2606 {
2607 /*
2608 * for each port in this object get the composite port object
2609 * assigned to that port and verify all of the input objects rules
2610 * are in the composite object. This verifies all rules are applied
2611 * to the originally intended port.
2612 */
2613 for(poi=sflist_firstpos(ipo->item_list,&ipos);
2614 poi;
2615 poi=sflist_nextpos(ipo->item_list,&ipos) )
2616 {
2617 switch(poi->type)
2618 {
2619 case PORT_OBJECT_ANY: /* do nothing */
2620 break;
2621
2622 case PORT_OBJECT_PORT:
2623 if( _po2_include_po_rules( p->pt_port_object[ poi->lport ], ipo ) )
2624 {
2625 FatalError("InputPortObject<->CompositePortObject consistency Check II failed!\n");
2626 }
2627 break;
2628
2629 case PORT_OBJECT_RANGE:
2630 {
2631 for(i=poi->lport;i<=poi->hport;i++)
2632 {
2633 /* small optimization*/
2634 if( lastpo != p->pt_port_object[ i ] )
2635 {
2636 if( _po2_include_po_rules( p->pt_port_object[ i ], ipo ) )
2637 {
2638 FatalError("InputPortObject<->CompositePortObject consistency Check II failed!\n");
2639 }
2640 lastpo = p->pt_port_object[ i ];
2641 }
2642 }
2643 }
2644 break;
2645 }
2646 }
2647 }
2648
2649 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,
2650 "***\n***Port Table Compiler Consistency Check Phase-II Passed !!! - Good to go Houston\n****\n"););
2651 return 0;
2652 }
2653
2654 /*
2655 * Compile the PortTable
2656 *
2657 * This builds a set of Port+Rule objects that are in some way an optimal
2658 * set of objects to indicate which rules to apply to which ports. Since
2659 * these groups are calculated consistency checking is done with the finished
2660 * objects.
2661 */
PortTableCompile(PortTable * p)2662 int PortTableCompile( PortTable * p )
2663 {
2664 /*
2665 * If not using an optimized Table use the rule_index_map in parser.c
2666 */
2667 if( !p->pt_optimize )
2668 {
2669 return 0;
2670 }
2671
2672 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"#PortTableCompile: Compiling Port Array Lists\n"););
2673
2674 if( PortTableCompileMergePortObjects( p ) )
2675 {
2676 FatalError("Could not create PortArryayLists\n");
2677 }
2678
2679 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"Done\n");fflush(stdout););
2680
2681 if(ScTestMode())
2682 PortTableConsistencyCheck(p);
2683
2684 return 0;
2685 }
2686 static
integer_compare(const void * arg1,const void * arg2)2687 int integer_compare( const void *arg1, const void *arg2 )
2688 {
2689 if( *(int*)arg1 < *(int*)arg2 ) return -1;
2690 if( *(int*)arg1 > *(int*)arg2 ) return 1;
2691 return 0;
2692 }
2693
2694 static
RuleListToSortedArray(SF_LIST * rl)2695 int * RuleListToSortedArray( SF_LIST * rl )
2696 {
2697 SF_LNODE * pos = NULL;
2698 int * prid;
2699 int * ra;
2700 int k=0;
2701
2702 if( !rl )
2703 return 0;
2704
2705 if(!rl->count)
2706 return NULL;
2707
2708 ra = (int *)SnortAlloc(rl->count * sizeof(int));
2709
2710 for( prid = sflist_firstpos(rl,&pos);
2711 prid!= 0 && k < (int)rl->count;
2712 prid = sflist_nextpos(rl,&pos) )
2713 {
2714 ra[k++] = *prid;
2715 }
2716
2717 /* sort the array */
2718 qsort(ra,rl->count,sizeof(int),integer_compare);
2719
2720 return ra;
2721 }
2722 /**sort and uniq rule list.
2723 */
RuleListSortUniq(SF_LIST * rl)2724 void RuleListSortUniq(
2725 SF_LIST * rl
2726 )
2727 {
2728 unsigned i;
2729 int lastRuleIndex = -1;
2730 SF_LNODE *pos = NULL;
2731 int *currNode = NULL;
2732 unsigned uniqElements = 0;
2733 int *node = 0;
2734 int * rlist = NULL;
2735
2736 rlist = RuleListToSortedArray(rl);
2737 if(!rlist )
2738 {
2739 return ;
2740 }
2741
2742 currNode = sflist_firstpos(rl,&pos);
2743 if (currNode == NULL)
2744 {
2745 free(rlist);
2746 return;
2747 }
2748
2749 for(i=0; i < rl->count; i++)
2750 {
2751 if (rlist[i] > lastRuleIndex)
2752 {
2753 *currNode = lastRuleIndex = rlist[i];
2754 //replace the next element in place
2755 currNode = sflist_nextpos(rl,&pos);
2756 uniqElements++;
2757 }
2758 }
2759
2760 //free the remaining list nodes
2761 while (uniqElements != rl->count)
2762 {
2763 node = sflist_remove_tail (rl);
2764 free(node);
2765 }
2766
2767 free(rlist);
2768 }
2769
2770 /**Sort and make rule index in all port objects unique. Multiple policies may add
2771 * the same rule which can lead to duplication.
2772 */
PortTableSortUniqRules(PortTable * p)2773 void PortTableSortUniqRules(
2774 PortTable * p
2775 )
2776 {
2777 PortObject * po;
2778 SF_LNODE *pos = NULL;
2779
2780 for(po =(PortObject*)sflist_firstpos(p->pt_polist,&pos);
2781 po != NULL;
2782 po =(PortObject*)sflist_nextpos(p->pt_polist,&pos) )
2783 {
2784 RuleListSortUniq(po->rule_list);
2785 }
2786 }
2787
2788 static
RuleHashToSortedArray(SFGHASH * rh)2789 int * RuleHashToSortedArray( SFGHASH * rh )
2790 {
2791 int * prid;
2792 int * ra;
2793 int k = 0;
2794 SFGHASH_NODE * node;
2795
2796 if( !rh )
2797 return 0;
2798
2799 if(!rh->count)
2800 return NULL;
2801
2802 ra = (int *)SnortAlloc(rh->count * sizeof(int));
2803
2804 for( node = sfghash_findfirst(rh);
2805 node != 0 && k < (int)rh->count;
2806 node = sfghash_findnext(rh) )
2807 {
2808 prid = node->data;
2809 if( prid )
2810 {
2811 ra[k++] = *prid;
2812 }
2813 }
2814
2815 /* sort the array */
2816 qsort(ra,rh->count,sizeof(int),integer_compare);
2817
2818 return ra;
2819 }
2820
2821 /*
2822 * Print Input Port List
2823 */
PortTablePrintInput(PortTable * p)2824 void PortTablePrintInput( PortTable * p )
2825 {
2826 PortObject * po;
2827 SF_LNODE * pos;
2828
2829 LogMessage("*** %d PortObjects in Table\n",p->pt_polist->count);
2830 for(po =(PortObject*)sflist_firstpos(p->pt_polist,&pos);
2831 po!=0;
2832 po =(PortObject*)sflist_nextpos(p->pt_polist,&pos) )
2833 {
2834 PortObjectPrint( po );
2835 }
2836 }
2837
PortTablePrintInputEx(PortTable * p,void (* print_index_map)(int index,char * buf,int bufsize))2838 void PortTablePrintInputEx( PortTable * p,
2839 void (*print_index_map)(int index, char *buf, int bufsize) )
2840 {
2841 PortObject * po;
2842 SF_LNODE * pos;
2843 for(po =(PortObject*)sflist_firstpos(p->pt_polist,&pos);
2844 po != NULL;
2845 po =(PortObject*)sflist_nextpos(p->pt_polist,&pos) )
2846 {
2847 PortObjectPrintEx( po, print_index_map );
2848 }
2849 }
2850 /*
2851 Prints Compiled Ports/Rules Objects
2852 */
PortTablePrintCompiledEx(PortTable * p,void (* print_index_map)(int index,char * buf,int bufsize))2853 int PortTablePrintCompiledEx( PortTable * p ,
2854 void (*print_index_map)(int index, char *buf, int bufsize) )
2855 {
2856 PortObject2 * po = NULL;
2857 SFGHASH_NODE * node = NULL;
2858
2859 LogMessage(" *** PortTableCompiled [ %d compiled port groups ] \n\n",
2860 p->pt_mpo_hash->count);
2861
2862 for(node = sfghash_findfirst(p->pt_mpo_hash);
2863 node!= 0;
2864 node = sfghash_findnext(p->pt_mpo_hash) )
2865 {
2866 po = node->data;
2867
2868 PortObject2PrintEx( po, print_index_map );
2869 }
2870
2871 return 0;
2872 }
2873
2874 /*
2875 Print port items. Used internally by sfportobject.c.
2876 Buffer assumed trusted.
2877 */
PortObjectItemPrint(PortObjectItem * poi,char * dstbuf,int bufsize)2878 static void PortObjectItemPrint ( PortObjectItem * poi, char *dstbuf, int bufsize )
2879 {
2880 SnortSnprintfAppend(dstbuf, bufsize, " ");
2881
2882 if( poi->flags & PORT_OBJECT_NOT_FLAG )
2883 SnortSnprintfAppend(dstbuf, bufsize, "!");
2884
2885 switch( poi->type )
2886 {
2887 case PORT_OBJECT_PORT :
2888 SnortSnprintfAppend(dstbuf, bufsize, "%u", poi->lport);
2889 break;
2890
2891 case PORT_OBJECT_RANGE :
2892 SnortSnprintfAppend(dstbuf, bufsize, "%u:%u",poi->lport,poi->hport);
2893 break;
2894
2895 case PORT_OBJECT_ANY:
2896 SnortSnprintfAppend(dstbuf, bufsize, "any");
2897 break;
2898
2899 default:
2900 SnortSnprintfAppend(dstbuf, bufsize, " unknown port type @ %p", (void*)poi);
2901 break;
2902 }
2903 }
2904
PortObjectPrintPortsRaw(PortObject * po)2905 void PortObjectPrintPortsRaw(PortObject * po )
2906 {
2907 PortObjectItem * poi = NULL;
2908 SF_LNODE * pos = NULL;
2909 char * buf;
2910 int bufsize;
2911
2912 /* Need to buffer the string so we only do one LogMessage,
2913 * due to syslog output. The largest string needed to represent
2914 * each portobject is the length required to represent:
2915 * " unknown port type @ 0x<8 max bytes>" (See PortObjectItemPrint), or:
2916 * 30 bytes. For the entire list, need room for spaces and brackets and
2917 * potential negations. Or:
2918 * list_size * (30 + 1space_for_each_element, +
2919 * 1potential_negation) + surrounding_whitespace + brackets + NULL */
2920
2921 bufsize = po->item_list->count * (30 + 1 + 1) + 5;
2922 buf = (char*)SnortAlloc(bufsize);
2923
2924 SnortSnprintfAppend(buf, bufsize, " [");
2925
2926 for(poi=(PortObjectItem*)sflist_firstpos(po->item_list, &pos);
2927 poi != 0;
2928 poi=(PortObjectItem*)sflist_nextpos(po->item_list, &pos) )
2929 {
2930 PortObjectItemPrint(poi, buf, bufsize);
2931 }
2932
2933 SnortSnprintfAppend(buf, bufsize, " ]");
2934
2935 LogMessage("%s", buf);
2936
2937 free(buf);
2938 }
2939
2940
PortObject2PrintPorts(PortObject2 * po)2941 void PortObject2PrintPorts(PortObject2 * po )
2942 {
2943 PortObjectItem * poi = NULL;
2944 SF_LNODE * pos = NULL;
2945 int bufsize = sizeof(po_print_buf);
2946
2947 po_print_buf[0] = '\0';
2948
2949 SnortSnprintfAppend(po_print_buf, bufsize, " PortObject ");
2950
2951 if( po->name )
2952 {
2953 SnortSnprintfAppend(po_print_buf, bufsize, "%s ", po->name);
2954 }
2955
2956 SnortSnprintfAppend(po_print_buf, bufsize,
2957 " Id:%d Ports:%d Rules:%d\n {\n Ports [",
2958 po->id, po->item_list->count, po->rule_hash->count);
2959
2960 if( PortObjectHasAny( (PortObject*)po ) )
2961 {
2962 SnortSnprintfAppend(po_print_buf, bufsize, "any");
2963 }
2964 else
2965 {
2966 for(poi=(PortObjectItem*)sflist_firstpos(po->item_list,&pos);
2967 poi != 0;
2968 poi=(PortObjectItem*)sflist_nextpos(po->item_list,&pos) )
2969 {
2970 PortObjectItemPrint(poi, po_print_buf, bufsize);
2971 }
2972 }
2973
2974 SnortSnprintfAppend(po_print_buf, bufsize, " ]\n }\n");
2975 LogMessage("%s", po_print_buf);
2976 }
2977
2978 /*
2979 Print Port Object - Prints input ports and rules (uncompiled)
2980 ports
2981 rules (input by user)
2982
2983 */
PortObjectPrintEx(PortObject * po,void (* print_index_map)(int index,char * buf,int bufsize))2984 void PortObjectPrintEx(PortObject * po,
2985 void (*print_index_map)(int index, char *buf, int bufsize) )
2986 {
2987 PortObjectItem * poi = NULL;
2988 SF_LNODE * pos = NULL;
2989 int k=0;
2990 int * rlist = NULL;
2991 unsigned i;
2992 int bufsize = sizeof(po_print_buf);
2993
2994 po_print_buf[0] = '\0';
2995
2996 if( !po )
2997 return ;
2998
2999 if( !po->rule_list )
3000 return ;
3001
3002 if( !po->rule_list->count )
3003 return ;
3004
3005 SnortSnprintfAppend(po_print_buf, bufsize, " PortObject ");
3006
3007 if( po->name )
3008 {
3009 SnortSnprintfAppend(po_print_buf, bufsize, "%s ", po->name);
3010 }
3011
3012 SnortSnprintfAppend(po_print_buf, bufsize,
3013 " Id:%d Ports:%d Rules:%d\n {\n",
3014 po->id, po->item_list->count,po->rule_list->count );
3015
3016 SnortSnprintfAppend(po_print_buf, bufsize, " Ports [\n ");
3017
3018 if( PortObjectHasAny( po ) )
3019 {
3020 SnortSnprintfAppend(po_print_buf, bufsize, "any");
3021 }
3022 else
3023 {
3024 for(poi=(PortObjectItem*)sflist_firstpos(po->item_list,&pos);
3025 poi != 0;
3026 poi=(PortObjectItem*)sflist_nextpos(po->item_list,&pos) )
3027 {
3028 PortObjectItemPrint(poi, po_print_buf, bufsize);
3029 }
3030 }
3031 SnortSnprintfAppend(po_print_buf, bufsize, " ]\n");
3032
3033 rlist = RuleListToSortedArray( po->rule_list );
3034 if(!rlist )
3035 {
3036 return ;
3037 }
3038
3039 SnortSnprintfAppend(po_print_buf, bufsize, " Rules [ \n ");
3040 for(i=0;i<po->rule_list->count;i++)
3041 {
3042 if( print_index_map )
3043 {
3044 print_index_map( rlist[i], po_print_buf, bufsize );
3045 }
3046 else
3047 {
3048 SnortSnprintfAppend(po_print_buf, bufsize, " %d",rlist[i]);
3049 }
3050 k++;
3051 if( k == 25 )
3052 {
3053 k=0;
3054 SnortSnprintfAppend(po_print_buf, bufsize, " \n ");
3055 }
3056 }
3057 SnortSnprintfAppend(po_print_buf, bufsize, " ]\n }\n");
3058
3059 LogMessage("%s", po_print_buf);
3060 free(rlist);
3061 }
3062 // extern void rule_index_map_print_index( int index );
PortObjectPrint(PortObject * po)3063 void PortObjectPrint (PortObject * po )
3064 {
3065 PortObjectPrintEx( po, rule_index_map_print_index );
3066 }
3067
PortObject2PrintEx(PortObject2 * po,void (* print_index_map)(int index,char * buf,int bufsize))3068 void PortObject2PrintEx(PortObject2 * po,
3069 void (*print_index_map)(int index, char *buf, int bufsize) )
3070 {
3071 PortObjectItem * poi = NULL;
3072 SF_LNODE * pos = NULL;
3073 int k=0;
3074 int * rlist = NULL;
3075 unsigned int i;
3076 int bufsize = sizeof(po_print_buf);
3077
3078 po_print_buf[0] = '\0';
3079
3080 SnortSnprintfAppend(po_print_buf, bufsize, " PortObject2 ");
3081
3082 if( po->name ) SnortSnprintfAppend(po_print_buf, bufsize, "%s ",po->name);
3083
3084 SnortSnprintfAppend(po_print_buf, bufsize, " Id:%d Ports:%d Rules:%d PortUsageCnt=%d\n {\n",
3085 po->id, po->item_list->count, po->rule_hash->count, po->port_cnt );
3086
3087 SnortSnprintfAppend(po_print_buf, bufsize, " Ports [\n ");
3088
3089 if( PortObjectHasAny( (PortObject*)po ) )
3090 {
3091 SnortSnprintfAppend(po_print_buf, bufsize, "any");
3092 }
3093 else
3094 {
3095 for(poi=(PortObjectItem*)sflist_firstpos(po->item_list,&pos);
3096 poi != 0;
3097 poi=(PortObjectItem*)sflist_nextpos(po->item_list,&pos) )
3098 {
3099 PortObjectItemPrint(poi, po_print_buf, bufsize);
3100 }
3101 }
3102
3103 SnortSnprintfAppend(po_print_buf, bufsize, " ]\n");
3104
3105 rlist = RuleHashToSortedArray( po->rule_hash );
3106 if(!rlist )
3107 return ;
3108
3109 SnortSnprintfAppend(po_print_buf, bufsize, " Rules [ \n ");
3110 for(i=0;i<po->rule_hash->count;i++)
3111 {
3112 if( print_index_map )
3113 {
3114 print_index_map( rlist[i], po_print_buf, bufsize );
3115 }
3116 else
3117 {
3118 SnortSnprintfAppend(po_print_buf, bufsize, " %d", rlist[i]);
3119 }
3120 k++;
3121 if( k == 25 )
3122 {
3123 k=0;
3124 SnortSnprintfAppend(po_print_buf, bufsize, " \n ");
3125 }
3126 }
3127 SnortSnprintfAppend(po_print_buf, bufsize, " ]\n }\n");
3128
3129 LogMessage("%s", po_print_buf);
3130
3131 free(rlist);
3132 }
PortObject2Print(PortObject2 * po)3133 void PortObject2Print (PortObject2 * po )
3134 {
3135 // void rule_index_map_print_index( int index );
3136 PortObject2PrintEx( po, rule_index_map_print_index );
3137 }
3138 /*
3139 Prints the original (normalized) PortGroups and
3140 as sepcified by the user
3141 */
PortTablePrintUserRules(PortTable * p)3142 void PortTablePrintUserRules( PortTable * p )
3143 {
3144 PortObject * po;
3145
3146 /* normalized user PortObjects and rule ids */
3147 LogMessage(">>>PortTable - Rules\n");
3148 for(po = (PortObject*)sflist_first(p->pt_polist);
3149 po!= 0;
3150 po = (PortObject*)sflist_next(p->pt_polist) )
3151 {
3152 PortObjectPrint( po );
3153 }
3154 /* port array of rule ids */
3155 }
3156
3157 /*
3158 Prints the Unique Port Groups and rules that reference them
3159 */
PortTablePrintPortGroups(PortTable * p)3160 void PortTablePrintPortGroups( PortTable * p )
3161 {
3162 PortObject2 * po;
3163 SFGHASH_NODE * ponode;
3164
3165 /* normalized user PortObjects and rule ids */
3166 LogMessage(">>>PortTable - Compiled Port Groups\n");
3167 LogMessage(" [ %d port groups ] \n\n",p->pt_mpo_hash->count);
3168
3169 for(ponode = sfghash_findfirst(p->pt_mpo_hash);
3170 ponode!= 0;
3171 ponode = sfghash_findnext(p->pt_mpo_hash) )
3172 {
3173 po = ponode->data;
3174
3175 PortObject2Print(po);
3176 }
3177 /* port array of rule ids */
3178 }
3179
3180 /*
3181 Print
3182 */
PortTablePrintPortPortObjects(PortTable * p)3183 void PortTablePrintPortPortObjects( PortTable * p )
3184 {
3185 int i;
3186 PortObject * po;
3187 SF_LIST * last = NULL;
3188 int bufsize = sizeof(po_print_buf);
3189
3190 po_print_buf[0] = '\0';
3191
3192 LogMessage(">>>Port PortObjects\n");
3193
3194 for(i=0;i<SFPO_MAX_PORTS;i++)
3195 {
3196 if( !p->pt_port_lists[i] ) continue;
3197
3198 if( p->pt_port_lists[i] == last )
3199 continue;
3200
3201 SnortSnprintfAppend(po_print_buf, bufsize, "---Port[%d] PortObjects [ ",i);
3202
3203 for(po=(PortObject*)sflist_first(p->pt_port_lists[i]);
3204 po != 0;
3205 po=(PortObject*)sflist_next(p->pt_port_lists[i]) )
3206 {
3207 SnortSnprintfAppend(po_print_buf, bufsize, "%d ",po->id);
3208 }
3209
3210 SnortSnprintfAppend(po_print_buf, bufsize, "]\n");
3211
3212 last = p->pt_port_lists[i] ;
3213
3214 }
3215
3216 LogMessage("%s", po_print_buf);
3217 }
3218
3219
3220 /*
3221 *
3222 * Port Object Parser
3223 *
3224 */
3225
3226 static
POParserInit(POParser * pop,char * s,PortVarTable * pvTable)3227 int POParserInit( POParser * pop, char * s, PortVarTable * pvTable )
3228 {
3229 memset(pop,0,sizeof(POParser));
3230 pop->pos = 0;
3231 pop->s = s;
3232 pop->slen = strlen(s);
3233 pop->errflag = 0;
3234 pop->pvTable = pvTable;
3235
3236 return 0;
3237 }
3238
3239 /*
3240 Get a Char
3241 */
3242 static
POPGetChar(POParser * pop)3243 int POPGetChar( POParser * pop )
3244 {
3245 int c;
3246 if( pop->slen > 0 )
3247 {
3248 c = pop->s[0];
3249 pop->slen--;
3250 pop->s++;
3251 pop->pos++;
3252 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"GetChar: %c, %d bytes left\n",c, pop->slen););
3253 return c;
3254 }
3255 return 0;
3256 }
3257 /*
3258 Skip whitespace till we find a non-whitespace char
3259 */
3260 static
POPGetChar2(POParser * pop)3261 int POPGetChar2( POParser * pop )
3262 {
3263 int c;
3264 for(;;)
3265 {
3266 c=POPGetChar( pop ) ;
3267 if( !c )
3268 return 0;
3269
3270 if( isspace(c) || c==',' )
3271 continue;
3272
3273 break;
3274 }
3275 return c;
3276 }
3277 /*
3278 Restore last char
3279 */
3280 static
POPUnGetChar(POParser * pop)3281 void POPUnGetChar( POParser * pop )
3282 {
3283 if( pop->pos > 0 )
3284 {
3285 pop->slen++;
3286 pop->s--;
3287 pop->pos--;
3288 }
3289 }
3290 /*
3291 Peek at next char
3292 */
3293 static
POPPeekChar(POParser * pop)3294 int POPPeekChar( POParser * pop )
3295 {
3296 if( pop->slen > 0)
3297 {
3298 return pop->s[0];
3299 }
3300 return 0;
3301 }
3302 #ifdef XXXX
3303 /* copy a simple alpha string */
3304 static
POPeekString(POParser * p,char * s,int smax)3305 void POPeekString(POParser * p, char * s, int smax)
3306 {
3307 int c;
3308 int cnt = 0;
3309 int k = p->slen;
3310
3311 smax--;
3312
3313 s[0] = 0;
3314
3315 while( k > 0 && cnt < smax )
3316 {
3317 c = p->s[ cnt ];
3318
3319 if( c == 0 ) break;
3320 if( !isalpha(c) ) break;
3321
3322 s[ cnt++ ] = c;
3323 s[ cnt ] = 0;
3324 k--;
3325 }
3326 }
3327 static
POGetString(POParser * p,char * s,int smax)3328 void POGetString(POParser * p, char * s, int smax)
3329 {
3330 int c;
3331 int cnt = 0;
3332
3333 smax--;
3334
3335 s[0] = 0;
3336
3337 while( p->slen > 0 && cnt < smax )
3338 {
3339 c = p->s[ 0 ];
3340
3341 if( c == 0 ) break;
3342 if( !isalpha(c) ) break;
3343
3344 s[ cnt++ ] = c;
3345 s[ cnt ] = 0;
3346 p->slen--;
3347 p->s++;
3348 }
3349 }
3350 #endif
3351
3352 /*
3353 Skip whitespace : ' ', '\t', '\n'
3354 */
3355 static
POPSkipSpace(POParser * p)3356 int POPSkipSpace( POParser * p )
3357 {
3358 int c;
3359 for( c = POPPeekChar(p);
3360 c != 0 ;
3361 c = POPPeekChar(p) )
3362 {
3363 if( !isspace(c) && c != ',' )
3364 return c;
3365
3366 POPGetChar(p);
3367 }
3368 return 0;
3369 }
3370 /*
3371 Get the Port Object Name
3372 */
3373 static
POParserName(POParser * pop)3374 char * POParserName( POParser * pop )
3375 {
3376 int k = 0;
3377 int c;
3378
3379 /* check if were done */
3380 if( !pop || !pop->s || !*(pop->s) )
3381 return 0;
3382
3383 /* Start the name - skip space */
3384 c = POPGetChar2(pop) ;
3385 if( !c )
3386 return 0;
3387
3388 if( c== '$' )/* skip leading '$' - old Var indicator */
3389 {
3390 c = POPGetChar2(pop) ;
3391 if( !c )
3392 return 0;
3393 }
3394
3395 if( isalnum(c) )
3396 {
3397 pop->token[k++] = (char)c;
3398 pop->token[k] = (char)0;
3399 }
3400 else
3401 {
3402 POPUnGetChar( pop );
3403 return 0; /* not a name */
3404 }
3405
3406 for( c = POPGetChar(pop);
3407 c != 0 && k < POP_MAX_BUFFER_SIZE;
3408 c = POPGetChar(pop) )
3409 {
3410 if( isalnum(c) || c== '_' || c=='-' || c=='.' )
3411 {
3412 pop->token[k++] = (char)c;
3413 pop->token[k] = (char)0;
3414 }
3415 else
3416 {
3417 POPUnGetChar( pop );
3418 break;
3419 }
3420 }
3421
3422 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,">>> POParserName : %s\n",pop->token););
3423
3424 return strdup(pop->token);
3425 }
3426
3427 /*
3428 * Read an unsigned short (a port)
3429 */
3430 static
POParserGetShort(POParser * pop)3431 uint16_t POParserGetShort(POParser * pop)
3432 {
3433 int c;
3434 int k = 0;
3435 char buffer[32];
3436 char * pend;
3437
3438
3439 POPSkipSpace(pop);
3440
3441 buffer[0] = 0;
3442
3443 while( (c = POPGetChar(pop)) != 0 )
3444 {
3445 if( isdigit(c) )
3446 {
3447 buffer[k++]=(char)c;
3448 buffer[k] =0;
3449 if( k == sizeof(buffer)-1 ) break; /* thats all that fits */
3450 }
3451 else
3452 {
3453 if( c && ( c!= ':' && c != ' ' && c != ']' && c != ',' && c != '\t' && c != '\n' ) )
3454 {
3455 pop->errflag = POPERR_NOT_A_NUMBER;
3456 return 0;
3457 }
3458 POPUnGetChar(pop);
3459 break;
3460 }
3461 }
3462
3463 c = (int)strtoul(buffer,&pend,10);
3464
3465 if(c > 65535 || c < 0)
3466 {
3467 pop->errflag = POPERR_BOUNDS;
3468 return 0;
3469 }
3470
3471 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"GetUNumber: %d\n",c););
3472
3473 return c;
3474 }
3475
_POParseVar(POParser * pop)3476 static PortObject *_POParseVar(POParser *pop)
3477 {
3478 PortObject *pox;
3479 char *name;
3480
3481 name = POParserName(pop);
3482
3483 if(!name)
3484 {
3485 pop->pos++;
3486 pop->errflag = POPERR_NO_NAME;
3487 return NULL;
3488 }
3489
3490 pox = PortVarTableFind(pop->pvTable, name);
3491 free(name);
3492
3493 if(!pox)
3494 {
3495 pop->errflag = POPERR_BAD_VARIABLE;
3496 return NULL;
3497 }
3498
3499 pox = PortObjectDup(pox);
3500
3501 if(!pox)
3502 {
3503 pop->errflag = POPERR_MALLOC_FAILED;
3504 return NULL;
3505 }
3506
3507 return pox;
3508 }
3509
3510 /*
3511 * Sets the PORT_OBJECT_NOT_FLAG flag on each port object item in the list
3512 */
_PONegateList(PortObject * po)3513 static void _PONegateList(PortObject *po)
3514 {
3515 PortObjectItem *poi;
3516 SF_LNODE * pos;
3517
3518 if(!po) return;
3519
3520 /* disable the NOT'd ports */
3521 for(poi=(PortObjectItem*)sflist_firstpos(po->item_list,&pos);
3522 poi != 0;
3523 poi=(PortObjectItem*)sflist_nextpos(po->item_list,&pos) )
3524 {
3525 poi->flags ^= PORT_OBJECT_NOT_FLAG;
3526 }
3527 }
3528
_POParsePort(POParser * pop)3529 static PortObject *_POParsePort(POParser *pop)
3530 {
3531 uint16_t hport, lport;
3532 char c;
3533 PortObject *po = PortObjectNew();
3534
3535 if(!po)
3536 {
3537 pop->errflag = POPERR_MALLOC_FAILED;
3538 return NULL;
3539 }
3540
3541 hport = MAXPORTS-1;
3542 pop->token[0]=0;
3543
3544 /* The string in pop should only be of the form <port> or <port>:<port> */
3545 lport = POParserGetShort(pop);
3546
3547 if(pop->errflag)
3548 {
3549 PortObjectFree(po);
3550 return NULL;
3551 }
3552
3553 c = POPPeekChar(pop);
3554
3555 if( c == ':' ) /* half open range */
3556 {
3557 POPGetChar(pop);
3558 c = POPPeekChar(pop);
3559
3560 if (((c == 0) && (pop->slen == 0)) ||
3561 (c == ','))
3562 {
3563 /* Open ended range, highport is 65k */
3564 hport = MAXPORTS-1;
3565 PortObjectAddRange(po, lport, hport, 0);
3566 return po;
3567 }
3568
3569 if( !isdigit((int)c) ) /* not a number */
3570 {
3571 pop->errflag = POPERR_NOT_A_NUMBER;
3572 PortObjectFree(po);
3573 return NULL;
3574 }
3575
3576 hport = POParserGetShort(pop);
3577
3578 if( pop->errflag )
3579 {
3580 PortObjectFree(po);
3581 return NULL;
3582 }
3583
3584 if(lport > hport)
3585 {
3586 pop->errflag = POPERR_INVALID_RANGE;
3587 PortObjectFree(po);
3588 return NULL;
3589 }
3590
3591 PortObjectAddRange(po, lport, hport, 0);
3592 }
3593 else
3594 {
3595 PortObjectAddPort(po, lport, 0);
3596 }
3597
3598 return po;
3599 }
3600
_POParseString(POParser * pop)3601 static PortObject* _POParseString(POParser *pop)
3602 {
3603 PortObject * po;
3604 PortObject * potmp = NULL;
3605 int local_neg = 0;
3606 char c;
3607 int list_count = 0;
3608
3609 po = PortObjectNew();
3610
3611 if(!po)
3612 {
3613 pop->errflag = POPERR_MALLOC_FAILED;
3614 return NULL;
3615 }
3616
3617 while( (c = POPGetChar2(pop)) != 0 )
3618 {
3619 if(c == '!')
3620 {
3621 local_neg = 1;
3622 continue;
3623 }
3624
3625 if(c == '$')
3626 {
3627 /* Don't dup this again - the returned PortObject has already
3628 * been dup'ed */
3629 potmp = _POParseVar(pop);
3630 }
3631 /* Start of a list. Tokenize list and recurse on it */
3632 else if(c == '[')
3633 {
3634 POParser local_pop;
3635 char *tok;
3636 char *end;
3637
3638 list_count++;
3639
3640 if( (end = strrchr(pop->s, (int)']')) == NULL )
3641 {
3642 pop->errflag = POPERR_NO_ENDLIST_BRACKET;
3643 PortObjectFree(po);
3644 return NULL;
3645 }
3646
3647 if( (tok = SnortStrndup(pop->s, end - pop->s)) == NULL)
3648 {
3649 pop->errflag = POPERR_MALLOC_FAILED;
3650 PortObjectFree(po);
3651 return NULL;
3652 }
3653
3654 POParserInit(&local_pop, tok, pop->pvTable);
3655
3656 /* Recurse */
3657 potmp = _POParseString(&local_pop);
3658 free(tok);
3659
3660 if(!potmp)
3661 {
3662 pop->errflag = local_pop.errflag;
3663 PortObjectFree(po);
3664 return NULL;
3665 }
3666
3667 /* Advance "cursor" to end of this list */
3668 for(; c && pop->s != end; c = POPGetChar2(pop))
3669 ;
3670 }
3671 else if(c == ']')
3672 {
3673 list_count--;
3674
3675 if(list_count < 0)
3676 {
3677 pop->errflag = POPERR_EXTRA_BRACKET;
3678 PortObjectFree(po);
3679 return NULL;
3680 }
3681
3682 continue;
3683 }
3684 else
3685 {
3686 POPUnGetChar(pop);
3687
3688 potmp = _POParsePort(pop);
3689 }
3690
3691 if(!potmp)
3692 {
3693 PortObjectFree(po);
3694 return NULL;
3695 }
3696
3697 if(local_neg)
3698 {
3699 /* Note: this intentionally only sets the negation flag! */
3700 /* The actual negation will take place when normalization is called */
3701 _PONegateList(potmp);
3702
3703 local_neg = 0;
3704 }
3705
3706 if(PortObjectAddPortObject(po, potmp, &pop->errflag))
3707 {
3708 PortObjectFree(po);
3709 PortObjectFree(potmp);
3710 return NULL;
3711 }
3712
3713 if (potmp)
3714 {
3715 PortObjectFree(potmp);
3716 potmp = NULL;
3717 }
3718 }
3719
3720 /* Check for mis-matched brackets */
3721 if(list_count)
3722 {
3723 if(list_count > 0) pop->errflag = POPERR_NO_ENDLIST_BRACKET;
3724 else pop->errflag = POPERR_EXTRA_BRACKET;
3725
3726 PortObjectFree(po);
3727 return NULL;
3728 }
3729
3730 return po;
3731 }
3732
3733 /*
3734 * PortObject : name value
3735 * PortObject : name [!][ value value value ... ]
3736 *
3737 * value : [!]port
3738 * [!]low-port[:high-port]
3739 *
3740 * inputs:
3741 * pvTable - PortVarTable to search for PortVar references in the current PortVar
3742 * pop - parsing structure
3743 * s - string with port object text
3744 *
3745 * nameflag - indicates a name must be present, this allows usage for
3746 * embedded rule or portvar declarations of portlists
3747 * returns:
3748 * (PortObject *) - a normalized version
3749 */
PortObjectParseString(PortVarTable * pvTable,POParser * pop,char * name,char * s,int nameflag)3750 PortObject * PortObjectParseString ( PortVarTable * pvTable, POParser * pop,
3751 char * name, char * s , int nameflag )
3752 {
3753 PortObject *po, *potmp;
3754
3755 DEBUG_WRAP(DebugMessage(DEBUG_PORTLISTS,"PortObjectParseString: %s\n",s););
3756
3757 POParserInit( pop, s, pvTable );
3758
3759 po = PortObjectNew();
3760 if(!po)
3761 {
3762 pop->errflag=POPERR_MALLOC_FAILED;
3763 return 0;
3764 }
3765
3766 if( nameflag ) /* parse a name */
3767 {
3768 po->name = POParserName( pop );
3769 if(!po->name )
3770 {
3771 pop->errflag=POPERR_NO_NAME;
3772 PortObjectFree(po);
3773 return 0;
3774 }
3775 }
3776 else
3777 {
3778 if( name )
3779 po->name = SnortStrdup(name);
3780 else
3781 po->name = SnortStrdup("noname");
3782 }
3783
3784 // LogMessage("PortObjectParseString: po->name=%s\n",po->name);
3785
3786 potmp = _POParseString(pop);
3787
3788 if(!potmp)
3789 {
3790 PortObjectFree(po);
3791 return NULL;
3792 }
3793
3794 PortObjectNormalize(potmp);
3795
3796 if(PortObjectAddPortObject(po, potmp, &pop->errflag))
3797 {
3798 PortObjectFree(po);
3799 PortObjectFree(potmp);
3800 return NULL;
3801 }
3802
3803 PortObjectFree(potmp);
3804
3805 return po;
3806 }
PortObjectParseError(POParser * pop)3807 char * PortObjectParseError( POParser * pop )
3808 {
3809 switch( pop->errflag )
3810 {
3811 case POPERR_NO_NAME: return "no name";
3812 case POPERR_NO_ENDLIST_BRACKET: return "no end of list bracket."
3813 " Elements must be comma separated,"
3814 " and no spaces may appear between"
3815 " brackets.";
3816 case POPERR_NOT_A_NUMBER: return "not a number";
3817 case POPERR_EXTRA_BRACKET: return "extra list bracket";
3818 case POPERR_NO_DATA: return "no data";
3819 case POPERR_ADDITEM_FAILED: return "add item failed";
3820 case POPERR_MALLOC_FAILED: return "mem alloc failed";
3821 case POPERR_INVALID_RANGE: return "invalid port range";
3822 case POPERR_DUPLICATE_ENTRY: return "duplicate ports in list";
3823 case POPERR_BOUNDS: return "value out of bounds for a port";
3824 case POPERR_BAD_VARIABLE: return "unrecognized variable";
3825 default:
3826 break;
3827 }
3828 return "unknown POParse error";
3829 }
3830
3831
3832 /*
3833 *
3834 * PORT VAR TABLE FUNCTIONS
3835 *
3836 */
3837
3838 /*
3839 * Create a PortVar Table
3840 *
3841 * The PortVar table used to store and lookup Named PortObjects
3842 */
PortVarTableCreate(void)3843 PortVarTable * PortVarTableCreate(void)
3844 {
3845 PortObject * po;
3846 SFGHASH * h;
3847
3848 /*
3849 * This is used during parsing of config,
3850 * so 1000 entries is ok, worst that happens is somewhat slower
3851 * config/rule processing.
3852 */
3853 h = sfghash_new(1000,0,0,PortObjectFree);
3854 if( !h )
3855 return 0;
3856
3857 /* Create default port objects */
3858 po = PortObjectNew();
3859 if( !po )
3860 {
3861 sfghash_delete(h);
3862 return 0;
3863 }
3864
3865 /* Default has an ANY port */
3866 PortObjectAddPortAny( po );
3867
3868 /* Add ANY to the table */
3869 PortVarTableAdd( h, po );
3870
3871 return h;
3872 }
3873
3874 /*
3875 * PortVarTableAdd()
3876 *
3877 * returns
3878 * -1 : error, no memory...
3879 * 0 : added
3880 * 1 : in table
3881 */
PortVarTableAdd(PortVarTable * h,PortObject * po)3882 int PortVarTableAdd( PortVarTable * h, PortObject * po )
3883 {
3884 int stat;
3885 stat = sfghash_add(h,po->name,po);
3886 if( stat == SFGHASH_INTABLE )
3887 return 1;
3888 if( stat == SFGHASH_OK )
3889 return 0;
3890 return -1;
3891 }
3892
PortVarTableFind(PortVarTable * h,char * name)3893 PortObject * PortVarTableFind( PortVarTable * h, char * name )
3894 {
3895 if (!h || !name)
3896 return NULL;
3897
3898 return sfghash_find(h,name);
3899 }
3900
3901 /*
3902 This deletes the table, the PortObjects and PortObjectItems,
3903 and rule list.
3904 */
PortVarTableFree(PortVarTable * pvt)3905 int PortVarTableFree(PortVarTable * pvt)
3906 {
3907 if( pvt )
3908 {
3909 sfghash_delete( pvt );
3910 }
3911 return 0;
3912 }
3913
3914
3915 /*
3916 TEST DRIVER
3917
3918 PorObjects use the follow creation strategy
3919
3920 po = PortObjectNew();
3921 PortObjectAddPort( po, 80, 0 );
3922 PortObjectAddPort( po, 8080, 0 );
3923 PortObjectAddPort( po, 8138, 0 );
3924 PortTableAddObject( p, po, k++ );
3925
3926 PortVarTable just stores PorObjects by Name
3927
3928 */
3929 //#define MAIN_PORTOBJECT
3930
3931 //char * sample1="http [ 80 8100:8200 !8150 ]";
3932 //char * sample2="httpx [ !http 8120 ]";
3933
3934 #ifdef MAIN_PORTOBJECT
main(int argc,char ** argv)3935 int main( int argc, char ** argv )
3936 {
3937 PortVarTable * pvTable;
3938 PortTable * p;
3939 PortObject * po;
3940 POParser pop;
3941 int i;
3942 int k=1;
3943 int debug=0;
3944 int names=1;
3945
3946 int lrc =100;
3947 int lrp =20;
3948
3949 char * portlist;
3950
3951 for(i=1;i<argc;i++)
3952 {
3953 if( strcmp(argv[i],"-debug")==0 ) debug=1;
3954 if( strcmp(argv[i],"-lrc")==0 ) lrc=atoi(argv[++i]);
3955 if( strcmp(argv[i],"-lrp")==0 ) lrp=atoi(argv[++i]);
3956 }
3957
3958 /*
3959 Create a PortVar table - this is automatic and not necessary
3960 */
3961 pvTable=PortVarTableCreate();
3962 if( !pvTable )
3963 {
3964 LogMessage("Cound not init port variables\n");
3965 exit(1);
3966 }
3967
3968 /*
3969 Create a table for src and one for dst
3970 we'll only add specific ports, no ANY ports,
3971 but ranges are ok.
3972 */
3973 p = PortTableNew();
3974 if(!p)
3975 {
3976 LogMessage("no memory\n");
3977 exit(0);
3978 }
3979 p->pt_lrc=lrc; // large rule count - primary
3980
3981 for(i=1;i<argc;i++)
3982 {
3983 if( argv[i][0] == '-' )
3984 {
3985 if( strcmp(argv[i],"-names")==0 ) names=0;/* disable names in var input*/
3986 continue;
3987 }
3988
3989 portlist = argv[i];
3990 //if( i==1) portlist = sample1;
3991 //if( i==2) portlist = sample2;
3992 //LogMessage("PortObject : '%s' \n",portlist);
3993
3994 /*
3995 This is separate from PortVar's since some rules may declare these inline
3996 */
3997 po = PortObjectParseString ( pvTable, &pop, argv[i], PORTLISTS, names/* bool 0/1 - name required in parse */);
3998 if( !po )
3999 {
4000 LogMessage(">>Bogus PortObject Definition (pos=%d,errflag=%d)\n>>%s\n>>%*s\n",
4001 pop.pos,pop.errflag,PORTLISTS,pop.pos,"^");
4002 continue; /* invalid parse - no port object to add */
4003 }
4004
4005 PortObjectPrint ( po );
4006
4007 if( PortVarTableAdd( pvTable, po ) ) /* requires a name : portlist http [ portlist ]*/
4008 {
4009 LogMessage("error: named port var '%s' already in table \n",po->name);
4010 }
4011
4012 // Lets test the lookup ...
4013 if( !PortVarTableFind(pvTable,po->name) )
4014 {
4015 LogMessage("Could not find PortVar: %s\n",po->name);
4016 exit(0);
4017 }
4018
4019 /*
4020 Assume each PortVar object has one rule and add it to the PortTable
4021 PortObjects that are defined in rules have no names and are not
4022 added to the PortVar table
4023 */
4024 PortTableAddObject(p,po,k++/*rule id*/);
4025 }
4026
4027
4028 PortTableCompile( p );
4029
4030 //PortTablePrintRules( p );
4031
4032 //if(debug)
4033 PortTablePrintPortGroups( p );
4034
4035 //PortTablePrintPortPortObjects( p );
4036
4037 PortTableDumpPortRules( p );
4038
4039 LogMessage("\n");
4040 LogMessage("#rule and port groups compiled successfully\n");
4041
4042 return 0;
4043 }
4044 #endif
4045
4046