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