DEBUG_WRAP(
DebugFormat(DEBUG_DETECT, "%d%*s%*d 0x%x\n",
- level, indent - offset, option_type_str[node->option_type],
- 54 - indent, node->num_children, node->option_data);
+ level, indent - offset, option_type_str[node->option_type],
+ 54 - indent, node->num_children, node->option_data);
for (i=0; i<node->num_children; i++)
print_option_tree(node->children[i], level+1);
);
}
+
#endif
void* add_detection_option_tree(
auto last_check = state.last_check;
if ( last_check.ts == p->pkth->ts &&
- last_check.packet_number == cur_eval_pkt_count &&
- last_check.rebuild_flag == (p->packet_flags & PKT_REBUILT_STREAM) &&
- !(p->packet_flags & PKT_ALLOW_MULTIPLE_DETECT) )
+ last_check.packet_number == cur_eval_pkt_count &&
+ last_check.rebuild_flag == (p->packet_flags & PKT_REBUILT_STREAM) &&
+ !(p->packet_flags & PKT_ALLOW_MULTIPLE_DETECT) )
{
if ( !last_check.flowbit_failed &&
- !(p->packet_flags & PKT_IP_RULE_2ND) &&
- !(p->proto_bits & (PROTO_BIT__TEREDO|PROTO_BIT__GTP)) )
+ !(p->packet_flags & PKT_IP_RULE_2ND) &&
+ !(p->proto_bits & (PROTO_BIT__TEREDO|PROTO_BIT__GTP)) )
{
return last_check.result;
}
IpsOption* opt = (IpsOption*)node->option_data;
try_again = opt->retry();
- PatternMatchData* pmd = opt->get_pattern();
+ PatternMatchData* pmd = opt->get_pattern(0, RULE_WO_DIR);
if ( pmd and pmd->last_check )
content_last = pmd->last_check + get_instance_id();
switch ( node->option_type )
{
case RULE_OPTION_TYPE_LEAF_NODE:
- // Add the match for this otn to the queue.
+ // Add the match for this otn to the queue.
{
OptTreeNode* otn = (OptTreeNode*)node->option_data;
int16_t app_proto = p->get_application_protocol();
if ( content_last )
{
if ( content_last->ts == p->pkth->ts &&
- content_last->packet_number == cur_eval_pkt_count &&
- content_last->rebuild_flag == (p->packet_flags & PKT_REBUILT_STREAM) )
+ content_last->packet_number == cur_eval_pkt_count &&
+ content_last->rebuild_flag == (p->packet_flags & PKT_REBUILT_STREAM) )
{
rval = DETECTION_OPTION_NO_MATCH;
break;
rval = node->evaluate(node->option_data, cursor, p);
break;
-
}
if ( rval == DETECTION_OPTION_NO_MATCH )
state.last_check.result = result;
return result;
}
-
else if ( rval == DETECTION_OPTION_FAILED_BIT )
{
eval_data->flowbit_failed = 1;
state.last_check.result = result;
return 0;
}
-
else if ( rval == DETECTION_OPTION_NO_ALERT )
{
// Cache the current flowbit_noalert flag, and set it
continue;
}
}
-
else if ( child_node->option_type == RULE_OPTION_TYPE_CONTENT )
{
// Check for an unbounded relative search. If this
// failed before, it's going to fail again so don't
// go down this path again
IpsOption* opt = (IpsOption*)node->option_data;
- PatternMatchData* pmd = opt->get_pattern();
+ PatternMatchData* pmd = opt->get_pattern(0, RULE_WO_DIR);
if ( pmd->unbounded() )
{
}
}
}
-
else if ( child_node->option_type == RULE_OPTION_TYPE_LEAF_NODE )
// Leaf node matched, don't eval again
continue;
}
if ( continue_loop &&
- rval == DETECTION_OPTION_MATCH &&
- node->relative_children )
+ rval == DETECTION_OPTION_MATCH &&
+ node->relative_children )
{
continue_loop = try_again;
}
-
else
continue_loop = false;
local_stats.latency_timeouts = timeouts;
local_stats.latency_suspends = suspends;
}
-
else
{
local_stats.elapsed = node_stats.elapsed;
}
}
-
detection_option_tree_root_t* new_root()
{
detection_option_tree_root_t* p = (detection_option_tree_root_t*)
fp_only = !ofl->ips_opt->fp_research();
}
- PatternMatchData* tmp = get_pmd(ofl);
+ // 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;
if ( !ofl->ips_opt )
continue;
- PatternMatchData* pmd = get_pmd(ofl);
+ PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR);
if ( !pmd )
continue;
{
static MpseAgent agent =
{
- pmx_create_tree, add_patrn_to_neg_list,
- fpDeletePMX, free_detection_option_root, neg_list_free
+ pmx_create_tree, add_patrn_to_neg_list,
+ fpDeletePMX, free_detection_option_root, neg_list_free
};
pg->mpse[pmd->pm_type] = MpseManager::get_search_engine(
snprintf(buf, sizeof(buf), "%2.02X ", (uint8_t)pattern[i]);
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
CAT_SET_KEY,
};
+enum RuleDirection
+{
+ RULE_FROM_CLIENT,
+ RULE_FROM_SERVER,
+ RULE_WO_DIR
+};
+
class SO_PUBLIC IpsOption
{
public:
{ return CAT_NONE; }
// for fast-pattern options like content
- virtual struct PatternMatchData* get_pattern()
+ virtual struct PatternMatchData* get_pattern(int /*proto*/, RuleDirection)
{ return nullptr; }
static int eval(void* v, Cursor& c, Packet* p)
min = max = 0;
}
-bool RangeCheck::is_set()
+bool RangeCheck::is_set() const
{
return (op != MAX);
}
return true;
}
-bool RangeCheck::eval(long c)
+bool RangeCheck::eval(long c) const
{
switch ( op )
{
bool operator==(const RangeCheck&) const;
void init();
- bool is_set();
+ bool is_set() const;
// FIXIT-L add ttl style syntax
bool parse(const char* s);
- bool eval(long);
+ bool eval(long) const;
};
#endif
int eval(Cursor& c, Packet*) override
{ return CheckANDPatternMatch(config, c); }
- PatternMatchData* get_pattern() override
+ PatternMatchData* get_pattern(int, RuleDirection) override
{ return &config->pmd; }
protected:
}
return true;
}
+
#endif
// FIXIT-P fp, fp_only are set after hash table comparisons so this must
-// return false to avoid unnecessary reevaluation and false positives.
+// return this == &ips to avoid unnecessary reevaluation and false positives.
// when this is fixed, add PatternMatchData::operator==().
bool ContentOption::operator==(const IpsOption& ips) const
{
{
return true;
}
-#else
- UNUSED(ips);
#endif
- return false;
+ return this == &ips;
}
//-------------------------------------------------------------------------
DebugMessage(DEBUG_PATTERN_MATCH, "Pattern match found\n");
return DETECTION_OPTION_MATCH;
}
-
else
{
DebugMessage(DEBUG_PATTERN_MATCH, "Pattern match failed\n");
bool retry() override;
- PatternMatchData* get_pattern() override
+ PatternMatchData* get_pattern(int, RuleDirection) override
{ return &config.pmd; }
int eval(Cursor&, Packet*) override;
return c;
}
-// see ContentOption::operator==() for why this is always false
+// see ContentOption::operator==()
bool RegexOption::operator==(const IpsOption& ips) const
{
#if 0
RegexOption& rhs = (RegexOption&)ips;
- if ( config.re == rhs.config.re and
- config.pmd.flags == rhs.config.pmd.flags and
- config.pmd.relative == rhs.config.pmd.relative )
+ if ( config.re == rhs.config.re and
+ config.pmd.flags == rhs.config.pmd.flags and
+ config.pmd.relative == rhs.config.pmd.relative )
return true;
-
-#else
- UNUSED(ips);
#endif
- return false;
+ return this == &ips;
}
static int hs_match(
config.re.erase(0, 1);
config.re.erase(config.re.length()-1, 1);
}
-
else if ( v.is("nocase") )
{
config.pmd.flags |= HS_FLAG_CASELESS;
std::string pii;
unsigned threshold = 1;
bool obfuscate_pii = false;
- int (*validate)(const uint8_t* buf, unsigned long long buflen) = nullptr;
+ int (* validate)(const uint8_t* buf, unsigned long long buflen) = nullptr;
inline bool operator==(const SdPatternConfig& rhs) const
{
uint32_t hash() const override;
bool operator==(const IpsOption&) const override;
- PatternMatchData* get_pattern() override
+ PatternMatchData* get_pattern(int, RuleDirection) override
{ return &config.pmd; }
int eval(Cursor&, Packet* p) override;
{
// FIXIT-L why is this failing but everything is working?
ParseError("can't initialize sd_pattern for %s (%d) %p",
- config.pii.c_str(), err, (void*)s_scratch);
+ config.pii.c_str(), err, (void*)s_scratch);
}
config.pmd.pattern_buf = config.pii.c_str();
}
SdPatternOption::~SdPatternOption()
-{
+{
if ( config.db )
hs_free_database(config.db);
}
return false;
}
-struct hsContext
+struct hsContext
{
- hsContext(const SdPatternConfig &c_, Packet* p_, const uint8_t* const start_)
- : config(c_), packet(p_), start(start_) {}
+ hsContext(const SdPatternConfig& c_, Packet* p_, const uint8_t* const start_)
+ : config(c_), packet(p_), start(start_) { }
unsigned int count = 0;
ctx->packet->obfuscator = new Obfuscator();
uint32_t off = ctx->buf - ctx->start;
- // FIXIT-L Make configurable or don't show any PII partials (0 for user defined??)
+ // FIXIT-L Make configurable or don't show any PII partials (0 for user defined??)
len = len > 4 ? len - 4 : len;
ctx->packet->obfuscator->push(off, len);
}
config.validate = SdLuhnAlgorithm;
config.obfuscate_pii = sc->obfuscate_pii;
}
-
else if (config.pii == "us_social")
{
config.pii = SD_SOCIAL_PATTERN;
config.obfuscate_pii = sc->obfuscate_pii;
}
-
else if (config.pii == "us_social_nodashes")
{
config.pii = SD_SOCIAL_NODASHES_PATTERN;
{
hs_compile_error_t* err = nullptr;
- if ( hs_compile(config.pii.c_str(), HS_FLAG_DOTALL|HS_FLAG_SOM_LEFTMOST, HS_MODE_BLOCK, nullptr, &config.db, &err)
+ if ( hs_compile(config.pii.c_str(), HS_FLAG_DOTALL|HS_FLAG_SOM_LEFTMOST, HS_MODE_BLOCK,
+ nullptr, &config.db, &err)
or !config.db )
{
ParseError("can't compile regex '%s'", config.pii.c_str());
}
static void sd_pattern_dtor(IpsOption* p)
-{
+{
delete p;
}
*
***************************************************************************/
static void AddRuleFuncToList(
- int (* rfunc) (Packet*, RuleTreeNode*, struct RuleFpList*, int),
+ int (* rfunc)(Packet*, RuleTreeNode*, struct RuleFpList*, int),
RuleTreeNode* rtn)
{
RuleFpList* idx;
return 1;
}
-PatternMatchData* get_pmd(OptFpList* ofl)
+PatternMatchData* get_pmd(OptFpList* ofl, int proto, RuleDirection direction)
{
if ( !ofl->ips_opt )
return nullptr;
- return ofl->ips_opt->get_pattern();
+ return ofl->ips_opt->get_pattern(proto, direction);
}
static void finalize_content(OptFpList* ofl)
{
- PatternMatchData* pmd = get_pmd(ofl);
+ PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR);
if ( !pmd )
return;
bool is_fast_pattern_only(OptFpList* ofl)
{
- PatternMatchData* pmd = get_pmd(ofl);
+ PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR);
if ( !pmd )
return false;
static void clear_fast_pattern_only(OptFpList* ofl)
{
- PatternMatchData* pmd = get_pmd(ofl);
+ PatternMatchData* pmd = get_pmd(ofl, 0, RULE_WO_DIR);
if ( pmd && pmd->fp_only > 0 )
pmd->fp_only = 0;
}
// reset the check if one of these are present.
- if ( fpl->ips_opt and !fpl->ips_opt->get_pattern() )
+ 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;
* 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, has_fp, sc->fast_pattern_config) )
ParseError("Failed to finish a port list rule.");
return nullptr;
#define PARSE_RULE_H
#include "detection/rules.h"
+#include "framework/ips_option.h"
struct OptFpList;
struct OptTreeNode;
const char* parse_rule_close(SnortConfig*, RuleTreeNode&, OptTreeNode*);
bool is_fast_pattern_only(OptFpList*);
-struct PatternMatchData* get_pmd(OptFpList*);
+struct PatternMatchData* get_pmd(OptFpList*, int proto, RuleDirection);
int get_rule_count();
#include "framework/range.h"
#include "detection/detect.h"
#include "detection/detection_defines.h"
+#include "detection/pattern_match_data.h"
#include "hash/sfhashfcn.h"
#include "profiler/profiler.h"
+#include "target_based/snort_protocols.h"
+#include "main/snort_debug.h"
//-------------------------------------------------------------------------
// dcerpc2 interface rule options
{
public:
Dce2IfaceOption(RangeCheck iface_version, bool iface_any_frag, Uuid iface_uuid) :
- IpsOption(s_name)
- { version = iface_version; any_frag = iface_any_frag; uuid = iface_uuid; }
+ IpsOption(s_name), version(iface_version), any_frag(iface_any_frag), uuid(iface_uuid)
+ {
+ memset(&pmd, 0, sizeof(pmd));
+ }
uint32_t hash() const override;
bool operator==(const IpsOption&) const override;
int eval(Cursor&, Packet*) override;
+ PatternMatchData* get_pattern(int proto, RuleDirection direction) override;
+ ~Dce2IfaceOption();
private:
- RangeCheck version;
- bool any_frag;
- Uuid uuid;
+ const RangeCheck version;
+ const bool any_frag;
+ const Uuid uuid;
+ PatternMatchData pmd;
};
+Dce2IfaceOption::~Dce2IfaceOption()
+{
+ if ( pmd.pattern_buf)
+ {
+ snort_free((char*)pmd.pattern_buf);
+ }
+}
+
+PatternMatchData* Dce2IfaceOption::get_pattern(int proto, RuleDirection direction)
+{
+ if (pmd.pattern_buf)
+ {
+ return &pmd;
+ }
+
+ if (proto == SNORT_PROTO_TCP)
+ {
+ const char client_fp[] = "\x05\x00\x00";
+ const char server_fp[] = "\x05\x00\x02";
+ const char no_dir_fp[] = "\x05\x00";
+
+ switch (direction)
+ {
+ case RULE_FROM_CLIENT:
+ pmd.pattern_size = 3;
+ pmd.pattern_buf = (char*)snort_alloc(pmd.pattern_size);
+ memcpy((void*)pmd.pattern_buf, client_fp, pmd.pattern_size);
+ break;
+
+ case RULE_FROM_SERVER:
+ pmd.pattern_size = 3;
+ pmd.pattern_buf = (char*)snort_alloc(pmd.pattern_size);
+ memcpy((void*)pmd.pattern_buf, server_fp, pmd.pattern_size);
+ break;
+
+ default:
+ pmd.pattern_size = 2;
+ pmd.pattern_buf = (char*)snort_alloc(pmd.pattern_size);
+ memcpy((void*)pmd.pattern_buf, no_dir_fp, pmd.pattern_size);
+ break;
+ }
+ return &pmd;
+ }
+ // FIXIT-L add udp fast pattern
+
+ return nullptr;
+}
+
uint32_t Dce2IfaceOption::hash() const
{
uint32_t a, b, c;
bool Dce2IfaceOption::operator==(const IpsOption& ips) const
{
- if ( strcmp(get_name(), ips.get_name()) )
- return false;
-
- const Dce2IfaceOption& rhs = (Dce2IfaceOption&)ips;
-
- if ((DCE2_UuidCompare(&uuid, &rhs.uuid) == 0) &&
- (version == rhs.version) &&
- (any_frag == rhs.any_frag))
- {
- return true;
- }
-
- return false;
+ // FIXIT-L
+ // Fast pattern is calculated only after the entire rule is parsed.
+ // The rule option can be mistaken as a duplicate because we don't take the fast pattern into
+ // account. Instead of comparing values, make sure it is the same object.
+ return this == &ips;
}
int Dce2IfaceOption::eval(Cursor&, Packet* p)