"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/sfutil/sfportobject.c" (16 Oct 2020, 99790 Bytes) of package /linux/misc/snort-2.9.17.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "sfportobject.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.9.16.1_vs_2.9.17.

    1 /****************************************************************************
    2  *
    3  * Copyright (C) 2014-2020 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
  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
  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 
  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
  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
  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
  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
  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 */
  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
  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 */
  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  */
  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  */
  467 void PortObjectItemFree (PortObjectItem * poi)
  468 {
  469     if(poi) free(poi);
  470 }
  471 
  472 /*
  473  *  Free the PortObject
  474  */
  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  */
  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  */
  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  */
  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  */
  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 */
  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  */
  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  */
  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  */
  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 */
  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 */
  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 */
  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  */
  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 }
  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 }
  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 */
  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  */
  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  */
 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 */
 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  */
 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
 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  */
 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  */
 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 */
 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
 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 */
 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 */
 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 */
 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 */
 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 */
 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  */
 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  */
 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 */
 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 
 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 
 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  */
 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 
 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 
 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 */
 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
 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
 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
 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 
 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
 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
 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 
 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  */
 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
 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  */
 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 */
 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
 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
 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  */
 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  */
 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
 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  */
 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 
 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 */
 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 */
 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 
 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 
 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 */
 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 );
 3063 void PortObjectPrint (PortObject * po )
 3064 {
 3065     PortObjectPrintEx( po, rule_index_map_print_index );
 3066 }
 3067 
 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 }
 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 */
 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 */
 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 */
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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
 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 
 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  */
 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 
 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 
 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 */
 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 }
 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 */
 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 */
 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 
 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 */
 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
 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