00001 //--------------------------------------------------------------------------
00002 // Copyright (C) 2014-2017 Cisco and/or its affiliates. All rights reserved.
00003 // Copyright (C) 2002-2013 Sourcefire, Inc.
00004 //
00005 // This program is free software; you can redistribute it and/or modify it
00006 // under the terms of the GNU General Public License Version 2 as published
00007 // by the Free Software Foundation. You may not use, modify or distribute
00008 // this program under any other version of the GNU General Public License.
00009 //
00010 // This program is distributed in the hope that it will be useful, but
00011 // WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00013 // General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License along
00016 // with this program; if not, write to the Free Software Foundation, Inc.,
00017 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00018 //--------------------------------------------------------------------------
00019 /*
00020 ** Dan Roelker <droelker@sourcefire.com>
00021 ** Marc Norton <mnorton@sourcefire.com>
00022 **
00023 ** NOTES
00024 ** 5.7.02 - Initial Checkin. Norton/Roelker
00025 **
00026 ** 6/13/05 - marc norton
00027 ** Added plugin support for fast pattern match data
00028 **
00029 */
00030
00031 #ifdef HAVE_CONFIG_H
00032 #include "config.h"
00033 #endif
00034
00035 #include "fp_create.h"
00036
00037 #include "framework/mpse.h"
00038 #include "hash/sfghash.h"
00039 #include "log/messages.h"
00040 #include "main/snort_config.h"
00041 #include "managers/mpse_manager.h"
00042 #include "parser/parse_rule.h"
00043 #include "parser/parser.h"
00044 #include "ports/port_table.h"
00045 #include "ports/rule_port_tables.h"
00046 #include "utils/stats.h"
00047 #include "utils/util.h"
00048
00049 #include "detection_options.h"
00050 #include "detect_trace.h"
00051 #include "fp_config.h"
00052 #include "fp_utils.h"
00053 #include "pattern_match_data.h"
00054 #include "pcrm.h"
00055 #include "service_map.h"
00056 #include "treenodes.h"
00057
00058 using namespace std;
00059
00060 static unsigned mpse_count = 0;
00061 static const char* s_group = "";
00062
00063 static void fpDeletePMX(void* data);
00064
00065 static int fpGetFinalPattern(
00066 FastPatternConfig*, PatternMatchData*, const char*& ret_pattern, int& ret_bytes);
00067
00068 static void print_nfp_info(const char*, OptTreeNode*);
00069 static void print_fp_info(const char*, const OptTreeNode*, const PatternMatchData*,
00070 const char* pattern, int pattern_length);
00071
00072 static int finalize_detection_option_tree(SnortConfig* sc, detection_option_tree_root_t* root)
00073 {
00074 if ( !root )
00075 return -1;
00076
00077 for ( int i=0; i<root->num_children; i++ )
00078 {
00079 detection_option_tree_node_t* node = root->children[i];
00080
00081 if ( void* dup_node = add_detection_option_tree(sc, node) )
00082 {
00083 // FIXIT-L delete dup_node and keep original?
00084 free_detection_option_tree(node);
00085 root->children[i] = (detection_option_tree_node_t*)dup_node;
00086 }
00087 print_option_tree(root->children[i], 0);
00088 }
00089
00090 return 0;
00091 }
00092
00093 static bool new_sig(int num_children, detection_option_tree_node_t** nodes, OptTreeNode* otn)
00094 {
00095 for ( int i = 0; i < num_children; ++i )
00096 {
00097 detection_option_tree_node_t* child = nodes[i];
00098
00099 if ( child->option_type != RULE_OPTION_TYPE_LEAF_NODE )
00100 continue;
00101
00102 OptTreeNode* cotn = (OptTreeNode*)child->option_data;
00103 SigInfo& csi = cotn->sigInfo;
00104 SigInfo& osi = otn->sigInfo;
00105
00106 if ( csi.gid == osi.gid and csi.sid == osi.sid and csi.rev == osi.rev )
00107 return false;
00108 }
00109 return true;
00110 }
00111
00112 static int otn_create_tree(OptTreeNode* otn, void** existing_tree)
00113 {
00114 detection_option_tree_node_t* node = nullptr, * child;
00115 bool need_leaf = false;
00116
00117 if (!existing_tree)
00118 return -1;
00119
00120 if (!*existing_tree)
00121 *existing_tree = new_root(otn);
00122
00123 detection_option_tree_root_t* root = (detection_option_tree_root_t*)*existing_tree;
00124
00125 if (!root->children)
00126 {
00127 root->num_children++;
00128 root->children = (detection_option_tree_node_t**)
00129 snort_calloc(root->num_children, sizeof(detection_option_tree_node_t*));
00130 need_leaf = true;
00131 }
00132
00133 int i = 0;
00134 child = root->children[i];
00135 OptFpList* opt_fp = otn->opt_func;
00136
00137 /* Build out sub-nodes for each option in the OTN fp list */
00138 while (opt_fp)
00139 {
00140 /* If child node does not match existing option_data,
00141 * Create a child branch from a given sub-node. */
00142 void* option_data = opt_fp->ips_opt;
00143 char found_child_match = 0;
00144
00145 if (opt_fp->type == RULE_OPTION_TYPE_LEAF_NODE)
00146 {
00147 opt_fp = opt_fp->next;
00148 continue;
00149 }
00150
00151 /* Don't add contents that are only for use in the
00152 * fast pattern matcher */
00153 if ( is_fast_pattern_only(opt_fp) )
00154 {
00155 opt_fp = opt_fp->next;
00156 continue;
00157 }
00158
00159 if (!child)
00160 {
00161 /* No children at this node */
00162 child = new_node(opt_fp->type, option_data);
00163 child->evaluate = opt_fp->OptTestFunc;
00164
00165 if (!node)
00166 root->children[i] = child;
00167 else
00168 node->children[i] = child;
00169
00170 child->num_children++;
00171 child->children = (detection_option_tree_node_t**)
00172 snort_calloc(child->num_children, sizeof(child->children));
00173 child->is_relative = opt_fp->isRelative;
00174
00175 if (node && child->is_relative)
00176 node->relative_children++;
00177
00178 need_leaf = true;
00179 }
00180 else
00181 {
00182 if (child->option_data != option_data)
00183 {
00184 if (!node)
00185 {
00186 for (i=1; i<root->num_children; i++)
00187 {
00188 child = root->children[i];
00189 if (child->option_data == option_data)
00190 {
00191 found_child_match = 1;
00192 break;
00193 }
00194 }
00195 }
00196 else
00197 {
00198 for (i=1; i<node->num_children; i++)
00199 {
00200 child = node->children[i];
00201 if (child->option_data == option_data)
00202 {
00203 found_child_match = 1;
00204 break;
00205 }
00206 }
00207 }
00208 }
00209 else
00210 {
00211 found_child_match = 1;
00212 }
00213
00214 if (found_child_match == 0)
00215 {
00216 /* No matching child node, create a new and add to array */
00217 detection_option_tree_node_t** tmp_children;
00218 child = new_node(opt_fp->type, option_data);
00219 child->evaluate = opt_fp->OptTestFunc;
00220 child->num_children++;
00221 child->children = (detection_option_tree_node_t**)
00222 snort_calloc(child->num_children, sizeof(child->children));
00223 child->is_relative = opt_fp->isRelative;
00224
00225 if (!node)
00226 {
00227 root->num_children++;
00228 tmp_children = (detection_option_tree_node_t**)
00229 snort_calloc(root->num_children, sizeof(tmp_children));
00230 memcpy(tmp_children, root->children,
00231 sizeof(detection_option_tree_node_t*) * (root->num_children-1));
00232
00233 snort_free(root->children);
00234 root->children = tmp_children;
00235 root->children[root->num_children-1] = child;
00236 }
00237 else
00238 {
00239 node->num_children++;
00240 tmp_children = (detection_option_tree_node_t**)
00241 snort_calloc(node->num_children, sizeof(tmp_children));
00242 memcpy(tmp_children, node->children,
00243 sizeof(detection_option_tree_node_t*) * (node->num_children-1));
00244
00245 snort_free(node->children);
00246 node->children = tmp_children;
00247 node->children[node->num_children-1] = child;
00248 if (child->is_relative)
00249 node->relative_children++;
00250 }
00251 need_leaf = true;
00252 }
00253 }
00254 node = child;
00255 i=0;
00256 child = node->children[i];
00257 opt_fp = opt_fp->next;
00258 }
00259
00260 // don't add a new leaf node unless we branched higher in the tree or this
00261 // is a different sig ( eg alert ip ( sid:1; ) vs alert tcp ( sid:2; ) )
00262 // note: same sig different policy branches at rtn (this is for same policy)
00263
00264 if ( !need_leaf )
00265 {
00266 if ( node )
00267 need_leaf = new_sig(node->num_children, node->children, otn);
00268 else
00269 need_leaf = new_sig(root->num_children, root->children, otn);
00270 }
00271
00272 if ( !need_leaf )
00273 return 0;
00274
00275 /* Append a leaf node that has option data of the SigInfo/otn pointer */
00276 child = new_node(RULE_OPTION_TYPE_LEAF_NODE, otn);
00277
00278 if (!node)
00279 {
00280 if (root->children[0])
00281 {
00282 detection_option_tree_node_t** tmp_children;
00283 root->num_children++;
00284 tmp_children = (detection_option_tree_node_t**)
00285 snort_calloc(root->num_children, sizeof(tmp_children));
00286 memcpy(tmp_children, root->children,
00287 sizeof(detection_option_tree_node_t*) * (root->num_children-1));
00288 snort_free(root->children);
00289 root->children = tmp_children;
00290 }
00291 root->children[root->num_children-1] = child;
00292 }
00293 else
00294 {
00295 if (node->children[0])
00296 {
00297 detection_option_tree_node_t** tmp_children;
00298 node->num_children++;
00299 tmp_children = (detection_option_tree_node_t**)
00300 snort_calloc(node->num_children, sizeof(tmp_children));
00301 memcpy(tmp_children, node->children,
00302 sizeof(detection_option_tree_node_t*) * (node->num_children-1));
00303 snort_free(node->children);
00304 node->children = tmp_children;
00305 }
00306 node->children[node->num_children-1] = child;
00307 }
00308
00309 return 0;
00310 }
00311
00312 static int add_patrn_to_neg_list(void* id, void** list)
00313 {
00314 if ( !id or !list )
00315 return -1;
00316
00317 NCListNode** ncl = (NCListNode**)list;
00318 NCListNode* node = (NCListNode*)snort_alloc(sizeof(NCListNode));
00319
00320 node->pmx = (PMX*)id;
00321 node->next = *ncl;
00322 *ncl = node;
00323
00324 return 0;
00325 }
00326
00327 static void neg_list_free(void** list)
00328 {
00329 NCListNode* ncln;
00330
00331 if (list == nullptr)
00332 return;
00333
00334 ncln = (NCListNode*)*list;
00335 while (ncln != nullptr)
00336 {
00337 NCListNode* tmp = ncln->next;
00338 snort_free(ncln);
00339 ncln = tmp;
00340 }
00341
00342 *list = nullptr;
00343 }
00344
00345 static int pmx_create_tree(SnortConfig* sc, void* id, void** existing_tree)
00346 {
00347 assert(existing_tree);
00348
00349 if (!id)
00350 {
00351 if ( !*existing_tree )
00352 return -1;
00353
00354 /* NULL input id (PMX *), last call for this pattern state */
00355 return finalize_detection_option_tree(sc, (detection_option_tree_root_t*)*existing_tree);
00356 }
00357
00358 PMX* pmx = (PMX*)id;
00359 OptTreeNode* otn = (OptTreeNode*)pmx->rule_node.rnRuleData;
00360
00361 if (!*existing_tree)
00362 *existing_tree = new_root(otn);
00363
00364 return otn_create_tree(otn, existing_tree);
00365 }
00366
00367 static int fpFinishPortGroupRule(
00368 SnortConfig* sc, PortGroup* pg,
00369 OptTreeNode* otn, PatternMatchData* pmd, FastPatternConfig* fp)
00370 {
00371 if ( !pmd )
00372 {
00373 pg->add_nfp_rule(otn);
00374 print_nfp_info(s_group, otn);
00375 return 0;
00376 }
00377 if ( !pg->mpse[pmd->pm_type] )
00378 {
00379 static MpseAgent agent =
00380 {
00381 pmx_create_tree, add_patrn_to_neg_list,
00382 fpDeletePMX, free_detection_option_root, neg_list_free
00383 };
00384
00385 pg->mpse[pmd->pm_type] = MpseManager::get_search_engine(
00386 sc, fp->get_search_api(), &agent);
00387
00388 if ( !pg->mpse[pmd->pm_type] )
00389 {
00390 ParseError("Failed to create pattern matcher for %d", pmd->pm_type);
00391 return -1;
00392 }
00393 mpse_count++;
00394
00395 if ( fp->get_search_opt() )
00396 pg->mpse[pmd->pm_type]->set_opt(1);
00397 }
00398 if (pmd->is_negated())
00399 pg->add_nfp_rule(otn);
00400
00401 else
00402 pg->add_rule();
00403
00404 const char* pattern;
00405 int pattern_length;
00406
00407 if (fpGetFinalPattern(fp, pmd, pattern, pattern_length) == -1)
00408 return -1;
00409
00410 if ( fp->get_debug_print_fast_patterns() )
00411 print_fp_info(s_group, otn, pmd, pattern, pattern_length);
00412
00413 PMX* pmx = (PMX*)snort_calloc(sizeof(PMX));
00414 pmx->rule_node.rnRuleData = otn;
00415 pmx->pmd = pmd;
00416
00417 Mpse::PatternDescriptor desc(
00418 pmd->is_no_case(), pmd->is_negated(), pmd->is_literal(), pmd->mpse_flags);
00419
00420 pg->mpse[pmd->pm_type]->add_pattern(sc, (const uint8_t*)pattern, pattern_length, desc, pmx);
00421
00422 return 0;
00423 }
00424
00425 static int fpFinishPortGroup(
00426 SnortConfig* sc, PortGroup* pg, FastPatternConfig* fp)
00427 {
00428 int i;
00429 int rules = 0;
00430
00431 if ((pg == nullptr) || (fp == nullptr))
00432 return -1;
00433
00434 for (i = PM_TYPE_PKT; i < PM_TYPE_MAX; i++)
00435 {
00436 if (pg->mpse[i] != nullptr)
00437 {
00438 if (pg->mpse[i]->get_pattern_count() != 0)
00439 {
00440 if ( !sc->test_mode() or sc->mem_check() )
00441 {
00442 if ( pg->mpse[i]->prep_patterns(sc) != 0 )
00443 FatalError("Failed to compile port group patterns.\n");
00444 }
00445
00446 if (fp->get_debug_mode())
00447 pg->mpse[i]->print_info();
00448 rules = 1;
00449 }
00450 else
00451 {
00452 MpseManager::delete_search_engine(pg->mpse[i]);
00453 pg->mpse[i] = nullptr;
00454 }
00455 }
00456 }
00457
00458 if ( pg->nfp_head )
00459 {
00460 RULE_NODE* ruleNode;
00461
00462 for (ruleNode = pg->nfp_head; ruleNode; ruleNode = ruleNode->rnNext)
00463 {
00464 OptTreeNode* otn = (OptTreeNode*)ruleNode->rnRuleData;
00465 otn_create_tree(otn, &pg->nfp_tree);
00466 }
00467
00468 finalize_detection_option_tree(sc, (detection_option_tree_root_t*)pg->nfp_tree);
00469 rules = 1;
00470
00471 pg->delete_nfp_rules();
00472 }
00473
00474 if (!rules)
00475 {
00476 /* Nothing in the port group so we can just free it */
00477 snort_free(pg);
00478 return -1;
00479 }
00480
00481 return 0;
00482 }
00483
00484 static void fpAddAlternatePatterns(SnortConfig* sc, PortGroup* pg,
00485 OptTreeNode* otn, PatternMatchData* pmd, FastPatternConfig* fp)
00486 {
00487 if ( fp->get_debug_print_fast_patterns() )
00488 print_fp_info(s_group, otn, pmd, pmd->pattern_buf, pmd->pattern_size);
00489
00490 PMX* pmx = (PMX*)snort_calloc(sizeof(PMX));
00491 pmx->rule_node.rnRuleData = otn;
00492 pmx->pmd = pmd;
00493
00494 Mpse::PatternDescriptor desc(
00495 pmd->is_no_case(), pmd->is_negated(), pmd->is_literal(), pmd->mpse_flags);
00496
00497 pg->mpse[pmd->pm_type]->add_pattern(
00498 sc, (const uint8_t*)pmd->pattern_buf, pmd->pattern_size, desc, pmx);
00499 }
00500
00501 static int fpAddPortGroupRule(
00502 SnortConfig* sc, PortGroup* pg, OptTreeNode* otn, FastPatternConfig* fp, bool srvc)
00503 {
00504 PatternMatchVector pmv;
00505
00506 // skip builtin rules, continue for text and so rules
00507 if ( !otn->sigInfo.text_rule )
00508 return -1;
00509
00510 /* Rule not enabled */
00511 if ( !otn->enabled )
00512 return -1;
00513
00514 OptFpList* next = nullptr;
00515 bool only_literal = !MpseManager::is_regex_capable(fp->get_search_api());
00516 pmv = get_fp_content(otn, next, srvc, only_literal);
00517
00518 if ( !pmv.empty() )
00519 {
00520 PatternMatchData* main_pmd = pmv.back();
00521 pmv.pop_back();
00522
00523 if ( !main_pmd->is_relative() && !main_pmd->is_negated() && main_pmd->fp_only >= 0 &&
00524 // FIXIT-L no_case consideration is mpse specific, delegate
00525 !main_pmd->offset && !main_pmd->depth && main_pmd->is_no_case() )
00526 {
00527 if ( !next || !next->ips_opt || !next->ips_opt->is_relative() )
00528 main_pmd->fp_only = 1;
00529 }
00530
00531 if (fpFinishPortGroupRule(sc, pg, otn, main_pmd, fp) == 0)
00532 {
00533 if (main_pmd->pattern_size > otn->longestPatternLen)
00534 otn->longestPatternLen = main_pmd->pattern_size;
00535 for (auto p : pmv)
00536 fpAddAlternatePatterns(sc, pg, otn, p, fp);
00537
00538 return 0;
00539 }
00540 }
00541
00542 // no fast pattern added
00543 if (fpFinishPortGroupRule(sc, pg, otn, nullptr, fp) != 0)
00544 return -1;
00545
00546 return 0;
00547 }
00548
00549 /*
00550 * Original PortRuleMaps for each protocol requires creating the following structures.
00551 *
00552 * PORT_RULE_MAP -> srcPortGroup,dstPortGroup,genericPortGroup
00553 * PortGroup -> pgPatData, pgPatDataUri (acsm objects), (also rule_node lists 1/rule,
00554 * not needed). each rule content added to an acsm object has a PMX data ptr
00555 * associated with it.
00556 * RULE_NODE -> iRuleNodeID (used for bitmap object index)
00557 * PMX -> RULE_NODE(->otn), PatternMatchData
00558 *
00559 * PortList model supports the same structures except:
00560 *
00561 * PortGroup -> no rule_node lists needed, PortObjects maintain a list of rules used
00562 *
00563 * Generation of PortRuleMaps and data is done differently.
00564 *
00565 * 1) Build tcp/udp/icmp/ip src and dst PortGroup objects based on the PortList Objects rules.
00566 *
00567 * 2) For each protocols PortList objects walk it's ports and assign the PORT_RULE_MAP src and
00568 * dst PortGroup[port] array pointers to that PortList objects PortGroup.
00569 *
00570 * Implementation:
00571 *
00572 * Each PortList Object will be translated into a PortGroup, then pointed to by the
00573 * PortGroup array in the PORT_RULE_MAP for the protocol
00574 *
00575 * protocol = tcp, udp, ip, icmp - one port_rule_map for each of these protocols
00576 * { create a port_rule_map
00577 * dst port processing
00578 * for each port-list object create a port_group object
00579 * { create a pattern match object, store its pointer in port_group
00580 * for each rule index in port-list object
00581 * {
00582 * get the gid+sid for the index
00583 * lookup up the otn
00584 * create pmx
00585 * create RULE_NODE, set iRuleNodeID within this port-list object
00586 * get longest content for the rule
00587 * set up pmx,RULE_NODE
00588 * add the content and pmx to the pattern match object
00589 * }
00590 * compile the pattern match object
00591 *
00592 * repeat for uri content
00593 * }
00594 * src port processing
00595 * repeat as for dst port processing
00596 * }
00597 * ** bidirectional rules - these are added to both src and dst PortList objects, so they are
00598 * automatically handled during conversion to port_group objects.
00599 */
00600 /*
00601 ** Build a Pattern group for the Uri-Content rules in this group
00602 **
00603 ** The patterns added for each rule must be sufficient so if we find any of them
00604 ** we proceed to fully analyze the OTN and RTN against the packet.
00605 **
00606 */
00607 /*
00608 * Init a port-list based rule map
00609 */
00610 struct PortIteratorData
00611 {
00612 PortIteratorData(PortGroup** a, PortGroup* g)
00613 {
00614 array = a;
00615 group = g;
00616 }
00617
00618 static void set(int port, void* pv)
00619 {
00620 PortIteratorData* pid = (PortIteratorData*)pv;
00621 pid->array[port] = pid->group;
00622 }
00623
00624 PortGroup** array;
00625 PortGroup* group;
00626 };
00627
00628 static int fpCreateInitRuleMap(
00629 PORT_RULE_MAP* prm, PortTable* src, PortTable* dst, PortObject* any)
00630 {
00631 /* setup the any-port content port group */
00632 prm->prmGeneric = any->group;
00633
00634 /* all rules that are any any some may not be content ? */
00635 prm->prmNumGenericRules = any->rule_list->count;
00636
00637 prm->prmNumSrcRules = 0;
00638 prm->prmNumDstRules = 0;
00639
00640 prm->prmNumSrcGroups = 0;
00641 prm->prmNumDstGroups = 0;
00642
00643 /* Process src PORT groups */
00644 if ( src )
00645 {
00646 for ( SFGHASH_NODE* node=sfghash_findfirst(src->pt_mpxo_hash);
00647 node;
00648 node=sfghash_findnext(src->pt_mpxo_hash) )
00649 {
00650 PortObject2* po = (PortObject2*)node->data;
00651
00652 if ( !po or !po->group )
00653 continue;
00654
00655 /* Add up the total src rules */
00656 prm->prmNumSrcRules += po->rule_hash->count;
00657
00658 /* Increment the port group count */
00659 prm->prmNumSrcGroups++;
00660
00661 /* Add this port group to the src table at each port that uses it */
00662 PortIteratorData pit_data(prm->prmSrcPort, po->group);
00663 PortObject2Iterate(po, PortIteratorData::set, &pit_data);
00664 }
00665 }
00666
00667 /* process destination port groups */
00668 if ( dst )
00669 {
00670 for ( SFGHASH_NODE* node=sfghash_findfirst(dst->pt_mpxo_hash);
00671 node;
00672 node=sfghash_findnext(dst->pt_mpxo_hash) )
00673 {
00674 PortObject2* po = (PortObject2*)node->data;
00675
00676 if ( !po or !po->group )
00677 continue;
00678
00679 /* Add up the total src rules */
00680 prm->prmNumDstRules += po->rule_hash->count;
00681
00682 /* Increment the port group count */
00683 prm->prmNumDstGroups++;
00684
00685 /* Add this port group to the src table at each port that uses it */
00686 PortIteratorData pit_data(prm->prmDstPort, po->group);
00687 PortObject2Iterate(po, PortIteratorData::set, &pit_data);
00688 }
00689 }
00690
00691 return 0;
00692 }
00693
00694 /*
00695 * Create and initialize the rule maps
00696 */
00697 static int fpCreateRuleMaps(SnortConfig* sc, RulePortTables* p)
00698 {
00699 sc->prmIpRTNX = prmNewMap();
00700 sc->prmIcmpRTNX = prmNewMap();
00701 sc->prmTcpRTNX = prmNewMap();
00702 sc->prmUdpRTNX = prmNewMap();
00703
00704 if (fpCreateInitRuleMap(sc->prmIpRTNX, p->ip.src, p->ip.dst, p->ip.any))
00705 return -1;
00706
00707 if (fpCreateInitRuleMap(sc->prmIcmpRTNX, p->icmp.src, p->icmp.dst, p->icmp.any))
00708 return -1;
00709
00710 if (fpCreateInitRuleMap(sc->prmTcpRTNX, p->tcp.src, p->tcp.dst, p->tcp.any))
00711 return -1;
00712
00713 if (fpCreateInitRuleMap(sc->prmUdpRTNX, p->udp.src, p->udp.dst, p->udp.any))
00714 return -1;
00715
00716 return 0;
00717 }
00718
00719 static void fpFreeRuleMaps(SnortConfig* sc)
00720 {
00721 if (sc == nullptr)
00722 return;
00723
00724 if (sc->prmIpRTNX != nullptr)
00725 {
00726 snort_free(sc->prmIpRTNX);
00727 sc->prmIpRTNX = nullptr;
00728 }
00729
00730 if (sc->prmIcmpRTNX != nullptr)
00731 {
00732 snort_free(sc->prmIcmpRTNX);
00733 sc->prmIcmpRTNX = nullptr;
00734 }
00735
00736 if (sc->prmTcpRTNX != nullptr)
00737 {
00738 snort_free(sc->prmTcpRTNX);
00739 sc->prmTcpRTNX = nullptr;
00740 }
00741
00742 if (sc->prmUdpRTNX != nullptr)
00743 {
00744 snort_free(sc->prmUdpRTNX);
00745 sc->prmUdpRTNX = nullptr;
00746 }
00747 }
00748
00749 static int fpGetFinalPattern(
00750 FastPatternConfig* fp, PatternMatchData* pmd,
00751 const char*& ret_pattern, int& ret_bytes)
00752 {
00753 if ( !fp or !pmd )
00754 {
00755 return -1;
00756 }
00757
00758 const char* pattern = pmd->pattern_buf;
00759 int bytes = pmd->pattern_size;
00760
00761 // Don't mess with:
00762 //
00763 // 1. fast pattern only contents - they should be inserted into the
00764 // pattern matcher as is since the content won't be evaluated as a rule
00765 // option.
00766 //
00767 // 2. negated contents since truncating them could inadvertently
00768 // disable evaluation of a rule - the shorter pattern may be found,
00769 // while the unaltered pattern may not be found, disabling inspection
00770 // of a rule we should inspect.
00771 //
00772 // 3. non-literals like regex - truncation could invalidate the
00773 // expression.
00774
00775 if ( pmd->fp_only > 0 or pmd->is_negated() or !pmd->is_literal() )
00776 {
00777 ret_pattern = pattern;
00778 ret_bytes = bytes;
00779 return 0;
00780 }
00781
00782 if ( pmd->is_fast_pattern() && (pmd->fp_offset || pmd->fp_length) )
00783 {
00784 /* (offset + length) potentially being larger than the pattern itself
00785 * is taken care of during parsing */
00786 assert(pmd->fp_offset + pmd->fp_length <= pmd->pattern_size);
00787 pattern = pmd->pattern_buf + pmd->fp_offset;
00788 bytes = pmd->fp_length ? pmd->fp_length : pmd->pattern_size - pmd->fp_length;
00789 }
00790 else
00791 {
00792 /* Trim leading null bytes for non-deterministic pattern matchers.
00793 * Assuming many packets may have strings of 0x00 bytes in them,
00794 * this should help performance with non-deterministic pattern matchers
00795 * that have a full next state vector at state 0. If no patterns are
00796 * inserted into the state machine that start with 0x00, failstates that
00797 * land us at state 0 will allow us to roll through the 0x00 bytes,
00798 * since the next state is deterministic in state 0 and we won't move
00799 * beyond state 0 as long as the next input char is 0x00 */
00800 if ( fp->get_trim() )
00801 {
00802 bytes =
00803 flp_trim(pmd->pattern_buf, pmd->pattern_size, &pattern);
00804
00805 if (bytes < (int)pmd->pattern_size)
00806 {
00807 /* The pattern is all '\0' - use the whole pattern
00808 * XXX This potentially hurts the performance boost
00809 * gained by stripping leading zeros */
00810 if (bytes == 0)
00811 {
00812 bytes = pmd->pattern_size;
00813 pattern = pmd->pattern_buf;
00814 }
00815 else
00816 {
00817 fp->trimmed();
00818 }
00819 }
00820 }
00821 }
00822
00823 ret_pattern = pattern;
00824 ret_bytes = fp->set_max(bytes);
00825
00826 return 0;
00827 }
00828
00829 static void fpPortGroupPrintRuleCount(PortGroup* pg, const char* what)
00830 {
00831 int type;
00832
00833 if (pg == nullptr)
00834 return;
00835
00836 LogMessage("PortGroup rule summary (%s):\n", what);
00837
00838 for (type = PM_TYPE_PKT; type < PM_TYPE_MAX; type++)
00839 {
00840 int count = pg->mpse[type] ? pg->mpse[type]->get_pattern_count() : 0;
00841
00842 if ( count )
00843 LogMessage("\t%s: %d\n", pm_type_strings[type], count);
00844 }
00845
00846 if ( pg->nfp_rule_count )
00847 LogMessage("\tNo content: %u\n", pg->nfp_rule_count);
00848 }
00849
00850 static void fpDeletePMX(void* pv)
00851 {
00852 if ( pv )
00853 snort_free(pv);
00854 }
00855
00856 /*
00857 * Create the PortGroup for these PortObject2 entities
00858 *
00859 * This builds the 1st pass multi-pattern state machines for
00860 * content and uricontent based on the rules in the PortObjects
00861 * hash table.
00862 */
00863 static int fpCreatePortObject2PortGroup(
00864 SnortConfig* sc, PortObject2* po, PortObject2* poaa)
00865 {
00866 SFGHASH_NODE* node;
00867 unsigned sid, gid;
00868 OptTreeNode* otn;
00869 PortGroup* pg;
00870 PortObject2* pox;
00871 FastPatternConfig* fp = sc->fast_pattern_config;
00872
00873 /* verify we have a port object */
00874 if (po == nullptr)
00875 return 0;
00876
00877 po->group = nullptr;
00878
00879 if (fp->get_debug_print_rule_group_build_details())
00880 PortObject2PrintPorts(po);
00881
00882 /* Check if we have any rules */
00883 if (po->rule_hash == nullptr)
00884 return 0;
00885
00886 /* create a port_group */
00887 pg = PortGroup::alloc();
00888 s_group = "port";
00889
00890 /*
00891 * Walk the rules in the PortObject and add to
00892 * the PortGroup pattern state machine
00893 * and to the port group RULE_NODE lists.
00894 * (The lists are still used in some cases
00895 * during detection to walk the rules in a group
00896 * so we have to load these as well...fpEvalHeader()... for now.)
00897 *
00898 * po src/dst ports : content/uri and nocontent
00899 * poaa any-any ports : content/uri and nocontent
00900 *
00901 * each PG has src or dst contents, generic-contents, and no-contents
00902 * (src/dst or any-any ports)
00903 *
00904 */
00905 pox = po;
00906
00907 while (pox != nullptr)
00908 {
00909 for (node = sfghash_findfirst(pox->rule_hash);
00910 node;
00911 node = sfghash_findnext(pox->rule_hash))
00912 {
00913 int* prindex = (int*)node->data;
00914
00915 /* be safe - no rule index, ignore it */
00916 if (prindex == nullptr)
00917 continue;
00918
00919 /* look up gid:sid */
00920 parser_get_rule_ids(*prindex, gid, sid);
00921
00922 /* look up otn */
00923 otn = OtnLookup(sc->otn_map, gid, sid);
00924 assert(otn);
00925
00926 if ( is_network_protocol(otn->proto) )
00927 fpAddPortGroupRule(sc, pg, otn, fp, false);
00928 }
00929
00930 if (fp->get_debug_print_rule_group_build_details())
00931 fpPortGroupPrintRuleCount(pg, pox == po ? "ports" : "any");
00932
00933 if (pox == poaa)
00934 break;
00935
00936 pox = poaa;
00937 }
00938
00939 /* This might happen if there was ip proto only rules
00940 * Don't return failure */
00941 if (fpFinishPortGroup(sc, pg, fp) != 0)
00942 return 0;
00943
00944 po->group = pg;
00945 return 0;
00946 }
00947
00948 /*
00949 * Create the port groups for this port table
00950 */
00951 static int fpCreatePortTablePortGroups(
00952 SnortConfig* sc, PortTable* p, PortObject2* poaa)
00953 {
00954 SFGHASH_NODE* node;
00955 int cnt=1;
00956 FastPatternConfig* fp = sc->fast_pattern_config;
00957
00958 if (fp->get_debug_print_rule_group_build_details())
00959 LogMessage("%d Port Groups in Port Table\n",p->pt_mpo_hash->count);
00960
00961 for (node=sfghash_findfirst(p->pt_mpo_hash);
00962 node;
00963 node=sfghash_findnext(p->pt_mpo_hash) )
00964 {
00965 PortObject2* po = (PortObject2*)node->data;
00966
00967 if ( !po )
00968 continue;
00969
00970 if (fp->get_debug_print_rule_group_build_details())
00971 LogMessage("Creating Port Group Object %d of %d\n",cnt++,p->pt_mpo_hash->count);
00972
00973 /* if the object is not referenced, don't add it to the PortGroups
00974 * as it may overwrite other objects that are more inclusive. */
00975 if (!po->port_cnt)
00976 continue;
00977
00978 if (fpCreatePortObject2PortGroup(sc, po, poaa))
00979 {
00980 LogMessage("fpCreatePortObject2PortGroup() failed\n");
00981 return -1;
00982 }
00983 }
00984
00985 return 0;
00986 }
00987
00988 /*
00989 * Create port group objects for all port tables
00990 *
00991 * note: any ports are standard PortObjects not PortObject2s so we have to
00992 * upgrade them for the create port group function
00993 */
00994 static int fpCreatePortGroups(SnortConfig* sc, RulePortTables* p)
00995 {
00996 PortObject2* po2, * add_any_any;
00997 FastPatternConfig* fp = sc->fast_pattern_config;
00998
00999 if (!get_rule_count())
01000 return 0;
01001
01002 /* IP */
01003 if ( !(po2 = PortObject2Dup(p->ip.any)) )
01004 FatalError("Could not create a PortObject2 for ip-any rules\n");
01005
01006 add_any_any = fp->get_split_any_any() ? nullptr : po2;
01007
01008 if (fp->get_debug_print_rule_group_build_details())
01009 LogMessage("\nIP-SRC ");
01010
01011 if (fpCreatePortTablePortGroups(sc, p->ip.src, add_any_any))
01012 {
01013 LogMessage("fpCreatePorTablePortGroups failed-ip.src\n");
01014 return -1;
01015 }
01016
01017 if (fp->get_debug_print_rule_group_build_details())
01018 LogMessage("\nIP-DST ");
01019
01020 if (fpCreatePortTablePortGroups(sc, p->ip.dst, add_any_any))
01021 {
01022 LogMessage("fpCreatePorTablePortGroups failed-ip.dst\n");
01023 return -1;
01024 }
01025
01026 if (fp->get_debug_print_rule_group_build_details())
01027 LogMessage("\nIP-ANY ");
01028
01029 if (fpCreatePortObject2PortGroup(sc, po2, nullptr))
01030 {
01031 LogMessage("fpCreatePorTablePortGroups failed-ip any\n");
01032 return -1;
01033 }
01034
01035 p->ip.any->group = po2->group;
01036 po2->group = nullptr;
01037 PortObject2Free(po2);
01038
01039 /* ICMP */
01040 if ( !(po2 = PortObject2Dup(p->icmp.any)) )
01041 FatalError("Could not create a PortObject2 for icmp-any rules\n");
01042
01043 add_any_any = fp->get_split_any_any() ? nullptr : po2;
01044
01045 if (fp->get_debug_print_rule_group_build_details())
01046 LogMessage("\nICMP-SRC ");
01047
01048 if (fpCreatePortTablePortGroups(sc, p->icmp.src, add_any_any))
01049 {
01050 LogMessage("fpCreatePorTablePortGroups failed-icmp.src\n");
01051 return -1;
01052 }
01053
01054 if (fp->get_debug_print_rule_group_build_details())
01055 LogMessage("\nICMP-DST ");
01056
01057 if (fpCreatePortTablePortGroups(sc, p->icmp.dst, add_any_any))
01058 {
01059 LogMessage("fpCreatePorTablePortGroups failed-icmp.src\n");
01060 return -1;
01061 }
01062
01063 if (fp->get_debug_print_rule_group_build_details())
01064 LogMessage("\nICMP-ANY ");
01065
01066 if (fpCreatePortObject2PortGroup(sc, po2, nullptr))
01067 {
01068 LogMessage("fpCreatePorTablePortGroups failed-icmp any\n");
01069 return -1;
01070 }
01071
01072 p->icmp.any->group = po2->group;
01073 po2->group = nullptr;
01074 PortObject2Free(po2);
01075
01076 if ( !(po2 = PortObject2Dup(p->tcp.any)) )
01077 FatalError("Could not create a PortObject2 for tcp-any rules\n");
01078
01079 add_any_any = fp->get_split_any_any() ? nullptr : po2;
01080
01081 if (fp->get_debug_print_rule_group_build_details())
01082 LogMessage("\nTCP-SRC ");
01083
01084 if (fpCreatePortTablePortGroups(sc, p->tcp.src, add_any_any))
01085 {
01086 LogMessage("fpCreatePorTablePortGroups failed-tcp.src\n");
01087 return -1;
01088 }
01089
01090 if (fp->get_debug_print_rule_group_build_details())
01091 LogMessage("\nTCP-DST ");
01092
01093 if (fpCreatePortTablePortGroups(sc, p->tcp.dst, add_any_any))
01094 {
01095 LogMessage("fpCreatePorTablePortGroups failed-tcp.dst\n");
01096 return -1;
01097 }
01098
01099 if (fp->get_debug_print_rule_group_build_details())
01100 LogMessage("\nTCP-ANY ");
01101
01102 if (fpCreatePortObject2PortGroup(sc, po2, nullptr))
01103 {
01104 LogMessage("fpCreatePorTablePortGroups failed-tcp any\n");
01105 return -1;
01106 }
01107
01108 p->tcp.any->group = po2->group;
01109 po2->group = nullptr;
01110 PortObject2Free(po2);
01111
01112 /* UDP */
01113 if ( !(po2 = PortObject2Dup(p->udp.any)) )
01114 FatalError("Could not create a PortObject2 for udp-any rules\n");
01115
01116 add_any_any = fp->get_split_any_any() ? nullptr : po2;
01117
01118 if (fp->get_debug_print_rule_group_build_details())
01119 LogMessage("\nUDP-SRC ");
01120
01121 if (fpCreatePortTablePortGroups(sc, p->udp.src, add_any_any))
01122 {
01123 LogMessage("fpCreatePorTablePortGroups failed-udp.src\n");
01124 return -1;
01125 }
01126
01127 if (fp->get_debug_print_rule_group_build_details())
01128 LogMessage("\nUDP-DST ");
01129
01130 if (fpCreatePortTablePortGroups(sc, p->udp.dst, add_any_any))
01131 {
01132 LogMessage("fpCreatePorTablePortGroups failed-udp.src\n");
01133 return -1;
01134 }
01135
01136 if (fp->get_debug_print_rule_group_build_details())
01137 LogMessage("\nUDP-ANY ");
01138
01139 if (fpCreatePortObject2PortGroup(sc, po2, nullptr))
01140 {
01141 LogMessage("fpCreatePorTablePortGroups failed-udp.src\n");
01142 return -1;
01143 }
01144
01145 p->udp.any->group = po2->group;
01146 po2->group = nullptr;
01147 PortObject2Free(po2);
01148
01149 /* SVC */
01150 if ( !(po2 = PortObject2Dup(p->svc_any)) )
01151 FatalError("Could not create a PortObject2 for svc-any rules\n");
01152
01153 if (fp->get_debug_print_rule_group_build_details())
01154 LogMessage("\nSVC-ANY ");
01155
01156 if (fpCreatePortObject2PortGroup(sc, po2, nullptr))
01157 {
01158 LogMessage("fpCreatePorTablePortGroups failed-svc_any\n");
01159 return -1;
01160 }
01161
01162 p->svc_any->group = po2->group;
01163 po2->group = nullptr;
01164 PortObject2Free(po2);
01165
01166 return 0;
01167 }
01168
01169 /*
01170 * Build a Port Group for this service based on the list of otns. The final
01171 * port_group pointer is stored using the service name as the key.
01172 *
01173 * p - hash table mapping services to port_groups
01174 * srvc- service name, key used to store the port_group
01175 * ...could use a service id instead (bytes, fixed length,etc...)
01176 * list- list of otns for this service
01177 */
01178 static void fpBuildServicePortGroupByServiceOtnList(
01179 SnortConfig* sc, SFGHASH* p, const char* srvc, SF_LIST* list, FastPatternConfig* fp)
01180 {
01181 PortGroup* pg = PortGroup::alloc();
01182 s_group = srvc;
01183
01184 /*
01185 * add each rule to the port group pattern matchers,
01186 * or to the no-content rule list
01187 */
01188 SF_LNODE* cursor;
01189
01190 for ( OptTreeNode* otn = (OptTreeNode*)sflist_first(list, &cursor);
01191 otn;
01192 otn = (OptTreeNode*)sflist_next(&cursor) )
01193 {
01194 if (fpAddPortGroupRule(sc, pg, otn, fp, true) != 0)
01195 continue;
01196 }
01197
01198 if (fpFinishPortGroup(sc, pg, fp) != 0)
01199 return;
01200
01201 /* Add the port_group using it's service name */
01202 sfghash_add(p, srvc, pg);
01203 }
01204
01205 /*
01206 * For each service we create a PortGroup based on the otn's defined to
01207 * be applicable to that service by the metadata option.
01208 *
01209 * Then we lookup the protocol/srvc ordinal in the target-based area
01210 * and assign the PortGroup for the srvc to it.
01211 *
01212 * spg - service port group (lookup should be by service id/tag)
01213 * - this table maintains a port_group ptr for each service
01214 * srm - service rule map table (lookup by ascii service name)
01215 * - this table maintains a SF_LIST ptr (list of rule otns) for each service
01216 *
01217 */
01218 static void fpBuildServicePortGroups(
01219 SnortConfig* sc, SFGHASH* spg, PortGroupVector& sopg, SFGHASH* srm, FastPatternConfig* fp)
01220 {
01221 for ( SFGHASH_NODE* n = sfghash_findfirst(srm);
01222 n;
01223 n=sfghash_findnext(srm) )
01224 {
01225 SF_LIST* list = (SF_LIST*)n->data;
01226 const char* srvc = (const char*)n->key;
01227
01228 assert(list and srvc);
01229
01230 fpBuildServicePortGroupByServiceOtnList(sc, spg, srvc, list, fp);
01231
01232 /* Add this PortGroup to the protocol-ordinal -> port_group table */
01233 PortGroup* pg = (PortGroup*)sfghash_find(spg, srvc);
01234 if ( !pg )
01235 {
01236 ParseError("*** failed to create and find a port group for '%s'",srvc);
01237 continue;
01238 }
01239 int16_t id = sc->proto_ref->find(srvc);
01240 assert(id != SFTARGET_UNKNOWN_PROTOCOL);
01241
01242 assert((unsigned)id < sopg.size());
01243 sopg[ id ] = pg;
01244 }
01245 }
01246
01247 /*
01248 * For each proto+dir+service build a PortGroup
01249 */
01250 static void fpCreateServiceMapPortGroups(SnortConfig* sc)
01251 {
01252 FastPatternConfig* fp = sc->fast_pattern_config;
01253
01254 sc->spgmmTable = ServicePortGroupMapNew();
01255 sc->sopgTable = new sopg_table_t(sc->proto_ref->get_count());
01256
01257 for ( int i = SNORT_PROTO_IP; i < SNORT_PROTO_MAX; i++ )
01258 {
01259 fpBuildServicePortGroups(sc, sc->spgmmTable->to_srv[i],
01260 sc->sopgTable->to_srv[i], sc->srmmTable->to_srv[i], fp);
01261
01262 fpBuildServicePortGroups(sc, sc->spgmmTable->to_cli[i],
01263 sc->sopgTable->to_cli[i], sc->srmmTable->to_cli[i], fp);
01264 }
01265 if ( !sc->sopgTable->set_user_mode() )
01266 {
01267 fp->set_stream_insert(true);
01268 ParseWarning(WARN_RULES, "legacy mode fast pattern searching enabled");
01269 }
01270 }
01271
01272 /*
01273 * Print the rule gid:sid based onm the otn list
01274 */
01275 static void fpPrintRuleList(SF_LIST* list)
01276 {
01277 OptTreeNode* otn;
01278 SF_LNODE* cursor;
01279
01280 for ( otn=(OptTreeNode*)sflist_first(list, &cursor);
01281 otn;
01282 otn=(OptTreeNode*)sflist_next(&cursor) )
01283 {
01284 LogMessage("| %u:%u\n", otn->sigInfo.gid, otn->sigInfo.sid);
01285 }
01286 }
01287
01288 static void fpPrintServiceRuleMapTable(SFGHASH* p, const char* proto, const char* dir)
01289 {
01290 SFGHASH_NODE* n;
01291
01292 if ( !p || !p->count )
01293 return;
01294
01295 std::string label = "service rule counts - ";
01296 label += proto;
01297 label += " ";
01298 label += dir;
01299 LogLabel(label.c_str());
01300
01301 for ( n = sfghash_findfirst(p);
01302 n;
01303 n = sfghash_findnext(p) )
01304 {
01305 SF_LIST* list;
01306
01307 list = (SF_LIST*)n->data;
01308 if ( !list )
01309 continue;
01310
01311 if ( !n->key )
01312 continue;
01313
01314 LogCount((const char*)n->key, list->count);
01315
01316 fpPrintRuleList(list);
01317 }
01318 }
01319
01320 static void fpPrintServiceRuleMaps(SnortConfig* sc, srmm_table_t* service_map)
01321 {
01322 for ( int i = SNORT_PROTO_IP; i < SNORT_PROTO_MAX; ++i )
01323 {
01324 const char* s = sc->proto_ref->get_name(i);
01325 fpPrintServiceRuleMapTable(service_map->to_srv[i], s, "to server");
01326 fpPrintServiceRuleMapTable(service_map->to_cli[i], s, "to client");
01327 }
01328 }
01329
01330 static void fp_print_service_rules(SnortConfig* sc, SFGHASH* cli, SFGHASH* srv, const char* msg)
01331 {
01332 if ( !cli->count and !srv->count )
01333 return;
01334
01335 std::string label = "service rule counts - ";
01336 label += msg;
01337 label += " to-srv to-cli";
01338 LogLabel(label.c_str());
01339
01340 uint16_t idx = 0;
01341 unsigned ctot = 0, stot = 0;
01342
01343 while ( const char* svc = sc->proto_ref->get_name_sorted(idx++) )
01344 {
01345 SF_LIST* clist = (SF_LIST*)sfghash_find(cli, svc);
01346 SF_LIST* slist = (SF_LIST*)sfghash_find(srv, svc);
01347
01348 if ( !clist and !slist )
01349 continue;
01350
01351 unsigned nc = clist ? clist->count : 0;
01352 unsigned ns = slist ? slist->count : 0;
01353
01354 LogMessage("%25.25s: %8u%8u\n", svc, nc, ns);
01355
01356 ctot += nc;
01357 stot += ns;
01358 }
01359 if ( ctot or stot )
01360 LogMessage("%25.25s: %8u%8u\n", "total", ctot, stot);
01361 }
01362
01363 static void fp_print_service_rules_by_proto(SnortConfig* sc, srmm_table_t* srmm)
01364 {
01365 for ( int i = SNORT_PROTO_IP; i < SNORT_PROTO_MAX; ++i )
01366 fp_print_service_rules(sc, srmm->to_srv[i], srmm->to_cli[i], sc->proto_ref->get_name(i));
01367 }
01368
01369 static void fp_sum_port_groups(PortGroup* pg, unsigned c[PM_TYPE_MAX])
01370 {
01371 if ( !pg )
01372 return;
01373
01374 for ( int i = PM_TYPE_PKT; i < PM_TYPE_MAX; ++i )
01375 if ( pg->mpse[i] and pg->mpse[i]->get_pattern_count() )
01376 c[i]++;
01377 }
01378
01379 static void fp_sum_service_groups(SFGHASH* h, unsigned c[PM_TYPE_MAX])
01380 {
01381 for ( SFGHASH_NODE* node=sfghash_findfirst(h);
01382 node; node=sfghash_findnext(h) )
01383 {
01384 PortGroup* pg = (PortGroup*)node->data;
01385 fp_sum_port_groups(pg, c);
01386 }
01387 }
01388
01389 static void fp_print_service_groups(srmm_table_t* srmm)
01390 {
01391 unsigned to_srv[PM_TYPE_MAX] = { 0 };
01392 unsigned to_cli[PM_TYPE_MAX] = { 0 };
01393
01394 for ( int i = SNORT_PROTO_IP; i < SNORT_PROTO_MAX; ++i )
01395 {
01396 fp_sum_service_groups(srmm->to_srv[i], to_srv);
01397 fp_sum_service_groups(srmm->to_cli[i], to_cli);
01398 }
01399
01400 bool label = true;
01401
01402 for ( int i = PM_TYPE_PKT; i < PM_TYPE_MAX; ++i )
01403 {
01404 if ( !to_srv[i] and !to_cli[i] )
01405 continue;
01406
01407 if ( label )
01408 {
01409 LogLabel("fast pattern service groups to-srv to-cli");
01410 label = false;
01411 }
01412 LogMessage("%25.25s: %8u%8u\n", pm_type_strings[i], to_srv[i], to_cli[i]);
01413 }
01414 }
01415
01416 static void fp_sum_port_groups(PortTable* tab, unsigned c[PM_TYPE_MAX])
01417 {
01418 for ( SFGHASH_NODE* node=sfghash_findfirst(tab->pt_mpxo_hash);
01419 node; node=sfghash_findnext(tab->pt_mpxo_hash) )
01420 {
01421 PortObject2* po = (PortObject2*)node->data;
01422 fp_sum_port_groups(po->group, c);
01423 PortObject2Finalize(po);
01424 }
01425 PortTableFinalize(tab);
01426 }
01427
01428 static void fp_print_port_groups(RulePortTables* port_tables)
01429 {
01430 unsigned src[PM_TYPE_MAX] = { 0 };
01431 unsigned dst[PM_TYPE_MAX] = { 0 };
01432 unsigned any[PM_TYPE_MAX] = { 0 };
01433
01434 fp_sum_port_groups(port_tables->ip.src, src);
01435 fp_sum_port_groups(port_tables->ip.dst, dst);
01436 fp_sum_port_groups((PortGroup*)port_tables->ip.any->group, any);
01437
01438 PortObjectFinalize(port_tables->ip.any);
01439 PortObjectFinalize(port_tables->ip.nfp);
01440
01441 fp_sum_port_groups(port_tables->icmp.src, src);
01442 fp_sum_port_groups(port_tables->icmp.dst, dst);
01443 fp_sum_port_groups((PortGroup*)port_tables->icmp.any->group, any);
01444
01445 PortObjectFinalize(port_tables->icmp.any);
01446 PortObjectFinalize(port_tables->icmp.nfp);
01447
01448 fp_sum_port_groups(port_tables->tcp.src, src);
01449 fp_sum_port_groups(port_tables->tcp.dst, dst);
01450 fp_sum_port_groups((PortGroup*)port_tables->tcp.any->group, any);
01451
01452 PortObjectFinalize(port_tables->tcp.any);
01453 PortObjectFinalize(port_tables->tcp.nfp);
01454
01455 fp_sum_port_groups(port_tables->udp.src, src);
01456 fp_sum_port_groups(port_tables->udp.dst, dst);
01457 fp_sum_port_groups((PortGroup*)port_tables->udp.any->group, any);
01458
01459 PortObjectFinalize(port_tables->udp.any);
01460 PortObjectFinalize(port_tables->udp.nfp);
01461
01462 bool label = true;
01463
01464 for ( int i = PM_TYPE_PKT; i < PM_TYPE_MAX; ++i )
01465 {
01466 if ( !src[i] and !dst[i] and !any[i] )
01467 continue;
01468
01469 if ( label )
01470 {
01471 LogLabel("fast pattern port groups src dst any");
01472 label = false;
01473 }
01474 LogMessage("%25.25s: %8u%8u%8u\n", pm_type_strings[i], src[i], dst[i], any[i]);
01475 }
01476 }
01477
01478 /*
01479 * Build Service based PortGroups using the rules
01480 * metadata option service parameter.
01481 */
01482 static int fpCreateServicePortGroups(SnortConfig* sc)
01483 {
01484 FastPatternConfig* fp = sc->fast_pattern_config;
01485
01486 sc->srmmTable = ServiceMapNew();
01487
01488 if (fpCreateServiceMaps(sc))
01489 return -1;
01490
01491 fp_print_service_rules_by_proto(sc, sc->srmmTable);
01492
01493 if ( fp->get_debug_print_rule_group_build_details() )
01494 fpPrintServiceRuleMaps(sc, sc->srmmTable);
01495
01496 fpCreateServiceMapPortGroups(sc);
01497
01498 if (fp->get_debug_print_rule_group_build_details())
01499 fpPrintServicePortGroupSummary(sc, sc->spgmmTable);
01500
01501 ServiceMapFree(sc->srmmTable);
01502 sc->srmmTable = nullptr;
01503 return 0;
01504 }
01505
01506 /*
01507 * Port list version
01508 *
01509 * 7/2007 - man
01510 *
01511 * Build Pattern Groups for 1st pass of content searching using
01512 * multi-pattern search method.
01513 */
01514 int fpCreateFastPacketDetection(SnortConfig* sc)
01515 {
01516 assert(sc);
01517
01518 RulePortTables* port_tables = sc->port_tables;
01519 FastPatternConfig* fp = sc->fast_pattern_config;
01520
01521 assert(port_tables);
01522 assert(fp);
01523
01524 if ( !get_rule_count() )
01525 {
01526 sc->sopgTable = new sopg_table_t(sc->proto_ref->get_count());
01527 return 0;
01528 }
01529
01530 mpse_count = 0;
01531
01532 MpseManager::start_search_engine(fp->get_search_api());
01533
01534 /* Use PortObjects to create PortGroups */
01535 if (fp->get_debug_print_rule_group_build_details())
01536 LogMessage("Creating Port Groups....\n");
01537
01538 if (fpCreatePortGroups(sc, port_tables))
01539 FatalError("Could not create PortGroup objects for PortObjects\n");
01540
01541 if (fp->get_debug_print_rule_group_build_details())
01542 LogMessage("Port Groups Done....\n");
01543
01544 /* Create rule_maps */
01545 if (fp->get_debug_print_rule_group_build_details())
01546 LogMessage("Creating Rule Maps....\n");
01547
01548 if (fpCreateRuleMaps(sc, port_tables))
01549 FatalError("Could not create rule maps\n");
01550
01551 if (fp->get_debug_print_rule_group_build_details())
01552 LogMessage("Rule Maps Done....\n");
01553
01554 if (fp->get_debug_print_rule_group_build_details())
01555 LogMessage("Creating Service Based Rule Maps....\n");
01556
01557 /* Build Service based port groups - rules require service metdata
01558 * i.e. 'metatdata: service [=] service-name, ... ;'
01559 *
01560 * Also requires a service attribute for lookup ...
01561 */
01562 if (fpCreateServicePortGroups(sc))
01563 FatalError("Could not create service based port groups\n");
01564
01565 if (fp->get_debug_print_rule_group_build_details())
01566 LogMessage("Service Based Rule Maps Done....\n");
01567
01568 fp_print_port_groups(port_tables);
01569 fp_print_service_groups(sc->spgmmTable);
01570
01571 if ( mpse_count )
01572 {
01573 LogLabel("search engine");
01574 MpseManager::print_mpse_summary(fp->get_search_api());
01575 }
01576
01577 if ( fp->get_num_patterns_truncated() )
01578 LogMessage("%25.25s: %-12u\n", "truncated patterns", fp->get_num_patterns_truncated());
01579
01580 if ( fp->get_num_patterns_trimmed() )
01581 LogMessage("%25.25s: %-12u\n", "prefix trims", fp->get_num_patterns_trimmed());
01582
01583 MpseManager::setup_search_engine(fp->get_search_api(), sc);
01584
01585 return 0;
01586 }
01587
01588 void fpDeleteFastPacketDetection(SnortConfig* sc)
01589 {
01590 if (sc == nullptr)
01591 return;
01592
01593 /* Cleanup the detection option tree */
01594 DetectionHashTableFree(sc->detection_option_hash_table);
01595 DetectionTreeHashTableFree(sc->detection_option_tree_hash_table);
01596
01597 fpFreeRuleMaps(sc);
01598 ServicePortGroupMapFree(sc->spgmmTable);
01599
01600 if ( sc->sopgTable )
01601 delete sc->sopgTable;
01602 }
01603
01604 static void print_nfp_info(const char* group, OptTreeNode* otn)
01605 {
01606 if ( otn->warned_fp )
01607 return;
01608
01609 ParseWarning(WARN_RULES, "%s rule %u:%u:%u has no fast pattern",
01610 group, otn->sigInfo.gid, otn->sigInfo.sid, otn->sigInfo.rev);
01611
01612 otn->warned_fp = true;
01613 }
01614
01615 void get_pattern_info(const PatternMatchData* pmd,
01616 const char* pattern, int pattern_length, string& hex, string& txt, string& opts)
01617 {
01618 char buf[8];
01619
01620 for ( int i = 0; i < pattern_length; ++i )
01621 {
01622 snprintf(buf, sizeof(buf), "%2.02X ", (uint8_t)pattern[i]);
01623 hex += buf;
01624 txt += isprint(pattern[i]) ? pattern[i] : '.';
01625 }
01626 opts = "(";
01627 if ( pmd->is_fast_pattern() )
01628 opts += " user";
01629 if ( pmd->fp_only > 0 )
01630 opts += " only";
01631 if ( pmd->is_negated() )
01632 opts += " negated";
01633 opts += " )";
01634 }
01635
01636 static void print_fp_info(const char* group, const OptTreeNode* otn, const PatternMatchData* pmd,
01637 const char* pattern, int pattern_length)
01638 {
01639 std::string hex, txt, opts;
01640
01641 get_pattern_info(pmd, pattern, pattern_length, hex, txt, opts);
01642 LogMessage("FP %s %u:%u:%u %s[%d] = '%s' |%s| %s\n",
01643 group, otn->sigInfo.gid, otn->sigInfo.sid, otn->sigInfo.rev,
01644 pm_type_strings[pmd->pm_type], pattern_length,
01645 txt.c_str(), hex.c_str(), opts.c_str());
01646 }
END OF CODE