sync code

This commit is contained in:
Ned Wright
2026-01-03 18:59:01 +00:00
parent c1058db57d
commit 2105628f05
188 changed files with 8272 additions and 2723 deletions

View File

@@ -46,6 +46,6 @@ ParameterMatcher::evalVariable() const
dbgTrace(D_RULEBASE_CONFIG)
<< "Did not find current parameter in context."
<< " Match parameter from current rule";
auto rule = getConfiguration<BasicRuleConfig>("rulebase", "rulesConfig");
auto rule = getConfigurationWithCache<BasicRuleConfig>("rulebase", "rulesConfig");
return rule.ok() && rule.unpack().isParameterActive(parameter_id);
}

View File

@@ -45,6 +45,6 @@ PracticeMatcher::evalVariable() const
return bc_practice_id_ctx.unpack().count(practice_id) > 0;
}
auto rule = getConfiguration<BasicRuleConfig>("rulebase", "rulesConfig");
auto rule = getConfigurationWithCache<BasicRuleConfig>("rulebase", "rulesConfig");
return rule.ok() && rule.unpack().isPracticeActive(practice_id);
}

View File

@@ -52,6 +52,6 @@ TriggerMatcher::evalVariable() const
<< makeSeparatedStr(bc_trigger_id_ctx.ok() ? *bc_trigger_id_ctx : set<GenericConfigId>(), ", ");
if (bc_trigger_id_ctx.ok()) return bc_trigger_id_ctx.unpack().count(trigger_id) > 0;
auto rule = getConfiguration<BasicRuleConfig>("rulebase", "rulesConfig");
auto rule = getConfigurationWithCache<BasicRuleConfig>("rulebase", "rulesConfig");
return rule.ok() && rule.unpack().isTriggerActive(trigger_id);
}

View File

@@ -104,7 +104,8 @@ GenericRulebase::Impl::getLogTriggerConf(const string& trigger_Id) const
ScopedContext ctx;
set<string> triggers = {trigger_Id};
ctx.registerValue<set<GenericConfigId>>(TriggerMatcher::ctx_key, triggers);
return getConfigurationWithDefault(LogTriggerConf(), "rulebase", "log");
auto config = getConfigurationWithCache<LogTriggerConf>("rulebase", "log");
return config.ok() ? config.unpack() : LogTriggerConf();
}
ParameterException
@@ -113,19 +114,20 @@ GenericRulebase::Impl::getParameterException(const string& parameter_Id) const
ScopedContext ctx;
set<string> exceptions = {parameter_Id};
ctx.registerValue<set<GenericConfigId>>(ParameterMatcher::ctx_key, exceptions);
return getConfigurationWithDefault(ParameterException(), "rulebase", "exception");
auto config = getConfigurationWithCache<ParameterException>("rulebase", "exception");
return config.ok() ? config.unpack() : ParameterException();
}
set<ParameterBehavior>
GenericRulebase::Impl::getBehavior(const ParameterKeyValues &key_value_pairs) const
{
auto &exceptions = getConfiguration<ParameterException>("rulebase", "exception");
auto exceptions = getConfigurationWithCache<ParameterException>("rulebase", "exception");
if (!exceptions.ok()) {
dbgTrace(D_RULEBASE_CONFIG) << "Could not find any exception with the current rule's context";
return {};
}
return (*exceptions).getBehavior(key_value_pairs);
return exceptions.unpack().getBehavior(key_value_pairs);
}
GenericRulebase::GenericRulebase() : Component("GenericRulebase"), pimpl(make_unique<Impl>()) {}

View File

@@ -64,10 +64,14 @@ GenericRulebaseContext::activate(const BasicRuleConfig &rule)
ZoneMatcher::ctx_key,
rule.getZoneId()
);
ctx.registerValue<GenericConfigId>(
ctx.registerQuickAccessValue<GenericConfigId>(
AssetMatcher::ctx_key,
rule.getAssetId()
);
ctx.registerQuickAccessValue<GenericConfigId>(
TriggerMatcher::ctx_key,
rule.getAssetId()
);
ctx.activate();
break;
}
@@ -87,7 +91,7 @@ GenericRulebaseContext::activate()
{
switch(registration_state) {
case RuleRegistrationState::UNINITIALIZED: {
auto maybe_rule = getConfiguration<BasicRuleConfig>("rulebase", "rulesConfig");
auto maybe_rule = setConfigurationInCache<BasicRuleConfig>("rulebase", "rulesConfig");
if (!maybe_rule.ok()) {
registration_state = RuleRegistrationState::UNREGISTERED;
return;

View File

@@ -244,7 +244,8 @@ MatchQuery::getAllKeys() const
bool
MatchQuery::matchAttributes(
const unordered_map<string, set<string>> &key_value_pairs,
set<string> &matched_override_keywords) const
set<string> &matched_override_keywords,
bool skip_irrelevant_key) const
{
dbgTrace(D_RULEBASE_CONFIG) << "Start matching attributes";
@@ -256,25 +257,47 @@ MatchQuery::matchAttributes(
}
return matchAttributes(key_value_pair->second, matched_override_keywords);
} else if (type == MatchType::Operator && operator_type == Operators::And) {
for (const MatchQuery &inner_match: items) {
if (!inner_match.matchAttributes(key_value_pairs, matched_override_keywords)) {
bool has_relevant_keys = false;
for (const MatchQuery &inner_match : items) {
// Skip irrelevant keys when skip_irrelevant_key is false
if (skip_irrelevant_key && key_value_pairs.find(inner_match.getKey()) == key_value_pairs.end()) {
dbgTrace(D_RULEBASE_CONFIG) << "Skipping irrelevant key in AND operator";
continue;
}
has_relevant_keys = true;
if (!inner_match.matchAttributes(key_value_pairs, matched_override_keywords, skip_irrelevant_key)) {
dbgTrace(D_RULEBASE_CONFIG) << "Failed to match attributes for AND operator";
return false;
}
}
if (!has_relevant_keys) {
dbgTrace(D_RULEBASE_CONFIG) << "No relevant keys found for AND operator";
return false;
}
dbgTrace(D_RULEBASE_CONFIG) << "Successfully matched all inner matches for AND operator";
return true;
} else if (type == MatchType::Operator && operator_type == Operators::Or) {
// With 'or' condition, evaluate matched override keywords first and add the ones that were fully matched
set<string> inner_override_keywords;
bool res = false;
bool has_relevant_keys = false;
for (const MatchQuery &inner_match: items) {
// Skip irrelevant keys when skip_irrelevant_key is false
if (skip_irrelevant_key && key_value_pairs.find(inner_match.getKey()) == key_value_pairs.end()) {
dbgTrace(D_RULEBASE_CONFIG) << "Skipping irrelevant key in OR operator";
continue;
}
has_relevant_keys = true;
inner_override_keywords.clear();
if (inner_match.matchAttributes(key_value_pairs, inner_override_keywords)) {
if (inner_match.matchAttributes(key_value_pairs, inner_override_keywords, skip_irrelevant_key)) {
matched_override_keywords.insert(inner_override_keywords.begin(), inner_override_keywords.end());
res = true;
}
}
if (!has_relevant_keys) {
dbgTrace(D_RULEBASE_CONFIG) << "No relevant keys found for OR operator";
return false;
}
dbgTrace(D_RULEBASE_CONFIG) << "Match result for OR operator is: " << res;
return res;
} else {
@@ -284,20 +307,23 @@ MatchQuery::matchAttributes(
}
MatchQuery::MatchResult
MatchQuery::getMatch( const unordered_map<string, set<string>> &key_value_pairs) const
MatchQuery::getMatch(
const unordered_map<string, set<string>> &key_value_pairs,
bool skip_irrelevant_key) const
{
MatchQuery::MatchResult matches;
matches.matched_keywords = make_shared<set<string>>();
matches.is_match = matchAttributes(key_value_pairs, *matches.matched_keywords);
matches.is_match = matchAttributes(key_value_pairs, *matches.matched_keywords, skip_irrelevant_key);
dbgTrace(D_RULEBASE_CONFIG) << "Match result: " << matches.is_match;
return matches;
}
bool
MatchQuery::matchAttributes(
const unordered_map<string, set<string>> &key_value_pairs) const
const unordered_map<string, set<string>> &key_value_pairs,
bool skip_irrelevant_key) const
{
return getMatch(key_value_pairs).is_match;
return getMatch(key_value_pairs, skip_irrelevant_key).is_match;
}
bool

View File

@@ -105,19 +105,22 @@ ParameterException::load(cereal::JSONInputArchive &archive_in)
for (const MatchBehaviorPair &match_query : match_queries) {
if (isGeoLocationExists(match_query.match)) return;
}
is_containing_kv_pair = checkKVPair();
}
set<ParameterBehavior>
ParameterException::getBehavior(
const unordered_map<string, set<string>> &key_value_pairs,
set<string> &matched_override_keywords) const
const unordered_map<string, set<string>> &key_value_pairs,
set<string> &matched_override_keywords,
bool skip_irrelevant_key) const
{
set<ParameterBehavior> matched_behaviors;
matched_override_keywords.clear();
dbgTrace(D_RULEBASE_CONFIG) << "Matching exception";
for (const MatchBehaviorPair &match_behavior_pair: match_queries) {
MatchQuery::MatchResult match_res = match_behavior_pair.match.getMatch(key_value_pairs);
MatchQuery::MatchResult match_res = match_behavior_pair.match.getMatch(key_value_pairs, skip_irrelevant_key);
if (match_res.is_match) {
dbgTrace(D_RULEBASE_CONFIG)
<< "Successfully matched an exception from a list of matches, behavior: "
@@ -136,7 +139,7 @@ ParameterException::getBehavior(
}
if (match_queries.empty()) {
MatchQuery::MatchResult match_res = match.getMatch(key_value_pairs);
MatchQuery::MatchResult match_res = match.getMatch(key_value_pairs, skip_irrelevant_key);
if (match_res.is_match) {
dbgTrace(D_RULEBASE_CONFIG) << "Successfully matched an exception.";
// When matching indicators with action=ignore, we expect no behavior override.
@@ -156,8 +159,70 @@ ParameterException::getBehavior(
}
set<ParameterBehavior>
ParameterException::getBehavior(const unordered_map<string, set<string>> &key_value_pairs) const
ParameterException::getBehavior(
const unordered_map<string, set<string>> &key_value_pairs,
bool skip_irrelevant_key) const
{
set<string> keywords; // placeholder only, this function will be used where there's no need for ignored keywords
return getBehavior(key_value_pairs, keywords);
return getBehavior(key_value_pairs, keywords, skip_irrelevant_key);
}
static bool
checkMatchQueryForKVPair(const MatchQuery &query)
{
if (query.getType() == MatchQuery::MatchType::Condition) {
return false;
}
if (query.getType() == MatchQuery::MatchType::Operator) {
if (query.getOperatorType() == MatchQuery::Operators::And) {
set<string> found_keys;
for (const MatchQuery &item : query.getItems()) {
if (item.getType() == MatchQuery::MatchType::Condition) {
found_keys.insert(item.getKey());
}
}
bool hasParamName = found_keys.find("paramName") != found_keys.end();
bool hasParamValue = found_keys.find("paramValue") != found_keys.end();
if (hasParamName && hasParamValue) {
return true;
}
bool hasHeaderName = found_keys.find("headerName") != found_keys.end();
bool hasHeaderValue = found_keys.find("headerValue") != found_keys.end();
if (hasHeaderName && hasHeaderValue) {
return true;
}
}
for (const MatchQuery &item : query.getItems()) {
if (item.getType() == MatchQuery::MatchType::Operator) {
if (checkMatchQueryForKVPair(item)) {
return true;
}
}
}
}
return false;
}
bool
ParameterException::checkKVPair() const
{
if (checkMatchQueryForKVPair(match)) {
return true;
}
for (const MatchBehaviorPair &match_behavior_pair : match_queries) {
if (checkMatchQueryForKVPair(match_behavior_pair.match)) {
return true;
}
}
return false;
}

View File

@@ -59,6 +59,7 @@ WebTriggerConf::load(cereal::JSONInputArchive &archive_in)
parseJSONKey<string>("response body", response_body, archive_in);
parseJSONKey<string>("response title", response_title, archive_in);
parseJSONKey<string>("content type", content_type, archive_in);
} catch (const exception &e) {
dbgWarning(D_RULEBASE_CONFIG) << "Failed to parse the web trigger configuration: '" << e.what() << "'";
archive_in.setNextName(nullptr);
@@ -185,6 +186,7 @@ LogTriggerConf::load(cereal::JSONInputArchive& archive_in)
setTriggersFlag("acLogGeoLocation", archive_in, SecurityType::AccessControl, log_geo_location);
setTriggersFlag("tpLogGeoLocation", archive_in, SecurityType::ThreatPrevention, log_geo_location);
setTriggersFlag("complianceLogGeoLocation", archive_in, SecurityType::Compliance, log_geo_location);
setTriggersFlag("shouldIgnoreExceptionLog", archive_in, SecurityType::ThreatPrevention, should_log_exception);
bool extend_logging = false;
parseJSONKey<bool>("extendLogging", extend_logging, archive_in);

View File

@@ -78,7 +78,7 @@ public:
MMDB_lookup_result_s result = MMDB_lookup_sockaddr(&max_mind_db_obj, &sockaddr_to_search, &maxminddb_error);
if (maxminddb_error != MMDB_SUCCESS) {
dbgWarning(D_GEO_DB) << "maxMindDB error: " << MMDB_strerror(maxminddb_error);
dbgDebug(D_GEO_DB) << "maxMindDB error: " << MMDB_strerror(maxminddb_error);
return genError("maxMindDB error: " + string(MMDB_strerror(maxminddb_error)));
}
if (result.found_entry) {
@@ -153,9 +153,9 @@ private:
}
}
if (status != MMDB_SUCCESS) {
dbgWarning(D_GEO_DB) << "maxMindDB error: " << MMDB_strerror(status);
dbgDebug(D_GEO_DB) << "maxMindDB error: " << MMDB_strerror(status);
} else if (!entry_data.has_data) {
dbgWarning(D_GEO_DB) << "maxMindDB Entry has no data";
dbgDebug(D_GEO_DB) << "maxMindDB Entry has no data";
} else {
string search_result(entry_data.utf8_string, entry_data.data_size);
return search_result;

View File

@@ -19,7 +19,7 @@
#include "enum_array.h"
#include "buffer.h"
#include "nginx_attachment_common.h"
#include "nano_attachment_common.h"
using namespace std;

View File

@@ -1,3 +1,3 @@
add_library(pm general_adaptor.cc kiss_hash.cc kiss_patterns.cc kiss_pm_stats.cc kiss_thin_nfa.cc kiss_thin_nfa_analyze.cc kiss_thin_nfa_build.cc kiss_thin_nfa_compile.cc pm_adaptor.cc pm_hook.cc debugpm.cc)
add_library(pm general_adaptor.cc kiss_hash.cc kiss_patterns.cc kiss_pm_stats.cc kiss_thin_nfa.cc kiss_thin_nfa_analyze.cc kiss_thin_nfa_build.cc kiss_thin_nfa_compile.cc pm_adaptor.cc pm_hook.cc debugpm.cc hyperscan_hook.cc)
add_subdirectory(pm_ut)