From: Russ Combs (rucombs) Date: Thu, 13 Oct 2016 19:13:23 +0000 (-0400) Subject: Merge pull request #675 in SNORT/snort3 from fp2 to master X-Git-Tag: 3.0.0-233~223 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f59f364c4ea9f9893893014ed4b993e4cd654159;p=thirdparty%2Fsnort3.git Merge pull request #675 in SNORT/snort3 from fp2 to master Squashed commit of the following: commit 07080ae448c2b753c2f4eaff4a5667677ab58cac Author: Russ Combs Date: Tue Oct 11 14:25:26 2016 -0400 update snort2lua commit 740f8a84e44b8b97ca9e81de015337351450d206 Author: Russ Combs Date: Mon Oct 10 20:33:53 2016 -0400 fix fp selection bug commit 4a44c5b15948f3c5bdcd501392e15efbda3fc4ad Author: Russ Combs Date: Mon Oct 10 19:08:27 2016 -0400 establish baseline unit tests commit 510ab5e00a2a92f02635259eba942d118a91389d Author: Russ Combs Date: Mon Oct 10 14:56:21 2016 -0400 replace broken nfp counts with warnings; prepare to update fp selection commit c208ae14acbc421c48b520d9fb58e4fe7881f109 Author: Russ Combs Date: Sun Oct 9 11:49:38 2016 -0400 change search_engine.debug_print_fast_pattern to show_fast_patterns and cleanup commit 41355c5e489906752d2f128989cbe426575870f6 Author: Russ Combs Date: Sat Oct 8 21:21:57 2016 -0400 remove cruft and broken match counts commit 151f310c2088a87c1f25b19858d289c1435da62f Author: Russ Combs Date: Sat Oct 8 20:19:29 2016 -0400 refactor / clean up --- diff --git a/src/detection/CMakeLists.txt b/src/detection/CMakeLists.txt index 974b9d234..782c8816c 100644 --- a/src/detection/CMakeLists.txt +++ b/src/detection/CMakeLists.txt @@ -22,6 +22,8 @@ add_library (detection STATIC fp_create.h fp_detect.cc fp_detect.h + fp_utils.cc + fp_utils.h pcrm.cc pcrm.h service_map.cc diff --git a/src/detection/Makefile.am b/src/detection/Makefile.am index ea68ba291..e405d0b4c 100644 --- a/src/detection/Makefile.am +++ b/src/detection/Makefile.am @@ -24,6 +24,8 @@ fp_create.cc \ fp_create.h \ fp_detect.cc \ fp_detect.h \ +fp_utils.cc \ +fp_utils.h \ pcrm.cc \ pcrm.h \ service_map.cc \ diff --git a/src/detection/fp_create.cc b/src/detection/fp_create.cc index aff64df26..c20f46074 100644 --- a/src/detection/fp_create.cc +++ b/src/detection/fp_create.cc @@ -61,20 +61,23 @@ #include "rules.h" #include "treenodes.h" #include "fp_detect.h" +#include "fp_utils.h" #include "detection_options.h" #include "detection_defines.h" #include "sfrim.h" #include "pattern_match_data.h" static unsigned mpse_count = 0; +static const char* s_group = ""; static void fpDeletePMX(void* data); static int fpGetFinalPattern( FastPatternConfig*, PatternMatchData*, const char*& ret_pattern, int& ret_bytes); -static void PrintFastPatternInfo( - OptTreeNode*, PatternMatchData*, const char* pattern, int pattern_length); +static void print_nfp_info(const char*, const OptTreeNode*); +static void print_fp_info(const char*, const OptTreeNode*, const PatternMatchData*, + const char* pattern, int pattern_length); static const char* const pm_type_strings[PM_TYPE_MAX] = { @@ -291,7 +294,7 @@ static int add_patrn_to_neg_list(void* id, void** list) return -1; NCListNode** ncl = (NCListNode**)list; - NCListNode* node = (NCListNode*)snort_calloc(sizeof(NCListNode)); + NCListNode* node = (NCListNode*)snort_alloc(sizeof(NCListNode)); node->pmx = (PMX*)id; node->next = *ncl; @@ -325,7 +328,9 @@ static int pmx_create_tree(SnortConfig* sc, void* id, void** existing_tree) if (!id) { - assert(*existing_tree); + if ( !*existing_tree ) + return -1; + /* NULL input id (PMX *), last call for this pattern state */ return finalize_detection_option_tree(sc, (detection_option_tree_root_t*)*existing_tree); } @@ -339,282 +344,58 @@ static int pmx_create_tree(SnortConfig* sc, void* id, void** existing_tree) return otn_create_tree(otn, existing_tree); } -/* FLP_Trim - * Trim zero byte prefixes, this increases uniqueness - * will not alter regex since they can't contain bald \0 - * - * returns - * length - of trimmed pattern - * buff - ptr to new beggining of trimmed buffer - */ -static int FLP_Trim(const char* p, int plen, const char** buff) -{ - int i; - int size = 0; - - if ( !p ) - return 0; - - for (i=0; ican_be_fp(); -} - -struct FpFoo -{ - CursorActionType cat; - PatternMatchData* pmd; - int size; - - FpFoo() - { cat = CAT_NONE; pmd = nullptr; size = 0; } - - FpFoo(CursorActionType c, PatternMatchData* p) - { - cat = c; - pmd = p; - size = FLP_Trim(pmd->pattern_buf, pmd->pattern_size, nullptr); - } - - bool is_better(FpFoo& rhs) - { - if ( size && !rhs.size ) - return true; - - if ( !rhs.pmd ) - return true; - - if ( !pmd->negated && rhs.pmd->negated ) - return true; - - if ( cat > rhs.cat ) - return true; - - if ( cat < rhs.cat ) - return false; - - if ( size > rhs.size ) - return true; - - return false; - } -}; - -static PmType get_pm_type(CursorActionType cat) -{ - switch ( cat ) - { - case CAT_SET_RAW: - case CAT_SET_OTHER: - return PM_TYPE_PKT; - - case CAT_SET_BODY: - return PM_TYPE_BODY; - - case CAT_SET_HEADER: - return PM_TYPE_HEADER; - - case CAT_SET_KEY: - return PM_TYPE_KEY; - - case CAT_SET_FILE: - return PM_TYPE_FILE; - - default: - break; - } - assert(false); - return PM_TYPE_MAX; -} - -bool set_fp_content(OptTreeNode* otn) -{ - CursorActionType curr_cat = CAT_SET_RAW; - FpFoo best; - PatternMatchData* pmd = nullptr; - bool content = false; - bool fp_only = true; - - for (OptFpList* ofl = otn->opt_func; ofl; ofl = ofl->next) - { - if ( !ofl->ips_opt ) - continue; - - CursorActionType cat = ofl->ips_opt->get_cursor_type(); - - if ( cat > CAT_ADJUST ) - { - curr_cat = cat; - fp_only = !ofl->ips_opt->fp_research(); - } - - // Set rule direction - RuleDirection dir = RULE_WO_DIR; - if (OtnFlowFromServer(otn)) - dir = RULE_FROM_SERVER; - else if (OtnFlowFromClient(otn)) - dir = RULE_FROM_CLIENT; - - PatternMatchData* tmp = get_pmd(ofl, otn->proto, dir); - - if ( !tmp ) - continue; - - content = true; - - if ( !fp_only ) - tmp->fp_only = -1; - - tmp->pm_type = get_pm_type(curr_cat); - - if ( tmp->fp ) - { - if ( pmd ) - ParseWarning(WARN_RULES, - "only one fast_pattern content per rule allowed - ignored"); - - else if ( !pmd_can_be_fp(tmp, curr_cat) ) - ParseWarning(WARN_RULES, - "content ineligible for fast_pattern matcher - ignored"); - - else - pmd = tmp; - } - - if ( !pmd_can_be_fp(tmp, curr_cat) ) - continue; - - FpFoo curr(curr_cat, tmp); - - if ( curr.is_better(best) ) - best = curr; - } - if ( !pmd && best.pmd ) - { - pmd = best.pmd; - pmd->fp = 1; - } - - if ( best.pmd and otn->proto == SNORT_PROTO_FILE and best.cat != CAT_SET_FILE ) - { - ParseWarning(WARN_RULES, "file rule %u:%u does not have file_data fast pattern", - otn->sigInfo.generator, otn->sigInfo.id); - - best.pmd->fp = 0; - return false; - } - - if ( pmd ) - return true; - - if ( content ) - ParseWarning(WARN_RULES, "content based rule %u:%u has no fast pattern", - otn->sigInfo.generator, otn->sigInfo.id); - - return false; -} - -static PatternMatchData* get_fp_content(OptTreeNode* otn, OptFpList*& next) -{ - for (OptFpList* ofl = otn->opt_func; ofl; ofl = ofl->next) - { - if ( !ofl->ips_opt ) - continue; - - PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR); - - if ( !pmd ) - continue; - - next = ofl->next; - - if ( pmd->fp ) - return pmd; - } - return nullptr; -} - static int fpFinishPortGroupRule( SnortConfig* sc, PortGroup* pg, OptTreeNode* otn, PatternMatchData* pmd, FastPatternConfig* fp) { - const char* pattern; - int pattern_length; - if ( !pmd ) { pg->add_nfp_rule(otn); - return 0; /* Not adding any content to pattern matcher */ + print_nfp_info(s_group, otn); + return 0; } - else + if ( !pg->mpse[pmd->pm_type] ) { - if (pmd->negated) - pg->add_nfp_rule(otn); + static MpseAgent agent = + { + pmx_create_tree, add_patrn_to_neg_list, + fpDeletePMX, free_detection_option_root, neg_list_free + }; - else - pg->add_rule(); + pg->mpse[pmd->pm_type] = MpseManager::get_search_engine( + sc, fp->get_search_api(), true, &agent); - if (fpGetFinalPattern(fp, pmd, pattern, pattern_length) == -1) + if ( !pg->mpse[pmd->pm_type] ) + { + ParseError("Failed to create pattern matcher for %d", pmd->pm_type); return -1; + } + mpse_count++; - /* create pmx */ - PMX* pmx = (PMX*)snort_calloc(sizeof(PMX)); - pmx->rule_node.rnRuleData = otn; - pmx->pmd = pmd; + if ( fp->get_search_opt() ) + pg->mpse[pmd->pm_type]->set_opt(1); + } + if (pmd->negated) + pg->add_nfp_rule(otn); - if (fp->get_debug_print_fast_patterns()) - PrintFastPatternInfo(otn, pmd, pattern, pattern_length); + else + pg->add_rule(); - if ( !pg->mpse[pmd->pm_type] ) - { - static MpseAgent agent = - { - pmx_create_tree, add_patrn_to_neg_list, - fpDeletePMX, free_detection_option_root, neg_list_free - }; + const char* pattern; + int pattern_length; - pg->mpse[pmd->pm_type] = MpseManager::get_search_engine( - sc, fp->get_search_api(), true, &agent); + if (fpGetFinalPattern(fp, pmd, pattern, pattern_length) == -1) + return -1; - if ( !pg->mpse[pmd->pm_type] ) - { - ParseError("Failed to create pattern matcher for %d", pmd->pm_type); - return -1; - } - mpse_count++; + if ( fp->get_debug_print_fast_patterns() ) + print_fp_info(s_group, otn, pmd, pattern, pattern_length); - if ( fp->get_search_opt() ) - pg->mpse[pmd->pm_type]->set_opt(1); - } + PMX* pmx = (PMX*)snort_calloc(sizeof(PMX)); + pmx->rule_node.rnRuleData = otn; + pmx->pmd = pmd; - Mpse::PatternDescriptor desc(pmd->no_case, pmd->negated, pmd->literal, pmd->flags); - pg->mpse[pmd->pm_type]->add_pattern(sc, (uint8_t*)pattern, pattern_length, desc, pmx); - } + Mpse::PatternDescriptor desc(pmd->no_case, pmd->negated, pmd->literal, pmd->flags); + pg->mpse[pmd->pm_type]->add_pattern(sc, (uint8_t*)pattern, pattern_length, desc, pmx); return 0; } @@ -678,7 +459,7 @@ static int fpFinishPortGroup( } static int fpAddPortGroupRule( - SnortConfig* sc, PortGroup* pg, OptTreeNode* otn, FastPatternConfig* fp) + SnortConfig* sc, PortGroup* pg, OptTreeNode* otn, FastPatternConfig* fp, bool srvc) { PatternMatchData* pmd = NULL; @@ -691,9 +472,9 @@ static int fpAddPortGroupRule( return -1; OptFpList* next = nullptr; - pmd = get_fp_content(otn, next); + pmd = get_fp_content(otn, next, srvc); - if ( pmd && pmd->fp ) + if ( pmd ) { if ( !pmd->relative && !pmd->negated && pmd->fp_only >= 0 && @@ -713,16 +494,7 @@ static int fpAddPortGroupRule( } } - /* If we get this far then no URI contents were added */ - - if ( pmd && fpFinishPortGroupRule(sc, pg, otn, pmd, fp) == 0) - { - if (pmd->pattern_size > otn->longestPatternLen) - otn->longestPatternLen = pmd->pattern_size; - return 0; - } - - /* No content added */ + // no fast pattern added if (fpFinishPortGroupRule(sc, pg, otn, NULL, fp) != 0) return -1; @@ -988,7 +760,7 @@ static int fpGetFinalPattern( if ( fp->get_trim() ) { bytes = - FLP_Trim(pmd->pattern_buf, pmd->pattern_size, &pattern); + flp_trim(pmd->pattern_buf, pmd->pattern_size, &pattern); if (bytes < (int)pmd->pattern_size) { @@ -1091,6 +863,7 @@ static int fpCreatePortObject2PortGroup( /* create a port_group */ pg = (PortGroup*)snort_calloc(sizeof(PortGroup)); + s_group = "port"; /* * Walk the rules in the PortObject and add to @@ -1129,7 +902,7 @@ static int fpCreatePortObject2PortGroup( assert(otn); if ( is_network_protocol(otn->proto) ) - fpAddPortGroupRule(sc, pg, otn, fp); + fpAddPortGroupRule(sc, pg, otn, fp, false); } if (fp->get_debug_print_rule_group_build_details()) @@ -1393,6 +1166,7 @@ static void fpBuildServicePortGroupByServiceOtnList( { OptTreeNode* otn; PortGroup* pg = (PortGroup*)snort_calloc(sizeof(PortGroup)); + s_group = srvc; /* * add each rule to the port group pattern matchers, @@ -1404,7 +1178,7 @@ static void fpBuildServicePortGroupByServiceOtnList( otn; otn = (OptTreeNode*)sflist_next(&cursor)) { - if (fpAddPortGroupRule(sc, pg, otn, fp) != 0) + if (fpAddPortGroupRule(sc, pg, otn, fp, true) != 0) continue; } @@ -1812,119 +1586,16 @@ void fpDeleteFastPacketDetection(SnortConfig* sc) delete sc->sopgTable; } -/* -** Wrapper for prmShowEventStats -*/ -void fpShowEventStats(SnortConfig* sc) +static void print_nfp_info(const char* group, const OptTreeNode* otn) { - if ((sc == NULL) || (sc->fast_pattern_config == NULL)) - return; - - /* If not debug, then we don't print anything. */ - if (!sc->fast_pattern_config->get_debug_mode()) - return; - - LogMessage("\n"); - LogMessage("** IP Event Stats --\n"); - prmShowEventStats(sc->prmIpRTNX); - - LogMessage("\n"); - LogMessage("** ICMP Event Stats --\n"); - prmShowEventStats(sc->prmIcmpRTNX); - - LogMessage("\n"); - LogMessage("** TCP Event Stats --\n"); - prmShowEventStats(sc->prmTcpRTNX); - - LogMessage("\n"); - LogMessage("** UDP Event Stats --\n"); - prmShowEventStats(sc->prmUdpRTNX); + ParseWarning(WARN_RULES, "%s rule %u:%u:%u has no fast pattern", + group, otn->sigInfo.generator, otn->sigInfo.id, otn->sigInfo.rev); } -static const char* PatternRawToContent(const char* pattern, int pattern_len) -{ - static char content_buf[1024]; - int max_write_size = sizeof(content_buf) - 64; - int i, j = 0; - int hex = 0; - - if ((pattern == NULL) || (pattern_len <= 0)) - return ""; - - content_buf[j++] = '"'; - - for (i = 0; i < pattern_len; i++) - { - uint8_t c = (uint8_t)pattern[i]; - - if ((c < 128) && isprint(c) && !isspace(c) - && (c != '|') && (c != '"') && (c != ';')) - { - if (hex) - { - content_buf[j-1] = '|'; - hex = 0; - } - - content_buf[j++] = c; - } - else - { - uint8_t up4, lo4; - - if (!hex) - { - content_buf[j++] = '|'; - hex = 1; - } - - up4 = c >> 4; - lo4 = c & 0x0f; - - if (up4 > 0x09) - up4 += ('A' - 0x0a); - else - up4 += '0'; - - if (lo4 > 0x09) - lo4 += ('A' - 0x0a); - else - lo4 += '0'; - - content_buf[j++] = up4; - content_buf[j++] = lo4; - content_buf[j++] = ' '; - } - - if (j > max_write_size) - break; - } - - if (j > max_write_size) - { - content_buf[j] = 0; - SnortSnprintfAppend(content_buf, sizeof(content_buf), - " ... \" (pattern too large)"); - } - else - { - if (hex) - content_buf[j-1] = '|'; - - content_buf[j++] = '"'; - content_buf[j] = 0; - } - - return content_buf; -} - -static void PrintFastPatternInfo(OptTreeNode* otn, PatternMatchData* pmd, +static void print_fp_info( + const char* group, const OptTreeNode* otn, const PatternMatchData* pmd, const char* pattern, int pattern_length) { - if ((otn == NULL) || (pmd == NULL)) - return; - -#if 0 std::string hex, txt; char buf[8]; @@ -1934,48 +1605,15 @@ static void PrintFastPatternInfo(OptTreeNode* otn, PatternMatchData* pmd, hex += buf; txt += isprint(pattern[i]) ? pattern[i] : '.'; } - printf("fast pattern[%d] = x%s '%s'\n", pattern_length, hex.c_str(), txt.c_str()); -#else - LogMessage("%u:%u\n", otn->sigInfo.generator, otn->sigInfo.id); - LogMessage(" Fast pattern matcher: %s\n", pm_type_strings[pmd->pm_type]); - LogMessage(" Fast pattern set: %s\n", pmd->fp ? "yes" : "no"); - LogMessage(" Fast pattern only: %d\n", pmd->fp_only); - LogMessage(" Negated: %s\n", pmd->negated ? "yes" : "no"); - - /* Fast pattern only patterns don't use offset and length */ - if ((pmd->fp_length != 0) && pmd->fp_only <= 0) - { - LogMessage(" Pattern : %d,%d\n", - pmd->fp_offset, pmd->fp_length); - LogMessage(" %s\n", - PatternRawToContent(pmd->pattern_buf + pmd->fp_offset, - pmd->fp_length)); - } - else - { - LogMessage(" Pattern offset,length: none\n"); - } + std::string opts = "("; + if ( pmd->fp ) opts += " user"; + if ( pmd->fp_only ) opts += " only"; + if ( pmd->negated ) opts += " negated"; + opts += " )"; - /* Fast pattern only patterns don't get truncated */ - if ( pmd->fp_only <= 0 && - (((pmd->fp_length != 0) && (pmd->fp_length > pattern_length)) || - ((pmd->fp_length == 0) && ((int)pmd->pattern_size > pattern_length))) ) - { - LogMessage(" Pattern truncated: %d to %d bytes\n", - pmd->fp_length ? pmd->fp_length : pmd->pattern_size, - pattern_length); - } - else - { - LogMessage(" Pattern truncated: no\n"); - } - - LogMessage(" Original pattern\n"); - LogMessage(" %s\n", - PatternRawToContent(pmd->pattern_buf,pmd->pattern_size)); - - LogMessage(" Final pattern\n"); - LogMessage(" %s\n", PatternRawToContent(pattern, pattern_length)); -#endif + LogMessage("FP %s %u:%u:%u %s[%d] = '%s' |%s| %s\n", + group, otn->sigInfo.generator, otn->sigInfo.id, otn->sigInfo.rev, + pm_type_strings[pmd->pm_type], pattern_length, + txt.c_str(), hex.c_str(), opts.c_str()); } diff --git a/src/detection/fp_create.h b/src/detection/fp_create.h index b1f875c9b..e96ca261a 100644 --- a/src/detection/fp_create.h +++ b/src/detection/fp_create.h @@ -54,11 +54,7 @@ struct NCListNode int fpCreateFastPacketDetection(SnortConfig*); void fpDeleteFastPacketDetection(SnortConfig*); -void fpShowEventStats(SnortConfig*); - void fpDeletePortGroup(void*); -bool set_fp_content(struct OptTreeNode*); - #endif diff --git a/src/detection/fp_detect.cc b/src/detection/fp_detect.cc index a70c4cd9b..2df4da52c 100644 --- a/src/detection/fp_detect.cc +++ b/src/detection/fp_detect.cc @@ -425,17 +425,9 @@ static int rule_tree_match( } if ( ret ) - { - // We have a qualified event from this tree - pomd->pg->event_count++; pmqs.qualified_events++; - } else - { - // This means that the event is non-qualified. - pomd->pg->match_count++; pmqs.non_qualified_events++; - } } if (eval_data.flowbit_failed) @@ -511,6 +503,8 @@ static int sortOrderByPriority(const void* e1, const void* e2) return 0; } +// FIXIT-L pattern length is not a valid event sort criterion for +// non-literals static int sortOrderByContentLength(const void* e1, const void* e2) { OptTreeNode* otn1; @@ -1042,18 +1036,11 @@ static inline int fpEvalHeaderSW(PortGroup* port_group, Packet* p, } if (rval) - { - // We have a qualified event from this tree - port_group->event_count++; pmqs.qualified_events++; - } else - { - // This means that the event is non-qualified. - port_group->match_count++; pmqs.non_qualified_events++; - } - pc.slow_searches++; + + pc.hard_evals++; } // FIXIT-L need to eval all IP layers, etc. diff --git a/src/detection/fp_detect.h b/src/detection/fp_detect.h index da9236f83..957b429d5 100644 --- a/src/detection/fp_detect.h +++ b/src/detection/fp_detect.h @@ -33,7 +33,6 @@ #include "config.h" #endif -#include "detection/fp_create.h" #include "main/snort_debug.h" #include "protocols/packet.h" #include "utils/sflsq.h" @@ -41,6 +40,8 @@ #define REBUILD_FLAGS (PKT_REBUILT_FRAG | PKT_REBUILT_STREAM) struct ProfileStats; +struct OptTreeNode; +struct PortGroup; extern THREAD_LOCAL ProfileStats rulePerfStats; extern THREAD_LOCAL ProfileStats ruleRTNEvalPerfStats; @@ -51,11 +52,11 @@ extern THREAD_LOCAL ProfileStats ruleNFPEvalPerfStats; ** This is the only function that is needed to do an ** inspection on a packet. */ -int fpEvalPacket(Packet* p); +int fpEvalPacket(Packet*); struct RuleTreeNode; -int fpLogEvent(const RuleTreeNode* rtn, const OptTreeNode* otn, Packet* p); -int fpEvalRTN(RuleTreeNode* rtn, Packet* p, int check_ports); +int fpLogEvent(const RuleTreeNode*, const OptTreeNode*, Packet*); +int fpEvalRTN(RuleTreeNode*, Packet*, int check_ports); /* ** This define is for the number of unique events @@ -105,7 +106,7 @@ struct OTNX_MATCH_DATA void otnx_match_data_init(int); void otnx_match_data_term(); -int fpAddMatch(OTNX_MATCH_DATA* omd_local, int pLen, const OptTreeNode* otn); +int fpAddMatch(OTNX_MATCH_DATA*, int pLen, const OptTreeNode*); OptTreeNode* GetOTN(uint32_t gid, uint32_t sid); /* counter for number of times we evaluate rules. Used to diff --git a/src/detection/fp_utils.cc b/src/detection/fp_utils.cc new file mode 100644 index 000000000..bec326eab --- /dev/null +++ b/src/detection/fp_utils.cc @@ -0,0 +1,597 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2016-2016 Cisco and/or its affiliates. All rights reserved. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +#include "fp_utils.h" + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#ifdef UNIT_TEST +#include "catch/catch.hpp" +#endif + +#include "ips_options/ips_flow.h" +#include "log/messages.h" +#include "ports/port_group.h" +#include "target_based/snort_protocols.h" + +#include "pattern_match_data.h" +#include "treenodes.h" + +//-------------------------------------------------------------------------- +// private utilities +//-------------------------------------------------------------------------- + +static void finalize_content(OptFpList* ofl) +{ + PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR); + + if ( !pmd ) + return; + + if ( pmd->negated ) + pmd->last_check = (PmdLastCheck*)snort_calloc( + ThreadConfig::get_instance_max(), sizeof(*pmd->last_check)); +} + +static void clear_fast_pattern_only(OptFpList* ofl) +{ + PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR); + + if ( pmd && pmd->fp_only > 0 ) + pmd->fp_only = 0; +} + +static bool pmd_can_be_fp(PatternMatchData* pmd, CursorActionType cat) +{ + if ( cat <= CAT_SET_OTHER ) + return false; + + return pmd->can_be_fp(); +} + +static PmType get_pm_type(CursorActionType cat) +{ + switch ( cat ) + { + case CAT_SET_RAW: + case CAT_SET_OTHER: + return PM_TYPE_PKT; + + case CAT_SET_BODY: + return PM_TYPE_BODY; + + case CAT_SET_HEADER: + return PM_TYPE_HEADER; + + case CAT_SET_KEY: + return PM_TYPE_KEY; + + case CAT_SET_FILE: + return PM_TYPE_FILE; + + default: + break; + } + assert(false); + return PM_TYPE_MAX; +} + +static RuleDirection get_dir(OptTreeNode* otn) +{ + if ( OtnFlowFromServer(otn) ) + return RULE_FROM_SERVER; + + if ( OtnFlowFromClient(otn) ) + return RULE_FROM_CLIENT; + + return RULE_WO_DIR; +} + +//-------------------------------------------------------------------------- +// public utilities +//-------------------------------------------------------------------------- + +PatternMatchData* get_pmd(OptFpList* ofl, int proto, RuleDirection direction) +{ + if ( !ofl->ips_opt ) + return nullptr; + + return ofl->ips_opt->get_pattern(proto, direction); +} + +bool is_fast_pattern_only(OptFpList* ofl) +{ + PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR); + + if ( !pmd ) + return false; + + return pmd->fp_only > 0; +} + +/* + * Trim zero byte prefixes, this increases uniqueness + * will not alter regex since they can't contain bald \0 + * + * returns + * length - of trimmed pattern + * buff - ptr to new beggining of trimmed buffer + */ +int flp_trim(const char* p, int plen, const char** buff) +{ + int i; + int size = 0; + + if ( !p ) + return 0; + + for (i=0; iopt_func; fpl; fpl = fpl->next) + { + // a relative option is following a fast_pattern/only and + if ( relative_is_bad_mkay ) + { + if (fpl->isRelative) + { + assert(fp); + clear_fast_pattern_only(fp); + } + } + + // reset the check if one of these are present. + if ( fpl->ips_opt and !fpl->ips_opt->get_pattern(0)) + { + if ( fpl->ips_opt->get_cursor_type() > CAT_NONE ) + relative_is_bad_mkay = false; + } + // set/unset the check on content options. + else + { + if ( is_fast_pattern_only(fpl) ) + { + fp = fpl; + relative_is_bad_mkay = true; + } + else + relative_is_bad_mkay = false; + } + finalize_content(fpl); + } +} + +//-------------------------------------------------------------------------- +// class to help determine which of two candidate patterns is better for +// a rule that does not have a valid fast_pattern flag. +//-------------------------------------------------------------------------- + +struct FpSelector +{ + CursorActionType cat; + PatternMatchData* pmd; + int size; + + FpSelector(CursorActionType, PatternMatchData*); + + FpSelector() + { cat = CAT_NONE; pmd = nullptr; size = 0; } + + bool is_better_than(FpSelector&, bool, RuleDirection); +}; + +FpSelector::FpSelector(CursorActionType c, PatternMatchData* p) +{ + cat = c; + pmd = p; + + // FIXIT-H unconditional trim is bad mkay? see fpGetFinalPattern + size = flp_trim(pmd->pattern_buf, pmd->pattern_size, nullptr); +} + +bool FpSelector::is_better_than(FpSelector& rhs, bool srvc, RuleDirection dir) +{ + if ( !pmd_can_be_fp(pmd, cat) ) + { + if ( pmd->fp ) + { + ParseWarning(WARN_RULES, "content ineligible for fast_pattern matcher - ignored"); + pmd->fp = 0; + } + return false; + } + + if ( !rhs.pmd ) + return true; + + if ( !srvc ) + { + if ( cat == CAT_SET_RAW and rhs.cat != CAT_SET_RAW ) + return true; + + if ( cat != CAT_SET_RAW and rhs.cat == CAT_SET_RAW ) + return false; + } + else if ( dir == RULE_FROM_SERVER ) + { + if ( cat != CAT_SET_KEY and rhs.cat == CAT_SET_KEY ) + return true; + + if ( cat == CAT_SET_KEY and rhs.cat != CAT_SET_KEY ) + return false; + } + if ( pmd->fp ) + { + if ( rhs.pmd->fp ) + { + ParseWarning(WARN_RULES, + "only one fast_pattern content per rule allowed - using first"); + pmd->fp = 0; + } + return true; + } + if ( rhs.pmd->fp ) + return false; + + if ( !pmd->negated && rhs.pmd->negated ) + return true; + + if ( size > rhs.size ) + return true; + + return false; +} + +//-------------------------------------------------------------------------- +// public methods +//-------------------------------------------------------------------------- + +PatternMatchData* get_fp_content(OptTreeNode* otn, OptFpList*& next, bool srvc) +{ + CursorActionType curr_cat = CAT_SET_RAW; + FpSelector best; + bool content = false; + bool fp_only = true; + + for (OptFpList* ofl = otn->opt_func; ofl; ofl = ofl->next) + { + if ( !ofl->ips_opt ) + continue; + + CursorActionType cat = ofl->ips_opt->get_cursor_type(); + + if ( cat > CAT_ADJUST ) + { + curr_cat = cat; + fp_only = !ofl->ips_opt->fp_research(); + } + + RuleDirection dir = get_dir(otn); + PatternMatchData* tmp = get_pmd(ofl, otn->proto, dir); + + if ( !tmp ) + continue; + + content = true; + + if ( !fp_only ) + tmp->fp_only = -1; + + tmp->pm_type = get_pm_type(curr_cat); + + FpSelector curr(curr_cat, tmp); + + if ( curr.is_better_than(best, srvc, dir) ) + { + best = curr; + next = ofl->next; + } + } + + if ( best.pmd and otn->proto == SNORT_PROTO_FILE and best.cat != CAT_SET_FILE ) + { + ParseWarning(WARN_RULES, "file rule %u:%u does not have file_data fast pattern", + otn->sigInfo.generator, otn->sigInfo.id); + return nullptr; + } + + if ( best.pmd ) + return best.pmd; + + if ( content ) + ParseWarning(WARN_RULES, "content based rule %u:%u has no eligible fast pattern", + otn->sigInfo.generator, otn->sigInfo.id); + + return nullptr; +} + +//-------------------------------------------------------------------------- +// unit tests +//-------------------------------------------------------------------------- + +#ifdef UNIT_TEST +static void set_pmd(PatternMatchData& pmd, unsigned flags, const char* s) +{ + memset(&pmd, 0, sizeof(pmd)); + pmd.negated = (flags & 0x01) != 0; + pmd.no_case = (flags & 0x02) != 0; + pmd.relative = (flags & 0x04) != 0; + pmd.literal = (flags & 0x08) != 0; + pmd.fp = (flags & 0x10) != 0; + pmd.pattern_buf = s; + pmd.pattern_size = strlen(s); +} + +TEST_CASE("pmd_no_options", "[PatternMatchData]") +{ + PatternMatchData pmd; + set_pmd(pmd, 0x0, "foo"); + CHECK(pmd.can_be_fp()); +} + +TEST_CASE("pmd_negated", "[PatternMatchData]") +{ + PatternMatchData pmd; + set_pmd(pmd, 0x1, "foo"); + CHECK(!pmd.can_be_fp()); +} + +TEST_CASE("pmd_no_case", "[PatternMatchData]") +{ + PatternMatchData pmd; + set_pmd(pmd, 0x2, "foo"); + CHECK(pmd.can_be_fp()); +} + +TEST_CASE("pmd_relative", "[PatternMatchData]") +{ + PatternMatchData pmd; + set_pmd(pmd, 0x4, "foo"); + CHECK(pmd.can_be_fp()); +} + +TEST_CASE("pmd_negated_no_case", "[PatternMatchData]") +{ + PatternMatchData pmd; + set_pmd(pmd, 0x3, "foo"); + CHECK(pmd.can_be_fp()); +} + +TEST_CASE("pmd_negated_relative", "[PatternMatchData]") +{ + PatternMatchData pmd; + set_pmd(pmd, 0x5, "foo"); + CHECK(!pmd.can_be_fp()); +} + +TEST_CASE("pmd_negated_no_case_offset", "[PatternMatchData]") +{ + PatternMatchData pmd; + set_pmd(pmd, 0x1, "foo"); + pmd.offset = 3; + CHECK(!pmd.can_be_fp()); +} + +TEST_CASE("pmd_negated_no_case_depth", "[PatternMatchData]") +{ + PatternMatchData pmd; + set_pmd(pmd, 0x3, "foo"); + pmd.depth = 1; + CHECK(!pmd.can_be_fp()); +} + +TEST_CASE("fp_simple", "[FastPatternSelect]") +{ + FpSelector test; + PatternMatchData pmd; + set_pmd(pmd, 0x0, "foo"); + FpSelector left(CAT_SET_RAW, &pmd); + CHECK(left.is_better_than(test, false, RULE_WO_DIR)); + + test.size = 1; + CHECK(left.is_better_than(test, false, RULE_WO_DIR)); +} + +TEST_CASE("fp_negated", "[FastPatternSelect]") +{ + PatternMatchData p0; + set_pmd(p0, 0x0, "foo"); + FpSelector s0(CAT_SET_RAW, &p0); + + PatternMatchData p1; + set_pmd(p1, 0x1, "foo"); + FpSelector s1(CAT_SET_RAW, &p1); + + CHECK(s0.is_better_than(s1, false, RULE_WO_DIR)); + CHECK(!s1.is_better_than(s0, false, RULE_WO_DIR)); +} + +TEST_CASE("fp_cat1", "[FastPatternSelect]") +{ + PatternMatchData p0; + set_pmd(p0, 0x0, "longer"); + FpSelector s0(CAT_SET_FILE, &p0); + + PatternMatchData p1; + set_pmd(p1, 0x0, "short"); + FpSelector s1(CAT_SET_BODY, &p1); + + CHECK(s0.is_better_than(s1, true, RULE_WO_DIR)); +} + +TEST_CASE("fp_cat2", "[FastPatternSelect]") +{ + PatternMatchData p0; + set_pmd(p0, 0x0, "foo"); + FpSelector s0(CAT_SET_RAW, &p0); + + PatternMatchData p1; + set_pmd(p1, 0x0, "foo"); + FpSelector s1(CAT_SET_FILE, &p1); + + CHECK(s0.is_better_than(s1, false, RULE_WO_DIR)); + CHECK(!s1.is_better_than(s0, false, RULE_WO_DIR)); +} + +TEST_CASE("fp_cat3", "[FastPatternSelect]") +{ + PatternMatchData p0; + set_pmd(p0, 0x0, "foo"); + FpSelector s0(CAT_SET_RAW, &p0); + + PatternMatchData p1; + set_pmd(p1, 0x0, "foo"); + FpSelector s1(CAT_SET_FILE, &p1); + + CHECK(!s0.is_better_than(s1, true, RULE_WO_DIR)); +} + +TEST_CASE("fp_size", "[FastPatternSelect]") +{ + PatternMatchData p0; + set_pmd(p0, 0x0, "longer"); + FpSelector s0(CAT_SET_HEADER, &p0); + + PatternMatchData p1; + set_pmd(p1, 0x0, "short"); + FpSelector s1(CAT_SET_HEADER, &p1); + + CHECK(s0.is_better_than(s1, false, RULE_WO_DIR)); +} + +TEST_CASE("fp_pkt_key_port", "[FastPatternSelect]") +{ + PatternMatchData p0; + set_pmd(p0, 0x0, "short"); + FpSelector s0(CAT_SET_RAW, &p0); + + PatternMatchData p1; + set_pmd(p1, 0x0, "longer"); + FpSelector s1(CAT_SET_KEY, &p1); + + CHECK(s0.is_better_than(s1, false, RULE_WO_DIR)); +} + +TEST_CASE("fp_pkt_key_port_user", "[FastPatternSelect]") +{ + PatternMatchData p0; + set_pmd(p0, 0x10, "short"); + FpSelector s0(CAT_SET_KEY, &p0); + + PatternMatchData p1; + set_pmd(p1, 0x0, "longer"); + FpSelector s1(CAT_SET_KEY, &p1); + + CHECK(s0.is_better_than(s1, false, RULE_WO_DIR)); +} + +TEST_CASE("fp_pkt_key_port_user_user", "[FastPatternSelect]") +{ + PatternMatchData p0; + set_pmd(p0, 0x10, "short"); + FpSelector s0(CAT_SET_KEY, &p0); + + PatternMatchData p1; + set_pmd(p1, 0x10, "longer"); + FpSelector s1(CAT_SET_KEY, &p1); + + CHECK(s0.is_better_than(s1, false, RULE_WO_DIR)); +} + +TEST_CASE("fp_pkt_key_port_user_user2", "[FastPatternSelect]") +{ + PatternMatchData p0; + set_pmd(p0, 0x0, "longer"); + FpSelector s0(CAT_SET_KEY, &p0); + + PatternMatchData p1; + set_pmd(p1, 0x10, "short"); + FpSelector s1(CAT_SET_KEY, &p1); + + CHECK(!s0.is_better_than(s1, false, RULE_WO_DIR)); +} + +TEST_CASE("fp_pkt_key_srvc_1", "[FastPatternSelect]") +{ + PatternMatchData p0; + set_pmd(p0, 0x0, "short"); + FpSelector s0(CAT_SET_RAW, &p0); + + PatternMatchData p1; + set_pmd(p1, 0x0, "longer"); + FpSelector s1(CAT_SET_KEY, &p1); + + CHECK(s1.is_better_than(s0, true, RULE_WO_DIR)); +} + +TEST_CASE("fp_pkt_key_srvc_2", "[FastPatternSelect]") +{ + PatternMatchData p0; + set_pmd(p0, 0x0, "longer"); + FpSelector s0(CAT_SET_RAW, &p0); + + PatternMatchData p1; + set_pmd(p1, 0x0, "short"); + FpSelector s1(CAT_SET_KEY, &p1); + + CHECK(s0.is_better_than(s1, true, RULE_WO_DIR)); +} + +TEST_CASE("fp_pkt_key_srvc_rsp", "[FastPatternSelect]") +{ + PatternMatchData p0; + set_pmd(p0, 0x0, "short"); + FpSelector s0(CAT_SET_RAW, &p0); + + PatternMatchData p1; + set_pmd(p1, 0x0, "longer"); + FpSelector s1(CAT_SET_KEY, &p1); + + CHECK(s0.is_better_than(s1, true, RULE_FROM_SERVER)); + CHECK(!s1.is_better_than(s0, true, RULE_FROM_SERVER)); +} +#endif + diff --git a/src/detection/fp_utils.h b/src/detection/fp_utils.h new file mode 100644 index 000000000..1f4d07c4d --- /dev/null +++ b/src/detection/fp_utils.h @@ -0,0 +1,41 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2014-2016 Cisco and/or its affiliates. All rights reserved. +// Copyright (C) 2002-2013 Sourcefire, Inc. +// Copyright (C) 1998-2002 Martin Roesch +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License Version 2 as published +// by the Free Software Foundation. You may not use, modify or distribute +// this program under any other version of the GNU General Public License. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +//-------------------------------------------------------------------------- + +#ifndef FP_UTILS_H +#define FP_UTILS_H + +// fast pattern utilities + +#include "framework/ips_option.h" + +struct OptFpList; +struct OptTreeNode; + +struct PatternMatchData* get_pmd(OptFpList*, int proto, RuleDirection); +bool is_fast_pattern_only(OptFpList*); +void validate_fast_pattern(OptTreeNode*); + +int flp_trim(const char* p, int plen, const char** buff); +bool set_fp_content(OptTreeNode*); + +PatternMatchData* get_fp_content(OptTreeNode*, OptFpList*&, bool srvc); + +#endif + diff --git a/src/detection/pattern_match_data.h b/src/detection/pattern_match_data.h index 50f86ee03..4cad2b418 100644 --- a/src/detection/pattern_match_data.h +++ b/src/detection/pattern_match_data.h @@ -21,11 +21,15 @@ #ifndef PATTERN_MATCH_DATA_H #define PATTERN_MATCH_DATA_H +#include #include #include -#include "main/snort_types.h" #include "detection/treenodes.h" +#include "framework/ips_option.h" // FIXIT-L not a good dependency +#include "main/snort_types.h" +#include "main/thread_config.h" +#include "utils/util.h" struct PmdLastCheck { @@ -38,10 +42,10 @@ struct PatternMatchData { // used by both bool negated; // search for "not this pattern" - bool fp; // for fast_pattern arguments bool no_case; // toggle case sensitivity bool relative; // do relative pattern searching bool literal; // true for plain contents only + bool fp; // for fast_pattern arguments uint16_t fp_offset; uint16_t fp_length; @@ -100,5 +104,11 @@ inline bool PatternMatchData::can_be_fp() const return true; } +// pmd related utilities +struct OptFpList; + +PatternMatchData* get_pmd(OptFpList*, int proto, RuleDirection); +bool is_fast_pattern_only(OptFpList*); + #endif diff --git a/src/detection/pcrm.cc b/src/detection/pcrm.cc index 3e043d98a..7378438de 100644 --- a/src/detection/pcrm.cc +++ b/src/detection/pcrm.cc @@ -44,21 +44,6 @@ #include "main/snort_config.h" #include "utils/util.h" -/* -** -** NAME -** prmNewMap:: -** -** DESCRIPTION -** Allocate new PORT_RULE_MAP and return pointer. -** -** FORMAL INPUTS -** None -** -** FORMAL OUTPUT -** PORT_RULE_MAP * - NULL if failed, ptr otherwise. -** -*/ PORT_RULE_MAP* prmNewMap() { PORT_RULE_MAP* p = (PORT_RULE_MAP*)snort_calloc(sizeof(PORT_RULE_MAP)); @@ -66,10 +51,6 @@ PORT_RULE_MAP* prmNewMap() } /* -** -** NAME -** prmFindRuleGroup:: -** ** DESCRIPTION ** Given a PORT_RULE_MAP, this function selects the PortGroup or ** PortGroups necessary to fully match a given dport, sport pair. @@ -79,14 +60,6 @@ PORT_RULE_MAP* prmNewMap() ** both th src and dst PortGroup ptrs are set. If neither of the ** ports are unique, then the gen PortGroup ptr is set. ** -** FORMAL INPUTS -** PORT_RULE_MAP * - the PORT_RULE_MAP to pick PortGroups from. -** int - the dst port value (0->64K or -1 for generic) -** int - the src port value (0->64K or -1 for generic) -** PortGroup ** - the src PortGroup ptr to set. -** PortGroup ** - the dst PortGroup ptr to set. -** PortGroup ** - the generic PortGroup ptr to set. -** ** FORMAL OUTPUT ** int - 0: Don't evaluate ** 1: There are port groups to evaluate @@ -174,156 +147,3 @@ int prmFindRuleGroupUdp(PORT_RULE_MAP* prm, int dport, int sport, PortGroup** sr return prmFindRuleGroup(prm, dport, sport, src, dst, gen); } -int prmFindGenericRuleGroup(PORT_RULE_MAP* p, PortGroup** gen) -{ - if ( !p or !gen ) - { - return 0; - } - - *gen = NULL; - if ((p->prmGeneric != NULL) && (p->prmGeneric->rule_count > 0)) - { - if (snort_conf->fast_pattern_config->get_split_any_any()) - { - *gen = p->prmGeneric; - return 1; - } - } - return 0; -} - -/* -** Access each Rule group by index (0-MAX_PORTS) -*/ -static PortGroup* prmFindDstRuleGroup(PORT_RULE_MAP* p, int port) -{ - if ( port < 0 || port >= MAX_PORTS ) - return 0; - - if ( p->prmDstPort[port]) - return p->prmDstPort[port]; - - return 0; -} - -/* -** Access each Rule group by index (0-MAX_PORTS) -*/ -static PortGroup* prmFindSrcRuleGroup(PORT_RULE_MAP* p, int port) -{ - if ( port < 0 || port >= MAX_PORTS ) - return 0; - - if ( p->prmSrcPort[port]) - return p->prmSrcPort[port]; - - return 0; -} - -/* -** -** NAME -** prmShowEventStats:: -** -** DESCRIPTION -** This function is used at the close of the Fast Packet -** inspection. It tells how many non-qualified and qualified -** hits occurred for each PortGroup. A non-qualified hit -** is defined by an initial match against a packet, but upon -** further inspection a hit was not validated. Non-qualified -** hits occur because we can match on the most unique aspect -** of a packet, this is the content. Snort has other flags -** then content though, so once we hit a content match we must -** verify these additional flags. Sometimes these flags do -** not pass the validation. A qualified hit is an event that -** has been fully qualified, and has been put in the event -** cache for event selection. Qualified hits are not a subset -** of non-qualified hits. Ideally, non-qualified hits should -** be zero. The reason for these stats is that it allows -** users to trouble shoot PortGroups. A poorly written rule -** may cause many non-qualified events, and these stats -** allow the user to track this down. -** -** FORMAL INPUTS -** PORT_RULE_MAP * - the PORT_RULE_MAP to show stats on. -** -** FORMAL OUTPUT -** int - 0 is successful. -** -*/ -int prmShowEventStats(PORT_RULE_MAP* p) -{ - int i; - PortGroup* pg; - - int NQEvents = 0; - int QEvents = 0; - - LogMessage("Packet Classification Rule Manager Stats ----\n"); - LogMessage("NumDstGroups : %d\n",p->prmNumDstGroups); - LogMessage("NumSrcGroups : %d\n",p->prmNumSrcGroups); - LogMessage("\n"); - LogMessage("NumDstRules : %d\n",p->prmNumDstRules); - LogMessage("NumSrcRules : %d\n",p->prmNumSrcRules); - LogMessage("NumGenericRules: %d\n",p->prmNumGenericRules); - LogMessage("\n"); - - LogMessage("%d Dst Groups In Use, %d Unique Rules, includes generic\n",p->prmNumDstGroups, - p->prmNumDstRules); - for (i=0; imatch_count; - QEvents += pg->event_count; - - if ( pg->match_count + pg->event_count ) - { - LogMessage(" Dst Port %5d : %d group entries \n",i, pg->rule_count); - LogMessage(" NQ Events : %d\n", pg->match_count); - LogMessage(" Q Events : %d\n", pg->event_count); - } - } - } - - LogMessage("%d Src Groups In Use, %d Unique Rules, includes generic\n",p->prmNumSrcGroups, - p->prmNumSrcRules); - for (i=0; imatch_count; - QEvents += pg->event_count; - - if ( pg->match_count + pg->event_count ) - { - LogMessage(" Src Port %5d : %d group entries \n",i, pg->rule_count); - LogMessage(" NQ Events : %d\n", pg->match_count); - LogMessage(" Q Events : %d\n", pg->event_count); - } - } - } - - pg = p->prmGeneric; - if (pg) - { - NQEvents += pg->match_count; - QEvents += pg->event_count; - - if ( pg->match_count + pg->event_count ) - { - LogMessage(" Generic Rules : %d group entries\n", pg->rule_count); - LogMessage(" NQ Events : %d\n", pg->match_count); - LogMessage(" Q Events : %d\n", pg->event_count); - } - } - - LogMessage("Total NQ Events : %d\n", NQEvents); - LogMessage("Total Q Events : %d\n", QEvents); - - return 0; -} - diff --git a/src/detection/pcrm.h b/src/detection/pcrm.h index 8fee0f112..76a579ed0 100644 --- a/src/detection/pcrm.h +++ b/src/detection/pcrm.h @@ -50,10 +50,6 @@ struct PORT_RULE_MAP PORT_RULE_MAP* prmNewMap(); -int prmShowEventStats(PORT_RULE_MAP*); - -int prmFindGenericRuleGroup(PORT_RULE_MAP*, PortGroup**); - int prmFindRuleGroupTcp(PORT_RULE_MAP*, int, int, PortGroup**, PortGroup**, PortGroup**); int prmFindRuleGroupUdp(PORT_RULE_MAP*, int, int, PortGroup**, PortGroup**, PortGroup**); int prmFindRuleGroupIp(PORT_RULE_MAP*, int, PortGroup**, PortGroup**); diff --git a/src/detection/service_map.cc b/src/detection/service_map.cc index cab80f44f..6502dc9e3 100644 --- a/src/detection/service_map.cc +++ b/src/detection/service_map.cc @@ -40,14 +40,15 @@ #include #include -#include "log/messages.h" -#include "main/snort_config.h" #include "hash/sfghash.h" -#include "utils/sflsq.h" #include "ips_options/ips_flow.h" -#include "detection/treenodes.h" -#include "detection/fp_detect.h" +#include "log/messages.h" +#include "main/snort_config.h" #include "parser/parser.h" +#include "utils/sflsq.h" + +#include "fp_create.h" +#include "treenodes.h" //------------------------------------------------------------------------- // service map stuff diff --git a/src/framework/ips_option.h b/src/framework/ips_option.h index b31cea5a3..f2ad4600a 100644 --- a/src/framework/ips_option.h +++ b/src/framework/ips_option.h @@ -85,7 +85,7 @@ public: { return CAT_NONE; } // for fast-pattern options like content - virtual struct PatternMatchData* get_pattern(int /*proto*/, RuleDirection) + virtual struct PatternMatchData* get_pattern(int /*proto*/, RuleDirection = RULE_WO_DIR) { return nullptr; } static int eval(void* v, Cursor& c, Packet* p) diff --git a/src/framework/range.cc b/src/framework/range.cc index 6cfbbfffc..f2e295a06 100644 --- a/src/framework/range.cc +++ b/src/framework/range.cc @@ -19,6 +19,10 @@ #include "framework/range.h" +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + #include #include #include diff --git a/src/main/modules.cc b/src/main/modules.cc index 4b568d556..c0d3f4042 100644 --- a/src/main/modules.cc +++ b/src/main/modules.cc @@ -217,9 +217,6 @@ static const Parameter search_engine_params[] = { "debug_print_rule_groups_compiled", Parameter::PT_BOOL, nullptr, "false", "prints compiled rule group information" }, - { "debug_print_fast_pattern", Parameter::PT_BOOL, nullptr, "false", - "print fast pattern info for each rule" }, - { "max_pattern_len", Parameter::PT_INT, "0:", "0", "truncate patterns when compiling into state machine (0 means no maximum)" }, @@ -232,12 +229,15 @@ static const Parameter search_engine_params[] = { "search_method", Parameter::PT_DYNAMIC, (void*)&get_search_methods, "ac_bnfa", "set fast pattern algorithm - choose available search engine" }, - { "split_any_any", Parameter::PT_BOOL, nullptr, "false", - "evaluate any-any rules separately to save memory" }, - { "search_optimize", Parameter::PT_BOOL, nullptr, "true", "tweak state machine construction for better performance" }, + { "show_fast_patterns", Parameter::PT_BOOL, nullptr, "false", + "print fast pattern info for each rule" }, + + { "split_any_any", Parameter::PT_BOOL, nullptr, "false", + "evaluate any-any rules separately to save memory" }, + { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr } }; @@ -312,9 +312,6 @@ bool SearchEngineModule::set(const char*, Value& v, SnortConfig* sc) if ( v.get_bool() ) fp->set_debug_print_rule_groups_compiled(); } - else if ( v.is("debug_print_fast_pattern") ) - fp->set_debug_print_fast_patterns(v.get_bool()); - else if ( v.is("max_pattern_len") ) fp->set_max_pattern_len(v.get_long()); @@ -329,12 +326,15 @@ bool SearchEngineModule::set(const char*, Value& v, SnortConfig* sc) if ( !fp->set_detect_search_method(v.get_string()) ) return false; } - else if ( v.is("split_any_any") ) - fp->set_split_any_any(v.get_long()); - else if ( v.is("search_optimize") ) fp->set_search_opt(v.get_long()); + else if ( v.is("show_fast_patterns") ) + fp->set_debug_print_fast_patterns(v.get_bool()); + + else if ( v.is("split_any_any") ) + fp->set_split_any_any(v.get_long()); + else return false; diff --git a/src/parser/parse_rule.cc b/src/parser/parse_rule.cc index 5db2c8106..af65c8f24 100644 --- a/src/parser/parse_rule.cc +++ b/src/parser/parse_rule.cc @@ -50,6 +50,7 @@ #include "detection/signature.h" #include "detection/fp_config.h" #include "detection/fp_create.h" +#include "detection/fp_utils.h" #include "detection/pattern_match_data.h" #include "detection/sfrim.h" #include "main/snort_debug.h" @@ -76,9 +77,6 @@ #include "managers/so_manager.h" #include "target_based/snort_protocols.h" -#define RULE_DIR_OPT__DIRECTIONAL "->" -#define RULE_DIR_OPT__BIDIRECTIONAL "<>" - #define SRC 0 #define DST 1 @@ -87,9 +85,8 @@ struct rule_count_t { int src; int dst; - int any; /* any-any */ - int both; /* src+dst ports specified */ - int nfp; /* no content */ + int any; + int both; }; static int rule_count = 0; @@ -123,7 +120,7 @@ static bool s_ignore = false; // for skipping drop rules when not inline, etc. */ static int FinishPortListRule( RulePortTables* port_tables, RuleTreeNode* rtn, OptTreeNode* otn, - int proto, bool has_fp, FastPatternConfig* fp) + int proto, FastPatternConfig* fp) { int large_port_group = 0; int src_cnt = 0; @@ -191,10 +188,6 @@ static int FinishPortListRule( * and use as reference in Port Objects */ rim_index = otn->ruleIndex; - /* Add up the nfp rules */ - if ( !has_fp ) - prc->nfp++; - /* If not an any-any rule test for port bleedover, if we are using a * single rule group, don't bother */ if (!fp->get_single_rule_group() && @@ -291,20 +284,16 @@ static int FinishPortListRule( /* add rule index to dst table if we have a specific dst port or port list */ if (!(rtn->flags & ANY_DST_PORT)) { - PortObject* pox; - prc->dst++; - - DebugMessage(DEBUG_PORTLISTS, - "Finishing rule: dst port rule\n"); + DebugMessage(DEBUG_PORTLISTS, "Finishing rule: dst port rule\n"); /* find the proper port object */ - pox = PortTableFindInputPortObjectPorts(dstTable, rtn->dst_portobject); - if (pox == NULL) + PortObject* pox = PortTableFindInputPortObjectPorts(dstTable, rtn->dst_portobject); + if ( !pox ) { /* Create a permanent port object */ pox = PortObjectDupPorts(rtn->dst_portobject); - if (pox == NULL) + if ( !pox ) { ParseError("could not dup a port object - out of memory."); return -1; @@ -320,10 +309,10 @@ static int FinishPortListRule( if (rtn->flags & BIDIRECTIONAL) { pox = PortTableFindInputPortObjectPorts(srcTable, rtn->dst_portobject); - if (pox == NULL) + if ( !pox ) { pox = PortObjectDupPorts(rtn->dst_portobject); - if (pox == NULL) + if ( !pox ) { ParseError("could not dup a bidir-port object - out of memory."); return -1; @@ -339,20 +328,17 @@ static int FinishPortListRule( /* add rule index to src table if we have a specific src port or port list */ if (!(rtn->flags & ANY_SRC_PORT)) { - PortObject* pox; - prc->src++; + PortObject* pox = PortTableFindInputPortObjectPorts(srcTable, rtn->src_portobject); - pox = PortTableFindInputPortObjectPorts(srcTable, rtn->src_portobject); - if (pox == NULL) + if ( !pox ) { pox = PortObjectDupPorts(rtn->src_portobject); - if (pox == NULL) + if ( !pox ) { ParseError("could not dup a port object - out of memory."); return -1; } - PortTableAddObject(srcTable, pox); } @@ -362,10 +348,10 @@ static int FinishPortListRule( if (rtn->flags & BIDIRECTIONAL) { pox = PortTableFindInputPortObjectPorts(dstTable, rtn->src_portobject); - if (pox == NULL) + if ( !pox ) { pox = PortObjectDupPorts(rtn->src_portobject); - if (pox == NULL) + if ( !pox ) { ParseError("could not dup a bidir-port object - out of memory."); return -1; @@ -373,11 +359,9 @@ static int FinishPortListRule( PortTableAddObject(dstTable, pox); } - PortObjectAddRule(pox, rim_index); } } - return 0; } @@ -389,7 +373,6 @@ static int ValidateIPList(sfip_var_t* addrset, const char* token) "destination IP in a rule. IP list: %s.", token); return -1; } - return 0; } @@ -407,16 +390,13 @@ static int ProcessIP( { int ret; - if (rtn->sip == NULL) + if ( !rtn->sip ) { sfip_var_t* tmp = sfvt_lookup_var(ip_vartable, addr); - if (tmp != NULL) + if ( tmp ) { rtn->sip = sfvar_create_alias(tmp, tmp->name); - if (rtn->sip == NULL) - ret = SFIP_FAILURE; - else - ret = SFIP_SUCCESS; + ret = rtn->sip ? SFIP_SUCCESS : SFIP_FAILURE; } else { @@ -466,16 +446,13 @@ static int ProcessIP( { int ret; - if (rtn->dip == NULL) + if ( !rtn->dip ) { sfip_var_t* tmp = sfvt_lookup_var(ip_vartable, addr); - if (tmp != NULL) + if ( tmp ) { rtn->dip = sfvar_create_alias(tmp, tmp->name); - if (rtn->dip == NULL) - ret = SFIP_FAILURE; - else - ret = SFIP_SUCCESS; + ret = rtn->dip ? SFIP_SUCCESS : SFIP_FAILURE; } else { @@ -536,7 +513,6 @@ static int ProcessIP( * * These should not be confused with the port objects used to merge ports and rules * to build port group objects. Those are generated after the otn processing. -* */ static PortObject* ParsePortListTcpUdpPort( PortVarTable* pvt, PortTable* noname, const char* port_str) @@ -544,14 +520,14 @@ static PortObject* ParsePortListTcpUdpPort( PortObject* portobject; POParser poparser; - if ((pvt == NULL) || (noname == NULL) || (port_str == NULL)) - return NULL; + if ( !pvt or !noname or !port_str ) + return nullptr; /* 1st - check if we have an any port */ if ( strcasecmp(port_str,"any")== 0 ) { portobject = PortVarTableFind(pvt, "any"); - if (portobject == NULL) + if ( !portobject ) ParseAbort("PortVarTable missing an 'any' variable."); return portobject; @@ -566,7 +542,7 @@ static PortObject* ParsePortListTcpUdpPort( /* look it up in the port var table */ portobject = PortVarTableFind(pvt, name); - if (portobject == NULL) + if ( !portobject ) ParseAbort("***PortVar Lookup failed on '%s'.", port_str); DebugFormat(DEBUG_PORTLISTS,"PortVarTableFind: '%s' found!\n", port_str); @@ -640,7 +616,7 @@ static int ParsePortList( RuleTreeNode* rtn, PortVarTable* pvt, PortTable* noname, const char* port_str, int dst_flag) { - PortObject* portobject = NULL; /* src or dst */ + PortObject* portobject; /* src or dst */ /* Get the protocol specific port object */ if ( rule_proto & (PROTO_BIT__TCP | PROTO_BIT__UDP) ) @@ -650,7 +626,7 @@ static int ParsePortList( else /* ICMP, IP - no real ports just Type and Protocol */ { portobject = PortVarTableFind(pvt, "any"); - if (portobject == NULL) + if ( !portobject ) { ParseError("PortVarTable missing an 'any' variable."); return -1; @@ -698,141 +674,97 @@ static int ParsePortList( return 0; } -/**************************************************************************** - * - * Function: TestHeader(RuleTreeNode *, RuleTreeNode *) - * - * Purpose: Check to see if the two header blocks are identical - * - * Arguments: rule => uh - * rtn => uuuuhhhhh.... - * - * Returns: 1 if they match, 0 if they don't - * - ***************************************************************************/ -static int TestHeader(RuleTreeNode* rule, RuleTreeNode* rtn) +static bool same_headers(RuleTreeNode* rule, RuleTreeNode* rtn) { - if ((rule == NULL) || (rtn == NULL)) - return 0; + if ( !rule or !rtn ) + return false; if (rule->type != rtn->type) - return 0; + return false; if (rule->proto != rtn->proto) - return 0; + return false; /* For custom rule type declarations */ if (rule->listhead != rtn->listhead) - return 0; + return false; if (rule->flags != rtn->flags) - return 0; + return false; - if ((rule->sip != NULL) && (rtn->sip != NULL) && - (sfvar_compare(rule->sip, rtn->sip) != SFIP_EQUAL)) - { - return 0; - } + if ( rule->sip and rtn->sip and sfvar_compare(rule->sip, rtn->sip) != SFIP_EQUAL ) + return false; - if ((rule->dip != NULL) && (rtn->dip != NULL) && - (sfvar_compare(rule->dip, rtn->dip) != SFIP_EQUAL)) - { - return 0; - } + if ( rule->dip and rtn->dip and sfvar_compare(rule->dip, rtn->dip) != SFIP_EQUAL ) + return false; /* compare the port group pointers - this prevents confusing src/dst port objects * with the same port set, and it's quicker. It does assume that we only have * one port object and pointer for each unique port set...this is handled by the * parsing and initial port object storage and lookup. This must be consistent during * the rule parsing phase. - man */ - if ((rule->src_portobject != rtn->src_portobject) - || (rule->dst_portobject != rtn->dst_portobject)) + if ( (rule->src_portobject != rtn->src_portobject) + or (rule->dst_portobject != rtn->dst_portobject)) { - return 0; + return false; } - - return 1; + return true; } -/**returns matched header node. -*/ static RuleTreeNode* findHeadNode( - SnortConfig* sc, RuleTreeNode* testNode, - PolicyId policyId) + SnortConfig* sc, RuleTreeNode* testNode, PolicyId policyId) { - RuleTreeNode* rtn; - OptTreeNode* otn; SFGHASH_NODE* hashNode; for (hashNode = sfghash_findfirst(sc->otn_map); hashNode; hashNode = sfghash_findnext(sc->otn_map)) { - otn = (OptTreeNode*)hashNode->data; - rtn = getRtnFromOtn(otn, policyId); + OptTreeNode* otn = (OptTreeNode*)hashNode->data; + RuleTreeNode* rtn = getRtnFromOtn(otn, policyId); - if (TestHeader(rtn, testNode)) + if (same_headers(rtn, testNode)) return rtn; } - return NULL; + return nullptr; } -/**************************************************************************** - * - * Function: XferHeader(RuleTreeNode *, RuleTreeNode *) - * - * Purpose: Transfer the rule block header data from point A to point B - * - * Arguments: rule => the place to xfer from - * rtn => the place to xfer to - * - * Returns: void function - * - ***************************************************************************/ -static void XferHeader(RuleTreeNode* test_node, RuleTreeNode* rtn) +static void XferHeader(RuleTreeNode* from, RuleTreeNode* to) { - rtn->flags = test_node->flags; - rtn->type = test_node->type; - rtn->sip = test_node->sip; - rtn->dip = test_node->dip; + to->flags = from->flags; + to->type = from->type; + to->sip = from->sip; + to->dip = from->dip; - rtn->proto = test_node->proto; + to->proto = from->proto; - rtn->src_portobject = test_node->src_portobject; - rtn->dst_portobject = test_node->dst_portobject; + to->src_portobject = from->src_portobject; + to->dst_portobject = from->dst_portobject; } /**************************************************************************** - * - * Function: AddRuleFuncToList(int (*func)(), RuleTreeNode *) - * * Purpose: Adds RuleTreeNode associated detection functions to the * current rule's function list * * Arguments: *func => function pointer to the detection function * rtn => pointer to the current rule - * - * Returns: void function - * ***************************************************************************/ static void AddRuleFuncToList( int (* rfunc)(Packet*, RuleTreeNode*, struct RuleFpList*, int), RuleTreeNode* rtn) { - RuleFpList* idx; - DebugMessage(DEBUG_CONFIGRULES,"Adding new rule to list\n"); + RuleFpList* idx = rtn->rule_func; - idx = rtn->rule_func; - if (idx == NULL) + if ( !idx ) { rtn->rule_func = (RuleFpList*)snort_calloc(sizeof(RuleFpList)); rtn->rule_func->RuleHeadFunc = rfunc; } else { - while (idx->next != NULL) + while ( idx->next ) idx = idx->next; idx->next = (RuleFpList*)snort_calloc(sizeof(RuleFpList)); @@ -842,18 +774,12 @@ static void AddRuleFuncToList( } /**************************************************************************** - * - * Function: AddrToFunc(RuleTreeNode *, u_long, u_long, int, int) - * * Purpose: Links the proper IP address testing function to the current RTN * based on the address, netmask, and addr flags * * Arguments: rtn => the pointer to the current rules list entry to attach to * mode => indicates whether this is a rule for the source * or destination IP for the rule - * - * Returns: void function - * ***************************************************************************/ static void AddrToFunc(RuleTreeNode* rtn, int mode) { @@ -869,7 +795,6 @@ static void AddrToFunc(RuleTreeNode* rtn, int mode) DebugMessage(DEBUG_CONFIGRULES,"CheckSrcIP -> "); AddRuleFuncToList(CheckSrcIP, rtn); } - break; case DST: @@ -878,15 +803,11 @@ static void AddrToFunc(RuleTreeNode* rtn, int mode) DebugMessage(DEBUG_CONFIGRULES,"CheckDstIP -> "); AddRuleFuncToList(CheckDstIP, rtn); } - break; } } /**************************************************************************** - * - * Function: PortToFunc(RuleTreeNode *, int, int, int) - * * Purpose: Links in the port analysis function for the current rule * * Arguments: rtn => the pointer to the current rules list entry to attach to @@ -894,9 +815,6 @@ static void AddrToFunc(RuleTreeNode* rtn, int mode) * except_flag => indicates negation (logical NOT) of the test * mode => indicates whether this is a rule for the source * or destination port for the rule - * - * Returns: void function - * ***************************************************************************/ static void PortToFunc(RuleTreeNode* rtn, int any_flag, int except_flag, int mode) { @@ -940,18 +858,8 @@ static void PortToFunc(RuleTreeNode* rtn, int any_flag, int except_flag, int mod } } -/**************************************************************************** - * - * Function: SetupRTNFuncList(RuleTreeNode *) - * - * Purpose: Configures the function list for the rule header detection - * functions (addrs and ports) - * - * Arguments: rtn => the pointer to the current rules list entry to attach to - * - * Returns: void function - * - ***************************************************************************/ +// Configures the function list for the rule header detection +// functions (addrs and ports) static void SetupRTNFuncList(RuleTreeNode* rtn) { DebugMessage(DEBUG_CONFIGRULES,"Initializing RTN function list!\n"); @@ -990,20 +898,7 @@ static void SetupRTNFuncList(RuleTreeNode* rtn) AddRuleFuncToList(RuleListEnd, rtn); } -/**************************************************************************** - * - * Function: ProcessHeadNode(RuleTreeNode *, ListHead *, int) - * - * Purpose: Process the header block info and add to the block list if - * necessary - * - * Arguments: test_node => data generated by the rules parsers - * list => List Block Header refernece - * protocol => ip protocol - * - * Returns: void function - * - ***************************************************************************/ +// Process the header block info and add to the block list if necessary static RuleTreeNode* ProcessHeadNode( SnortConfig* sc, RuleTreeNode* test_node, ListHead* list) { @@ -1012,7 +907,7 @@ static RuleTreeNode* ProcessHeadNode( /* if it doesn't match any of the existing nodes, make a new node and * stick it at the end of the list */ - if (rtn == NULL) + if ( !rtn ) { DebugMessage(DEBUG_CONFIGRULES,"Building New Chain head node\n"); head_count++; @@ -1041,64 +936,45 @@ static RuleTreeNode* ProcessHeadNode( return rtn; } -/**************************************************************************** - * - * Function: mergeDuplicateOtn() - * - * Purpose: Conditionally removes duplicate SID/GIDs. Keeps duplicate with - * higher revision. If revision is the same, keeps newest rule. - * - * Arguments: otn_cur => The current version - * rtn => the RTN chain to check - * char => String describing the rule - * - * Returns: 0 if original rule stays, 1 if new rule stays - * - ***************************************************************************/ +// Conditionally removes duplicate SID/GIDs. Keeps duplicate with +// higher revision. If revision is the same, keeps newest rule. static int mergeDuplicateOtn( SnortConfig* sc, OptTreeNode* otn_cur, OptTreeNode* otn_new, RuleTreeNode* rtn_new) { - RuleTreeNode* rtn_cur = NULL; - RuleTreeNode* rtnTmp2 = NULL; - unsigned i; - if (otn_cur->proto != otn_new->proto) { - ParseError("GID %u SID %u in rule duplicates previous rule, with " - "different protocol.", + ParseError("GID %u SID %u in rule duplicates previous rule, with different protocol.", otn_new->sigInfo.generator, otn_new->sigInfo.id); - return 0; + return true; } - rtn_cur = getRtnFromOtn(otn_cur); + RuleTreeNode* rtn_cur = getRtnFromOtn(otn_cur); - if ((rtn_cur != NULL) && (rtn_cur->type != rtn_new->type)) + if ( rtn_cur and rtn_cur->type != rtn_new->type ) { - ParseError("GID %u SID %u in rule duplicates previous rule, with " - "different type.", + ParseError("GID %u SID %u in rule duplicates previous rule, with different type.", otn_new->sigInfo.generator, otn_new->sigInfo.id); - return 0; + return true; } if ( otn_new->sigInfo.rev < otn_cur->sigInfo.rev ) { - //current OTN is newer version. Keep current and discard the new one. - //OTN is for new policy group, salvage RTN + // current OTN is newer version. Keep current and discard the new one. + // OTN is for new policy group, salvage RTN deleteRtnFromOtn(otn_new); - ParseWarning(WARN_RULES, - "%u:%u duplicates previous rule. Using revision %u.", + ParseWarning(WARN_RULES, "%u:%u duplicates previous rule. Using revision %u.", otn_cur->sigInfo.generator, otn_cur->sigInfo.id, otn_cur->sigInfo.rev); - /* Now free the OTN itself -- this function is also used - * by the hash-table calls out of OtnRemove, so it cannot - * be modified to delete data for rule options */ + // Now free the OTN itself -- this function is also used + // by the hash-table calls out of OtnRemove, so it cannot + // be modified to delete data for rule options OtnFree(otn_new); - //Add rtn to current otn for the first rule instance in a policy, - //otherwise ignore it - if (rtn_cur == NULL) + // Add rtn to current otn for the first rule instance in a policy, + // otherwise ignore it + if ( !rtn_cur ) { addRtnToOtn(otn_cur, rtn_new); } @@ -1106,17 +982,16 @@ static int mergeDuplicateOtn( { DestroyRuleTreeNode(rtn_new); } - - return 0; + return true; } - //delete current rule instance and keep the new one + // delete current rule instance and keep the new one - for (i = 0; i < otn_cur->proto_node_num; i++) + for ( unsigned i = 0; i < otn_cur->proto_node_num; ++i ) { - rtnTmp2 = deleteRtnFromOtn(otn_cur, i); + RuleTreeNode* rtnTmp2 = deleteRtnFromOtn(otn_cur, i); - if (rtnTmp2 && (i != get_ips_policy()->policy_id)) + if ( rtnTmp2 and (i != get_ips_policy()->policy_id) ) { addRtnToOtn(otn_new, rtnTmp2, i); } @@ -1126,98 +1001,20 @@ static int mergeDuplicateOtn( { if (SnortConfig::conf_error_out()) { - ParseError( - "%u:%u:%u duplicates previous rule.", + ParseError("%u:%u:%u duplicates previous rule.", otn_new->sigInfo.generator, otn_new->sigInfo.id, otn_new->sigInfo.rev); - return 0; + return true; } else { - ParseWarning(WARN_RULES, - "%u:%u duplicates previous rule. Using revision %u.", + ParseWarning(WARN_RULES, "%u:%u duplicates previous rule. Using revision %u.", otn_new->sigInfo.generator, otn_new->sigInfo.id, otn_new->sigInfo.rev); } } OtnRemove(sc->otn_map, otn_cur); DestroyRuleTreeNode(rtn_cur); - return 1; -} - -PatternMatchData* get_pmd(OptFpList* ofl, int proto, RuleDirection direction) -{ - if ( !ofl->ips_opt ) - return nullptr; - - return ofl->ips_opt->get_pattern(proto, direction); -} - -static void finalize_content(OptFpList* ofl) -{ - PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR); - - if ( !pmd ) - return; - - if ( pmd->negated ) - pmd->last_check = (PmdLastCheck*)snort_calloc( - ThreadConfig::get_instance_max(), sizeof(*pmd->last_check)); -} - -bool is_fast_pattern_only(OptFpList* ofl) -{ - PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR); - - if ( !pmd ) - return false; - - return pmd->fp_only > 0; -} - -static void clear_fast_pattern_only(OptFpList* ofl) -{ - PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR); - - if ( pmd && pmd->fp_only > 0 ) - pmd->fp_only = 0; -} - -static void ValidateFastPattern(OptTreeNode* otn) -{ - OptFpList* fp = nullptr; - bool relative_is_bad_mkay = false; - - for (OptFpList* fpl = otn->opt_func; fpl; fpl = fpl->next) - { - // a relative option is following a fast_pattern/only and - if ( relative_is_bad_mkay ) - { - if (fpl->isRelative) - { - assert(fp); - clear_fast_pattern_only(fp); - } - } - - // reset the check if one of these are present. - if ( fpl->ips_opt and !fpl->ips_opt->get_pattern(0, RULE_WO_DIR)) - { - if ( fpl->ips_opt->get_cursor_type() > CAT_NONE ) - relative_is_bad_mkay = false; - } - // set/unset the check on content options. - else - { - if ( is_fast_pattern_only(fpl) ) - { - fp = fpl; - relative_is_bad_mkay = true; - } - else - relative_is_bad_mkay = false; - } - finalize_content(fpl); - } + return false; } int get_rule_count() @@ -1256,10 +1053,10 @@ void parse_rule_print() LogCount("option chains", otn_count); LogCount("chain headers", head_count); - unsigned ip = ipCnt.src + ipCnt.dst + ipCnt.any + ipCnt.both + ipCnt.nfp; - unsigned icmp = icmpCnt.src + icmpCnt.dst + icmpCnt.any + icmpCnt.both + icmpCnt.nfp; - unsigned tcp = tcpCnt.src + tcpCnt.dst + tcpCnt.any + tcpCnt.both + tcpCnt.nfp; - unsigned udp = udpCnt.src + udpCnt.dst + udpCnt.any + udpCnt.both + udpCnt.nfp; + unsigned ip = ipCnt.src + ipCnt.dst + ipCnt.any + ipCnt.both; + unsigned icmp = icmpCnt.src + icmpCnt.dst + icmpCnt.any + icmpCnt.both; + unsigned tcp = tcpCnt.src + tcpCnt.dst + tcpCnt.any + tcpCnt.both; + unsigned udp = udpCnt.src + udpCnt.dst + udpCnt.any + udpCnt.both; if ( !ip and !icmp and !tcp and !udp ) return; @@ -1283,10 +1080,6 @@ void parse_rule_print() LogMessage("%8s%8u%8u%8u%8u\n", "both", tcpCnt.both, udpCnt.both, icmpCnt.both, ipCnt.both); - if ( tcpCnt.nfp || udpCnt.nfp || icmpCnt.nfp || ipCnt.nfp ) - LogMessage("%8s%8u%8u%8u%8u\n", "slow", - tcpCnt.nfp, udpCnt.nfp, icmpCnt.nfp, ipCnt.nfp); - LogMessage("%8s%8u%8u%8u%8u\n", "total", tcp, udp, icmp, ip); } @@ -1368,10 +1161,10 @@ void parse_rule_dir(SnortConfig*, const char* s, RuleTreeNode& rtn) if ( s_ignore ) return; - if (strcmp(s, RULE_DIR_OPT__BIDIRECTIONAL) == 0) + if (strcmp(s, "<>") == 0) rtn.flags |= BIDIRECTIONAL; - else if ( strcmp(s, RULE_DIR_OPT__DIRECTIONAL) ) + else if ( strcmp(s, "->") ) ParseError("illegal direction specifier: %s", s); } @@ -1465,8 +1258,6 @@ const char* parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* ot } } - bool has_fp = set_fp_content(otn); - /* The IPs in the test node get free'd in ProcessHeadNode if there is * already a matching RTN. The portobjects will get free'd when the * port var table is free'd */ @@ -1481,7 +1272,7 @@ const char* parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* ot { otn->ruleIndex = otn_dup->ruleIndex; - if (mergeDuplicateOtn(sc, otn_dup, otn, new_rtn) == 0) + if ( mergeDuplicateOtn(sc, otn_dup, otn, new_rtn) ) { /* We are keeping the old/dup OTN and trashing the new one * we just created - it's free'd in the remove dup function */ @@ -1524,7 +1315,7 @@ const char* parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* ot OptFpList* fpl = AddOptFuncToList(OptListEnd, otn); fpl->type = RULE_OPTION_TYPE_LEAF_NODE; - ValidateFastPattern(otn); + validate_fast_pattern(otn); OtnLookupAdd(sc->otn_map, otn); if ( is_service_protocol(otn->proto) ) @@ -1537,7 +1328,7 @@ const char* parse_rule_close(SnortConfig* sc, RuleTreeNode& rtn, OptTreeNode* ot * After otn processing we can finalize port object processing for this rule */ if ( FinishPortListRule( - sc->port_tables, new_rtn, otn, rtn.proto, has_fp, sc->fast_pattern_config) ) + sc->port_tables, new_rtn, otn, rtn.proto, sc->fast_pattern_config) ) ParseError("Failed to finish a port list rule."); return nullptr; diff --git a/src/ports/port_group.cc b/src/ports/port_group.cc index 0f2b15325..f64e9f253 100644 --- a/src/ports/port_group.cc +++ b/src/ports/port_group.cc @@ -27,51 +27,22 @@ void PortGroup::add_rule() rule_count++; } -/* -** -** DESCRIPTION -** Adds a RULE_NODE to a PortGroup. This particular -** function is specific in that it adds "no content" rules. -** A "no content" rule is a snort rule that has no "content" -** or "uri" flag, and hence does not need to be pattern -** matched. -** -** Each RULE_NODE in a PortGroup is given a RULE_NODE -** ID. This allows us to track particulars as to what -** rules have been alerted upon, and allows other neat -** things like correlating events on different streams. -** The RULE_NODE IDs may not be consecutive, because -** we can add RULE_NODES into "content", "uri", and -** "no content" lists. -** -** FORMAL INPUTS -** PortGroup* - PortGroup to add the rule to. -** void* - ptr to the user information -** -** FORMAL OUTPUT -** int - 0 is successful, 1 is failure -** -*/ bool PortGroup::add_nfp_rule(void* rd) { if ( !nfp_head ) { - nfp_head = (RULE_NODE*)snort_calloc(sizeof(RULE_NODE)); + nfp_head = (RULE_NODE*)snort_alloc(sizeof(RULE_NODE)); nfp_tail = nfp_head; - nfp_head->rnNext = 0; - nfp_head->rnRuleData = rd; + nfp_head->rnNext = nullptr; } else { - nfp_tail->rnNext = (RULE_NODE*)snort_calloc(sizeof(RULE_NODE)); + nfp_tail->rnNext = (RULE_NODE*)snort_alloc(sizeof(RULE_NODE)); nfp_tail = nfp_tail->rnNext; - nfp_tail->rnNext = 0; - nfp_tail->rnRuleData = rd; + nfp_tail->rnNext = nullptr; } - /* - ** Set RULE_NODE ID to unique identifier - */ + nfp_tail->rnRuleData = rd; nfp_tail->iRuleNodeID = rule_count; nfp_rule_count++; diff --git a/src/ports/port_group.h b/src/ports/port_group.h index 5dacd0291..ed34e658d 100644 --- a/src/ports/port_group.h +++ b/src/ports/port_group.h @@ -63,10 +63,6 @@ struct PortGroup unsigned rule_count; unsigned nfp_rule_count; - // FIXIT-L these runtime counts are only valid with one packet thread - unsigned match_count; - unsigned event_count; - void add_rule(); bool add_nfp_rule(void*); void delete_nfp_rules(); diff --git a/src/utils/stats.cc b/src/utils/stats.cc index 75a1862b5..4d523276c 100644 --- a/src/utils/stats.cc +++ b/src/utils/stats.cc @@ -190,7 +190,7 @@ const PegInfo daq_names[] = const PegInfo pc_names[] = { { "analyzed", "packets sent to detection" }, - { "slow searches", "non-fast pattern rule evaluations" }, + { "hard evals", "non-fast pattern rule evaluations" }, { "raw searches", "fast pattern searches in raw packet data" }, { "cooked searches", "fast pattern searches in cooked packet data" }, { "pkt searches", "fast pattern searches in packet data" }, @@ -322,7 +322,6 @@ void PrintStatistics() timing_stats(); // FIXIT-L below stats need to be made consistent with above - fpShowEventStats(snort_conf); print_thresholding(snort_conf->threshold_config, 1); { diff --git a/src/utils/stats.h b/src/utils/stats.h index 0f2e9a2ba..4a98a8444 100644 --- a/src/utils/stats.h +++ b/src/utils/stats.h @@ -41,7 +41,7 @@ typedef std::vector IndexVec; struct PacketCount { PegCount total_from_daq; - PegCount slow_searches; + PegCount hard_evals; PegCount raw_searches; PegCount cooked_searches; PegCount pkt_searches; diff --git a/tools/snort2lua/config_states/config_detection.cc b/tools/snort2lua/config_states/config_detection.cc index d507462a2..c451599e2 100644 --- a/tools/snort2lua/config_states/config_detection.cc +++ b/tools/snort2lua/config_states/config_detection.cc @@ -111,9 +111,8 @@ bool Detection::convert(std::istringstream& data_stream) } else if (!keyword.compare("debug-print-fast-pattern")) { - table_api.add_diff_option_comment("debug-print-fast-pattern", - "debug_print_fast_pattern"); - tmpval = table_api.add_option("debug_print_fast_pattern", true); + table_api.add_diff_option_comment("debug-print-fast-pattern", "show_fast_patterns"); + tmpval = table_api.add_option("show_fast_patterns", true); } else if (!keyword.compare("max_queue_events")) {