"Fossies" - the Fresh Open Source Software Archive

Member "snort-2.9.17/src/fpcreate.c" (16 Oct 2020, 106500 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 "fpcreate.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 **  $Id$
    3 **
    4 **  fpcreate.c
    5 **
    6 **  Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
    7 **  Copyright (C) 2002-2013 Sourcefire, Inc.
    8 **  Dan Roelker <droelker@sourcefire.com>
    9 **  Marc Norton <mnorton@sourcefire.com>
   10 **
   11 **  NOTES
   12 **  5.7.02 - Initial Checkin. Norton/Roelker
   13 **
   14 **  This program is free software; you can redistribute it and/or modify
   15 **  it under the terms of the GNU General Public License Version 2 as
   16 **  published by the Free Software Foundation.  You may not use, modify or
   17 **  distribute this program under any other version of the GNU General
   18 **  Public License.
   19 **
   20 **  This program is distributed in the hope that it will be useful,
   21 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
   22 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   23 **  GNU General Public License for more details.
   24 **
   25 **  You should have received a copy of the GNU General Public License
   26 **  along with this program; if not, write to the Free Software
   27 **  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   28 **
   29 ** 6/13/05 - marc norton
   30 **   Added plugin support for fast pattern match data
   31 **
   32 */
   33 
   34 #include <stdio.h>
   35 #include <stdlib.h>
   36 #include <string.h>
   37 
   38 #ifdef HAVE_CONFIG_H
   39 #include "config.h"
   40 #endif
   41 
   42 #include "snort.h"
   43 #include "rules.h"
   44 #include "treenodes.h"
   45 #include "treenodes.h"
   46 #include "parser.h"
   47 #include "fpcreate.h"
   48 #include "fpdetect.h"
   49 #include "sp_pattern_match.h"
   50 #include "sp_icmp_code_check.h"
   51 #include "sp_icmp_type_check.h"
   52 #include "sp_file_data.h"
   53 #include "sp_ip_proto.h"
   54 #include "plugin_enum.h"
   55 #include "util.h"
   56 #include "rules.h"
   57 #include "treenodes.h"
   58 #include "treenodes.h"
   59 #include "parser.h"
   60 #include "target-based/sftarget_reader.h"
   61 #include "mpse.h"
   62 #include "bitop_funcs.h"
   63 
   64 #ifdef INTEL_SOFT_CPM
   65 #include "sfutil/intel-soft-cpm.h"
   66 #endif
   67 
   68 #include "snort.h"
   69 #include "sp_clientserver.h"
   70 #include "sfutil/sfportobject.h"
   71 #include "sfutil/sfrim.h"
   72 #include "detection_options.h"
   73 #include "sfPolicy.h"
   74 #include "dynamic-plugins/sp_dynamic.h"
   75 #include "dynamic-plugins/sp_preprocopt.h"
   76 #include "dynamic-plugins/sf_dynamic_define.h"
   77 
   78 /*
   79  *  Content flag values
   80  */
   81 enum
   82 {
   83     PGCT_NOCONTENT=0,
   84     PGCT_CONTENT=1,
   85     PGCT_URICONTENT=2
   86 };
   87 
   88 static void fpAddIpProtoOnlyRule(SF_LIST **, OptTreeNode *);
   89 static void fpRegIpProto(uint8_t *, OptTreeNode *);
   90 static int fpCreatePortGroups(SnortConfig *, rule_port_tables_t *);
   91 static void fpDeletePortGroup(void *);
   92 static void fpDeletePMX(void *data);
   93 static int fpGetFinalPattern(FastPatternConfig *fp, PatternMatchData *pmd,
   94         char **ret_pattern, int *ret_bytes);
   95 static FPContentInfo * GetLongestDynamicContent(FPContentInfo *content_list);
   96 static PatternMatchData * GetDynamicFastPatternPmd(DynamicData *dd, int dd_type);
   97 static inline int IsDynamicContentFpEligible(FPContentInfo *content);
   98 static inline PatternMatchData * DynamicContentToPmd(FPContentInfo *content_info);
   99 static inline void FreeDynamicContentList(FPContentInfo *fplist);
  100 static PatternMatchData * GetLongestPmdContent(OptTreeNode *otn, int type);
  101 static int fpFinishPortGroupRule(SnortConfig *sc, PORT_GROUP *pg, PmType pm_type,
  102         OptTreeNode *otn, PatternMatchData *pmd, FastPatternConfig *fp);
  103 static int fpFinishPortGroup(SnortConfig *sc, PORT_GROUP *pg, FastPatternConfig *fp);
  104 static int fpAllocPms(SnortConfig *sc, PORT_GROUP *pg, FastPatternConfig *fp);
  105 static int fpAddPortGroupRule(SnortConfig *sc, PORT_GROUP *pg, OptTreeNode *otn, FastPatternConfig *fp);
  106 static int fpAddPortGroupPrmx(PORT_GROUP *pg, OptTreeNode *otn, int cflag);
  107 static inline int IsPmdFpEligible(PatternMatchData *content);
  108 static void PrintFastPatternInfo(OptTreeNode *otn, PatternMatchData *pmd,
  109         const char *pattern, int pattern_length, PmType pm_type);
  110 static int GetPreprocOptPmdList(OptTreeNode *, PatternMatchData **);
  111 static int UsePreprocOptFastPatterns(PatternMatchData *, PatternMatchData *);
  112 
  113 static const char *pm_type_strings[PM_TYPE__MAX] =
  114 {
  115     "Normal Content",
  116     "HTTP Uri content",
  117     "HTTP Header content",
  118     "HTTP Client body content",
  119     "HTTP Method content",
  120 };
  121 
  122 /*
  123 #define LOCAL_DEBUG
  124 */
  125 
  126 extern rule_index_map_t * ruleIndexMap;
  127 extern int rule_count;
  128 
  129 #ifdef TARGET_BASED
  130 #include "target-based/sftarget_protocol_reference.h"
  131 
  132 static sopg_table_t * ServicePortGroupTableNew(void)
  133 {
  134     return (sopg_table_t *)SnortAlloc(sizeof(sopg_table_t));
  135 }
  136 
  137 /*
  138  * Test if this otn is for traffic to the server
  139  */
  140 static int fpOtnFlowToServer( OptTreeNode * otn )
  141 {
  142     if( OtnFlowFromClient(otn) )
  143         return  1;
  144 
  145     if (otn->ds_list[PLUGIN_DYNAMIC])
  146     {
  147         DynamicData *dd = (DynamicData *)otn->ds_list[PLUGIN_DYNAMIC];
  148         DynamicOptionType optType = OPTION_TYPE_FLOWFLAGS;
  149         int flags = FLOW_TO_SERVER;
  150 
  151         if (dd->hasOptionFunction(dd->contextData, optType, flags))
  152             return 1;
  153     }
  154 
  155     return 0;
  156 }
  157 /*
  158  * Test if this otn is for traffic to the client
  159  */
  160 static
  161 int fpOtnFlowToClient( OptTreeNode * otn )
  162 {
  163     if( OtnFlowFromServer(otn) )
  164         return 1;
  165 
  166     if (otn->ds_list[PLUGIN_DYNAMIC])
  167     {
  168         DynamicData *dd = (DynamicData *)otn->ds_list[PLUGIN_DYNAMIC];
  169         DynamicOptionType optType = OPTION_TYPE_FLOWFLAGS;
  170         int flags = FLOW_TO_CLIENT;
  171 
  172         if (dd->hasOptionFunction(dd->contextData, optType, flags))
  173             return 1;
  174     }
  175 
  176     return 0;
  177 }
  178 
  179 #if 0
  180 Not currently used
  181 /*
  182 * Extract the Icmp Type field to determine the PortGroup.
  183 *
  184 * returns :
  185 *   -1 : any, or not an EQ tests
  186 *   >0 : any other ip type
  187 *
  188 */
  189 static
  190 int GetOtnIcmpType (OptTreeNode * otn )
  191 {
  192    int                 type;
  193    IcmpTypeCheckData * IcmpType;
  194 
  195    IcmpType = (IcmpTypeCheckData *)otn->ds_list[PLUGIN_ICMP_TYPE];
  196 
  197    if( IcmpType && (IcmpType->operator == ICMP_TYPE_TEST_EQ) )
  198    {
  199        type = IcmpType->icmp_type;
  200    }
  201    else
  202    {
  203        return -1;
  204    }
  205 
  206    return -1;
  207 }
  208 #endif
  209 
  210 static SFGHASH * alloc_srvmap(void)
  211 {
  212    SFGHASH *p = sfghash_new(1000,
  213                             0,
  214                             0,
  215                             /*nodes are lists,free them in sfghash_delete*/
  216                             (void(*)(void*))sflist_free);
  217    if (p == NULL)
  218        FatalError("could not allocate a service rule map - no memory?\n");
  219 
  220    return p;
  221 }
  222 
  223 static srmm_table_t * ServiceMapNew(void)
  224 {
  225     srmm_table_t *table = (srmm_table_t *)SnortAlloc(sizeof(srmm_table_t));
  226 
  227     table->tcp_to_srv = alloc_srvmap();
  228     table->tcp_to_cli = alloc_srvmap();
  229 
  230     table->udp_to_srv = alloc_srvmap();
  231     table->udp_to_cli = alloc_srvmap();
  232 
  233     table->icmp_to_srv = alloc_srvmap();
  234     table->icmp_to_cli = alloc_srvmap();
  235 
  236     table->ip_to_srv = alloc_srvmap();
  237     table->ip_to_cli = alloc_srvmap();
  238 
  239     return table;
  240 }
  241 
  242 static void ServiceTableFree(SFGHASH *table)
  243 {
  244     if (table != NULL)
  245         sfghash_delete(table);
  246 }
  247 
  248 static void ServiceMapFree(srmm_table_t *srvc_map)
  249 {
  250     if (srvc_map == NULL)
  251         return;
  252 
  253     ServiceTableFree(srvc_map->tcp_to_srv);
  254     ServiceTableFree(srvc_map->tcp_to_cli);
  255     ServiceTableFree(srvc_map->udp_to_srv);
  256     ServiceTableFree(srvc_map->udp_to_cli);
  257     ServiceTableFree(srvc_map->icmp_to_srv);
  258     ServiceTableFree(srvc_map->icmp_to_cli);
  259     ServiceTableFree(srvc_map->ip_to_srv);
  260     ServiceTableFree(srvc_map->ip_to_cli);
  261 
  262     free(srvc_map);
  263 }
  264 
  265 static SFGHASH * alloc_spgmm(void)
  266 {
  267    SFGHASH * p;
  268 
  269    /* TODO: keys are ascii service names - for now ! */
  270    p = sfghash_new(1000, /* # rows in table */
  271                    0, /* size: of key 0 = ascii, >0 = fixed size */
  272                    0, /* bool:user keys,  if true just store this pointer, don't copy the key */
  273                    fpDeletePortGroup);
  274                    /* ??? Why shouldn't we delete the port groups ??? */
  275                    //(void(*)(void*))0 /* free nodes are port_groups do not delete here */ );
  276 
  277    if (p == NULL)
  278        FatalError("could not allocate a service port_group map : no memory?\n");
  279 
  280    return p;
  281 }
  282 
  283 static srmm_table_t * ServicePortGroupMapNew(void)
  284 {
  285     srmm_table_t *table = (srmm_table_t *)SnortAlloc(sizeof(srmm_table_t));
  286 
  287     table->tcp_to_srv = alloc_spgmm();
  288     table->tcp_to_cli = alloc_spgmm();
  289 
  290     table->udp_to_srv = alloc_spgmm();
  291     table->udp_to_cli = alloc_spgmm();
  292 
  293     table->icmp_to_srv = alloc_spgmm();
  294     table->icmp_to_cli = alloc_spgmm();
  295 
  296     table->ip_to_srv = alloc_spgmm();
  297     table->ip_to_cli = alloc_spgmm();
  298 
  299     return table;
  300 }
  301 
  302 static void ServicePortGroupTableFree(SFGHASH *table)
  303 {
  304 #if 0
  305     SFGHASH_NODE *node;
  306     PORT_GROUP *pg;
  307 
  308     /* Not sure why we wouldn't want to free the data */
  309     for (node = sfghash_findfirst(table);
  310          node != NULL;
  311          node = sfghash_findnext(table))
  312     {
  313         pg = (PORT_GROUP *)node->data;
  314         if (pg == NULL)
  315             continue;
  316 
  317         /* XXX XXX (if we need to recycle these) free the PORT_GROUP */
  318         node->data = NULL;
  319     }
  320 #endif
  321 
  322     if (table == NULL)
  323         return;
  324 
  325     sfghash_delete(table);
  326 }
  327 
  328 static void ServicePortGroupMapFree(srmm_table_t *srvc_pg_map)
  329 {
  330     if (srvc_pg_map == NULL)
  331         return;
  332 
  333     ServicePortGroupTableFree(srvc_pg_map->tcp_to_srv);
  334     ServicePortGroupTableFree(srvc_pg_map->tcp_to_cli);
  335     ServicePortGroupTableFree(srvc_pg_map->udp_to_srv);
  336     ServicePortGroupTableFree(srvc_pg_map->udp_to_cli);
  337     ServicePortGroupTableFree(srvc_pg_map->icmp_to_srv);
  338     ServicePortGroupTableFree(srvc_pg_map->icmp_to_cli);
  339     ServicePortGroupTableFree(srvc_pg_map->ip_to_srv);
  340     ServicePortGroupTableFree(srvc_pg_map->ip_to_cli);
  341 
  342     free(srvc_pg_map);
  343 }
  344 
  345 /*
  346  * Add the otn to the list stored by the key = servicename.
  347  *
  348  * table - table of service/otn-list pairs
  349  * servicename - ascii service name from rule metadata option
  350  * otn - rule - may be content,-no-content, or uri-content
  351  *
  352  */
  353 static
  354 void ServiceMapAddOtnRaw( SFGHASH * table, char * servicename, OptTreeNode * otn )
  355 {
  356     SF_LIST * list;
  357     OptTreeNode * otn_tmp = NULL;
  358 
  359     list = (SF_LIST*) sfghash_find( table, servicename );
  360 
  361     if( !list )
  362     {
  363         /* create the list */
  364         list = sflist_new();
  365         if( !list )
  366             FatalError("service_rule_map: could not create a  service rule-list\n");
  367 
  368         /* add the service list to the table */
  369         if( sfghash_add( table, servicename, list ) != SFGHASH_OK )
  370         {
  371             FatalError("service_rule_map: could not add a rule to the rule-service-map\n");
  372         }
  373     }
  374 
  375     if( list->tail && (otn_tmp = list->tail->ndata) && (otn_tmp == otn))
  376        return;
  377 
  378     /* add the rule since this is not duplicate */
  379     if( sflist_add_tail( list, otn ) )
  380         FatalError("service_rule_map: could not add a rule to the service rule-list\n");
  381 }
  382 /*
  383  *  maintain a table of service maps, one for each protocol and direction,
  384  *  each service map maintains a list of otn's for each service it maps to a
  385  *  service name.
  386  */
  387 static int ServiceMapAddOtn(srmm_table_t *srmm, int proto, char *servicename, OptTreeNode *otn)
  388 {
  389     SFGHASH * to_srv; /* to srv service rule map */
  390     SFGHASH * to_cli; /* to cli service rule map */
  391 
  392     if( !servicename )
  393         return 0;
  394 
  395     if(!otn )
  396         return 0;
  397 
  398     if( proto == IPPROTO_TCP)
  399     {
  400         to_srv = srmm->tcp_to_srv;
  401         to_cli = srmm->tcp_to_cli;
  402     }
  403     else if( proto == IPPROTO_UDP)
  404     {
  405         to_srv = srmm->udp_to_srv;
  406         to_cli = srmm->udp_to_cli;
  407     }
  408     else if( proto == IPPROTO_ICMP )
  409     {
  410         to_srv = srmm->icmp_to_srv;
  411         to_cli = srmm->icmp_to_cli;
  412     }
  413     else if( proto ==  ETHERNET_TYPE_IP )
  414     {
  415         to_srv = srmm->ip_to_srv;
  416         to_cli = srmm->ip_to_cli;
  417     }
  418     else
  419     {
  420         return 0;
  421     }
  422 
  423     if( fpOtnFlowToServer(otn) )
  424     {
  425         ServiceMapAddOtnRaw( to_srv, servicename, otn );
  426     }
  427     else if( fpOtnFlowToClient(otn) )
  428     {
  429         ServiceMapAddOtnRaw( to_cli, servicename, otn );
  430     }
  431     else /* else add to both sides */
  432     {
  433         ServiceMapAddOtnRaw( to_srv, servicename, otn );
  434         ServiceMapAddOtnRaw( to_cli, servicename, otn );
  435     }
  436 
  437     return 0;
  438 }
  439 // TARGET_BASED
  440 #endif
  441 
  442 /*
  443 **  The following functions are wrappers to the pcrm routines,
  444 **  that utilize the variables that we have intialized by
  445 **  calling fpCreateFastPacketDetection().  These functions
  446 **  are also used in the file fpdetect.c, where we do lookups
  447 **  on the initialized variables.
  448 */
  449 #ifdef TARGET_BASED
  450 int prmFindRuleGroupIp(PORT_RULE_MAP *prm, int ip_proto, PORT_GROUP **ip_group, PORT_GROUP ** gen)
  451 {
  452     PORT_GROUP *unused_a;
  453     PORT_GROUP *unused_b;
  454     PORT_GROUP *unused_c;
  455     return prmFindRuleGroup(prm, ip_proto, -1, &unused_a, ip_group, &unused_b, &unused_c, gen);
  456 }
  457 
  458 int prmFindRuleGroupIcmp(PORT_RULE_MAP *prm, int type, PORT_GROUP **type_group, PORT_GROUP ** gen)
  459 {
  460     PORT_GROUP *unused_a;
  461     PORT_GROUP *unused_b;
  462     PORT_GROUP *unused_c;
  463     return prmFindRuleGroup(prm, type, -1, &unused_a, type_group, &unused_b, &unused_c, gen);
  464 }
  465 
  466 int prmFindRuleGroupTcp(PORT_RULE_MAP *prm, int dport, int sport, PORT_GROUP ** src, PORT_GROUP **dst,
  467         PORT_GROUP **nssrc, PORT_GROUP **nsdst, PORT_GROUP ** gen)
  468 {
  469     return prmFindRuleGroup( prm, dport, sport, src, dst, nssrc, nsdst, gen);
  470 }
  471 
  472 int prmFindRuleGroupUdp(PORT_RULE_MAP *prm, int dport, int sport, PORT_GROUP ** src, PORT_GROUP ** dst,
  473         PORT_GROUP **nssrc, PORT_GROUP **nsdst, PORT_GROUP ** gen)
  474 {
  475     return prmFindRuleGroup( prm, dport, sport, src, dst, nssrc, nsdst, gen);
  476 }
  477 
  478 #else
  479 
  480 int prmFindRuleGroupIp(PORT_RULE_MAP *prm, int ip_proto, PORT_GROUP **ip_group, PORT_GROUP ** gen)
  481 {
  482     PORT_GROUP *unused_a;
  483     return prmFindRuleGroup(prm, ip_proto, -1, &unused_a, ip_group, gen);
  484 }
  485 
  486 int prmFindRuleGroupIcmp(PORT_RULE_MAP *prm, int type, PORT_GROUP **type_group, PORT_GROUP ** gen)
  487 {
  488     PORT_GROUP *unused_a;
  489     return prmFindRuleGroup(prm, type, -1, &unused_a, type_group, gen);
  490 }
  491 
  492 int prmFindRuleGroupTcp(PORT_RULE_MAP *prm, int dport, int sport, PORT_GROUP ** src, PORT_GROUP **dst, PORT_GROUP ** gen)
  493 {
  494     return prmFindRuleGroup( prm, dport, sport, src, dst, gen);
  495 }
  496 
  497 int prmFindRuleGroupUdp(PORT_RULE_MAP *prm, int dport, int sport, PORT_GROUP ** src, PORT_GROUP ** dst, PORT_GROUP ** gen)
  498 {
  499     return prmFindRuleGroup( prm, dport, sport, src, dst, gen);
  500 }
  501 #endif // TARGET_BASED
  502 
  503 void free_detection_option_root(void **existing_tree)
  504 {
  505     detection_option_tree_root_t *root;
  506 
  507     if (!existing_tree || !*existing_tree)
  508         return;
  509 
  510     root = *existing_tree;
  511     free(root->children);
  512     free(root);
  513     *existing_tree = NULL;
  514 }
  515 
  516 void free_detection_option_tree(detection_option_tree_node_t *node)
  517 {
  518     int i;
  519     for (i=0;i<node->num_children;i++)
  520     {
  521         free_detection_option_tree(node->children[i]);
  522     }
  523     free(node->children);
  524     free(node);
  525 }
  526 
  527 /* These aren't currently used */
  528 //static int num_trees = 0;
  529 //static int num_nc_trees = 0;
  530 //static int num_dup_trees = 0;
  531 int finalize_detection_option_tree(SnortConfig *sc, detection_option_tree_root_t *root)
  532 {
  533     detection_option_tree_node_t *node = NULL;
  534     void *dup_node = NULL;
  535     int i;
  536 
  537     if (!root)
  538         return -1;
  539 
  540     for (i=0;i<root->num_children;i++)
  541     {
  542         node = root->children[i];
  543         if (add_detection_option_tree(sc, node, &dup_node) == DETECTION_OPTION_EQUAL)
  544         {
  545             free_detection_option_tree(node);
  546             root->children[i] = (detection_option_tree_node_t *)dup_node;
  547             //num_dup_trees++;
  548         }
  549         else
  550         {
  551             //num_trees++;
  552         }
  553 #ifdef DEBUG_OPTION_TREE
  554         print_option_tree(root->children[i], 0);
  555 #endif
  556     }
  557 
  558     return 0;
  559 }
  560 
  561 int otn_create_tree(OptTreeNode *otn, void **existing_tree)
  562 {
  563     detection_option_tree_node_t *node = NULL, *child;
  564     detection_option_tree_root_t *root = NULL;
  565     OptFpList *opt_fp = NULL;
  566     int i;
  567 
  568     if (!existing_tree)
  569         return -1;
  570 
  571     if (!*existing_tree)
  572     {
  573         *existing_tree = SnortAlloc(sizeof(detection_option_tree_root_t));
  574     }
  575     root = *existing_tree;
  576 #ifdef PPM_MGR
  577     root->tree_state = RULE_STATE_ENABLED;
  578 #endif
  579 
  580     opt_fp = otn->opt_func;
  581 
  582     if (!root->children)
  583     {
  584         root->num_children++;
  585         root->children = SnortAlloc(sizeof(detection_option_tree_node_t *) * root->num_children);
  586     }
  587 
  588     i = 0;
  589     child = root->children[i];
  590 
  591     /* Build out sub-nodes for each option in the OTN fp list */
  592     while (opt_fp)
  593     {
  594         /* If child node does not match existing option_data,
  595          * Create a child branch from a given sub-node. */
  596         void *option_data = opt_fp->context;
  597         char found_child_match = 0;
  598 
  599         if (opt_fp->type == RULE_OPTION_TYPE_LEAF_NODE)
  600         {
  601             opt_fp = opt_fp->next;
  602             continue;
  603         }
  604 
  605         /* Don't add contents that are only for use in the
  606          * fast pattern matcher */
  607         if ((opt_fp->type == RULE_OPTION_TYPE_CONTENT)
  608                 || (opt_fp->type == RULE_OPTION_TYPE_CONTENT_URI))
  609         {
  610             PatternMatchData *pmd = (PatternMatchData *)option_data;
  611             if (pmd->fp_only)
  612             {
  613                 opt_fp = opt_fp->next;
  614                 continue;
  615             }
  616         }
  617 
  618         if (!child)
  619         {
  620             /* No children at this node */
  621             child = SnortAlloc(sizeof(detection_option_tree_node_t));
  622             child->option_data = option_data;
  623             child->option_type = opt_fp->type;
  624             child->evaluate = opt_fp->OptTestFunc;
  625             if (!node)
  626             {
  627                 root->children[i] = child;
  628             }
  629             else
  630             {
  631                 node->children[i] = child;
  632             }
  633             child->num_children++;
  634             child->children = SnortAlloc(sizeof(detection_option_tree_node_t *) * child->num_children);
  635             child->last_check.is_relative = opt_fp->isRelative;
  636             if (node && child->last_check.is_relative)
  637             {
  638                 node->relative_children++;
  639             }
  640         }
  641         else
  642         {
  643             if (child->option_data != option_data)
  644             {
  645                 if (!node)
  646                 {
  647                     for (i=1;i<root->num_children;i++)
  648                     {
  649                         child = root->children[i];
  650                         if (child->option_data == option_data)
  651                         {
  652                             found_child_match = 1;
  653                             break;
  654                         }
  655                     }
  656                 }
  657                 else
  658                 {
  659                     for (i=1;i<node->num_children;i++)
  660                     {
  661                         child = node->children[i];
  662                         if (child->option_data == option_data)
  663                         {
  664                             found_child_match = 1;
  665                             break;
  666                         }
  667                     }
  668                 }
  669             }
  670             else
  671             {
  672                 found_child_match = 1;
  673             }
  674 
  675             if (found_child_match == 0)
  676             {
  677                 /* No matching child node, create a new and add to array */
  678                 detection_option_tree_node_t **tmp_children;
  679                 child = SnortAlloc(sizeof(detection_option_tree_node_t));
  680                 child->option_data = option_data;
  681                 child->option_type = opt_fp->type;
  682                 child->evaluate = opt_fp->OptTestFunc;
  683                 child->num_children++;
  684                 child->children = SnortAlloc(sizeof(detection_option_tree_node_t *) * child->num_children);
  685                 child->last_check.is_relative = opt_fp->isRelative;
  686 
  687                 if (!node)
  688                 {
  689                     root->num_children++;
  690                     tmp_children = SnortAlloc(sizeof(detection_option_tree_node_t *) * root->num_children);
  691                     memcpy(tmp_children, root->children,
  692                             sizeof(detection_option_tree_node_t *) * (root->num_children-1));
  693 
  694                     free(root->children);
  695                     root->children = tmp_children;
  696                     root->children[root->num_children-1] = child;
  697                 }
  698                 else
  699                 {
  700                     node->num_children++;
  701                     tmp_children = SnortAlloc(sizeof(detection_option_tree_node_t *) * node->num_children);
  702                     memcpy(tmp_children, node->children,
  703                             sizeof(detection_option_tree_node_t *) * (node->num_children-1));
  704 
  705                     free(node->children);
  706                     node->children = tmp_children;
  707                     node->children[node->num_children-1] = child;
  708                     if (child->last_check.is_relative)
  709                         node->relative_children++;
  710                 }
  711             }
  712         }
  713         node = child;
  714         i=0;
  715         child = node->children[i];
  716         opt_fp = opt_fp->next;
  717     }
  718 
  719     /* Append a leaf node that has option data of the SigInfo/otn pointer */
  720     child = SnortAlloc(sizeof(detection_option_tree_node_t));
  721     child->option_data = otn;
  722     child->option_type = RULE_OPTION_TYPE_LEAF_NODE;
  723     if (!node)
  724     {
  725         if (root->children[0])
  726         {
  727             detection_option_tree_node_t **tmp_children;
  728             root->num_children++;
  729             tmp_children = SnortAlloc(sizeof(detection_option_tree_node_t *) * root->num_children);
  730             memcpy(tmp_children, root->children,
  731                     sizeof(detection_option_tree_node_t *) * (root->num_children-1));
  732             free(root->children);
  733             root->children = tmp_children;
  734         }
  735         root->children[root->num_children-1] = child;
  736     }
  737     else
  738     {
  739         if (node->children[0])
  740         {
  741             detection_option_tree_node_t **tmp_children;
  742             node->num_children++;
  743             tmp_children = SnortAlloc(sizeof(detection_option_tree_node_t *) * node->num_children);
  744             memcpy(tmp_children, node->children,
  745                     sizeof(detection_option_tree_node_t *) * (node->num_children-1));
  746             free(node->children);
  747             node->children = tmp_children;
  748         }
  749         node->children[node->num_children-1] = child;
  750     }
  751 
  752     return 0;
  753 }
  754 
  755 static int add_patrn_to_neg_list(void *id, void **list)
  756 {
  757     PMX *pmx = (PMX *)id;
  758     NCListNode **ncl = (NCListNode **)list;
  759     NCListNode *new;
  760 
  761     if ((id == NULL) || (list == NULL))
  762         return -1;
  763 
  764     new = (NCListNode *)SnortAlloc(sizeof(NCListNode));
  765     new->pmx = pmx;
  766     new->next = *ncl;
  767     *ncl = new;
  768 
  769     return 0;
  770 }
  771 
  772 static void neg_list_free(void **list)
  773 {
  774     NCListNode *ncln;
  775 
  776     if (list == NULL)
  777         return;
  778 
  779     ncln = (NCListNode *)*list;
  780     while (ncln != NULL)
  781     {
  782         NCListNode *tmp = ncln->next;
  783         free(ncln);
  784         ncln = tmp;
  785     }
  786 
  787     *list = NULL;
  788 }
  789 
  790 int pmx_create_tree(struct _SnortConfig *sc, void *id, void **existing_tree)
  791 {
  792     PMX              *pmx    = NULL;
  793     RULE_NODE        *rnNode = NULL;
  794     OptTreeNode      *otn    = NULL;
  795 
  796     if (!existing_tree)
  797         return -1;
  798 
  799     if (!*existing_tree)
  800     {
  801         *existing_tree = SnortAlloc(sizeof(detection_option_tree_root_t));
  802     }
  803 
  804     if (!id)
  805     {
  806         /* NULL input id (PMX *), last call for this pattern state */
  807         return finalize_detection_option_tree(sc, (detection_option_tree_root_t *)*existing_tree);
  808     }
  809 
  810     pmx    = (PMX*)id;
  811     rnNode = (RULE_NODE*)(pmx->RuleNode);
  812     otn    = (OptTreeNode *)rnNode->rnRuleData;
  813     return otn_create_tree(otn, existing_tree);
  814 }
  815 
  816 /*
  817 **  The following functions deal with the intialization of the
  818 **  detection engine.  These are set through parser.c with the
  819 **  option 'config detection:'.  This functionality may be
  820 **  broken out later into it's own file to separate from this
  821 **  file's functionality.
  822 */
  823 
  824 /*
  825 **  Initialize detection options.
  826 */
  827 
  828 FastPatternConfig * FastPatternConfigNew(void)
  829 {
  830     FastPatternConfig *fp =
  831         (FastPatternConfig *)SnortAlloc(sizeof(FastPatternConfig));
  832 
  833     fpSetDefaults(fp);
  834     return fp;
  835 }
  836 
  837 void fpSetDefaults(FastPatternConfig *fp)
  838 {
  839     if (fp == NULL)
  840         return;
  841 
  842     memset(fp, 0, sizeof(FastPatternConfig));
  843 
  844     fp->inspect_stream_insert = 1;
  845     fp->search_method = MPSE_AC_BNFA;
  846     fp->max_queue_events = 5;
  847     fp->bleedover_port_limit = 1024;
  848 }
  849 
  850 void FastPatternConfigFree(FastPatternConfig *fp)
  851 {
  852     if (fp == NULL)
  853         return;
  854 
  855     free(fp);
  856 }
  857 
  858 
  859 int fpDetectGetSingleRuleGroup(FastPatternConfig *fp)
  860 {
  861     return fp->portlists_flags & PL_SINGLE_RULE_GROUP;
  862 }
  863 int fpDetectGetBleedOverPortLimit(FastPatternConfig *fp)
  864 {
  865     return fp->bleedover_port_limit;
  866 }
  867 int fpDetectGetBleedOverWarnings(FastPatternConfig *fp)
  868 {
  869     return fp->portlists_flags & PL_BLEEDOVER_WARNINGS_ENABLED;
  870 }
  871 int fpDetectGetDebugPrintNcRules(FastPatternConfig *fp)
  872 {
  873     return fp->portlists_flags & PL_DEBUG_PRINT_NC_DETECT_RULES;
  874 }
  875 int fpDetectGetDebugPrintRuleGroupBuildDetails(FastPatternConfig *fp)
  876 {
  877     return fp->portlists_flags & PL_DEBUG_PRINT_RULEGROWP_BUILD;
  878 }
  879 int fpDetectGetDebugPrintRuleGroupsCompiled(FastPatternConfig *fp)
  880 {
  881     return fp->portlists_flags & PL_DEBUG_PRINT_RULEGROUPS_COMPILED;
  882 }
  883 int fpDetectGetDebugPrintRuleGroupsUnCompiled(FastPatternConfig *fp)
  884 {
  885     return fp->portlists_flags & PL_DEBUG_PRINT_RULEGROUPS_UNCOMPILED;;
  886 }
  887 int fpDetectGetDebugPrintFastPatterns(FastPatternConfig *fp)
  888 {
  889     return fp->debug_print_fast_pattern;
  890 }
  891 int fpDetectSplitAnyAny(FastPatternConfig *fp)
  892 {
  893     return fp->split_any_any;
  894 }
  895 void fpDetectSetSingleRuleGroup(FastPatternConfig *fp)
  896 {
  897     fp->portlists_flags |= PL_SINGLE_RULE_GROUP;
  898 }
  899 void fpDetectSetBleedOverPortLimit(FastPatternConfig *fp, unsigned int n)
  900 {
  901     fp->bleedover_port_limit = n;
  902 }
  903 void fpDetectSetBleedOverWarnings(FastPatternConfig *fp)
  904 {
  905     fp->portlists_flags |= PL_BLEEDOVER_WARNINGS_ENABLED;
  906 }
  907 void fpDetectSetDebugPrintNcRules(FastPatternConfig *fp)
  908 {
  909     fp->portlists_flags |= PL_DEBUG_PRINT_NC_DETECT_RULES;
  910 }
  911 void fpDetectSetDebugPrintRuleGroupBuildDetails(FastPatternConfig *fp)
  912 {
  913     fp->portlists_flags |= PL_DEBUG_PRINT_RULEGROWP_BUILD;
  914 }
  915 void fpDetectSetDebugPrintRuleGroupsCompiled(FastPatternConfig *fp)
  916 {
  917     fp->portlists_flags |= PL_DEBUG_PRINT_RULEGROUPS_COMPILED;
  918 }
  919 void fpDetectSetDebugPrintRuleGroupsUnCompiled(FastPatternConfig *fp)
  920 {
  921     fp->portlists_flags |= PL_DEBUG_PRINT_RULEGROUPS_UNCOMPILED;
  922 }
  923 void fpDetectSetDebugPrintFastPatterns(FastPatternConfig *fp, int flag)
  924 {
  925     fp->debug_print_fast_pattern = flag;
  926 }
  927 void fpSetDetectSearchOpt(FastPatternConfig *fp, int flag)
  928 {
  929     fp->search_opt = flag;
  930     if (flag)
  931         LogMessage("    Search-Method-Optimizations = enabled\n");
  932 }
  933 
  934 /*
  935    Search method is set using:
  936    config detect: search-method ac-bnfa | ac | ac-full | ac-sparsebands | ac-sparse | ac-banded | ac-std | verbose
  937 */
  938 int fpSetDetectSearchMethod(FastPatternConfig *fp, char *method)
  939 {
  940     LogMessage("Detection:\n");
  941 
  942     if( !strcasecmp(method,"ac-std") )
  943     {
  944        fp->search_method = MPSE_AC;
  945        LogMessage("   Search-Method = AC-Std\n");
  946     }
  947     else if( !strcasecmp(method,"ac-bnfa-q") ||
  948              !strcasecmp(method,"ac-bnfa") )
  949     {
  950        fp->search_method = MPSE_AC_BNFA_Q;
  951        LogMessage("   Search-Method = AC-BNFA-Q\n");
  952     }
  953     else if( !strcasecmp(method,"ac-bnfa-nq") )
  954     {
  955        fp->search_method = MPSE_AC_BNFA;
  956        LogMessage("   Search-Method = AC-BNFA\n");
  957     }
  958     else if( !strcasecmp(method,"ac-q") ||
  959              !strcasecmp(method,"ac") )
  960     {
  961        fp->search_method = MPSE_ACF_Q;
  962        LogMessage("   Search-Method = AC-Full-Q\n");
  963     }
  964     else if( !strcasecmp(method,"ac-split") )
  965     {
  966         fp->search_method = MPSE_ACF_Q;
  967         fp->split_any_any = 1;
  968         LogMessage("   Search-Method = AC-Full-Q\n");
  969         LogMessage("    Split Any/Any group = enabled\n");
  970     }
  971     else if( !strcasecmp(method,"ac-nq") )
  972     {
  973        fp->search_method = MPSE_ACF;
  974        LogMessage("   Search-Method = AC-Full\n");
  975     }
  976     else if( !strcasecmp(method,"acs") )
  977     {
  978        fp->search_method = MPSE_ACS;
  979        LogMessage("   Search-Method = AC-Sparse\n");
  980     }
  981     else if( !strcasecmp(method,"ac-banded") )
  982     {
  983        fp->search_method = MPSE_ACB;
  984        LogMessage("   Search-Method = AC-Banded\n");
  985     }
  986     else if( !strcasecmp(method,"ac-sparsebands") )
  987     {
  988        fp->search_method = MPSE_ACSB;
  989        LogMessage("   Search-Method = AC-Sparse-Bands\n");
  990     }
  991     /* These are for backwards compatability - and will be removed in future releases*/
  992     else if( !strcasecmp(method,"mwm") )
  993     {
  994        fp->search_method = MPSE_LOWMEM;
  995        LogMessage("   Search-Method = Low-Mem (MWM depracated)\n");
  996     }
  997     else if( !strcasecmp(method,"lowmem-q") ||
  998              !strcasecmp(method,"lowmem") )
  999     {
 1000        fp->search_method = MPSE_LOWMEM_Q;
 1001        LogMessage("   Search-Method = Low-Mem-Q\n");
 1002     }
 1003     else if( !strcasecmp(method,"lowmem-nq") )
 1004     {
 1005        fp->search_method = MPSE_LOWMEM;
 1006        LogMessage("   Search-Method = Low-Mem\n");
 1007     }
 1008 #ifdef INTEL_SOFT_CPM
 1009     else if( !strcasecmp(method,"intel-cpm") )
 1010     {
 1011        fp->search_method = MPSE_INTEL_CPM;
 1012        LogMessage("   Search-Method = Intel CPM\n");
 1013     }
 1014 #endif
 1015     else
 1016     {
 1017        return -1;
 1018     }
 1019 
 1020     return 0;
 1021 }
 1022 
 1023 void fpDetectSetSplitAnyAny(FastPatternConfig *fp, int enable)
 1024 {
 1025     if (enable)
 1026     {
 1027         fp->split_any_any = 1;
 1028         LogMessage("    Split Any/Any group = enabled\n");
 1029     }
 1030     else
 1031     {
 1032         fp->split_any_any = 0;
 1033     }
 1034 }
 1035 
 1036 /*
 1037 **  Set the debug mode for the detection engine.
 1038 */
 1039 void fpSetDebugMode(FastPatternConfig *fp)
 1040 {
 1041     fp->debug = 1;
 1042 }
 1043 
 1044 /*
 1045 **  Revert the detection engine back to not inspecting packets
 1046 **  that are going to be rebuilt.
 1047 */
 1048 void fpSetStreamInsert(FastPatternConfig *fp)
 1049 {
 1050     fp->inspect_stream_insert = 0;
 1051 }
 1052 
 1053 /*
 1054 **  Sets the maximum number of events to queue up in fpdetect before
 1055 **  selecting an event.
 1056 */
 1057 void fpSetMaxQueueEvents(FastPatternConfig *fp, unsigned int num_events)
 1058 {
 1059     fp->max_queue_events = num_events;
 1060 }
 1061 
 1062 /*
 1063 **  Sets the maximum length of patterns to be inserted into the
 1064 **  pattern matcher used.
 1065 */
 1066 void fpSetMaxPatternLen(FastPatternConfig *fp, unsigned int max_len)
 1067 {
 1068     if (fp->max_pattern_len != 0)
 1069     {
 1070         LogMessage("WARNING: Maximum pattern length redefined.\n");
 1071     }
 1072     fp->max_pattern_len = max_len;
 1073     LogMessage("    Maximum pattern length = %u\n", max_len);
 1074 }
 1075 
 1076 /* FLP_Trim
 1077   *
 1078   * Trim zero byte prefixes, this increases uniqueness
 1079   *
 1080   * returns
 1081   *   length - of trimmed pattern
 1082   *   buff - ptr to new beggining of trimmed buffer
 1083   */
 1084 static int FLP_Trim( char * p, int plen, char ** buff )
 1085  {
 1086     int i;
 1087     int size = 0;
 1088 
 1089     if( !p )
 1090         return 0;
 1091 
 1092     for(i=0;i<plen;i++)
 1093     {
 1094         if( p[i] != 0 ) break;
 1095     }
 1096 
 1097     if( i < plen )
 1098         size = plen - i;
 1099     else
 1100         size = 0;
 1101 
 1102     if( buff && (size==0) )
 1103     {
 1104         *buff = 0;
 1105     }
 1106     else if( buff )
 1107     {
 1108         *buff = &p[i];
 1109     }
 1110     return size;
 1111  }
 1112 
 1113 
 1114 static inline PatternMatchData * DynamicContentToPmd(FPContentInfo *content_info)
 1115 {
 1116     PatternMatchData *pmd;
 1117 
 1118     if (content_info == NULL)
 1119         return NULL;
 1120 
 1121     pmd = (PatternMatchData *)SnortAlloc(sizeof(PatternMatchData));
 1122     pmd->pattern_buf = (char *)SnortAlloc(content_info->length);
 1123     memcpy(pmd->pattern_buf, content_info->content, content_info->length);
 1124     pmd->pattern_size = content_info->length;
 1125     pmd->nocase = content_info->noCaseFlag;
 1126     pmd->exception_flag = content_info->exception_flag;
 1127     pmd->fp = content_info->fp;
 1128     pmd->fp_offset = content_info->fp_offset;
 1129     pmd->fp_length = content_info->fp_length;
 1130     pmd->fp_only = content_info->fp_only;
 1131     pmd->http_buffer = content_info->uri_buffer & 0xF;  // FIXTHIS make include
 1132 
 1133     return pmd;
 1134 }
 1135 
 1136 static PatternMatchData * DynamicFpContentsToPmdList(FPContentInfo *fp_list)
 1137 {
 1138     FPContentInfo *tmp;
 1139     PatternMatchData *pmd_list = NULL;
 1140 
 1141     if (fp_list == NULL)
 1142         return NULL;
 1143 
 1144     for (tmp = fp_list; tmp != NULL; tmp = tmp->next)
 1145     {
 1146         PatternMatchData *pmd = DynamicContentToPmd(tmp);
 1147         if (pmd != NULL)
 1148         {
 1149             /* Add these flags to indicate these patterns are only
 1150              * for the fast pattern matcher */
 1151             pmd->fp = 1;
 1152             pmd->fp_only = 1;
 1153 
 1154             /* Add to list of pmds */
 1155             (void)AppendPmdToList(&pmd_list, pmd);
 1156         }
 1157     }
 1158 
 1159     return pmd_list;
 1160 }
 1161 
 1162 static inline void FreeDynamicContentList(FPContentInfo *fplist)
 1163 {
 1164     while (fplist != NULL)
 1165     {
 1166         FPContentInfo *tmp = fplist->next;
 1167         if (fplist->content != NULL)
 1168             free(fplist->content);
 1169         free(fplist);
 1170         fplist = tmp;
 1171     }
 1172 }
 1173 
 1174 static PatternMatchData * GetDynamicFastPatternPmd(DynamicData *dd, int dd_type)
 1175 {
 1176     FPContentInfo *dc_list = NULL;
 1177 
 1178     if (dd == NULL)
 1179         return NULL;
 1180 
 1181     if (dd->getDynamicContents(dd->contextData, dd_type, &dc_list) == 0)
 1182     {
 1183         PatternMatchData *pmd = DynamicContentToPmd(GetLongestDynamicContent(dc_list));
 1184         FreeDynamicContentList(dc_list);
 1185         return pmd;
 1186     }
 1187 
 1188     return NULL;
 1189 }
 1190 
 1191 static inline int IsDynamicContentFpEligible(FPContentInfo *content)
 1192 {
 1193     if (content == NULL)
 1194         return 0;
 1195 
 1196     if ((content->content != NULL) && (content->length != 0))
 1197     {
 1198         /* Negative contents cannot be considered for dynamic rules since
 1199          * detection option tree evaluation only looks at content types
 1200          * for short circuiting rules found in the pattern matcher and
 1201          * essentially the dynamic rule will always have to be evaluated
 1202          * anyway in the no content tree */
 1203         if (content->exception_flag)
 1204             return 0;
 1205 
 1206         return 1;
 1207     }
 1208 
 1209     return 0;
 1210 }
 1211 
 1212 static FPContentInfo * GetLongestDynamicContent(FPContentInfo *content_list)
 1213 {
 1214     FPContentInfo *content = NULL;
 1215     FPContentInfo *content_zero = NULL;
 1216     FPContentInfo *tmp;
 1217     int max_size = 0;
 1218     int max_zero_size = 0;
 1219 
 1220     if (content_list == NULL)
 1221         return NULL;
 1222 
 1223     for (tmp = content_list; tmp != NULL; tmp = tmp->next)
 1224     {
 1225         if (tmp->fp)
 1226             return tmp;
 1227 
 1228         /* XXX COOKIE contents and some others should not be in the content list
 1229          * See GetDynamicContents() in sf_snort_detection_engine.c */
 1230 
 1231         if (IsDynamicContentFpEligible(tmp))
 1232         {
 1233             int size = FLP_Trim(tmp->content, tmp->length, NULL);
 1234 
 1235             /* In case we get all zeros patterns */
 1236             if ((size == 0) && (tmp->length > max_zero_size))
 1237             {
 1238                 max_zero_size = tmp->length;
 1239                 content_zero = tmp;
 1240             }
 1241             else if (size > max_size)
 1242             {
 1243                 max_size = size;
 1244                 content = tmp;
 1245             }
 1246         }
 1247     }
 1248 
 1249     if (content != NULL)
 1250         return content;
 1251     else if (content_zero != NULL)
 1252         return content_zero;
 1253 
 1254     return NULL;
 1255 
 1256 }
 1257 
 1258 static inline int IsPmdFpEligible(PatternMatchData *content)
 1259 {
 1260     if (content == NULL)
 1261         return 0;
 1262 
 1263     if ((content->pattern_buf != NULL) && (content->pattern_size != 0) && (!content->protected_pattern))
 1264     {
 1265         /* We don't add cookie and some other contents to fast pattern matcher */
 1266         if(content->http_buffer && !IsHttpBufFpEligible(content->http_buffer))
 1267             return 0;
 1268 
 1269         if (content->exception_flag)
 1270         {
 1271             /* Negative contents can only be considered if they are not relative
 1272              * and don't have any offset or depth.  This is because the pattern
 1273              * matcher does not take these into consideration and may find the
 1274              * content in a non-relevant section of the payload and thus disable
 1275              * the rule when it shouldn't be.
 1276              * Also case sensitive patterns cannot be considered since patterns
 1277              * are inserted into the pattern matcher without case which may
 1278              * lead to false negatives */
 1279             if (content->use_doe || !content->nocase
 1280                     || (content->offset != 0) || (content->depth != 0))
 1281             {
 1282                 return 0;
 1283             }
 1284         }
 1285 
 1286         return 1;
 1287     }
 1288 
 1289     return 0;
 1290 }
 1291 
 1292 static PatternMatchData * GetLongestPmdContent(OptTreeNode *otn, int type)
 1293 {
 1294     PatternMatchData *pmd = NULL;
 1295     PatternMatchData *pmd_not = NULL;
 1296     PatternMatchData *pmd_zero = NULL;
 1297     PatternMatchData *pmd_zero_not = NULL;
 1298     OptFpList *ofl;
 1299     int max_size = 0;
 1300     int max_zero_size = 0;
 1301     uint8_t base64_buf_flag = 0;
 1302     uint8_t mime_buf_flag = 0;
 1303 
 1304     if (otn == NULL)
 1305         return NULL;
 1306 
 1307     for (ofl = otn->opt_func; ofl != NULL; ofl = ofl->next)
 1308     {
 1309         PatternMatchData *tmp = (PatternMatchData *)ofl->context;
 1310         FileData *filedata;
 1311 
 1312         switch (ofl->type)
 1313         {
 1314             case RULE_OPTION_TYPE_CONTENT:
 1315                 if (type != CONTENT_NORMAL)
 1316                     continue;
 1317                 else if(base64_buf_flag || mime_buf_flag)
 1318                     continue;
 1319                 break;
 1320             case RULE_OPTION_TYPE_CONTENT_URI:
 1321                 base64_buf_flag = 0;
 1322                 mime_buf_flag = 0;
 1323                 if (type != CONTENT_HTTP)
 1324                     continue;
 1325                 break;
 1326             case RULE_OPTION_TYPE_BASE64_DATA:
 1327                 base64_buf_flag =1;
 1328                 continue;
 1329             case RULE_OPTION_TYPE_PKT_DATA:
 1330                 base64_buf_flag = 0;
 1331                 mime_buf_flag = 0;
 1332                 continue;
 1333             case RULE_OPTION_TYPE_FILE_DATA:
 1334                 filedata = (FileData *)ofl->context;
 1335                 if(filedata->mime_decode_flag)
 1336                     mime_buf_flag = 1;
 1337                 continue;
 1338 
 1339             default:
 1340                 continue;
 1341         }
 1342 
 1343         if (tmp->fp)
 1344             return tmp;
 1345 
 1346         if (IsPmdFpEligible(tmp))
 1347         {
 1348             int size = FLP_Trim(tmp->pattern_buf, tmp->pattern_size, NULL);
 1349 
 1350             /* In case we get all zeros patterns */
 1351             if ((size == 0) && ((int)tmp->pattern_size > max_zero_size))
 1352             {
 1353                 if (tmp->exception_flag)
 1354                 {
 1355                     pmd_zero_not = tmp;
 1356                 }
 1357                 else
 1358                 {
 1359                     max_zero_size = tmp->pattern_size;
 1360                     pmd_zero = tmp;
 1361                 }
 1362             }
 1363             else if (size > max_size)
 1364             {
 1365                 if (tmp->exception_flag)
 1366                 {
 1367                     pmd_not = tmp;
 1368                 }
 1369                 else
 1370                 {
 1371                     max_size = size;
 1372                     pmd = tmp;
 1373                 }
 1374             }
 1375         }
 1376     }
 1377 
 1378     if (pmd != NULL)
 1379         return pmd;
 1380     else if (pmd_zero != NULL)
 1381         return pmd_zero;
 1382     else if (pmd_not != NULL)
 1383         return pmd_not;
 1384     else if (pmd_zero_not != NULL)
 1385         return pmd_zero_not;
 1386 
 1387     return NULL;
 1388 }
 1389 
 1390 static int GetPreprocOptPmdList(OptTreeNode *otn, PatternMatchData **pmd_list)
 1391 {
 1392     OptFpList *ofl;
 1393     int dir = 0;
 1394 
 1395     if ((otn == NULL) || (pmd_list == NULL))
 1396         return -1;
 1397 
 1398     if (otn->ds_list[PLUGIN_DYNAMIC] != NULL)
 1399     {
 1400         DynamicData *dd = otn->ds_list[PLUGIN_DYNAMIC];
 1401         FPContentInfo *fp_contents = NULL;
 1402 
 1403         if (dd->getPreprocFpContents(dd->contextData, &fp_contents) == 0)
 1404         {
 1405             *pmd_list = DynamicFpContentsToPmdList(fp_contents);
 1406             FreeDynamicContentList(fp_contents);
 1407 
 1408             if (*pmd_list == NULL)
 1409                 return -1;
 1410 
 1411             return 0;
 1412         }
 1413 
 1414         return -1;
 1415     }
 1416 
 1417     if (otn->ds_list[PLUGIN_CLIENTSERVER] != NULL)
 1418     {
 1419         ClientServerData *csd = (ClientServerData *)otn->ds_list[PLUGIN_CLIENTSERVER];
 1420         if (csd->from_server)
 1421             dir = PKT_FROM_SERVER;
 1422         else if (csd->from_client)
 1423             dir = PKT_FROM_CLIENT;
 1424     }
 1425 
 1426     for (ofl = otn->opt_func; ofl != NULL; ofl = ofl->next)
 1427     {
 1428         if (ofl->type == RULE_OPTION_TYPE_PREPROCESSOR)
 1429         {
 1430             FPContentInfo *fp_contents = NULL;
 1431 
 1432             if (GetPreprocFastPatterns(ofl->context, otn->proto, dir, &fp_contents) == 0)
 1433             {
 1434                 PatternMatchData *tmp_list = DynamicFpContentsToPmdList(fp_contents);
 1435                 (void)AppendPmdToList(pmd_list, tmp_list);
 1436 
 1437                 FreeDynamicContentList(fp_contents);
 1438             }
 1439         }
 1440     }
 1441 
 1442     if (*pmd_list == NULL)
 1443         return -1;
 1444 
 1445     return 0;
 1446 }
 1447 
 1448 static int UsePreprocOptFastPatterns(PatternMatchData *pmd, PatternMatchData *preproc_pmds)
 1449 {
 1450     int pmd_size;
 1451     PatternMatchData *tmp;
 1452 
 1453     if ((pmd == NULL) || !IsPmdFpEligible(pmd))
 1454         return 1;
 1455 
 1456     if (preproc_pmds == NULL)
 1457         return 0;
 1458 
 1459     pmd_size = FLP_Trim(pmd->pattern_buf, pmd->pattern_size, NULL);
 1460 
 1461     for (tmp = preproc_pmds; tmp != NULL; tmp = tmp->next)
 1462     {
 1463         int tmp_size = FLP_Trim(tmp->pattern_buf, tmp->pattern_size, NULL);
 1464 
 1465         /* If both are not contents or both are not not contents,
 1466          * compare pattern length */
 1467         if ((tmp->exception_flag && pmd->exception_flag)
 1468                 || (!tmp->exception_flag && !pmd->exception_flag))
 1469         {
 1470             if (tmp_size > pmd_size)
 1471                 return 1;
 1472         }
 1473 
 1474         /* If the preproc pattern is not notted and the content pmd is,
 1475          * use the preproc patterns */
 1476         if (!tmp->exception_flag && pmd->exception_flag)
 1477             return 1;
 1478     }
 1479 
 1480     return 0;
 1481 }
 1482 
 1483 static int fpFinishPortGroupRule(SnortConfig *sc, PORT_GROUP *pg, PmType pm_type,
 1484         OptTreeNode *otn, PatternMatchData *pmd_list, FastPatternConfig *fp)
 1485 {
 1486     PMX * pmx;
 1487     RULE_NODE * rn;
 1488     char *pattern;
 1489     int pattern_length;
 1490     PatternMatchData *pmd;
 1491     int pg_type;
 1492 
 1493     if ((pg == NULL) || (otn == NULL) || (fp == NULL))
 1494         return -1;
 1495 
 1496     switch (pm_type)
 1497     {
 1498         case PM_TYPE__CONTENT:
 1499             if (pmd_list == NULL)
 1500                 return -1;
 1501             pg_type = PGCT_CONTENT;
 1502             break;
 1503         case PM_TYPE__HTTP_URI_CONTENT:
 1504         case PM_TYPE__HTTP_HEADER_CONTENT:
 1505         case PM_TYPE__HTTP_CLIENT_BODY_CONTENT:
 1506             if (pmd_list == NULL)
 1507                 return -1;
 1508             pg_type = PGCT_URICONTENT;
 1509             break;
 1510         case PM_TYPE__MAX:
 1511         default:
 1512             if (pmd_list != NULL)
 1513                 return -1;
 1514             fpAddPortGroupPrmx(pg, otn, PGCT_NOCONTENT);
 1515             return 0;  /* Not adding any content to pattern matcher */
 1516     }
 1517 
 1518     for (pmd = pmd_list; pmd != NULL; pmd = pmd->next)
 1519     {
 1520         if (pmd->exception_flag)
 1521             fpAddPortGroupPrmx(pg, otn, PGCT_NOCONTENT);
 1522         else
 1523             fpAddPortGroupPrmx(pg, otn, pg_type);
 1524 
 1525         if (fpGetFinalPattern(fp, pmd, &pattern, &pattern_length) == -1)
 1526             return -1;
 1527 
 1528         /* create a rule_node */
 1529         rn = (RULE_NODE *)SnortAlloc(sizeof(RULE_NODE));
 1530         rn->rnRuleData = otn;
 1531 
 1532         /* create pmx */
 1533         pmx = (PMX *)SnortAlloc(sizeof(PMX));
 1534         pmx->RuleNode = rn;
 1535         pmx->PatternMatchData = pmd;
 1536 
 1537         if (fpDetectGetDebugPrintFastPatterns(fp))
 1538             PrintFastPatternInfo(otn, pmd, pattern, pattern_length, pm_type);
 1539 
 1540         mpseAddPatternWithSnortConfig(
 1541                 sc,
 1542                 pg->pgPms[pm_type],
 1543                 pattern,
 1544                 pattern_length,
 1545                 pmd->nocase,
 1546                 pmd->offset,
 1547                 pmd->depth,
 1548                 (unsigned)pmd->exception_flag,
 1549                 pmx,
 1550                 rn->iRuleNodeID
 1551                 );
 1552     }
 1553 
 1554     return 0;
 1555 }
 1556 
 1557 static int fpFinishPortGroup(SnortConfig *sc, PORT_GROUP *pg, FastPatternConfig *fp)
 1558 {
 1559     PmType i;
 1560     int rules = 0;
 1561 
 1562     if ((pg == NULL) || (fp == NULL))
 1563         return -1;
 1564 
 1565     for (i = PM_TYPE__CONTENT; i < PM_TYPE__MAX; i++)
 1566     {
 1567         if (pg->pgPms[i] != NULL)
 1568         {
 1569             if (mpseGetPatternCount(pg->pgPms[i]) != 0)
 1570             {
 1571                 if (mpsePrepPatternsWithSnortConf(sc, pg->pgPms[i], pmx_create_tree,
 1572                             add_patrn_to_neg_list) != 0)
 1573                 {
 1574                     FatalError("%s(%d) Failed to compile port group "
 1575                             "patterns.\n", __FILE__, __LINE__);
 1576                 }
 1577 
 1578                 if (fp->debug)
 1579                     mpsePrintInfo(pg->pgPms[i]);
 1580                 rules = 1;
 1581             }
 1582             else
 1583             {
 1584                 mpseFree(pg->pgPms[i]);
 1585                 pg->pgPms[i] = NULL;
 1586             }
 1587         }
 1588     }
 1589 
 1590     if (pg->pgHeadNC != NULL)
 1591     {
 1592         RULE_NODE *ruleNode;
 1593 
 1594         for (ruleNode = pg->pgHeadNC; ruleNode; ruleNode = ruleNode->rnNext)
 1595         {
 1596             OptTreeNode *otn = (OptTreeNode *)ruleNode->rnRuleData;
 1597             otn_create_tree(otn, &pg->pgNonContentTree);
 1598         }
 1599 
 1600         finalize_detection_option_tree(sc, (detection_option_tree_root_t*)pg->pgNonContentTree);
 1601         rules = 1;
 1602     }
 1603 
 1604     if (!rules)
 1605     {
 1606         /* Nothing in the port group so we can just free it */
 1607         free(pg);
 1608         return -1;
 1609     }
 1610 
 1611     return 0;
 1612 }
 1613 
 1614 static int fpAllocPms(SnortConfig *sc, PORT_GROUP *pg, FastPatternConfig *fp)
 1615 {
 1616     PmType i;
 1617 
 1618     for (i = PM_TYPE__CONTENT; i < PM_TYPE__MAX; i++)
 1619     {
 1620         /* init pattern matchers  */
 1621         pg->pgPms[i] = mpseNewWithSnortConfig(sc, fp->search_method,
 1622                 MPSE_INCREMENT_GLOBAL_CNT,
 1623                 fpDeletePMX,
 1624                 free_detection_option_root,
 1625                 neg_list_free);
 1626 
 1627         if (pg->pgPms[i] == NULL)
 1628         {
 1629             PmType j;
 1630 
 1631             for (j = PM_TYPE__CONTENT; j < i; j++)
 1632             {
 1633                 mpseFree(pg->pgPms[j]);
 1634                 pg->pgPms[j] = NULL;
 1635             }
 1636 
 1637             LogMessage("%s(%d) Failed to create pattern matcher for pattern "
 1638                     "matcher type: %d\n", __FILE__, __LINE__, i);
 1639 
 1640             return -1;
 1641         }
 1642 
 1643         if (fp->search_opt)
 1644             mpseSetOpt(pg->pgPms[i], 1);
 1645     }
 1646 
 1647     return 0;
 1648 }
 1649 
 1650 static PmType GetPmType (HTTP_BUFFER hb_type)
 1651 {
 1652     switch ( hb_type )
 1653     {
 1654     case HTTP_BUFFER_URI:
 1655         return PM_TYPE__HTTP_URI_CONTENT;
 1656 
 1657     case HTTP_BUFFER_HEADER:
 1658         return PM_TYPE__HTTP_HEADER_CONTENT;
 1659 
 1660     case HTTP_BUFFER_CLIENT_BODY:
 1661         return PM_TYPE__HTTP_CLIENT_BODY_CONTENT;
 1662 
 1663     default:
 1664         break;
 1665     }
 1666     return PM_TYPE__CONTENT;
 1667 }
 1668 
 1669 static int fpAddPortGroupRule(SnortConfig *sc, PORT_GROUP *pg, OptTreeNode *otn, FastPatternConfig *fp)
 1670 {
 1671     PatternMatchData *pmd = NULL;
 1672     PatternMatchData *pmd_uri = NULL;
 1673     PatternMatchData *preproc_opt_pmds = NULL;
 1674 
 1675     if ((pg == NULL) || (otn == NULL))
 1676         return -1;
 1677 
 1678     /* Preprocessor or decoder rule, skip inserting it */
 1679     if (otn->sigInfo.rule_type != SI_RULE_TYPE_DETECT)
 1680         return -1;
 1681 
 1682     /* Rule not enabled */
 1683     if (otn->rule_state != RULE_STATE_ENABLED)
 1684         return -1;
 1685 
 1686     /* Check for an so dynamic rule */
 1687     if (otn->ds_list[PLUGIN_DYNAMIC] != NULL)
 1688     {
 1689         DynamicData *dd = otn->ds_list[PLUGIN_DYNAMIC];
 1690 
 1691         /* The pmds returned here will have been dynamically allocated */
 1692         pmd = GetDynamicFastPatternPmd(dd, CONTENT_NORMAL);
 1693         if ((pmd != NULL) && pmd->fp)
 1694         {
 1695             if (fpFinishPortGroupRule(sc, pg, PM_TYPE__CONTENT, otn, pmd, fp) == 0)
 1696             {
 1697                 /* Need to do this so the pmd can be freed later */
 1698                 (void)AppendPmdToList(&dd->pmds, pmd);
 1699                 if (pmd->pattern_size > otn->longestPatternLen)
 1700                     otn->longestPatternLen = pmd->pattern_size;
 1701                 return 0;
 1702             }
 1703 
 1704             PatternMatchFree((void *)pmd);
 1705             pmd = NULL;
 1706         }
 1707 
 1708         pmd_uri = GetDynamicFastPatternPmd(dd, CONTENT_HTTP);
 1709         if (pmd_uri != NULL)
 1710         {
 1711             PmType pm_type = GetPmType(pmd_uri->http_buffer);
 1712 
 1713             if (fpFinishPortGroupRule(sc, pg, pm_type, otn, pmd_uri, fp) == 0)
 1714             {
 1715                 /* Using the http content so free this */
 1716                 if (pmd != NULL)
 1717                     PatternMatchFree((void *)pmd);
 1718 
 1719                 (void)AppendPmdToList(&dd->pmds, pmd_uri);
 1720                 if (pmd_uri->pattern_size > otn->longestPatternLen)
 1721                     otn->longestPatternLen = pmd_uri->pattern_size;
 1722                 return 0;
 1723             }
 1724 
 1725             PatternMatchFree((void *)pmd_uri);
 1726             pmd_uri = NULL;
 1727         }
 1728 
 1729         /* If we get this far then no URI contents were added */
 1730 
 1731         if (GetPreprocOptPmdList(otn, &preproc_opt_pmds) == 0)
 1732         {
 1733             if (UsePreprocOptFastPatterns(pmd, preproc_opt_pmds))
 1734             {
 1735                 /* Preprocessor rule option fast pattern contents
 1736                  * will be used so free and NULL the content pmd */
 1737                 if (pmd != NULL)
 1738                     FreePmdList(pmd);
 1739 
 1740                 pmd = preproc_opt_pmds;
 1741             }
 1742             else
 1743             {
 1744                 /* The content rule option fast pattern is a better choice
 1745                  * than the preprocessor rule option fast patterns, so use it */
 1746                 FreePmdList(preproc_opt_pmds);
 1747             }
 1748         }
 1749 
 1750         if (fpFinishPortGroupRule(sc, pg, PM_TYPE__CONTENT, otn, pmd, fp) == 0)
 1751         {
 1752             (void)AppendPmdToList(&dd->pmds, pmd);
 1753             if (pmd->pattern_size > otn->longestPatternLen)
 1754                 otn->longestPatternLen = pmd->pattern_size;
 1755             return 0;
 1756         }
 1757 
 1758         /* Either no content or adding pmd failed */
 1759 
 1760         /* Either single pmd or preprocessor rule option pmd list */
 1761         if (pmd != NULL)
 1762             FreePmdList(pmd);
 1763 
 1764         if (fpFinishPortGroupRule(sc, pg, PM_TYPE__MAX, otn, NULL, fp) != 0)
 1765             return -1;
 1766 
 1767         return 0;
 1768     }
 1769 
 1770     pmd = GetLongestPmdContent(otn, CONTENT_NORMAL);
 1771 
 1772     /* Pull it out of the ds_list so we can treat it as a one item list
 1773      * It will get free'd via the detection option tree callback for
 1774      * content rule options - the ds pmd list is useless at this point
 1775      * and should not be used anyway because of detection option tree
 1776      * duplicate handling - see FinalizeContentUniqueness() */
 1777     (void)RemovePmdFromList(pmd);
 1778 
 1779     if ((pmd != NULL) && pmd->fp)
 1780     {
 1781         if (fpFinishPortGroupRule(sc, pg, PM_TYPE__CONTENT, otn, pmd, fp) == 0)
 1782         {
 1783             if (pmd->pattern_size > otn->longestPatternLen)
 1784                 otn->longestPatternLen = pmd->pattern_size;
 1785 
 1786             return 0;
 1787         }
 1788     }
 1789 
 1790     /* http buffer contents take precedence over normal contents if
 1791      * no normal contents have the fast_pattern option */
 1792     pmd_uri = GetLongestPmdContent(otn, CONTENT_HTTP);
 1793     (void)RemovePmdFromList(pmd_uri);
 1794     if (pmd_uri != NULL)
 1795     {
 1796         PmType pm_type = GetPmType(pmd_uri->http_buffer);
 1797 
 1798         if (fpFinishPortGroupRule(sc, pg, pm_type, otn, pmd_uri, fp) == 0)
 1799         {
 1800             if (pmd_uri->pattern_size > otn->longestPatternLen)
 1801                 otn->longestPatternLen = pmd_uri->pattern_size;
 1802             return 0;
 1803         }
 1804     }
 1805 
 1806     /* If we get this far then no URI contents were added */
 1807 
 1808     if (GetPreprocOptPmdList(otn, &preproc_opt_pmds) == 0)
 1809     {
 1810         if (!UsePreprocOptFastPatterns(pmd, preproc_opt_pmds))
 1811         {
 1812             /* The content rule option fast pattern is a better choice
 1813              * than the preprocessor rule option fast patterns, so use it */
 1814             FreePmdList(preproc_opt_pmds);
 1815         }
 1816         else
 1817         {
 1818             pmd = preproc_opt_pmds;
 1819 
 1820             /* Need to be able to free this list */
 1821             (void)AppendPmdToList(
 1822                     (PatternMatchData **)&otn->preproc_fp_list,
 1823                     preproc_opt_pmds);
 1824         }
 1825     }
 1826 
 1827     if (fpFinishPortGroupRule(sc, pg, PM_TYPE__CONTENT, otn, pmd, fp) == 0)
 1828     {
 1829         if (pmd->pattern_size > otn->longestPatternLen)
 1830             otn->longestPatternLen = pmd->pattern_size;
 1831         return 0;
 1832     }
 1833 
 1834 #if 0
 1835     /* XXX Not currently used */
 1836     /* If the "or" content rule option should ever be instated, some sort of
 1837      * decision should be made between this and other normal "and" contents.
 1838      * Adding one content is probably preferable over adding multiple contents,
 1839      * but if the one content is only one, two bytes and the "or" contents are
 1840      * more unique, then adding the "or" contents might be preferable.  Maybe
 1841      * if the "and" content is more unique than the least unique "or" content */
 1842     pmd = otn->ds_list[PLUGIN_PATTERN_MATCH_OR];
 1843     if (pmd != NULL)
 1844         fpAddAllContents(pg->pgPms[PM_TYPE__CONTENT], otn, id, pmd, fp);
 1845 #endif
 1846 
 1847     /* No content added */
 1848     if (pmd == preproc_opt_pmds)
 1849         FreePmdList(pmd);
 1850 
 1851     if (fpFinishPortGroupRule(sc, pg, PM_TYPE__MAX, otn, NULL, fp) != 0)
 1852         return -1;
 1853 
 1854     return 0;
 1855 }
 1856 
 1857 /*
 1858  * Original PortRuleMaps for each protocol requires creating the following structures.
 1859  *          -pcrm.h
 1860  *          PORT_RULE_MAP -> srcPortGroup,dstPortGroup,genericPortGroup
 1861  *          PORT_GROUP    -> pgPatData, pgPatDataUri (acsm objects), (also rule_node lists 1/rule, not neeed)
 1862  *                           each rule content added to an acsm object has a PMX data ptr associated with it.
 1863  *          RULE_NODE     -> iRuleNodeID (used for bitmap object index)
 1864  *
 1865  *          -fpcreate.h
 1866  *          PMX   -> RULE_NODE(->otn), PatternMatchData
 1867  *
 1868  *  PortList model supports the same structures except:
 1869  *
 1870  *          -pcrm.h
 1871  *          PORT_GROUP    -> no rule_node lists needed, PortObjects maintain a list of rules used
 1872  *
 1873  *  Generation of PortRuleMaps and data is done differently.
 1874  *
 1875  *    1) Build tcp/udp/icmp/ip src and dst PORT_GROUP objects based on the PortList Objects rules.
 1876  *
 1877  *    2) For each protocols PortList objects walk it's ports and assign the PORT_RULE_MAP src and dst
 1878  *         PORT_GROUP[port] array pointers to that PortList objects PORT_GROUP.
 1879  *
 1880  *    Implementation:
 1881  *
 1882  *    Each PortList Object will be translated into a PORT_GROUP, than pointed to by the
 1883  *    PORT_GROUP array in the PORT_RULE_MAP for the procotocol
 1884  *
 1885  *    protocol = tcp, udp, ip, icmp - one port_rule_map for each of these protocols
 1886  *    { create a port_rule_map
 1887  *      dst port processing
 1888  *          for each port-list object create a port_group object
 1889  *          {   create a pattern match object, store its pointer in port_group
 1890  *              for each rule index in port-list object
 1891  *              {
 1892  *                  get the gid+sid for the index
 1893  *                  lookup up the otn
 1894  *                  create pmx
 1895  *                  create RULE_NODE, set iRuleNodeID within this port-list object
 1896  *                  get longest content for the rule
 1897  *                  set up pmx,RULE_NODE
 1898  *                  add the content and pmx to the pattern match object
 1899  *              }
 1900  *              compile the pattern match object
 1901  *
 1902  *              repeat for uri content
 1903  *          }
 1904  *      src port processing
 1905  *          repeat as for dst port processing
 1906  *    }
 1907  *    ** bidirectional rules - these are added to both src and dst PortList objects, so they are
 1908  *    automatically handled during conversion to port_group objects.
 1909  */
 1910 /*
 1911 **  Build a Pattern group for the Uri-Content rules in this group
 1912 **
 1913 **  The patterns added for each rule must be suffcient so if we find any of them
 1914 **  we proceed to fully analyze the OTN and RTN against the packet.
 1915 **
 1916 */
 1917 /*
 1918  *  Init a port-list based rule map
 1919  */
 1920 static int fpCreateInitRuleMap ( 
 1921         PORT_RULE_MAP * prm,
 1922         PortTable * src,
 1923         PortTable * dst,
 1924         PortObject * anyany,
 1925         PortObject * nc,
 1926         PortTable * ns_src, // TARGET_BASED
 1927         PortTable * ns_dst )// TARGET_BASED 
 1928 {
 1929     SFGHASH_NODE   * node;
 1930     PortObjectItem * poi;
 1931     PortObject2    * po;
 1932     int              i;
 1933 
 1934     /* setup the any-any-port content port group */
 1935     prm->prmGeneric =(PORT_GROUP*) anyany->data;
 1936 
 1937     /* all rules that are any any some may not be content ? */
 1938     prm->prmNumGenericRules = anyany->rule_list->count;
 1939 
 1940     prm->prmNumSrcRules= 0;
 1941     prm->prmNumDstRules= 0;
 1942 
 1943     prm->prmNumSrcGroups= 0;
 1944     prm->prmNumDstGroups= 0;
 1945 #ifdef TARGET_BASED
 1946     prm->prmNumNoServiceSrcRules= 0;
 1947     prm->prmNumNoServiceDstRules= 0;
 1948     prm->prmNumNoServiceSrcGroups= 0;
 1949     prm->prmNumNoServiceDstGroups= 0;
 1950 #endif
 1951 
 1952     /* Process src PORT groups */
 1953     if(src )
 1954     {
 1955         for( node=sfghash_findfirst(src->pt_mpxo_hash);
 1956                 node;
 1957                 node=sfghash_findnext(src->pt_mpxo_hash) )
 1958         {
 1959             po = (PortObject2*)node->data;
 1960 
 1961             if( !po ) continue;
 1962             if( !po->data ) continue;
 1963 
 1964             /* Add up the total src rules */
 1965             prm->prmNumSrcRules  += po->rule_hash->count;
 1966 
 1967             /* Increment the port group count */
 1968             prm->prmNumSrcGroups++;
 1969 
 1970             /* Add this port group to the src table at each port that uses it */
 1971             for( poi = (PortObjectItem*)sflist_first(po->item_list);
 1972                     poi;
 1973                     poi = (PortObjectItem*)sflist_next(po->item_list) )
 1974             {
 1975                 switch(poi->type)
 1976                 {
 1977                     case PORT_OBJECT_ANY:
 1978                         break;
 1979                     case PORT_OBJECT_PORT:
 1980 #if 0
 1981                         /* This test is always true since poi->lport is a 16 bit
 1982                          * int and MAX_PORTS is 64K.  If this relationship should
 1983                          * change, the test should be compiled back in.
 1984                          */
 1985                         if(  poi->lport < MAX_PORTS )
 1986 #endif
 1987                             prm->prmSrcPort[ poi->lport ] = (PORT_GROUP*)po->data;
 1988                         break;
 1989                     case PORT_OBJECT_RANGE:
 1990                         for(i= poi->lport;i<= poi->hport;i++ )
 1991                         {
 1992                             prm->prmSrcPort[ i ] = (PORT_GROUP*)po->data;
 1993                         }
 1994                         break;
 1995                 }
 1996             }
 1997         }
 1998     }
 1999 
 2000     /* process destination port groups */
 2001     if( dst )
 2002     {
 2003         for( node=sfghash_findfirst(dst->pt_mpxo_hash);
 2004                 node;
 2005                 node=sfghash_findnext(dst->pt_mpxo_hash) )
 2006         {
 2007             po = (PortObject2*)node->data;
 2008 
 2009             if( !po ) continue;
 2010             if( !po->data ) continue;
 2011 
 2012             /* Add up the total src rules */
 2013             prm->prmNumDstRules  += po->rule_hash->count;
 2014 
 2015             /* Increment the port group count */
 2016             prm->prmNumDstGroups++;
 2017 
 2018             /* Add this port group to the src table at each port that uses it */
 2019             for( poi = (PortObjectItem*)sflist_first(po->item_list);
 2020                     poi;
 2021                     poi = (PortObjectItem*)sflist_next(po->item_list) )
 2022             {
 2023                 switch(poi->type)
 2024                 {
 2025                     case PORT_OBJECT_ANY:
 2026                         break;
 2027                     case PORT_OBJECT_PORT:
 2028 #if 0
 2029                         /* This test is always true since poi->lport is a 16 bit
 2030                          * int and MAX_PORTS is 64K.  If this relationship should
 2031                          * change, the test should be compiled back in.
 2032                          */
 2033                         if(  poi->lport < MAX_PORTS )
 2034 #endif
 2035                             prm->prmDstPort[ poi->lport ] = (PORT_GROUP*)po->data;
 2036                         break;
 2037                     case PORT_OBJECT_RANGE:
 2038                         for(i= poi->lport;i<= poi->hport;i++ )
 2039                         {
 2040                             prm->prmDstPort[ i ] = (PORT_GROUP*)po->data;
 2041                         }
 2042                         break;
 2043                 }
 2044             }
 2045         }
 2046     }
 2047 
 2048     if( ns_src )
 2049     {
 2050         for( node=sfghash_findfirst(ns_src->pt_mpxo_hash);
 2051                 node;
 2052                 node=sfghash_findnext(ns_src->pt_mpxo_hash) )
 2053         {
 2054             po = (PortObject2*)node->data;
 2055 
 2056             if( !po ) continue;
 2057             if( !po->data ) continue;
 2058 
 2059             /* Add up the total ns_src rules */
 2060 #ifdef TARGET_BASED
 2061             prm->prmNumNoServiceSrcRules += po->rule_hash->count;
 2062 
 2063             /* Increment the port group count */
 2064             prm->prmNumNoServiceSrcGroups ++;
 2065 #endif
 2066             /* Add this port group to the ns_src table at each port that uses it */
 2067             for( poi = (PortObjectItem*)sflist_first(po->item_list); poi;
 2068                     poi = (PortObjectItem*)sflist_next(po->item_list) )
 2069             {
 2070                 switch(poi->type)
 2071                 {
 2072                     case PORT_OBJECT_ANY:
 2073                         break;
 2074                     case PORT_OBJECT_PORT:
 2075 #if 0
 2076                         /* This test is always true since poi->lport is a 16 bit
 2077                          * int and MAX_PORTS is 64K.  If this relationship should
 2078                          * change, the test should be compiled back in.
 2079                          */
 2080                         if(  poi->lport < MAX_PORTS )
 2081 #endif
 2082 #ifdef TARGET_BASED
 2083                             prm->prmNoServiceSrcPort[ poi->lport ] = (PORT_GROUP*)po->data;
 2084 #endif
 2085                         break;
 2086                     case PORT_OBJECT_RANGE:
 2087 #ifdef TARGET_BASED
 2088                         for(i= poi->lport;i<= poi->hport;i++ )
 2089                         {
 2090                             prm->prmNoServiceSrcPort[ i ] = (PORT_GROUP*)po->data;
 2091                         }
 2092 #endif
 2093                         break;
 2094                 }
 2095             }
 2096         }
 2097     }
 2098 
 2099     if( ns_dst )
 2100     {
 2101         for( node=sfghash_findfirst(ns_dst->pt_mpxo_hash); node;
 2102                 node=sfghash_findnext(ns_dst->pt_mpxo_hash) )
 2103         {
 2104             po = (PortObject2*)node->data;
 2105 
 2106             if( !po ) continue;
 2107             if( !po->data ) continue;
 2108 
 2109 #ifdef TARGET_BASED
 2110             /* Add up the total ns_dst rules */
 2111             prm->prmNumNoServiceDstRules += po->rule_hash->count;
 2112 
 2113             /* Increment the port group count */
 2114             prm->prmNumNoServiceDstGroups ++;
 2115 #endif
 2116 
 2117             /* Add this port group to the ns_dst table at each port that uses it */
 2118             for( poi = (PortObjectItem*)sflist_first(po->item_list);
 2119                     poi;
 2120                     poi = (PortObjectItem*)sflist_next(po->item_list) )
 2121             {
 2122                 switch(poi->type)
 2123                 {
 2124                     case PORT_OBJECT_ANY:
 2125                         break;
 2126                     case PORT_OBJECT_PORT:
 2127 #if 0
 2128                         /* This test is always true since poi->lport is a 16 bit
 2129                          * int and MAX_PORTS is 64K.  If this relationship should
 2130                          * change, the test should be compiled back in.
 2131                          */
 2132                         if(  poi->lport < MAX_PORTS )
 2133 #endif
 2134 #ifdef TARGET_BASED
 2135                             prm->prmNoServiceDstPort[ poi->lport ] = (PORT_GROUP*)po->data;
 2136 #endif
 2137                         break;
 2138                     case PORT_OBJECT_RANGE:
 2139 #ifdef TARGET_BASED
 2140                         for(i= poi->lport;i<= poi->hport;i++ )
 2141                         {
 2142                             prm->prmNoServiceDstPort[ i ] = (PORT_GROUP*)po->data;
 2143                         }
 2144 #endif
 2145                         break;
 2146                 }
 2147             }
 2148         }
 2149     }
 2150 
 2151     return 0;
 2152 }
 2153 /*
 2154  * Create and initialize the rule maps
 2155  */
 2156 static int fpCreateRuleMaps(SnortConfig *sc, rule_port_tables_t *p)
 2157 {
 2158     sc->prmTcpRTNX = prmNewMap();
 2159     if (sc->prmTcpRTNX == NULL)
 2160         return 1;
 2161 
 2162 #ifdef TARGET_BASED
 2163     if (fpCreateInitRuleMap(sc->prmTcpRTNX, p->tcp_src, p->tcp_dst, p->tcp_anyany, p->tcp_nocontent, p->ns_tcp_src, p->ns_tcp_dst ))
 2164         return -1;
 2165 #endif
 2166 
 2167     sc->prmUdpRTNX = prmNewMap();
 2168     if (sc->prmUdpRTNX == NULL)
 2169         return -1;
 2170 
 2171 #ifdef TARGET_BASED
 2172     if (fpCreateInitRuleMap(sc->prmUdpRTNX, p->udp_src, p->udp_dst, p->udp_anyany, p->udp_nocontent, p->ns_udp_src, p->ns_udp_dst))
 2173         return -1;
 2174 #endif
 2175 
 2176     sc->prmIpRTNX = prmNewMap();
 2177     if (sc->prmIpRTNX == NULL)
 2178         return 1;
 2179 
 2180 #ifdef TARGET_BASED
 2181     if (fpCreateInitRuleMap(sc->prmIpRTNX, p->ip_src, p->ip_dst, p->ip_anyany, p->ip_nocontent, p->ns_ip_src, p->ns_ip_dst))
 2182         return -1;
 2183 #endif
 2184 
 2185     sc->prmIcmpRTNX = prmNewMap();
 2186     if (sc->prmIcmpRTNX == NULL)
 2187         return 1;
 2188 
 2189 #ifdef TARGET_BASED
 2190     if (fpCreateInitRuleMap(sc->prmIcmpRTNX, p->icmp_src, p->icmp_dst, p->icmp_anyany, p->icmp_nocontent, p->ns_icmp_src, p->ns_icmp_dst))
 2191         return -1;
 2192 #endif
 2193 
 2194     return 0;
 2195 }
 2196 
 2197 static void fpFreeRuleMaps(SnortConfig *sc)
 2198 {
 2199     if (sc == NULL)
 2200         return;
 2201 
 2202     if (sc->prmTcpRTNX != NULL)
 2203     {
 2204         free(sc->prmTcpRTNX);
 2205         sc->prmTcpRTNX = NULL;
 2206     }
 2207 
 2208     if (sc->prmUdpRTNX != NULL)
 2209     {
 2210         free(sc->prmUdpRTNX);
 2211         sc->prmUdpRTNX = NULL;
 2212     }
 2213 
 2214     if (sc->prmIpRTNX != NULL)
 2215     {
 2216         free(sc->prmIpRTNX);
 2217         sc->prmIpRTNX = NULL;
 2218     }
 2219 
 2220     if (sc->prmIcmpRTNX != NULL)
 2221     {
 2222         free(sc->prmIcmpRTNX);
 2223         sc->prmIcmpRTNX = NULL;
 2224     }
 2225 }
 2226 
 2227 static int fpGetFinalPattern(FastPatternConfig *fp, PatternMatchData *pmd,
 2228         char **ret_pattern, int *ret_bytes)
 2229 {
 2230     char *pattern;
 2231     int bytes;
 2232 
 2233     assert(fp);
 2234     assert(pmd);
 2235     assert(ret_pattern);
 2236     assert(ret_bytes);
 2237 
 2238     if ((fp == NULL) || (pmd == NULL) || (ret_pattern == NULL) || (ret_bytes == NULL))
 2239     {
 2240         return -1;
 2241     }
 2242 
 2243     pattern = pmd->pattern_buf;
 2244     bytes = pmd->pattern_size;
 2245 
 2246     /* Don't mess with fast pattern only contents - they should be inserted
 2247      * into the pattern matcher as is since the content won't be evaluated
 2248      * as a rule option.
 2249      * Don't mess with negated contents since truncating them could
 2250      * inadvertantly disable evaluation of a rule - the shorter pattern
 2251      * may be found, while the unaltered pattern may not be found,
 2252      * disabling inspection of a rule we should inspect */
 2253     if (pmd->fp_only || pmd->exception_flag)
 2254     {
 2255         *ret_pattern = pattern;
 2256         *ret_bytes = bytes;
 2257 
 2258         return 0;
 2259     }
 2260 
 2261     if (pmd->fp && (pmd->fp_length != 0))
 2262     {
 2263         /* (offset + length) potentially being larger than the pattern itself
 2264          * is taken care of during parsing */
 2265         pattern = pmd->pattern_buf + pmd->fp_offset;
 2266         bytes = pmd->fp_length;
 2267     }
 2268     else
 2269     {
 2270         /* Trim leading null bytes for non-deterministic pattern matchers.
 2271          * Assuming many packets may have strings of 0x00 bytes in them,
 2272          * this should help performance with non-deterministic pattern matchers
 2273          * that have a full next state vector at state 0.  If no patterns are
 2274          * inserted into the state machine that start with 0x00, failstates that
 2275          * land us at state 0 will allow us to roll through the 0x00 bytes,
 2276          * since the next state is deterministic in state 0 and we won't move
 2277          * beyond state 0 as long as the next input char is 0x00 */
 2278         if ((fp->search_method == MPSE_AC_BNFA_Q)
 2279                 || (fp->search_method == MPSE_AC_BNFA))
 2280         {
 2281             bytes =
 2282                 FLP_Trim(pmd->pattern_buf, pmd->pattern_size, &pattern);
 2283 
 2284             if (bytes < (int)pmd->pattern_size)
 2285             {
 2286                 /* The patten is all '\0' - use the whole pattern
 2287                  * XXX This potentially hurts the performance boost
 2288                  * gained by stripping leading zeros */
 2289                 if (bytes == 0)
 2290                 {
 2291                     bytes = pmd->pattern_size;
 2292                     pattern = pmd->pattern_buf;
 2293                 }
 2294                 else
 2295                 {
 2296                     fp->num_patterns_trimmed++;
 2297                 }
 2298             }
 2299         }
 2300     }
 2301 
 2302     if ((fp->max_pattern_len != 0)
 2303             && (bytes > fp->max_pattern_len))
 2304     {
 2305         bytes = fp->max_pattern_len;
 2306         fp->num_patterns_truncated++;
 2307     }
 2308 
 2309     *ret_pattern = pattern;
 2310     *ret_bytes = bytes;
 2311 
 2312     return 0;
 2313 }
 2314 
 2315 void fpDynamicDataFree(void *data)
 2316 {
 2317     DynamicData *dd = (DynamicData *)data;
 2318     PatternMatchData *pmd;
 2319 
 2320     if (dd == NULL)
 2321         return;
 2322 
 2323     pmd = (PatternMatchData *)dd->pmds;
 2324     while (pmd != NULL)
 2325     {
 2326         PatternMatchData *tmp = pmd->next;
 2327         PatternMatchFree((void *)pmd);
 2328         pmd = tmp;
 2329     }
 2330 
 2331     free(dd);
 2332 }
 2333 
 2334 /*
 2335  *  Add a rule to the proper port group RULE_NODE list
 2336  *
 2337  *  cflag : content flag  ( 0=no content, 1=content, 2=uri-content)
 2338  */
 2339 static int fpAddPortGroupPrmx(PORT_GROUP *pg, OptTreeNode *otn, int cflag)
 2340 {
 2341     /* Add the no content rule_node to the port group (NClist) */
 2342     switch (cflag)
 2343     {
 2344         case PGCT_NOCONTENT:
 2345             prmxAddPortRuleNC( pg, otn );
 2346             break;
 2347         case PGCT_CONTENT:
 2348             prmxAddPortRule( pg, otn );
 2349             break;
 2350         case PGCT_URICONTENT:
 2351             prmxAddPortRuleUri( pg, otn );
 2352             break;
 2353         default:
 2354             return -1;
 2355     }
 2356 
 2357     return 0;
 2358 }
 2359 
 2360 static void fpPortGroupPrintRuleCount(PORT_GROUP *pg)
 2361 {
 2362     PmType type;
 2363 
 2364     if (pg == NULL)
 2365         return;
 2366 
 2367     LogMessage("PortGroup rule summary:\n");
 2368 
 2369     for (type = PM_TYPE__CONTENT; type < PM_TYPE__MAX; type++)
 2370     {
 2371         int count = mpseGetPatternCount(pg->pgPms[type]);
 2372 
 2373         switch (type)
 2374         {
 2375             case PM_TYPE__CONTENT:
 2376                 LogMessage("\tContent: %d\n", count);
 2377                 break;
 2378             case PM_TYPE__HTTP_URI_CONTENT:
 2379                 LogMessage("\tHttp Uri Content: %d\n", count);
 2380                 break;
 2381             case PM_TYPE__HTTP_HEADER_CONTENT:
 2382                 LogMessage("\tHttp Header Content: %d\n", count);
 2383                 break;
 2384             case PM_TYPE__HTTP_CLIENT_BODY_CONTENT:
 2385                 LogMessage("\tHttp Client Body Content: %d\n", count);
 2386                 break;
 2387             default:
 2388                 break;
 2389         }
 2390     }
 2391 
 2392     LogMessage("\tNo content: %u\n", pg->pgNoContentCount);
 2393 }
 2394 
 2395 static void fpDeletePMX(void *data)
 2396 {
 2397     PMX *pmx = (PMX *)data;
 2398 
 2399     if (data == NULL)
 2400         return;
 2401 
 2402     if (pmx->RuleNode != NULL)
 2403         free(pmx->RuleNode);
 2404 
 2405     free(pmx);
 2406 }
 2407 
 2408 static void fpDeletePortGroup(void *data)
 2409 {
 2410     PORT_GROUP *pg = (PORT_GROUP *)data;
 2411     RULE_NODE *rn, *tmpRn;
 2412     PmType i;
 2413 
 2414     rn = pg->pgHead;
 2415     while (rn)
 2416     {
 2417         tmpRn = rn->rnNext;
 2418         free(rn);
 2419         rn = tmpRn;
 2420     }
 2421     pg->pgHead = NULL;
 2422 
 2423     rn = pg->pgUriHead;
 2424     while (rn)
 2425     {
 2426         tmpRn = rn->rnNext;
 2427         free(rn);
 2428         rn = tmpRn;
 2429     }
 2430     pg->pgUriHead = NULL;
 2431 
 2432     rn = pg->pgHeadNC;
 2433     while (rn)
 2434     {
 2435         tmpRn = rn->rnNext;
 2436         free(rn);
 2437         rn = tmpRn;
 2438     }
 2439     pg->pgHeadNC = NULL;
 2440 
 2441     for (i = PM_TYPE__CONTENT; i < PM_TYPE__MAX; i++)
 2442     {
 2443         if (pg->pgPms[i] != NULL)
 2444         {
 2445             mpseFree(pg->pgPms[i]);
 2446             pg->pgPms[i] = NULL;
 2447         }
 2448     }
 2449 
 2450     free_detection_option_root(&pg->pgNonContentTree);
 2451 
 2452     free(pg);
 2453 }
 2454 
 2455 /*
 2456  *  Create the PortGroup for these PortObject2 entitiies
 2457  *
 2458  *  This builds the 1st pass multi-pattern state machines for
 2459  *  content and uricontent based on the rules in the PortObjects
 2460  *  hash table.
 2461  */
 2462 static int fpCreatePortObject2PortGroup(SnortConfig *sc, PortObject2 *po, PortObject2 *poaa)
 2463 {
 2464     SFGHASH_NODE *node;
 2465     unsigned sid, gid;
 2466     OptTreeNode * otn;
 2467     PORT_GROUP * pg;
 2468     PortObject2 *pox;
 2469     FastPatternConfig *fp = sc->fast_pattern_config;
 2470 
 2471     /* verify we have a port object */
 2472     if (po == NULL)
 2473         return 0;
 2474 
 2475     po->data = 0;
 2476 
 2477     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2478         PortObject2PrintPorts( po );
 2479 
 2480     /* Check if we have any rules */
 2481     if (po->rule_hash == NULL)
 2482         return 0;
 2483 
 2484     /* create a port_group */
 2485     pg = (PORT_GROUP *)SnortAlloc(sizeof(PORT_GROUP));
 2486 
 2487     if (fpAllocPms(sc, pg, fp) != 0)
 2488     {
 2489         free(pg);
 2490         return -1;
 2491     }
 2492 
 2493     /*
 2494      * Walk the rules in the PortObject and add to
 2495      * the PORT_GROUP pattern state machine
 2496      *  and to the port group RULE_NODE lists.
 2497      * (The lists are still used in some cases
 2498      *  during detection to walk the rules in a group
 2499      *  so we have to load these as well...fpEvalHeader()... for now.)
 2500      *
 2501      * po   src/dst ports : content/uri and nocontent
 2502      * poaa any-any ports : content/uri and nocontent
 2503      *
 2504      * each PG has src or dst contents, generic-contents, and no-contents
 2505      * (src/dst or any-any ports)
 2506      *
 2507      */
 2508     pox = po;
 2509 
 2510     while (pox != NULL)
 2511     {
 2512         for (node = sfghash_findfirst(pox->rule_hash);
 2513                 node;
 2514                 node = sfghash_findnext(pox->rule_hash))
 2515         {
 2516             int *prindex = (int *)node->data;
 2517 
 2518             /* be safe - no rule index, ignore it */
 2519             if (prindex == NULL)
 2520                 continue;
 2521 
 2522             /* look up gid:sid */
 2523             gid = RuleIndexMapGid(ruleIndexMap, *prindex);
 2524             sid = RuleIndexMapSid(ruleIndexMap, *prindex);
 2525 
 2526             /* look up otn */
 2527             otn = OtnLookup(sc->otn_map, gid, sid);
 2528             if (otn == NULL)
 2529             {
 2530                 LogMessage("fpCreatePortObject2PortGroup...failed otn lookup, "
 2531                         "gid=%u sid=%u\n", gid, sid);
 2532                 continue;
 2533             }
 2534 
 2535             if (otn->proto == ETHERNET_TYPE_IP)
 2536             {
 2537                 /* If only one detection option and it's ip_proto it will be evaluated
 2538                  * at decode time instead of detection time */
 2539                 if ((otn->ds_list[PLUGIN_IP_PROTO_CHECK] != NULL) &&
 2540                         (otn->num_detection_opts == 1))
 2541                 {
 2542                     fpAddIpProtoOnlyRule(sc->ip_proto_only_lists, otn);
 2543                     continue;
 2544                 }
 2545 
 2546                 fpRegIpProto(sc->ip_proto_array, otn);
 2547             }
 2548 
 2549             if (fpAddPortGroupRule(sc, pg, otn, fp) != 0)
 2550                 continue;
 2551         }
 2552 
 2553         if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2554             fpPortGroupPrintRuleCount(pg);
 2555 
 2556         if (pox == poaa)
 2557             break;
 2558 
 2559         pox = poaa;
 2560     }
 2561 
 2562     /* This might happen if there was ip proto only rules
 2563      * Don't return failure */
 2564     if (fpFinishPortGroup(sc, pg, fp) != 0)
 2565         return 0;
 2566 
 2567     po->data = pg;
 2568     po->data_free = fpDeletePortGroup;
 2569 
 2570     return 0;
 2571 }
 2572 
 2573 /*
 2574  *  Create the port groups for this port table
 2575  */
 2576 static int fpCreatePortTablePortGroups(SnortConfig *sc, PortTable *p, PortObject2 *poaa)
 2577 {
 2578    SFGHASH_NODE * node;
 2579    int cnt=1;
 2580    FastPatternConfig *fp = sc->fast_pattern_config;
 2581 
 2582    if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2583        LogMessage("%d Port Groups in Port Table\n",p->pt_mpo_hash->count);
 2584 
 2585    for (node=sfghash_findfirst(p->pt_mpo_hash);  //p->pt_mpxo_hash
 2586         node;
 2587         node=sfghash_findnext(p->pt_mpo_hash) ) //p->pt->mpxo_hash
 2588    {
 2589         PortObject2 * po;
 2590 
 2591         po = (PortObject2*)node->data;
 2592         if (po == NULL)
 2593             continue;
 2594 
 2595         if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2596             LogMessage("Creating Port Group Object %d of %d\n",cnt++,p->pt_mpo_hash->count);
 2597 
 2598         /* if the object is not referenced, don't add it to the PORT_GROUPs
 2599          * as it may overwrite other objects that are more inclusive. */
 2600         if (!po->port_cnt)
 2601             continue;
 2602 
 2603         if (fpCreatePortObject2PortGroup(sc, po, poaa))
 2604         {
 2605             LogMessage("fpCreatePortObject2PortGroup() failed\n");
 2606             return -1;
 2607         }
 2608 
 2609         if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2610             mpsePrintSummary(fp->search_method);
 2611    }
 2612 
 2613    return 0;
 2614 }
 2615 
 2616 /*
 2617  *  Create port group objects for all port tables
 2618  *
 2619  *  note: any-any ports are standard PortObjects not PortObject2's so we have to
 2620  *  uprade them for the create port group function
 2621  */
 2622 static int fpCreatePortGroups(SnortConfig *sc, rule_port_tables_t *p)
 2623 {
 2624     PortObject2 *po2, *add_any_any = NULL;
 2625     FastPatternConfig *fp = sc->fast_pattern_config;
 2626 
 2627     if (!rule_count)
 2628         return 0 ;
 2629 
 2630     /* TCP */
 2631     /* convert the tcp-any-any to a PortObject2 creature */
 2632     po2 = PortObject2Dup(p->tcp_anyany);
 2633     if (po2 == NULL)
 2634         FatalError("Could not create a PortObject version 2 for tcp-any-any rules\n!");
 2635 
 2636     if (!fpDetectSplitAnyAny(fp))
 2637         add_any_any = po2;
 2638 
 2639     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2640         LogMessage("TCP-SRC\n");
 2641 
 2642     if (fpCreatePortTablePortGroups(sc, p->tcp_src, add_any_any))
 2643     {
 2644         LogMessage("fpCreatePorTablePortGroups failed-tcp_src\n");
 2645         return -1;
 2646     }
 2647 
 2648     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2649         LogMessage("TCP-DST\n");
 2650 
 2651     if (fpCreatePortTablePortGroups(sc, p->tcp_dst, add_any_any))
 2652     {
 2653         LogMessage("fpCreatePorTablePortGroups failed-tcp_dst\n");
 2654         return -1;
 2655     }
 2656 
 2657 #ifdef TARGET_BASED
 2658     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2659         LogMessage("NS-TCP-SRC\n");
 2660 
 2661     if (fpCreatePortTablePortGroups(sc, p->ns_tcp_src, add_any_any))
 2662     {
 2663         LogMessage("fpCreatePortTablePortGroups failed-ns_tcp_src\n");
 2664         return -1;
 2665     }
 2666 
 2667     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2668         LogMessage("NS-TCP-DST\n");
 2669 
 2670     if (fpCreatePortTablePortGroups(sc, p->ns_tcp_dst, add_any_any))
 2671     {
 2672         LogMessage("fpCreatePortTablePortGroups failed-ns_tcp_dst\n");
 2673         return -1;
 2674     }
 2675 #endif
 2676 
 2677     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2678         LogMessage("TCP-ANYANY\n");
 2679 
 2680     if (fpCreatePortObject2PortGroup(sc, po2, 0))
 2681     {
 2682         LogMessage("fpCreatePorTablePortGroups failed-tcp any-any\n");
 2683         return -1;
 2684     }
 2685 
 2686     /* save the any-any port group */
 2687     p->tcp_anyany->data = po2->data;
 2688     p->tcp_anyany->data_free = fpDeletePortGroup;
 2689     po2->data = 0;
 2690     /* release the dummy PortObject2 copy of tcp-any-any */
 2691     //LogMessage("fpcreate: calling PortObjectFree2(po2), line = %d\n",__LINE__ );
 2692     PortObject2Free(po2);
 2693 
 2694     /* UDP */
 2695     po2 = PortObject2Dup(p->udp_anyany);
 2696     if (po2 == NULL )
 2697         FatalError("Could not create a PortObject version 2 for udp-any-any rules\n!");
 2698 
 2699     if (!fpDetectSplitAnyAny(fp))
 2700         add_any_any = po2;
 2701 
 2702     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2703         LogMessage("UDP-SRC\n");
 2704 
 2705     if (fpCreatePortTablePortGroups(sc, p->udp_src, add_any_any))
 2706     {
 2707         LogMessage("fpCreatePorTablePortGroups failed-udp_src\n");
 2708         return -1;
 2709     }
 2710 
 2711     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2712         LogMessage("UDP-DST\n");
 2713 
 2714     if (fpCreatePortTablePortGroups(sc, p->udp_dst, add_any_any))
 2715     {
 2716         LogMessage("fpCreatePorTablePortGroups failed-udp_dst\n");
 2717         return -1;
 2718     }
 2719 
 2720 #ifdef TARGET_BASED
 2721     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2722         LogMessage("NS-UDP-SRC\n");
 2723 
 2724     if (fpCreatePortTablePortGroups(sc, p->ns_udp_src, add_any_any))
 2725     {
 2726         LogMessage("fpCreatePorTablePortGroups failed-ns_udp_src\n");
 2727         return -1;
 2728     }
 2729 
 2730     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2731         LogMessage("NS-UDP-DST\n");
 2732 
 2733     if (fpCreatePortTablePortGroups(sc, p->ns_udp_dst, add_any_any))
 2734     {
 2735         LogMessage("fpCreatePorTablePortGroups failed-ns_udp_dst\n");
 2736         return -1;
 2737     }
 2738 #endif // TARGET_BASED
 2739 
 2740     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2741         LogMessage("UDP-ANYANY\n");
 2742 
 2743     if (fpCreatePortObject2PortGroup(sc, po2, 0))
 2744     {
 2745         LogMessage("fpCreatePortObject2PortGroup failed-udp_anyany\n");
 2746         return -1;
 2747     }
 2748 
 2749     p->udp_anyany->data = po2->data;
 2750     p->udp_anyany->data_free = fpDeletePortGroup;
 2751     po2->data = 0;
 2752     //LogMessage("fpcreate: calling PortObjectFree2(po2), line = %d\n",__LINE__ );
 2753     PortObject2Free(po2);
 2754 
 2755     /* ICMP */
 2756     po2 = PortObject2Dup(p->icmp_anyany);
 2757     if (po2 == NULL)
 2758         FatalError("Could not create a PortObject version 2 for icmp-any-any rules\n!");
 2759 
 2760     if (!fpDetectSplitAnyAny(fp))
 2761         add_any_any = po2;
 2762 
 2763     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2764         LogMessage("\nICMP-SRC ");
 2765 
 2766     if (fpCreatePortTablePortGroups(sc, p->icmp_src, add_any_any))
 2767     {
 2768         LogMessage("fpCreatePorTablePortGroups failed-icmp_src\n");
 2769         return -1;
 2770     }
 2771 
 2772     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2773         LogMessage("\nICMP-DST ");
 2774 
 2775     if (fpCreatePortTablePortGroups(sc, p->icmp_dst, add_any_any))
 2776     {
 2777         LogMessage("fpCreatePorTablePortGroups failed-icmp_src\n");
 2778         return -1;
 2779     }
 2780 
 2781 #ifdef TARGET_BASED
 2782     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2783         LogMessage("\nNS-ICMP-SRC"); 
 2784     if (fpCreatePortTablePortGroups(sc, p->ns_icmp_src, add_any_any))
 2785     {
 2786         LogMessage("fpCreatePorTablePortGroups failed-ns_icmp_src\n");
 2787         return -1;
 2788     }
 2789 
 2790     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2791         LogMessage("\nNS-ICMP-DST");
 2792 
 2793     if (fpCreatePortTablePortGroups(sc, p->ns_icmp_dst, add_any_any))
 2794     {
 2795         LogMessage("fpCreatePorTablePortGroups failed-ns_icmp_dst\n");
 2796         return -1;
 2797     }
 2798 #endif // TARGET_BASED
 2799 
 2800     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2801         LogMessage("\nICMP-ANYANY ");
 2802 
 2803     if (fpCreatePortObject2PortGroup(sc, po2, 0))
 2804     {
 2805         LogMessage("fpCreatePorTablePortGroups failed-icmp any-any\n");
 2806         return -1;
 2807     }
 2808 
 2809     p->icmp_anyany->data = po2->data;
 2810     p->icmp_anyany->data_free = fpDeletePortGroup;
 2811     po2->data = 0;
 2812     //LogMessage("fpcreate: calling PortObjectFree2(po2), line = %d\n",__LINE__ );
 2813     PortObject2Free(po2);
 2814 
 2815     /* IP */
 2816     po2 = PortObject2Dup(p->ip_anyany);
 2817     if (po2 == NULL)
 2818         FatalError("Could not create a PortObject version 2 for ip-any-any rules\n!");
 2819 
 2820     if (!fpDetectSplitAnyAny(fp))
 2821         add_any_any = po2;
 2822 
 2823     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2824         LogMessage("\nIP-SRC ");
 2825 
 2826     if (fpCreatePortTablePortGroups(sc, p->ip_src, add_any_any))
 2827     {
 2828         LogMessage("fpCreatePorTablePortGroups failed-ip_src\n");
 2829         return -1;
 2830     }
 2831 
 2832     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2833         LogMessage("\nIP-DST ");
 2834 
 2835     if (fpCreatePortTablePortGroups(sc, p->ip_dst, add_any_any))
 2836     {
 2837         LogMessage("fpCreatePorTablePortGroups failed-ip_dst\n");
 2838         return -1;
 2839     }
 2840 
 2841 #ifdef TARGET_BASED
 2842     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2843         LogMessage("\nNS-IP-SRC ");
 2844 
 2845     if (fpCreatePortTablePortGroups(sc, p->ns_ip_src, add_any_any))
 2846     {
 2847         LogMessage("fpCreatePorTablePortGroups failed-ns_ip_src\n");
 2848         return -1;
 2849     }
 2850 
 2851     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2852         LogMessage("\nNS-IP-DST ");
 2853 
 2854     if (fpCreatePortTablePortGroups(sc, p->ns_ip_dst, add_any_any))
 2855     {
 2856         LogMessage("fpCreatePorTablePortGroups failed-ns_ip_dst\n");
 2857         return -1;
 2858     }
 2859 #endif // TARGET_BASED
 2860 
 2861     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 2862         LogMessage("\nIP-ANYANY ");
 2863 
 2864     if (fpCreatePortObject2PortGroup(sc, po2, 0))
 2865     {
 2866         LogMessage("fpCreatePorTablePortGroups failed-ip any-any\n");
 2867         return -1;
 2868     }
 2869 
 2870     p->ip_anyany->data = po2->data;
 2871     p->ip_anyany->data_free = fpDeletePortGroup;
 2872     po2->data = 0;
 2873     //LogMessage("fpcreate: calling PortObjectFree2(po2), line = %d\n",__LINE__ );
 2874     PortObject2Free(po2);
 2875 
 2876     return 0;
 2877 }
 2878 
 2879 
 2880 
 2881 /*
 2882  *  Scan the master otn lists and and pass
 2883  *
 2884  *
 2885  *  enabled - if true requires otn to be enabled
 2886  *  fcn - callback
 2887  *  proto - IP,TCP,IDP,ICMP protocol flag
 2888  *  otn   - OptTreeNode
 2889  */
 2890 void fpWalkOtns(int enabled, OtnWalkFcn fcn)
 2891 {
 2892     RuleTreeNode *rtn;
 2893     SFGHASH_NODE *hashNode;
 2894     OptTreeNode *otn  = NULL;
 2895     tSfPolicyId policyId = 0;
 2896 
 2897     if (snort_conf == NULL)
 2898         return;
 2899 
 2900     for (hashNode = sfghash_findfirst(snort_conf->otn_map);
 2901             hashNode;
 2902             hashNode = sfghash_findnext(snort_conf->otn_map))
 2903     {
 2904         otn = (OptTreeNode *)hashNode->data;
 2905         for ( policyId = 0;
 2906               policyId < otn->proto_node_num;
 2907               policyId++ )
 2908         {
 2909             rtn = getRtnFromOtn(otn, policyId);
 2910 
 2911             /* There can be gaps in the list of rtns. */
 2912             if (rtn == NULL)
 2913                 continue;
 2914 
 2915             if ((rtn->proto == IPPROTO_TCP) || (rtn->proto == IPPROTO_UDP)
 2916                 || (rtn->proto == IPPROTO_ICMP) || (rtn->proto == ETHERNET_TYPE_IP))
 2917             {
 2918                 //do operation
 2919 
 2920                 if ( enabled && (otn->rule_state != RULE_STATE_ENABLED) )
 2921                 {
 2922                     continue;
 2923                 }
 2924 
 2925                 fcn( rtn->proto, rtn, otn );
 2926             }
 2927         }
 2928     }
 2929 }
 2930 
 2931 #ifdef TARGET_BASED
 2932 /*
 2933  *  Scan the master otn lists and load the Service maps
 2934  *  for service based rule grouping.
 2935  */
 2936 static int fpCreateServiceMaps(SnortConfig *sc)
 2937 {
 2938     RuleTreeNode *rtn;
 2939     SFGHASH_NODE *hashNode;
 2940     OptTreeNode *otn  = NULL;
 2941     tSfPolicyId policyId = 0;
 2942     unsigned int svc_idx;
 2943 
 2944     for (hashNode = sfghash_findfirst(sc->otn_map);
 2945          hashNode;
 2946          hashNode = sfghash_findnext(sc->otn_map))
 2947     {
 2948         otn = (OptTreeNode *)hashNode->data;
 2949         for ( policyId = 0;
 2950               policyId < otn->proto_node_num;
 2951               policyId++ )
 2952         {
 2953             rtn = getRtnFromOtn(otn, policyId);
 2954 
 2955             if (rtn && ((rtn->proto == IPPROTO_TCP) || (rtn->proto == IPPROTO_UDP)
 2956                     || (rtn->proto == IPPROTO_ICMP) || (rtn->proto == ETHERNET_TYPE_IP)))
 2957             {
 2958                 /* Non-content preprocessor or decoder rule.
 2959                  * don't add it */
 2960                 if (otn->sigInfo.rule_type != SI_RULE_TYPE_DETECT)
 2961                     continue;
 2962 
 2963                 /* Not enabled, don't do the FP content */
 2964                 if (otn->rule_state != RULE_STATE_ENABLED)
 2965                     continue;
 2966 
 2967                 for (svc_idx = 0; svc_idx < otn->sigInfo.num_services; svc_idx++)
 2968                 {
 2969                     if (ServiceMapAddOtn(sc->srmmTable, rtn->proto, otn->sigInfo.services[svc_idx].service, otn))
 2970                         return -1;
 2971                 }
 2972             }
 2973         }
 2974     }
 2975 
 2976     return 0;
 2977 }
 2978 
 2979 
 2980 /*
 2981 * Build a Port Group for this service based on the list of otns. The final
 2982 * port_group pointer is stored using the service name as the key.
 2983 *
 2984 * p   - hash table mapping services to port_groups
 2985 * srvc- service name, key used to store the port_group
 2986 *       ...could use a service id instead (bytes, fixed length,etc...)
 2987 * list- list of otns for this service
 2988 */
 2989 void fpBuildServicePortGroupByServiceOtnList(SnortConfig *sc, SFGHASH *p, const char *srvc, SF_LIST *list, FastPatternConfig *fp)
 2990 {
 2991     OptTreeNode * otn;
 2992     int status;
 2993     PORT_GROUP *pg = (PORT_GROUP *)SnortAlloc(sizeof(PORT_GROUP));
 2994 
 2995     if (fpAllocPms(sc, pg, fp) != 0)
 2996     {
 2997         free(pg);
 2998         return;
 2999     }
 3000 
 3001     /*
 3002      * add each rule to the port group pattern matchers,
 3003      * or to the no-content rule list
 3004      */
 3005     for (otn = sflist_first(list);
 3006             otn;
 3007             otn = sflist_next(list))
 3008     {
 3009         if (otn->proto == ETHERNET_TYPE_IP)
 3010         {
 3011             /* If only one detection option and it's ip_proto it will be evaluated
 3012              * at decode time instead of detection time
 3013              * These will have already been added when adding port groups */
 3014             if ((otn->ds_list[PLUGIN_IP_PROTO_CHECK] != NULL) &&
 3015                     (otn->num_detection_opts == 1))
 3016             {
 3017                 continue;
 3018             }
 3019         }
 3020 
 3021         if (fpAddPortGroupRule(sc, pg, otn, fp) != 0)
 3022             continue;
 3023     }
 3024 
 3025     if (fpFinishPortGroup(sc, pg, fp) != 0)
 3026         return;
 3027 
 3028     /* Add the port_group using it's service name */
 3029     status = sfghash_add(p, srvc, pg);
 3030     switch(status)
 3031     {
 3032         case SFGHASH_OK :
 3033              /* port_group is successfully added using it's service name */
 3034              break;
 3035         case SFGHASH_ERR :
 3036              LogMessage("fpBuildServicePortGroupByServiceOtnList : Hash table is NULL. \n");
 3037              break;
 3038         case SFGHASH_INTABLE :
 3039              break;
 3040         case SFGHASH_NOMEM :
 3041              LogMessage("Failed to allocate memory to port_group/service.\n");
 3042              break;
 3043         default :
 3044              break;
 3045 
 3046     }
 3047 }
 3048 
 3049 /*
 3050  * For each service we create a PORT_GROUP based on the otn's defined to
 3051  * be applicable to that service by the metadata option.
 3052  *
 3053  * Than we lookup the protocol/srvc oridinal in the target-based area
 3054  * and assign the PORT_GROUP for the srvc to it.
 3055  *
 3056  * spg - service port group (lookup should be by service id/tag)
 3057  *     - this table maintains a port_group ptr for each service
 3058  * srm - service rule map table (lookup by ascii service name)
 3059  *     - this table maintains a sf_list ptr (list of rule otns) for each service
 3060  *
 3061  */
 3062 void fpBuildServicePortGroups(SnortConfig *sc, SFGHASH *spg, PORT_GROUP **sopg, SFGHASH *srm, FastPatternConfig *fp)
 3063 {
 3064     SFGHASH_NODE * n;
 3065     const char * srvc;
 3066     SF_LIST * list;
 3067     PORT_GROUP * pg;
 3068 
 3069     for(n=sfghash_findfirst(srm);
 3070         n;
 3071         n=sfghash_findnext(srm) )
 3072     {
 3073         list = (SF_LIST *)n->data;
 3074         if(!list)continue;
 3075 
 3076         srvc = n->key;
 3077         if(!srvc)continue;
 3078 
 3079         fpBuildServicePortGroupByServiceOtnList(sc, spg, srvc, list, fp);
 3080 
 3081         /* Add this PORT_GROUP to the protocol-ordinal -> port_group table */
 3082         pg = sfghash_find( spg, srvc );
 3083         if( pg )
 3084         {
 3085             int16_t id;
 3086             id = FindProtocolReference(srvc);
 3087             if(id==SFTARGET_UNKNOWN_PROTOCOL)
 3088             {
 3089                 id = AddProtocolReference(srvc);
 3090                 if(id <=0 )
 3091                 {
 3092                     FatalError("Could not AddProtocolReference!\n");
 3093                 }
 3094                 if( id >= MAX_PROTOCOL_ORDINAL )
 3095                 {
 3096                     LogMessage("fpBuildServicePortGroups: protocol-ordinal=%d exceeds "
 3097                                "limit of %d for service=%s\n",id,MAX_PROTOCOL_ORDINAL,srvc);
 3098                 }
 3099             }
 3100             else if( id > 0 )
 3101             {
 3102                 if( id < MAX_PROTOCOL_ORDINAL )
 3103                 {
 3104                     sopg[ id ] = pg;
 3105                     LogMessage("fpBuildServicePortGroups: adding protocol-ordinal=%d "
 3106                                "as service=%s\n",id,srvc);
 3107                 }
 3108                 else
 3109                 {
 3110                     LogMessage("fpBuildServicePortGroups: protocol-ordinal=%d exceeds "
 3111                                "limit of %d for service=%s\n",id,MAX_PROTOCOL_ORDINAL,srvc);
 3112                 }
 3113             }
 3114             else /* id < 0 */
 3115             {
 3116                 LogMessage("fpBuildServicePortGroups: adding protocol-ordinal=%d for "
 3117                            "service=%s, can't use that !!!\n",id,srvc);
 3118 
 3119             }
 3120         }
 3121         else
 3122         {
 3123             LogMessage("*** fpBuildServicePortGroups: failed to create and find a port group for '%s' !!! \n",srvc );
 3124         }
 3125     }
 3126 }
 3127 
 3128 /*
 3129  * For each proto+dir+service build a PORT_GROUP
 3130  */
 3131 static void fpCreateServiceMapPortGroups(SnortConfig *sc)
 3132 {
 3133     FastPatternConfig *fp = sc->fast_pattern_config;
 3134 
 3135     sc->spgmmTable = ServicePortGroupMapNew();
 3136     sc->sopgTable = ServicePortGroupTableNew();
 3137 
 3138     fpBuildServicePortGroups(sc, sc->spgmmTable->tcp_to_srv, sc->sopgTable->tcp_to_srv,
 3139                              sc->srmmTable->tcp_to_srv, fp);
 3140     fpBuildServicePortGroups(sc, sc->spgmmTable->tcp_to_cli, sc->sopgTable->tcp_to_cli,
 3141                              sc->srmmTable->tcp_to_cli, fp);
 3142 
 3143     fpBuildServicePortGroups(sc, sc->spgmmTable->udp_to_srv, sc->sopgTable->udp_to_srv,
 3144                              sc->srmmTable->udp_to_srv, fp);
 3145     fpBuildServicePortGroups(sc, sc->spgmmTable->udp_to_cli, sc->sopgTable->udp_to_cli,
 3146                              sc->srmmTable->udp_to_cli, fp);
 3147 
 3148     fpBuildServicePortGroups(sc, sc->spgmmTable->icmp_to_srv, sc->sopgTable->icmp_to_srv,
 3149                              sc->srmmTable->icmp_to_srv, fp);
 3150     fpBuildServicePortGroups(sc, sc->spgmmTable->icmp_to_cli, sc->sopgTable->icmp_to_cli,
 3151                              sc->srmmTable->icmp_to_cli, fp);
 3152 
 3153     fpBuildServicePortGroups(sc, sc->spgmmTable->ip_to_srv, sc->sopgTable->ip_to_srv,
 3154                              sc->srmmTable->ip_to_srv, fp);
 3155     fpBuildServicePortGroups(sc, sc->spgmmTable->ip_to_cli, sc->sopgTable->ip_to_srv,
 3156                              sc->srmmTable->ip_to_cli, fp);
 3157 }
 3158 
 3159 PORT_GROUP * fpGetServicePortGroupByOrdinal(sopg_table_t *sopg, int proto, int dir, int16_t proto_ordinal)
 3160 {
 3161    //SFGHASH_NODE * n;
 3162    PORT_GROUP *pg = NULL;
 3163 
 3164    if (proto_ordinal >= MAX_PROTOCOL_ORDINAL)
 3165        return NULL;
 3166 
 3167    if (sopg == NULL)
 3168        return NULL;
 3169 
 3170    switch (proto)
 3171    {
 3172        case IPPROTO_TCP:
 3173            if (dir == TO_SERVER)
 3174                pg = sopg->tcp_to_srv[proto_ordinal];
 3175            else
 3176                pg = sopg->tcp_to_cli[proto_ordinal];
 3177 
 3178            break;
 3179 
 3180        case IPPROTO_UDP:
 3181            if (dir == TO_SERVER)
 3182                pg = sopg->udp_to_srv[proto_ordinal];
 3183            else
 3184                pg = sopg->udp_to_cli[proto_ordinal];
 3185 
 3186            break;
 3187 
 3188        case IPPROTO_ICMP:
 3189            if (dir == TO_SERVER)
 3190                pg = sopg->icmp_to_srv[proto_ordinal];
 3191            else
 3192                pg = sopg->icmp_to_cli[proto_ordinal];
 3193 
 3194            break;
 3195 
 3196        case ETHERNET_TYPE_IP:
 3197            if (dir == TO_SERVER)
 3198                pg = sopg->ip_to_srv[proto_ordinal];
 3199            else
 3200                pg = sopg->ip_to_cli[proto_ordinal];
 3201 
 3202            break;
 3203 
 3204        default:
 3205            break;
 3206    }
 3207 
 3208    return pg;
 3209 }
 3210 
 3211 
 3212 /*
 3213  *  Print the rule gid:sid based onm the otn list
 3214  */
 3215 void fpPrintRuleList( SF_LIST * list )
 3216 {
 3217     OptTreeNode * otn;
 3218 
 3219     for( otn=(OptTreeNode*)sflist_first(list);
 3220          otn;
 3221          otn=(OptTreeNode*)sflist_next(list) )
 3222     {
 3223          LogMessage("|   %u:%u\n",otn->sigInfo.generator,otn->sigInfo.id);
 3224     }
 3225 }
 3226 static
 3227 void fpPrintServiceRuleMapTable(  SFGHASH * p, char * msg )
 3228 {
 3229      SFGHASH_NODE * n;
 3230 
 3231      if( !p || !p->count )
 3232          return;
 3233 
 3234      LogMessage("| Protocol [%s] %d services\n",msg,p->count );
 3235      LogMessage("----------------------------------------------------\n");
 3236 
 3237      for( n = sfghash_findfirst(p);
 3238           n;
 3239           n = sfghash_findnext(p) )
 3240      {
 3241           SF_LIST * list;
 3242 
 3243           list = (SF_LIST*)n->data;
 3244           if( !list ) continue;
 3245 
 3246           if( !n->key ) continue;
 3247 
 3248           LogMessage("| Service [%s] %d rules, rule list follows as gid:sid.\n",
 3249               (char*)n->key, list->count);
 3250 
 3251           fpPrintRuleList( list );
 3252      }
 3253      LogMessage("----------------------------------------------------\n");
 3254 }
 3255 
 3256 static void fpPrintServiceRuleMaps(srmm_table_t *service_map)
 3257 {
 3258     LogMessage("+---------------------------------------------------\n");
 3259     LogMessage("| Service Rule Maps\n");
 3260     LogMessage("----------------------------------------------------\n");
 3261     fpPrintServiceRuleMapTable( service_map->tcp_to_srv,  "tcp to server" );
 3262     fpPrintServiceRuleMapTable( service_map->tcp_to_cli,  "tcp to client" );
 3263 
 3264     fpPrintServiceRuleMapTable( service_map->udp_to_srv,  "udp to server" );
 3265     fpPrintServiceRuleMapTable( service_map->udp_to_cli,  "udp to client" );
 3266 
 3267     fpPrintServiceRuleMapTable( service_map->icmp_to_srv, "icmp to server" );
 3268     fpPrintServiceRuleMapTable( service_map->icmp_to_cli, "icmp to client" );
 3269 
 3270     fpPrintServiceRuleMapTable( service_map->ip_to_srv,   "ip to server" );
 3271     fpPrintServiceRuleMapTable( service_map->ip_to_cli,   "ip to client" );
 3272 }
 3273 
 3274 /*
 3275  *
 3276  */
 3277 void fpPrintServicePortGroupSummary(srmm_table_t *srvc_pg_map)
 3278 {
 3279 
 3280     LogMessage("+--------------------------------\n");
 3281     LogMessage("| Service-PortGroup Table Summary \n");
 3282     LogMessage("---------------------------------\n");
 3283 
 3284     if(srvc_pg_map->tcp_to_srv->count)
 3285     LogMessage("| tcp to server  : %d services\n",srvc_pg_map->tcp_to_srv->count);
 3286     if(srvc_pg_map->tcp_to_cli->count)
 3287     LogMessage("| tcp to cient   : %d services\n",srvc_pg_map->tcp_to_cli->count);
 3288 
 3289     if(srvc_pg_map->udp_to_srv->count)
 3290     LogMessage("| udp to server  : %d services\n",srvc_pg_map->udp_to_srv->count);
 3291     if(srvc_pg_map->udp_to_cli->count)
 3292     LogMessage("| udp to cient   : %d services\n",srvc_pg_map->udp_to_cli->count);
 3293 
 3294     if(srvc_pg_map->icmp_to_srv->count)
 3295     LogMessage("| icmp to server : %d services\n",srvc_pg_map->icmp_to_srv->count);
 3296     if(srvc_pg_map->icmp_to_cli->count)
 3297     LogMessage("| icmp to cient  : %d services\n",srvc_pg_map->icmp_to_cli->count);
 3298 
 3299     if(srvc_pg_map->ip_to_srv->count)
 3300     LogMessage("| ip to server   : %d services\n",srvc_pg_map->ip_to_srv->count);
 3301     if(srvc_pg_map->ip_to_cli->count)
 3302     LogMessage("| ip to cient    : %d services\n",srvc_pg_map->ip_to_cli->count);
 3303     LogMessage("---------------------------------\n");
 3304 }
 3305 
 3306 /*
 3307  *  Build Service based PORT_GROUPs using the rules
 3308  *  metadata option service parameter.
 3309  */
 3310 static int fpCreateServicePortGroups(SnortConfig *sc)
 3311 {
 3312     FastPatternConfig *fp = sc->fast_pattern_config;
 3313 
 3314     sc->srmmTable = ServiceMapNew();
 3315 
 3316     if (fpCreateServiceMaps(sc))
 3317         return -1;
 3318 
 3319     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 3320         fpPrintServiceRuleMaps(sc->srmmTable);
 3321 
 3322     fpCreateServiceMapPortGroups(sc);
 3323 
 3324     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 3325         fpPrintServicePortGroupSummary(sc->spgmmTable);
 3326 
 3327     //srvcmap_term();
 3328 
 3329     return 0;
 3330 }
 3331 //TARGET_BASED
 3332 #endif
 3333 
 3334 /*
 3335 *  Port list version
 3336 *
 3337 *  7/2007 - man
 3338 *
 3339 *  Build Pattern Groups for 1st pass of content searching using
 3340 *  multi-pattern search method.
 3341 */
 3342 int fpCreateFastPacketDetection(SnortConfig *sc)
 3343 {
 3344     rule_port_tables_t *port_tables;
 3345     FastPatternConfig *fp;
 3346 
 3347     /* This is somewhat necessary because of how the detection option trees
 3348      * are added via a callback from the pattern matcher */
 3349     if(!rule_count || (sc == NULL))
 3350         return 0;
 3351 
 3352     port_tables = sc->port_tables;
 3353     fp = sc->fast_pattern_config;
 3354 
 3355     if ((port_tables == NULL) || (fp == NULL))
 3356         return 0;
 3357 
 3358 #ifdef INTEL_SOFT_CPM
 3359     if (fp->search_method == MPSE_INTEL_CPM)
 3360         IntelPmStartInstance();
 3361 #endif
 3362 
 3363     /* Use PortObjects to create PORT_GROUPs */
 3364     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 3365         LogMessage("Creating Port Groups....\n");
 3366 
 3367     if (fpCreatePortGroups(sc, port_tables))
 3368         FatalError("Could not create PortGroup objects for PortObjects\n");
 3369 
 3370     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 3371         LogMessage("Port Groups Done....\n");
 3372 
 3373     /* Create rule_maps */
 3374     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 3375         LogMessage("Creating Rule Maps....\n");
 3376 
 3377     if (fpCreateRuleMaps(sc, port_tables))
 3378         FatalError("Could not create rule maps\n");
 3379 
 3380     if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 3381         LogMessage("Rule Maps Done....\n");
 3382 
 3383 #ifndef TARGET_BASED
 3384     LogMessage("\n");
 3385     LogMessage("[ Port Based Pattern Matching Memory ]\n" );
 3386     mpsePrintSummary(fp->search_method);
 3387     if (fp->max_pattern_len != 0)
 3388     {
 3389         LogMessage("[ Number of patterns truncated to %d bytes: %d ]\n",
 3390                 fp->max_pattern_len, fp->num_patterns_truncated);
 3391     }
 3392     if (fp->num_patterns_trimmed != 0)
 3393     {
 3394         LogMessage("[ Number of null byte prefixed patterns trimmed: %d ]\n",
 3395                 fp->num_patterns_trimmed);
 3396     }
 3397 #else
 3398     if (IsAdaptiveConfiguredForSnortConfig(sc) || fpDetectGetDebugPrintFastPatterns(fp))
 3399     {
 3400         if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 3401             LogMessage("Creating Service Based Rule Maps....\n");
 3402 
 3403         /* Build Service based port groups - rules require service metdata
 3404          * i.e. 'metatdata: service [=] service-name, ... ;'
 3405          *
 3406          * Also requires a service attribute for lookup ...
 3407          */
 3408         if (fpCreateServicePortGroups(sc))
 3409             FatalError("Could not create service based port groups\n");
 3410 
 3411         if (fpDetectGetDebugPrintRuleGroupBuildDetails(fp))
 3412             LogMessage("Service Based Rule Maps Done....\n");
 3413 
 3414         LogMessage("\n");
 3415         LogMessage("[ Port and Service Based Pattern Matching Memory ]\n" );
 3416     }
 3417     else
 3418     {
 3419         LogMessage("\n");
 3420         LogMessage("[ Port Based Pattern Matching Memory ]\n" );
 3421     }
 3422 
 3423     mpsePrintSummary(fp->search_method);
 3424     if (fp->max_pattern_len != 0)
 3425     {
 3426         LogMessage("[ Number of patterns truncated to %d bytes: %d ]\n",
 3427                 fp->max_pattern_len, fp->num_patterns_truncated);
 3428     }
 3429     if (fp->num_patterns_trimmed != 0)
 3430     {
 3431         LogMessage("[ Number of null byte prefixed patterns trimmed: %d ]\n",
 3432                 fp->num_patterns_trimmed);
 3433     }
 3434 #endif
 3435 
 3436 #ifdef INTEL_SOFT_CPM
 3437     if (fp->search_method == MPSE_INTEL_CPM)
 3438         IntelPmCompile(sc);
 3439 #endif
 3440 
 3441     return 0;
 3442 }
 3443 
 3444 void fpDeleteFastPacketDetection(SnortConfig *sc)
 3445 {
 3446     if (sc == NULL)
 3447         return;
 3448 
 3449     /* Cleanup the detection option tree */
 3450     DetectionHashTableFree(sc->detection_option_hash_table);
 3451     DetectionTreeHashTableFree(sc->detection_option_tree_hash_table);
 3452 
 3453     fpFreeRuleMaps(sc);
 3454 
 3455 #ifdef TARGET_BASED
 3456     ServiceMapFree(sc->srmmTable);
 3457     ServicePortGroupMapFree(sc->spgmmTable);
 3458     if (sc->sopgTable != NULL)
 3459         free(sc->sopgTable);
 3460 #endif
 3461 
 3462 }
 3463 
 3464 /*
 3465 **  Wrapper for prmShowEventStats
 3466 */
 3467 void fpShowEventStats(SnortConfig *sc)
 3468 {
 3469     if ((sc == NULL) || (sc->fast_pattern_config == NULL))
 3470         return;
 3471 
 3472     /* If not debug, then we don't print anything. */
 3473     if (!sc->fast_pattern_config->debug)
 3474         return;
 3475 
 3476     LogMessage("\n");
 3477     LogMessage("** TCP Event Stats --\n");
 3478     prmShowEventStats(sc->prmTcpRTNX);
 3479 
 3480     LogMessage("\n");
 3481     LogMessage("** UDP Event Stats --\n");
 3482     prmShowEventStats(sc->prmUdpRTNX);
 3483 
 3484     LogMessage("\n");
 3485     LogMessage("** ICMP Event Stats --\n");
 3486     prmShowEventStats(sc->prmIcmpRTNX);
 3487 
 3488     LogMessage("\n");
 3489     LogMessage("** IP Event Stats --\n");
 3490     prmShowEventStats(sc->prmIpRTNX);
 3491 }
 3492 
 3493 static void fpAddIpProtoOnlyRule(SF_LIST **ip_proto_only_lists, OptTreeNode *otn)
 3494 {
 3495     uint8_t ip_protos[NUM_IP_PROTOS];
 3496     unsigned int i;
 3497 
 3498     if ((otn->ds_list[PLUGIN_IP_PROTO_CHECK] == NULL) ||
 3499         (otn->num_detection_opts != 1))
 3500     {
 3501         return;
 3502     }
 3503 
 3504     if (GetIpProtos(otn->ds_list[PLUGIN_IP_PROTO_CHECK], ip_protos, sizeof(ip_protos)) != 0)
 3505         FatalError("%s(%d) Error getting ip protocols\n", __FILE__, __LINE__);
 3506 
 3507     for (i = 0; i < NUM_IP_PROTOS; i++)
 3508     {
 3509         OptTreeNode *dup;
 3510 
 3511         if (ip_protos[i])
 3512         {
 3513             if (ip_proto_only_lists[i] == NULL)
 3514             {
 3515                 ip_proto_only_lists[i] = sflist_new();
 3516                 if (ip_proto_only_lists[i] == NULL)
 3517                 {
 3518                     FatalError("%s(%d) Could not allocate memory for "
 3519                                "ip_proto array\n", __FILE__, __LINE__);
 3520                 }
 3521             }
 3522 
 3523             /* Search for dups */
 3524             for (dup = (OptTreeNode *)sflist_first(ip_proto_only_lists[i]);
 3525                  dup != NULL;
 3526                  dup = (OptTreeNode *)sflist_next(ip_proto_only_lists[i]))
 3527             {
 3528                 if (dup == otn)
 3529                     return;
 3530             }
 3531 
 3532             if (sflist_add_head(ip_proto_only_lists[i], otn) != 0)
 3533             {
 3534                 FatalError("%s(%d) Failed to add otn to ip_proto array\n",
 3535                            __FILE__, __LINE__);
 3536             }
 3537         }
 3538     }
 3539 }
 3540 
 3541 static void fpRegIpProto(uint8_t *ip_proto_array, OptTreeNode *otn)
 3542 {
 3543     uint8_t ip_protos[NUM_IP_PROTOS];
 3544     unsigned int i;
 3545 
 3546     if (GetIpProtos(otn->ds_list[PLUGIN_IP_PROTO_CHECK], ip_protos, sizeof(ip_protos)) != 0)
 3547         FatalError("%s(%d) Error getting ip protocols\n", __FILE__, __LINE__);
 3548 
 3549     for (i = 0; i < NUM_IP_PROTOS; i++)
 3550         if (ip_protos[i]) ip_proto_array[i] = 1;
 3551 }
 3552 
 3553 const char * PatternRawToContent(const char *pattern, int pattern_len)
 3554 {
 3555     static char content_buf[1024];
 3556     int max_write_size = sizeof(content_buf) - 64;
 3557     int i, j = 0;
 3558     int hex = 0;
 3559 
 3560     if ((pattern == NULL) || (pattern_len <= 0))
 3561         return "";
 3562 
 3563     content_buf[j++] = '"';
 3564 
 3565     for (i = 0; i < pattern_len; i++)
 3566     {
 3567         uint8_t c = (uint8_t)pattern[i];
 3568 
 3569         if ((c < 128) && isprint(c) && !isspace(c)
 3570                 && (c != '|') && (c != '"') && (c != ';'))
 3571         {
 3572             if (hex)
 3573             {
 3574                 content_buf[j-1] = '|';
 3575                 hex = 0;
 3576             }
 3577 
 3578             content_buf[j++] = c;
 3579         }
 3580         else
 3581         {
 3582             uint8_t up4, lo4;
 3583 
 3584             if (!hex)
 3585             {
 3586                 content_buf[j++] = '|';
 3587                 hex = 1;
 3588             }
 3589 
 3590             up4 = c >> 4;
 3591             lo4 = c & 0x0f;
 3592 
 3593             if (up4 > 0x09) up4 += ('A' - 0x0a);
 3594             else up4 += '0';
 3595 
 3596             if (lo4 > 0x09) lo4 += ('A' - 0x0a);
 3597             else lo4 += '0';
 3598 
 3599             content_buf[j++] = up4;
 3600             content_buf[j++] = lo4;
 3601             content_buf[j++] = ' ';
 3602         }
 3603 
 3604         if (j > max_write_size)
 3605             break;
 3606     }
 3607 
 3608     if (j > max_write_size)
 3609     {
 3610         content_buf[j] = 0;
 3611         SnortSnprintfAppend(content_buf, sizeof(content_buf),
 3612                 " ... \" (pattern too large)");
 3613     }
 3614     else
 3615     {
 3616         if (hex)
 3617             content_buf[j-1] = '|';
 3618 
 3619         content_buf[j++] = '"';
 3620         content_buf[j] = 0;
 3621     }
 3622 
 3623     return content_buf;
 3624 }
 3625 
 3626 static void PrintFastPatternInfo(OptTreeNode *otn, PatternMatchData *pmd,
 3627         const char *pattern, int pattern_length, PmType pm_type)
 3628 {
 3629     if ((otn == NULL) || (pmd == NULL))
 3630         return;
 3631 
 3632     LogMessage("%u:%u\n", otn->sigInfo.generator, otn->sigInfo.id);
 3633     LogMessage("  Fast pattern matcher: %s\n", pm_type_strings[pm_type]);
 3634     LogMessage("  Fast pattern set: %s\n", pmd->fp ? "yes" : "no");
 3635     LogMessage("  Fast pattern only: %s\n", pmd->fp_only ? "yes" : "no");
 3636     LogMessage("  Negated: %s\n", pmd->exception_flag ? "yes" : "no");
 3637 
 3638     /* Fast pattern only patterns don't use offset and length */
 3639     if ((pmd->fp_length != 0) && !pmd->fp_only)
 3640     {
 3641         LogMessage("  Pattern <offset,length>: %d,%d\n",
 3642                 pmd->fp_offset, pmd->fp_length);
 3643         LogMessage("    %s\n",
 3644                 PatternRawToContent(pmd->pattern_buf + pmd->fp_offset,
 3645                     pmd->fp_length));
 3646     }
 3647     else
 3648     {
 3649         LogMessage("  Pattern offset,length: none\n");
 3650     }
 3651 
 3652     /* Fast pattern only patterns don't get truncated */
 3653     if (!pmd->fp_only
 3654             && (((pmd->fp_length != 0) && (pmd->fp_length > pattern_length))
 3655                 || ((pmd->fp_length == 0) && ((int)pmd->pattern_size > pattern_length))))
 3656     {
 3657         LogMessage("  Pattern truncated: %d to %d bytes\n",
 3658                 pmd->fp_length ? pmd->fp_length : pmd->pattern_size,
 3659                 pattern_length);
 3660     }
 3661     else
 3662     {
 3663         LogMessage("  Pattern truncated: no\n");
 3664     }
 3665 
 3666     LogMessage("  Original pattern\n");
 3667     LogMessage("    %s\n",
 3668             PatternRawToContent(pmd->pattern_buf,pmd->pattern_size));
 3669 
 3670     LogMessage("  Final pattern\n");
 3671     LogMessage("    %s\n", PatternRawToContent(pattern, pattern_length));
 3672 }