fp_create.h
fp_detect.cc
fp_detect.h
+ fp_utils.cc
+ fp_utils.h
pcrm.cc
pcrm.h
service_map.cc
fp_create.h \
fp_detect.cc \
fp_detect.h \
+fp_utils.cc \
+fp_utils.h \
pcrm.cc \
pcrm.h \
service_map.cc \
#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] =
{
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;
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);
}
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; i<plen; i++)
- {
- if ( p[i] != 0 )
- break;
- }
-
- if ( i < plen )
- size = plen - i;
- else
- size = 0;
-
- if ( buff && (size==0) )
- {
- *buff = 0;
- }
- else if ( buff )
- {
- *buff = &p[i];
- }
- return size;
-}
-
-static bool pmd_can_be_fp(PatternMatchData* pmd, CursorActionType cat)
-{
- if ( cat <= CAT_SET_OTHER )
- return false;
-
- return pmd->can_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;
}
}
static int fpAddPortGroupRule(
- SnortConfig* sc, PortGroup* pg, OptTreeNode* otn, FastPatternConfig* fp)
+ SnortConfig* sc, PortGroup* pg, OptTreeNode* otn, FastPatternConfig* fp, bool srvc)
{
PatternMatchData* pmd = NULL;
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 &&
}
}
- /* 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;
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)
{
/* create a port_group */
pg = (PortGroup*)snort_calloc(sizeof(PortGroup));
+ s_group = "port";
/*
* Walk the rules in the PortObject and add to
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())
{
OptTreeNode* otn;
PortGroup* pg = (PortGroup*)snort_calloc(sizeof(PortGroup));
+ s_group = srvc;
/*
* add each rule to the port group pattern matchers,
otn;
otn = (OptTreeNode*)sflist_next(&cursor))
{
- if (fpAddPortGroupRule(sc, pg, otn, fp) != 0)
+ if (fpAddPortGroupRule(sc, pg, otn, fp, true) != 0)
continue;
}
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];
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 <offset,length>: %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());
}
int fpCreateFastPacketDetection(SnortConfig*);
void fpDeleteFastPacketDetection(SnortConfig*);
-void fpShowEventStats(SnortConfig*);
-
void fpDeletePortGroup(void*);
-bool set_fp_content(struct OptTreeNode*);
-
#endif
}
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)
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;
}
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.
#include "config.h"
#endif
-#include "detection/fp_create.h"
#include "main/snort_debug.h"
#include "protocols/packet.h"
#include "utils/sflsq.h"
#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;
** 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
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
--- /dev/null
+//--------------------------------------------------------------------------
+// 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 <string.h>
+
+#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; i<plen; i++)
+ {
+ if ( p[i] != 0 )
+ break;
+ }
+
+ if ( i < plen )
+ size = plen - i;
+ else
+ size = 0;
+
+ if ( buff && (size==0) )
+ {
+ *buff = 0;
+ }
+ else if ( buff )
+ {
+ *buff = &p[i];
+ }
+ return size;
+}
+
+void validate_fast_pattern(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))
+ {
+ 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
+
--- /dev/null
+//--------------------------------------------------------------------------
+// Copyright (C) 2014-2016 Cisco and/or its affiliates. All rights reserved.
+// Copyright (C) 2002-2013 Sourcefire, Inc.
+// Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
+//
+// 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
+
#ifndef PATTERN_MATCH_DATA_H
#define PATTERN_MATCH_DATA_H
+#include <assert.h>
#include <ctype.h>
#include <sys/time.h>
-#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
{
{
// 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;
return true;
}
+// pmd related utilities
+struct OptFpList;
+
+PatternMatchData* get_pmd(OptFpList*, int proto, RuleDirection);
+bool is_fast_pattern_only(OptFpList*);
+
#endif
#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));
}
/*
-**
-** NAME
-** prmFindRuleGroup::
-**
** DESCRIPTION
** Given a PORT_RULE_MAP, this function selects the PortGroup or
** PortGroups necessary to fully match a given dport, sport pair.
** 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
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; i<MAX_PORTS; i++)
- {
- pg = prmFindDstRuleGroup(p, i);
- if (pg)
- {
- NQEvents += pg->match_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; i<MAX_PORTS; i++)
- {
- pg = prmFindSrcRuleGroup(p, i);
- if (pg)
- {
- NQEvents += pg->match_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;
-}
-
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**);
#include <stdlib.h>
#include <string.h>
-#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
{ 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)
#include "framework/range.h"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
#include <errno.h>
#include <stdlib.h>
#include <string.h>
{ "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)" },
{ "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 }
};
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());
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;
#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"
#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
{
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;
*/
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;
* 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() &&
/* 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;
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;
/* 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);
}
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;
PortTableAddObject(dstTable, pox);
}
-
PortObjectAddRule(pox, rim_index);
}
}
-
return 0;
}
"destination IP in a rule. IP list: %s.", token);
return -1;
}
-
return 0;
}
{
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
{
{
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
{
*
* 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)
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;
/* 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);
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) )
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;
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));
}
/****************************************************************************
- *
- * 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)
{
DebugMessage(DEBUG_CONFIGRULES,"CheckSrcIP -> ");
AddRuleFuncToList(CheckSrcIP, rtn);
}
-
break;
case DST:
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
* 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)
{
}
}
-/****************************************************************************
- *
- * 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");
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)
{
/* 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++;
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);
}
{
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);
}
{
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()
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;
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);
}
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);
}
}
}
- 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 */
{
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 */
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) )
* 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;
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++;
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();
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" },
timing_stats();
// FIXIT-L below stats need to be made consistent with above
- fpShowEventStats(snort_conf);
print_thresholding(snort_conf->threshold_config, 1);
{
struct PacketCount
{
PegCount total_from_daq;
- PegCount slow_searches;
+ PegCount hard_evals;
PegCount raw_searches;
PegCount cooked_searches;
PegCount pkt_searches;
}
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"))
{