From f284f1824c0c19f29857bce4352987b15aeae448 Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Mon, 26 Jun 2023 13:53:56 +0100 Subject: [PATCH 01/28] Remove manifest --- CMakeLists.txt | 1 - src/condition.hpp | 3 +- src/context.hpp | 2 +- src/exclusion/input_filter.hpp | 11 ++ src/exclusion/object_filter.hpp | 13 +-- src/exclusion/rule_filter.hpp | 7 ++ src/iterator.hpp | 1 - src/manifest.cpp | 41 ------- src/manifest.hpp | 53 --------- src/object_store.cpp | 17 +-- src/object_store.hpp | 14 +-- src/parser/parser.hpp | 7 +- src/parser/parser_v1.cpp | 13 +-- src/parser/parser_v2.cpp | 54 +++------ src/rule.hpp | 8 ++ src/ruleset.hpp | 31 ++++- src/ruleset_builder.cpp | 51 +-------- src/ruleset_builder.hpp | 10 -- src/utils.hpp | 7 ++ src/waf.hpp | 2 +- tests/TestAdditive.cpp | 5 - tests/collection_test.cpp | 49 ++++---- tests/condition_test.cpp | 45 +++----- tests/context_test.cpp | 181 ++++++++++-------------------- tests/input_filter_test.cpp | 141 +++++++++++------------ tests/manifest_test.cpp | 134 ---------------------- tests/object_filter_test.cpp | 126 ++++++++++----------- tests/object_store_test.cpp | 43 +++---- tests/parser_v2_input_filters.cpp | 72 +++++------- tests/parser_v2_rule_filters.cpp | 36 ++---- tests/parser_v2_rules_test.cpp | 18 +-- tests/rule_filter_test.cpp | 42 +++---- tests/rule_test.cpp | 49 ++++---- tests/waf_test.cpp | 56 +++++++++ 34 files changed, 489 insertions(+), 854 deletions(-) delete mode 100644 src/manifest.cpp delete mode 100644 src/manifest.hpp delete mode 100644 tests/manifest_test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 69b7916a2..b8875ad38 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,7 +70,6 @@ set(LIBDDWAF_SOURCE ${libddwaf_SOURCE_DIR}/src/context_allocator.cpp ${libddwaf_SOURCE_DIR}/src/event.cpp ${libddwaf_SOURCE_DIR}/src/object.cpp - ${libddwaf_SOURCE_DIR}/src/manifest.cpp ${libddwaf_SOURCE_DIR}/src/object_store.cpp ${libddwaf_SOURCE_DIR}/src/collection.cpp ${libddwaf_SOURCE_DIR}/src/condition.cpp diff --git a/src/condition.hpp b/src/condition.hpp index 38646f091..806f67a47 100644 --- a/src/condition.hpp +++ b/src/condition.hpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include @@ -31,7 +30,7 @@ class condition { enum class data_source : uint8_t { values, keys }; struct target_type { - manifest::target_type root; + target_index root; std::string name; std::vector key_path{}; std::vector transformers{}; diff --git a/src/context.hpp b/src/context.hpp index f3c6e20a7..693b0c559 100644 --- a/src/context.hpp +++ b/src/context.hpp @@ -28,7 +28,7 @@ class context { using object_set = std::unordered_set; explicit context(ruleset::ptr ruleset) - : ruleset_(std::move(ruleset)), store_(ruleset_->manifest, ruleset_->free_fn) + : ruleset_(std::move(ruleset)), store_(ruleset_->free_fn) { rule_filter_cache_.reserve(ruleset_->rule_filters.size()); input_filter_cache_.reserve(ruleset_->input_filters.size()); diff --git a/src/exclusion/input_filter.hpp b/src/exclusion/input_filter.hpp index 43fe503b8..7d8adf703 100644 --- a/src/exclusion/input_filter.hpp +++ b/src/exclusion/input_filter.hpp @@ -40,6 +40,17 @@ class input_filter { std::string_view get_id() { return id_; } + void get_addresses(std::unordered_set &addresses) const { + for (const auto &cond : conditions_) { + for (const auto &target : cond->get_targets()) { + addresses.emplace(target.name); + } + } + + for (const auto &[name, target] : filter_->get_targets()) { + addresses.emplace(name); + } + } protected: std::string id_; std::vector conditions_; diff --git a/src/exclusion/object_filter.hpp b/src/exclusion/object_filter.hpp index 1c0fe7cf2..b3e73af84 100644 --- a/src/exclusion/object_filter.hpp +++ b/src/exclusion/object_filter.hpp @@ -21,7 +21,6 @@ #include #include #include -#include #include namespace ddwaf::exclusion { @@ -238,25 +237,25 @@ inline std::ostream &operator<<(std::ostream &os, const path_trie::traverser::st class object_filter { public: - using cache_type = std::unordered_set; + using cache_type = std::unordered_set; explicit object_filter(const ddwaf::object_limits &limits = {}) : limits_(limits) {} - void insert(manifest::target_type target, const std::vector &key_path = {}) + void insert(target_index target, std::string name, const std::vector &key_path = {}) { target_paths_[target].insert(key_path); - targets_.emplace(target); + targets_.emplace(std::move(name), target); } memory::unordered_set match( const object_store &store, cache_type &cache, ddwaf::timer &deadline) const; - const std::unordered_set &get_targets() const { return targets_; } + const std::unordered_map &get_targets() const { return targets_; } protected: object_limits limits_; - std::unordered_map target_paths_; - std::unordered_set targets_; + std::unordered_map target_paths_; + std::unordered_map targets_; }; } // namespace ddwaf::exclusion diff --git a/src/exclusion/rule_filter.hpp b/src/exclusion/rule_filter.hpp index 60184ffb6..358efedd5 100644 --- a/src/exclusion/rule_filter.hpp +++ b/src/exclusion/rule_filter.hpp @@ -32,6 +32,13 @@ class rule_filter { std::string_view get_id() { return id_; } + void get_addresses(std::unordered_set &addresses) const { + for (const auto &cond : conditions_) { + for (const auto &target : cond->get_targets()) { + addresses.emplace(target.name); + } + } + } protected: std::string id_; std::vector conditions_; diff --git a/src/iterator.hpp b/src/iterator.hpp index ae75161ec..b693ce031 100644 --- a/src/iterator.hpp +++ b/src/iterator.hpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/src/manifest.cpp b/src/manifest.cpp deleted file mode 100644 index b6f94b95e..000000000 --- a/src/manifest.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// Unless explicitly stated otherwise all files in this repository are -// dual-licensed under the Apache-2.0 License or BSD-3-Clause License. -// -// This product includes software developed at Datadog (https://www.datadoghq.com/). -// Copyright 2021 Datadog, Inc. - -#include -#include - -namespace ddwaf { -manifest::target_type manifest::insert(const std::string &root) -{ - auto it = targets_.find(root); - if (it == targets_.end()) { - auto [new_it, res] = targets_.emplace(root, ++index_); - it = new_it; - } - return it->second; -} - -std::optional manifest::find(const std::string &root) const -{ - auto it = targets_.find(root); - if (it == targets_.end()) { - return std::nullopt; - } - return {it->second}; -} - -void manifest::remove_unused(const std::unordered_set &valid_targets) -{ - for (auto it = targets_.begin(); it != targets_.end();) { - if (valid_targets.find(it->second) == valid_targets.end()) { - it = targets_.erase(it); - } else { - ++it; - } - } -} - -} // namespace ddwaf diff --git a/src/manifest.hpp b/src/manifest.hpp deleted file mode 100644 index f7f76114a..000000000 --- a/src/manifest.hpp +++ /dev/null @@ -1,53 +0,0 @@ -// Unless explicitly stated otherwise all files in this repository are -// dual-licensed under the Apache-2.0 License or BSD-3-Clause License. -// -// This product includes software developed at Datadog (https://www.datadoghq.com/). -// Copyright 2021 Datadog, Inc. - -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace ddwaf { - -// TODO bring back manifest builder? -class manifest { -public: - using target_type = uint32_t; - manifest::target_type insert(const std::string &root); - std::optional find(const std::string &root) const; - - // Remove unused targets - void remove_unused(const std::unordered_set &valid_targets); - - // TODO This is problematic because if the manifest is modified after the - // first call to this function, the array will be out-of-sync. At the - // same time we can't invalidate it. - // This is not really a problem in practice since each ruleset has its - // own manifest copy, but it would be better to avoid an inconsistent - // interface that could be misused. - const std::vector &get_root_addresses() - { - if (root_addresses_.empty()) { - for (const auto &[id, target] : targets_) { root_addresses_.emplace_back(id.c_str()); } - } - return root_addresses_; - } - -protected: - std::unordered_map targets_; - target_type index_{0}; - - // Root address memory to be returned to the API caller - std::vector root_addresses_; -}; - -} // namespace ddwaf diff --git a/src/object_store.cpp b/src/object_store.cpp index c1c479b2b..098e5c6ac 100644 --- a/src/object_store.cpp +++ b/src/object_store.cpp @@ -10,11 +10,11 @@ namespace ddwaf { -object_store::object_store(const manifest &m, ddwaf_object_free_fn free_fn) - : manifest_(m), obj_free_(free_fn) +object_store::object_store(ddwaf_object_free_fn free_fn) + : obj_free_(free_fn) { if (obj_free_ != nullptr) { - objects_to_free_.reserve(8); + objects_to_free_.reserve(default_num_objects); } } @@ -38,7 +38,7 @@ bool object_store::insert(const ddwaf_object &input) return false; } - std::size_t entries = static_cast(input.nbEntries); + auto entries = static_cast(input.nbEntries); if (entries == 0) { // Objects with no addresses are considered valid as they are harmless return true; @@ -62,12 +62,7 @@ bool object_store::insert(const ddwaf_object &input) } std::string key(array[i].parameterName, length); - auto opt_target = manifest_.find(key); - if (!opt_target.has_value()) { - continue; - } - - auto target = *opt_target; + auto target = get_target_index(key); objects_[target] = &array[i]; latest_batch_.emplace(target); } @@ -75,7 +70,7 @@ bool object_store::insert(const ddwaf_object &input) return true; } -const ddwaf_object *object_store::get_target(manifest::target_type target) const +const ddwaf_object *object_store::get_target(target_index target) const { auto it = objects_.find(target); return it != objects_.end() ? it->second : nullptr; diff --git a/src/object_store.hpp b/src/object_store.hpp index cf39bb5b5..a890bde0e 100644 --- a/src/object_store.hpp +++ b/src/object_store.hpp @@ -8,16 +8,16 @@ #include #include -#include #include #include #include +#include namespace ddwaf { class object_store { public: - explicit object_store(const manifest &m, ddwaf_object_free_fn free_fn = ddwaf_object_free); + explicit object_store(ddwaf_object_free_fn free_fn = ddwaf_object_free); ~object_store(); object_store(const object_store &) = default; object_store(object_store &&) = default; @@ -26,9 +26,9 @@ class object_store { bool insert(const ddwaf_object &input); - const ddwaf_object *get_target(manifest::target_type target) const; + const ddwaf_object *get_target(target_index target) const; - bool is_new_target(const manifest::target_type target) const + bool is_new_target(const target_index target) const { return latest_batch_.find(target) != latest_batch_.cend(); } @@ -38,10 +38,10 @@ class object_store { explicit operator bool() const { return !objects_.empty(); } protected: - const ddwaf::manifest &manifest_; + static constexpr unsigned default_num_objects = 8; - memory::unordered_set latest_batch_; - memory::unordered_map objects_; + memory::unordered_set latest_batch_; + memory::unordered_map objects_; memory::vector objects_to_free_; ddwaf_object_free_fn obj_free_; diff --git a/src/parser/parser.hpp b/src/parser/parser.hpp index d626217da..d39ce92bd 100644 --- a/src/parser/parser.hpp +++ b/src/parser/parser.hpp @@ -7,7 +7,6 @@ #pragma once #include "parser/specification.hpp" -#include #include #include #include @@ -29,7 +28,7 @@ void parse( namespace v2 { rule_spec_container parse_rules(parameter::vector &rule_array, base_section_info &info, - manifest &target_manifest, std::unordered_map &rule_data_ids, + std::unordered_map &rule_data_ids, const object_limits &limits, rule::source_type source = rule::source_type::base); rule_data_container parse_rule_data(parameter::vector &rule_data, base_section_info &info, @@ -37,8 +36,8 @@ rule_data_container parse_rule_data(parameter::vector &rule_data, base_section_i override_spec_container parse_overrides(parameter::vector &override_array, base_section_info &info); -filter_spec_container parse_filters(parameter::vector &filter_array, base_section_info &info, - manifest &target_manifest, const object_limits &limits); +filter_spec_container parse_filters(parameter::vector &filter_array, + base_section_info &info, const object_limits &limits); } // namespace v2 } // namespace ddwaf::parser diff --git a/src/parser/parser_v1.cpp b/src/parser/parser_v1.cpp index 1c1ab94e4..e44483405 100644 --- a/src/parser/parser_v1.cpp +++ b/src/parser/parser_v1.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include #include @@ -28,8 +27,7 @@ namespace ddwaf::parser::v1 { namespace { -condition::ptr parseCondition(parameter::map &rule, manifest &target_manifest, - std::vector transformers, ddwaf::object_limits limits) +condition::ptr parseCondition(parameter::map &rule, std::vector transformers, ddwaf::object_limits limits) { auto operation = at(rule, "operation"); auto params = at(rule, "parameters"); @@ -95,7 +93,7 @@ condition::ptr parseCondition(parameter::map &rule, manifest &target_manifest, } condition::target_type target; - target.root = target_manifest.insert(root); + target.root = get_target_index(root); target.name = std::move(root); if (!key_path.empty()) { target.key_path.emplace_back(key_path); @@ -108,8 +106,7 @@ condition::ptr parseCondition(parameter::map &rule, manifest &target_manifest, std::move(targets), std::move(processor), std::string{}, limits); } -void parseRule(parameter::map &rule, base_section_info &info, manifest &target_manifest, - std::unordered_set &rule_ids, ddwaf::ruleset &rs, ddwaf::object_limits limits) +void parseRule(parameter::map &rule, base_section_info &info, std::unordered_set &rule_ids, ddwaf::ruleset &rs, ddwaf::object_limits limits) { auto id = at(rule, "id"); if (rule_ids.find(id) != rule_ids.end()) { @@ -135,7 +132,7 @@ void parseRule(parameter::map &rule, base_section_info &info, manifest &target_m conditions.reserve(conditions_array.size()); for (const auto &cond_param : conditions_array) { auto cond = static_cast(cond_param); - conditions.push_back(parseCondition(cond, target_manifest, rule_transformers, limits)); + conditions.push_back(parseCondition(cond, rule_transformers, limits)); } std::unordered_map tags; @@ -178,7 +175,7 @@ void parse( const auto &rule_param = rules_array[i]; try { auto rule = static_cast(rule_param); - parseRule(rule, section, rs.manifest, rule_ids, rs, limits); + parseRule(rule, section, rule_ids, rs, limits); } catch (const std::exception &e) { DDWAF_WARN("%s", e.what()); section.add_failed("index:" + std::to_string(i), e.what()); diff --git a/src/parser/parser_v2.cpp b/src/parser/parser_v2.cpp index e16680c9f..96ba74129 100644 --- a/src/parser/parser_v2.cpp +++ b/src/parser/parser_v2.cpp @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -130,9 +129,7 @@ std::vector parse_transformers( return transformers; } -condition::ptr parse_rule_condition(const parameter::map &root, manifest &target_manifest, - std::unordered_map &rule_data_ids, condition::data_source source, - const std::vector &transformers, const object_limits &limits) +condition::ptr parse_rule_condition(const parameter::map &root, std::unordered_map &rule_data_ids, condition::data_source source, const std::vector &transformers, const object_limits &limits) { auto operation = at(root, "operator"); auto params = at(root, "parameters"); @@ -163,7 +160,7 @@ condition::ptr parse_rule_condition(const parameter::map &root, manifest &target } condition::target_type target; - target.root = target_manifest.insert(address); + target.root = get_target_index(address); target.name = address; target.key_path = std::move(kp); @@ -183,9 +180,7 @@ condition::ptr parse_rule_condition(const parameter::map &root, manifest &target std::move(targets), std::move(processor), std::move(rule_data_id), limits); } -rule_spec parse_rule(parameter::map &rule, manifest &target_manifest, - std::unordered_map &rule_data_ids, const object_limits &limits, - rule::source_type source) +rule_spec parse_rule(parameter::map &rule, std::unordered_map &rule_data_ids, const object_limits &limits, rule::source_type source) { std::vector rule_transformers; auto data_source = ddwaf::condition::data_source::values; @@ -199,7 +194,7 @@ rule_spec parse_rule(parameter::map &rule, manifest &target_manifest, for (const auto &cond_param : conditions_array) { auto cond = static_cast(cond_param); conditions.push_back(parse_rule_condition( - cond, target_manifest, rule_data_ids, data_source, rule_transformers, limits)); + cond, rule_data_ids, data_source, rule_transformers, limits)); } std::unordered_map tags; @@ -283,8 +278,7 @@ std::pair parse_override(const parameter::map &node) return {current, type}; } -condition::ptr parse_filter_condition( - const parameter::map &root, manifest &target_manifest, const object_limits &limits) +condition::ptr parse_filter_condition(const parameter::map &root, const object_limits &limits) { auto operation = at(root, "operator"); auto params = at(root, "parameters"); @@ -316,7 +310,7 @@ condition::ptr parse_filter_condition( } condition::target_type target; - target.root = target_manifest.insert(address); + target.root = get_target_index(address); target.name = address; target.key_path = std::move(key_path); target.source = condition::data_source::values; @@ -334,9 +328,7 @@ condition::ptr parse_filter_condition( std::move(targets), std::move(processor), std::string{}, limits); } -input_filter_spec parse_input_filter( - const parameter::map &filter, manifest &target_manifest, const object_limits &limits) - +input_filter_spec parse_input_filter(const parameter::map &filter, const object_limits &limits) { // Check for conditions first std::vector conditions; @@ -346,7 +338,7 @@ input_filter_spec parse_input_filter( for (const auto &cond : conditions_array) { conditions.push_back( - parse_filter_condition(static_cast(cond), target_manifest, limits)); + parse_filter_condition(static_cast(cond), limits)); } } @@ -360,7 +352,7 @@ input_filter_spec parse_input_filter( } } - std::unordered_set input_targets; + std::unordered_set input_targets; auto obj_filter = std::make_shared(limits); auto inputs_array = at(filter, "inputs"); @@ -373,23 +365,16 @@ input_filter_spec parse_input_filter( auto input_map = static_cast(input_param); auto address = at(input_map, "address"); - auto optional_target = target_manifest.find(address); - if (!optional_target.has_value()) { - // This address isn't used by any rule so we skip it. - DDWAF_DEBUG("Address %s not used by any existing rule", address.c_str()); - continue; - } - + auto target = get_target_index(address); auto key_path = at>(input_map, "key_path", {}); - obj_filter->insert(*optional_target, key_path); + obj_filter->insert(target, std::move(address), key_path); } return {std::move(conditions), std::move(obj_filter), std::move(rules_target)}; } -rule_filter_spec parse_rule_filter( - const parameter::map &filter, manifest &target_manifest, const object_limits &limits) +rule_filter_spec parse_rule_filter(const parameter::map &filter, const object_limits &limits) { // Check for conditions first std::vector conditions; @@ -399,7 +384,7 @@ rule_filter_spec parse_rule_filter( for (const auto &cond : conditions_array) { conditions.push_back( - parse_filter_condition(static_cast(cond), target_manifest, limits)); + parse_filter_condition(static_cast(cond), limits)); } } @@ -424,9 +409,7 @@ std::string index_to_id(unsigned idx) { return "index:" + std::to_string(idx); } } // namespace -rule_spec_container parse_rules(parameter::vector &rule_array, base_section_info &info, - manifest &target_manifest, std::unordered_map &rule_data_ids, - const object_limits &limits, rule::source_type source) +rule_spec_container parse_rules(parameter::vector &rule_array, base_section_info &info, std::unordered_map &rule_data_ids, const object_limits &limits, rule::source_type source) { rule_spec_container rules; for (unsigned i = 0; i < rule_array.size(); ++i) { @@ -441,7 +424,7 @@ rule_spec_container parse_rules(parameter::vector &rule_array, base_section_info continue; } - auto rule = parse_rule(rule_map, target_manifest, rule_data_ids, limits, source); + auto rule = parse_rule(rule_map, rule_data_ids, limits, source); DDWAF_DEBUG("Parsed rule %s", id.c_str()); info.add_loaded(id); rules.emplace(std::move(id), std::move(rule)); @@ -552,8 +535,7 @@ override_spec_container parse_overrides(parameter::vector &override_array, base_ return overrides; } -filter_spec_container parse_filters(parameter::vector &filter_array, base_section_info &info, - manifest &target_manifest, const object_limits &limits) +filter_spec_container parse_filters(parameter::vector &filter_array, base_section_info &info, const object_limits &limits) { filter_spec_container filters; for (unsigned i = 0; i < filter_array.size(); i++) { @@ -569,11 +551,11 @@ filter_spec_container parse_filters(parameter::vector &filter_array, base_sectio } if (node.find("inputs") != node.end()) { - auto filter = parse_input_filter(node, target_manifest, limits); + auto filter = parse_input_filter(node, limits); filters.ids.emplace(id); filters.input_filters.emplace(id, std::move(filter)); } else { - auto filter = parse_rule_filter(node, target_manifest, limits); + auto filter = parse_rule_filter(node, limits); filters.ids.emplace(id); filters.rule_filters.emplace(id, std::move(filter)); } diff --git a/src/rule.hpp b/src/rule.hpp index 905ef5c70..af3be1757 100644 --- a/src/rule.hpp +++ b/src/rule.hpp @@ -86,6 +86,14 @@ class rule { const std::vector &get_actions() const { return actions_; } + void get_addresses(std::unordered_set &addresses) const { + for (const auto &cond : conditions_) { + for (const auto &target : cond->get_targets()) { + addresses.emplace(target.name); + } + } + } + void set_actions(std::vector new_actions) { actions_ = std::move(new_actions); } protected: diff --git a/src/ruleset.hpp b/src/ruleset.hpp index fd8c6c356..f963289ce 100644 --- a/src/ruleset.hpp +++ b/src/ruleset.hpp @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -14,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -51,10 +51,32 @@ struct ruleset { for (const auto &[id, rule] : rules_) { insert_rule(rule); } } + [[nodiscard]] const std::vector &get_root_addresses() + { + if (root_addresses.empty()) { + for (const auto &rule : rules) { + rule->get_addresses(unique_root_addresses); + } + + for (const auto &[id, filter] : rule_filters) { + filter->get_addresses(unique_root_addresses); + } + + for (const auto &[id, filter] : input_filters) { + filter->get_addresses(unique_root_addresses); + } + + for (const auto &str : unique_root_addresses) { + root_addresses.emplace_back(str.c_str()); + } + } + + return root_addresses; + } + ddwaf_object_free_fn free_fn{ddwaf_object_free}; std::shared_ptr event_obfuscator; - ddwaf::manifest manifest; std::unordered_map rule_filters; std::unordered_map input_filters; @@ -67,6 +89,11 @@ struct ruleset { std::unordered_map base_priority_collections; std::unordered_map user_collections; std::unordered_map base_collections; + + // Root addresses, lazily computed + std::unordered_set unique_root_addresses; + // Root address memory to be returned to the API caller + std::vector root_addresses; }; } // namespace ddwaf diff --git a/src/ruleset_builder.cpp b/src/ruleset_builder.cpp index cc9ab647c..32971df3a 100644 --- a/src/ruleset_builder.cpp +++ b/src/ruleset_builder.cpp @@ -71,8 +71,6 @@ std::shared_ptr ruleset_builder::build(parameter::map &root, base_rules constexpr static change_state base_rule_update = change_state::rules | change_state::overrides; constexpr static change_state filters_update = base_rule_update | change_state::custom_rules | change_state::filters; - constexpr static change_state manifest_update = - change_state::rules | change_state::custom_rules | change_state::filters; // When a configuration with 'rules' or 'rules_override' is received, we // need to regenerate the ruleset from the base rules as we want to ensure @@ -80,16 +78,9 @@ std::shared_ptr ruleset_builder::build(parameter::map &root, base_rules if ((state & base_rule_update) != change_state::none) { final_base_rules_.clear(); base_rules_by_tags_.clear(); - inputs_from_base_rules_.clear(); // Initially, new rules are generated from their spec for (const auto &[id, spec] : base_rules_) { - for (const auto &cond : spec.conditions) { - for (const auto &target : cond->get_targets()) { - inputs_from_base_rules_.emplace(target.root); - } - } - auto rule_ptr = std::make_shared( id, spec.name, spec.tags, spec.conditions, spec.actions, spec.enabled, spec.source); @@ -130,16 +121,9 @@ std::shared_ptr ruleset_builder::build(parameter::map &root, base_rules if ((state & change_state::custom_rules) != change_state::none) { final_user_rules_.clear(); user_rules_by_tags_.clear(); - inputs_from_user_rules_.clear(); // Initially, new rules are generated from their spec for (const auto &[id, spec] : user_rules_) { - for (const auto &cond : spec.conditions) { - for (const auto &target : cond->get_targets()) { - inputs_from_user_rules_.emplace(target.root); - } - } - auto rule_ptr = std::make_shared( id, spec.name, spec.tags, spec.conditions, spec.actions, spec.enabled, spec.source); @@ -153,7 +137,6 @@ std::shared_ptr ruleset_builder::build(parameter::map &root, base_rules if ((state & filters_update) != change_state::none) { rule_filters_.clear(); input_filters_.clear(); - inputs_from_filters_.clear(); // First generate rule filters for (const auto &[id, filter] : exclusions_.rule_filters) { @@ -165,12 +148,6 @@ std::shared_ptr ruleset_builder::build(parameter::map &root, base_rules auto filter_ptr = std::make_shared( id, filter.conditions, std::move(rule_targets)); rule_filters_.emplace(filter_ptr->get_id(), filter_ptr); - - for (const auto &cond : filter.conditions) { - for (const auto &target : cond->get_targets()) { - inputs_from_filters_.emplace(target.root); - } - } } // Finally input filters @@ -183,32 +160,10 @@ std::shared_ptr ruleset_builder::build(parameter::map &root, base_rules auto filter_ptr = std::make_shared( id, filter.conditions, std::move(rule_targets), filter.filter); input_filters_.emplace(filter_ptr->get_id(), filter_ptr); - - for (const auto &target : filter.filter->get_targets()) { - inputs_from_filters_.emplace(target); - } - - for (const auto &cond : filter.conditions) { - for (const auto &target : cond->get_targets()) { - inputs_from_filters_.emplace(target.root); - } - } } } - if ((state & manifest_update) != change_state::none) { - // Remove unnecessary targets using all the targets contained within - // rule conditions, filter conditions and object filters - std::unordered_set all_targets; - all_targets.insert(inputs_from_base_rules_.begin(), inputs_from_base_rules_.end()); - all_targets.insert(inputs_from_user_rules_.begin(), inputs_from_user_rules_.end()); - all_targets.insert(inputs_from_filters_.begin(), inputs_from_filters_.end()); - - target_manifest_.remove_unused(all_targets); - } - auto rs = std::make_shared(); - rs->manifest = target_manifest_; rs->insert_rules(final_base_rules_); rs->insert_rules(final_user_rules_); rs->dynamic_processors = dynamic_processors_; @@ -240,7 +195,7 @@ ruleset_builder::change_state ruleset_builder::load(parameter::map &root, base_r if (!rules.empty()) { base_rules_ = parser::v2::parse_rules( - rules, section, target_manifest_, rule_data_ids_, limits_); + rules, section, rule_data_ids_, limits_); } else { DDWAF_DEBUG("Clearing all base rules"); base_rules_.clear(); @@ -263,7 +218,7 @@ ruleset_builder::change_state ruleset_builder::load(parameter::map &root, base_r // be discarded after decltype(rule_data_ids_) rule_data_ids; - auto new_user_rules = parser::v2::parse_rules(rules, section, target_manifest_, + auto new_user_rules = parser::v2::parse_rules(rules, section, rule_data_ids, limits_, rule::source_type::user); user_rules_ = std::move(new_user_rules); } else { @@ -338,7 +293,7 @@ ruleset_builder::change_state ruleset_builder::load(parameter::map &root, base_r auto exclusions = static_cast(it->second); if (!exclusions.empty()) { exclusions_ = - parser::v2::parse_filters(exclusions, section, target_manifest_, limits_); + parser::v2::parse_filters(exclusions, section, limits_); } else { DDWAF_DEBUG("Clearing all exclusions"); exclusions_.clear(); diff --git a/src/ruleset_builder.hpp b/src/ruleset_builder.hpp index 5b5fd6da8..e97f31cfc 100644 --- a/src/ruleset_builder.hpp +++ b/src/ruleset_builder.hpp @@ -7,7 +7,6 @@ #pragma once #include "parser/specification.hpp" -#include #include #include #include @@ -63,9 +62,6 @@ class ruleset_builder { const ddwaf_object_free_fn free_fn_; std::shared_ptr event_obfuscator_; - // The same manifest is used across updates, so we need to ensure that - // unused targets are regularly cleaned up. - manifest target_manifest_; // Map representing rule data IDs to processor type, this is obtained // from parsing the ruleset ('rules' key). std::unordered_map rule_data_ids_; @@ -98,16 +94,10 @@ class ruleset_builder { rule_tag_map base_rules_by_tags_; rule_tag_map user_rules_by_tags_; - // The list of tagets used by the rules in final_rules_, used for manifest cleanup - std::unordered_set inputs_from_base_rules_; - std::unordered_set inputs_from_user_rules_; - // Filters std::unordered_map rule_filters_; std::unordered_map input_filters_; // The list of targets used by rule_filters_, input_filters_ and their internal - // object filters, used for manifest cleanup - std::unordered_set inputs_from_filters_; }; } // namespace ddwaf diff --git a/src/utils.hpp b/src/utils.hpp index 45aeb4e83..3ac19eae4 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -31,6 +31,12 @@ size_t find_string_cutoff( namespace ddwaf { +using target_index = std::size_t; + +inline target_index get_target_index(const std::string &address) { + return std::hash()(address); +} + namespace object { inline bool is_container(const ddwaf_object *obj) @@ -65,4 +71,5 @@ template class scope_exit { protected: Fn fn_; }; + } // namespace ddwaf diff --git a/src/waf.hpp b/src/waf.hpp index f365e6681..c249c9d36 100644 --- a/src/waf.hpp +++ b/src/waf.hpp @@ -28,7 +28,7 @@ class waf { [[nodiscard]] const std::vector &get_root_addresses() const { - return ruleset_->manifest.get_root_addresses(); + return ruleset_->get_root_addresses(); } protected: diff --git a/tests/TestAdditive.cpp b/tests/TestAdditive.cpp index 3d2afbab7..98099b866 100644 --- a/tests/TestAdditive.cpp +++ b/tests/TestAdditive.cpp @@ -6,11 +6,6 @@ #include "test.h" -void populateManifest(ddwaf::manifest &manifest) -{ - for (const auto *key : {"value", "key", "mixed", "mixed2"}) { manifest.insert(key); } -} - TEST(TestAdditive, TestMultiCall) { // Initialize a PowerWAF rule diff --git a/tests/collection_test.cpp b/tests/collection_test.cpp index 34bebbb15..4bee7ae66 100644 --- a/tests/collection_test.cpp +++ b/tests/collection_test.cpp @@ -19,8 +19,7 @@ TYPED_TEST(TestCollection, SingleRuleMatch) { std::vector targets; - ddwaf::manifest manifest; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"192.168.0.1"})); @@ -36,7 +35,7 @@ TYPED_TEST(TestCollection, SingleRuleMatch) rule_collection.insert(rule); collection_cache cache; - ddwaf::object_store store(manifest); + ddwaf::object_store store; { ddwaf_object root; ddwaf_object tmp; @@ -72,10 +71,9 @@ TYPED_TEST(TestCollection, MultipleRuleCachedMatch) { std::vector rules; TypeParam rule_collection; - ddwaf::manifest manifest; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( @@ -95,7 +93,7 @@ TYPED_TEST(TestCollection, MultipleRuleCachedMatch) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); @@ -113,7 +111,7 @@ TYPED_TEST(TestCollection, MultipleRuleCachedMatch) } ddwaf::timer deadline{2s}; - ddwaf::object_store store(manifest); + ddwaf::object_store store; collection_cache cache; { @@ -150,10 +148,9 @@ TYPED_TEST(TestCollection, MultipleRuleFailAndMatch) { std::vector rules; TypeParam rule_collection; - ddwaf::manifest manifest; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( @@ -172,7 +169,7 @@ TYPED_TEST(TestCollection, MultipleRuleFailAndMatch) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); @@ -189,7 +186,7 @@ TYPED_TEST(TestCollection, MultipleRuleFailAndMatch) } ddwaf::timer deadline{2s}; - ddwaf::object_store store(manifest); + ddwaf::object_store store; collection_cache cache; { @@ -224,11 +221,10 @@ TYPED_TEST(TestCollection, MultipleRuleFailAndMatch) // Validate that the rule cache is acted on TYPED_TEST(TestCollection, SingleRuleMultipleCalls) { - ddwaf::manifest manifest; std::vector conditions; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); conditions.emplace_back(std::make_shared( std::move(targets), std::make_unique( @@ -237,7 +233,7 @@ TYPED_TEST(TestCollection, SingleRuleMultipleCalls) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); conditions.emplace_back(std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"}))); @@ -258,7 +254,7 @@ TYPED_TEST(TestCollection, SingleRuleMultipleCalls) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); memory::vector events; @@ -274,7 +270,7 @@ TYPED_TEST(TestCollection, SingleRuleMultipleCalls) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); memory::vector events; @@ -291,10 +287,9 @@ TEST(TestPriorityCollection, NoRegularMatchAfterPriorityMatch) std::vector rules; collection regular; priority_collection priority; - ddwaf::manifest manifest; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( @@ -313,7 +308,7 @@ TEST(TestPriorityCollection, NoRegularMatchAfterPriorityMatch) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); @@ -331,7 +326,7 @@ TEST(TestPriorityCollection, NoRegularMatchAfterPriorityMatch) } ddwaf::timer deadline{2s}; - ddwaf::object_store store(manifest); + ddwaf::object_store store; collection_cache cache; { @@ -371,10 +366,9 @@ TEST(TestPriorityCollection, PriorityMatchAfterRegularMatch) std::vector rules; collection regular; priority_collection priority; - ddwaf::manifest manifest; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( @@ -393,7 +387,7 @@ TEST(TestPriorityCollection, PriorityMatchAfterRegularMatch) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); @@ -411,7 +405,7 @@ TEST(TestPriorityCollection, PriorityMatchAfterRegularMatch) } ddwaf::timer deadline{2s}; - ddwaf::object_store store(manifest); + ddwaf::object_store store; collection_cache cache; { @@ -451,10 +445,9 @@ TEST(TestPriorityCollection, NoPriorityMatchAfterPriorityMatch) { std::vector rules; priority_collection priority; - ddwaf::manifest manifest; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( @@ -473,7 +466,7 @@ TEST(TestPriorityCollection, NoPriorityMatchAfterPriorityMatch) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); @@ -491,7 +484,7 @@ TEST(TestPriorityCollection, NoPriorityMatchAfterPriorityMatch) } ddwaf::timer deadline{2s}; - ddwaf::object_store store(manifest); + ddwaf::object_store store; collection_cache cache; { diff --git a/tests/condition_test.cpp b/tests/condition_test.cpp index 2a646d2f2..df170cdfc 100644 --- a/tests/condition_test.cpp +++ b/tests/condition_test.cpp @@ -13,8 +13,7 @@ TEST(TestCondition, Match) { std::vector targets; - ddwaf::manifest manifest; - targets.push_back({manifest.insert("server.request.query"), "server.request.query"}); + targets.push_back({get_target_index("server.request.query"), "server.request.query"}); auto cond = std::make_shared( std::move(targets), std::make_unique(".*", 0, true)); @@ -24,7 +23,7 @@ TEST(TestCondition, Match) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "value")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -44,9 +43,8 @@ TEST(TestCondition, MatchWithKeyPath) { std::vector targets; - ddwaf::manifest manifest; targets.push_back( - {manifest.insert("server.request.query"), "server.request.query", {"key"}, {}}); + {get_target_index("server.request.query"), "server.request.query", {"key"}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique(".*", 0, true)); @@ -59,7 +57,7 @@ TEST(TestCondition, MatchWithKeyPath) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "server.request.query", &submap); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -80,9 +78,8 @@ TEST(TestCondition, MatchWithTransformer) { std::vector targets; - ddwaf::manifest manifest; targets.push_back( - {manifest.insert("server.request.query"), "server.request.query", {}, {PWT_LOWERCASE}}); + {get_target_index("server.request.query"), "server.request.query", {}, {PWT_LOWERCASE}}); auto cond = std::make_shared( std::move(targets), std::make_unique("value", 0, true)); @@ -92,7 +89,7 @@ TEST(TestCondition, MatchWithTransformer) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "VALUE")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -112,8 +109,7 @@ TEST(TestCondition, MatchWithMultipleTransformers) { std::vector targets; - ddwaf::manifest manifest; - targets.push_back({manifest.insert("server.request.query"), "server.request.query", {}, + targets.push_back({get_target_index("server.request.query"), "server.request.query", {}, {PWT_COMPRESS_WHITE, PWT_LOWERCASE}}); auto cond = std::make_shared( @@ -124,7 +120,7 @@ TEST(TestCondition, MatchWithMultipleTransformers) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, " VALUE ")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -144,8 +140,7 @@ TEST(TestCondition, MatchOnKeys) { std::vector targets; - ddwaf::manifest manifest; - targets.push_back({manifest.insert("server.request.query"), "server.request.query", {}, {}, + targets.push_back({get_target_index("server.request.query"), "server.request.query", {}, {}, condition::data_source::keys}); auto cond = std::make_shared( @@ -159,7 +154,7 @@ TEST(TestCondition, MatchOnKeys) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "server.request.query", &value); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -180,8 +175,7 @@ TEST(TestCondition, MatchOnKeysWithTransformer) { std::vector targets; - ddwaf::manifest manifest; - targets.push_back({manifest.insert("server.request.query"), "server.request.query", {}, + targets.push_back({get_target_index("server.request.query"), "server.request.query", {}, {PWT_LOWERCASE}, condition::data_source::keys}); auto cond = std::make_shared( @@ -195,7 +189,7 @@ TEST(TestCondition, MatchOnKeysWithTransformer) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "server.request.query", &value); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -216,8 +210,7 @@ TEST(TestCondition, NoMatch) { std::vector targets; - ddwaf::manifest manifest; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip"}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip"}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{})); @@ -227,7 +220,7 @@ TEST(TestCondition, NoMatch) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -240,8 +233,7 @@ TEST(TestCondition, ExcludeInput) { std::vector targets; - ddwaf::manifest manifest; - targets.push_back({manifest.insert("server.request.query"), "server.request.query"}); + targets.push_back({get_target_index("server.request.query"), "server.request.query"}); auto cond = std::make_shared( std::move(targets), std::make_unique(".*", 0, true)); @@ -251,7 +243,7 @@ TEST(TestCondition, ExcludeInput) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "value")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -264,8 +256,7 @@ TEST(TestCondition, ExcludeKeyPath) { std::vector targets; - ddwaf::manifest manifest; - targets.push_back({manifest.insert("server.request.query"), "server.request.query"}); + targets.push_back({get_target_index("server.request.query"), "server.request.query"}); auto cond = std::make_shared( std::move(targets), std::make_unique(".*", 0, true)); @@ -279,7 +270,7 @@ TEST(TestCondition, ExcludeKeyPath) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "server.request.query", &map); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; diff --git a/tests/context_test.cpp b/tests/context_test.cpp index e41e6f51b..457675783 100644 --- a/tests/context_test.cpp +++ b/tests/context_test.cpp @@ -24,8 +24,7 @@ TEST(TestContext, MatchTimeout) { std::vector targets; - ddwaf::manifest manifest; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"192.168.0.1"})); @@ -39,7 +38,6 @@ TEST(TestContext, MatchTimeout) auto ruleset = std::make_shared(); ruleset->insert_rule(rule); - ruleset->manifest = manifest; ddwaf::timer deadline{0s}; ddwaf::test::context ctx(ruleset); @@ -57,8 +55,7 @@ TEST(TestContext, NoMatch) { std::vector targets; - ddwaf::manifest manifest; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"192.168.0.1"})); @@ -72,7 +69,6 @@ TEST(TestContext, NoMatch) auto ruleset = std::make_shared(); ruleset->insert_rule(rule); - ruleset->manifest = manifest; ddwaf::timer deadline{2s}; ddwaf::test::context ctx(ruleset); @@ -91,8 +87,7 @@ TEST(TestContext, Match) { std::vector targets; - ddwaf::manifest manifest; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"192.168.0.1"})); @@ -106,7 +101,6 @@ TEST(TestContext, Match) auto ruleset = std::make_shared(); ruleset->insert_rule(rule); - ruleset->manifest = manifest; ddwaf::timer deadline{2s}; ddwaf::test::context ctx(ruleset); @@ -124,10 +118,9 @@ TEST(TestContext, Match) TEST(TestContext, MatchMultipleRulesInCollectionSingleRun) { auto ruleset = std::make_shared(); - ddwaf::manifest manifest; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( @@ -146,7 +139,7 @@ TEST(TestContext, MatchMultipleRulesInCollectionSingleRun) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); @@ -162,8 +155,6 @@ TEST(TestContext, MatchMultipleRulesInCollectionSingleRun) ruleset->insert_rule(rule); } - ruleset->manifest = manifest; - ddwaf::timer deadline{2s}; ddwaf::test::context ctx(ruleset); @@ -198,10 +189,9 @@ TEST(TestContext, MatchMultipleRulesInCollectionSingleRun) TEST(TestContext, MatchMultipleRulesWithPrioritySingleRun) { auto ruleset = std::make_shared(); - ddwaf::manifest manifest; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( @@ -220,7 +210,7 @@ TEST(TestContext, MatchMultipleRulesWithPrioritySingleRun) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); @@ -237,8 +227,6 @@ TEST(TestContext, MatchMultipleRulesWithPrioritySingleRun) ruleset->insert_rule(rule); } - ruleset->manifest = manifest; - { ddwaf::test::context ctx(ruleset); @@ -283,10 +271,9 @@ TEST(TestContext, MatchMultipleRulesWithPrioritySingleRun) TEST(TestContext, MatchMultipleRulesInCollectionDoubleRun) { auto ruleset = std::make_shared(); - ddwaf::manifest manifest; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( @@ -305,7 +292,7 @@ TEST(TestContext, MatchMultipleRulesInCollectionDoubleRun) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); @@ -321,8 +308,6 @@ TEST(TestContext, MatchMultipleRulesInCollectionDoubleRun) ruleset->insert_rule(rule); } - ruleset->manifest = manifest; - ddwaf::timer deadline{2s}; ddwaf::test::context ctx(ruleset); @@ -369,10 +354,9 @@ TEST(TestContext, MatchMultipleRulesInCollectionDoubleRun) TEST(TestContext, MatchMultipleRulesWithPriorityDoubleRunPriorityLast) { auto ruleset = std::make_shared(); - ddwaf::manifest manifest; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( @@ -391,7 +375,7 @@ TEST(TestContext, MatchMultipleRulesWithPriorityDoubleRunPriorityLast) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); @@ -407,8 +391,6 @@ TEST(TestContext, MatchMultipleRulesWithPriorityDoubleRunPriorityLast) ruleset->insert_rule(rule); } - ruleset->manifest = manifest; - ddwaf::timer deadline{2s}; ddwaf::test::context ctx(ruleset); @@ -475,10 +457,9 @@ TEST(TestContext, MatchMultipleRulesWithPriorityDoubleRunPriorityLast) TEST(TestContext, MatchMultipleRulesWithPriorityDoubleRunPriorityFirst) { auto ruleset = std::make_shared(); - ddwaf::manifest manifest; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( @@ -497,7 +478,7 @@ TEST(TestContext, MatchMultipleRulesWithPriorityDoubleRunPriorityFirst) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); @@ -513,8 +494,6 @@ TEST(TestContext, MatchMultipleRulesWithPriorityDoubleRunPriorityFirst) ruleset->insert_rule(rule); } - ruleset->manifest = manifest; - ddwaf::timer deadline{2s}; ddwaf::test::context ctx(ruleset); @@ -563,10 +542,9 @@ TEST(TestContext, MatchMultipleRulesWithPriorityDoubleRunPriorityFirst) TEST(TestContext, MatchMultipleRulesWithPriorityUntilAllActionsMet) { auto ruleset = std::make_shared(); - ddwaf::manifest manifest; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( @@ -585,7 +563,7 @@ TEST(TestContext, MatchMultipleRulesWithPriorityUntilAllActionsMet) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); @@ -601,8 +579,6 @@ TEST(TestContext, MatchMultipleRulesWithPriorityUntilAllActionsMet) ruleset->insert_rule(rule); } - ruleset->manifest = manifest; - ddwaf::timer deadline{2s}; ddwaf::test::context ctx(ruleset); @@ -667,10 +643,9 @@ TEST(TestContext, MatchMultipleRulesWithPriorityUntilAllActionsMet) TEST(TestContext, MatchMultipleCollectionsSingleRun) { auto ruleset = std::make_shared(); - ddwaf::manifest manifest; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( @@ -689,7 +664,7 @@ TEST(TestContext, MatchMultipleCollectionsSingleRun) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); @@ -705,8 +680,6 @@ TEST(TestContext, MatchMultipleCollectionsSingleRun) ruleset->insert_rule(rule); } - ruleset->manifest = manifest; - ddwaf::timer deadline{2s}; ddwaf::test::context ctx(ruleset); @@ -724,10 +697,9 @@ TEST(TestContext, MatchMultipleCollectionsSingleRun) TEST(TestContext, MatchMultiplePriorityCollectionsSingleRun) { auto ruleset = std::make_shared(); - ddwaf::manifest manifest; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( @@ -746,7 +718,7 @@ TEST(TestContext, MatchMultiplePriorityCollectionsSingleRun) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); @@ -762,8 +734,6 @@ TEST(TestContext, MatchMultiplePriorityCollectionsSingleRun) ruleset->insert_rule(rule); } - ruleset->manifest = manifest; - ddwaf::timer deadline{2s}; ddwaf::test::context ctx(ruleset); @@ -781,10 +751,9 @@ TEST(TestContext, MatchMultiplePriorityCollectionsSingleRun) TEST(TestContext, MatchMultipleCollectionsDoubleRun) { auto ruleset = std::make_shared(); - ddwaf::manifest manifest; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( @@ -803,7 +772,7 @@ TEST(TestContext, MatchMultipleCollectionsDoubleRun) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); @@ -819,8 +788,6 @@ TEST(TestContext, MatchMultipleCollectionsDoubleRun) ruleset->insert_rule(rule); } - ruleset->manifest = manifest; - ddwaf::timer deadline{2s}; ddwaf::test::context ctx(ruleset); @@ -850,10 +817,9 @@ TEST(TestContext, MatchMultipleCollectionsDoubleRun) TEST(TestContext, MatchMultiplePriorityCollectionsDoubleRun) { auto ruleset = std::make_shared(); - ddwaf::manifest manifest; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( @@ -872,7 +838,7 @@ TEST(TestContext, MatchMultiplePriorityCollectionsDoubleRun) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); @@ -888,8 +854,6 @@ TEST(TestContext, MatchMultiplePriorityCollectionsDoubleRun) ruleset->insert_rule(rule); } - ruleset->manifest = manifest; - ddwaf::timer deadline{2s}; ddwaf::test::context ctx(ruleset); @@ -919,13 +883,12 @@ TEST(TestContext, MatchMultiplePriorityCollectionsDoubleRun) TEST(TestContext, RuleFilterWithCondition) { auto ruleset = std::make_shared(); - ddwaf::manifest manifest; // Generate rule ddwaf::rule::ptr rule; { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); @@ -944,7 +907,7 @@ TEST(TestContext, RuleFilterWithCondition) // Generate filter { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( @@ -957,8 +920,6 @@ TEST(TestContext, RuleFilterWithCondition) ruleset->rule_filters.emplace(filter->get_id(), filter); } - ruleset->manifest = manifest; - ddwaf::timer deadline{2s}; ddwaf::test::context ctx(ruleset); @@ -980,13 +941,12 @@ TEST(TestContext, RuleFilterWithCondition) TEST(TestContext, RuleFilterTimeout) { auto ruleset = std::make_shared(); - ddwaf::manifest manifest; // Generate rule ddwaf::rule::ptr rule; { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); @@ -1005,7 +965,7 @@ TEST(TestContext, RuleFilterTimeout) // Generate filter { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( @@ -1018,8 +978,6 @@ TEST(TestContext, RuleFilterTimeout) ruleset->rule_filters.emplace(filter->get_id(), filter); } - ruleset->manifest = manifest; - ddwaf::timer deadline{0s}; ddwaf::test::context ctx(ruleset); @@ -1036,13 +994,12 @@ TEST(TestContext, RuleFilterTimeout) TEST(TestContext, NoRuleFilterWithCondition) { auto ruleset = std::make_shared(); - ddwaf::manifest manifest; // Generate rule ddwaf::rule::ptr rule; { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); @@ -1061,7 +1018,7 @@ TEST(TestContext, NoRuleFilterWithCondition) // Generate filter { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( @@ -1074,8 +1031,6 @@ TEST(TestContext, NoRuleFilterWithCondition) ruleset->rule_filters.emplace(filter->get_id(), filter); } - ruleset->manifest = manifest; - ddwaf::timer deadline{2s}; ddwaf::test::context ctx(ruleset); @@ -1279,7 +1234,6 @@ TEST(TestContext, MultipleRuleFiltersOverlappingRules) TEST(TestContext, MultipleRuleFiltersNonOverlappingRulesWithConditions) { auto ruleset = std::make_shared(); - ddwaf::manifest manifest; // Generate rule constexpr unsigned num_rules = 10; @@ -1302,7 +1256,7 @@ TEST(TestContext, MultipleRuleFiltersNonOverlappingRulesWithConditions) { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( @@ -1318,7 +1272,7 @@ TEST(TestContext, MultipleRuleFiltersNonOverlappingRulesWithConditions) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); @@ -1331,8 +1285,6 @@ TEST(TestContext, MultipleRuleFiltersNonOverlappingRulesWithConditions) ruleset->rule_filters.emplace(filter->get_id(), filter); } - ruleset->manifest = manifest; - { ddwaf_object root; ddwaf_object tmp; @@ -1374,7 +1326,6 @@ TEST(TestContext, MultipleRuleFiltersNonOverlappingRulesWithConditions) TEST(TestContext, MultipleRuleFiltersOverlappingRulesWithConditions) { auto ruleset = std::make_shared(); - ddwaf::manifest manifest; // Generate rule constexpr unsigned num_rules = 10; @@ -1397,7 +1348,7 @@ TEST(TestContext, MultipleRuleFiltersOverlappingRulesWithConditions) { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( @@ -1413,7 +1364,7 @@ TEST(TestContext, MultipleRuleFiltersOverlappingRulesWithConditions) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); @@ -1426,8 +1377,6 @@ TEST(TestContext, MultipleRuleFiltersOverlappingRulesWithConditions) ruleset->rule_filters.emplace(filter->get_id(), filter); } - ruleset->manifest = manifest; - { ddwaf_object root; ddwaf_object tmp; @@ -1470,8 +1419,7 @@ TEST(TestContext, MultipleRuleFiltersOverlappingRulesWithConditions) TEST(TestContext, InputFilterExclude) { - ddwaf::manifest manifest; - condition::target_type client_ip{manifest.insert("http.client_ip"), "http.client_ip", {}}; + condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}}; std::vector targets{client_ip}; auto cond = std::make_shared(std::move(targets), @@ -1485,7 +1433,7 @@ TEST(TestContext, InputFilterExclude) "id", "name", std::move(tags), std::move(conditions), std::vector{}); auto obj_filter = std::make_shared(); - obj_filter->insert(client_ip.root); + obj_filter->insert(client_ip.root, client_ip.name); std::vector filter_conditions; std::set filter_rules{rule.get()}; @@ -1494,7 +1442,6 @@ TEST(TestContext, InputFilterExclude) auto ruleset = std::make_shared(); ruleset->insert_rule(rule); - ruleset->manifest = manifest; ruleset->input_filters.emplace(filter->get_id(), filter); ddwaf::timer deadline{2s}; @@ -1514,8 +1461,7 @@ TEST(TestContext, InputFilterExclude) TEST(TestContext, InputFilterExcludeRule) { - ddwaf::manifest manifest; - condition::target_type client_ip{manifest.insert("http.client_ip"), "http.client_ip", {}}; + condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}}; std::vector targets{client_ip}; auto cond = std::make_shared(std::move(targets), @@ -1529,7 +1475,7 @@ TEST(TestContext, InputFilterExcludeRule) "id", "name", std::move(tags), std::move(conditions), std::vector{}); auto obj_filter = std::make_shared(); - obj_filter->insert(client_ip.root); + obj_filter->insert(client_ip.root, client_ip.name); std::vector filter_conditions; std::set filter_rules{rule.get()}; @@ -1538,7 +1484,6 @@ TEST(TestContext, InputFilterExcludeRule) auto ruleset = std::make_shared(); ruleset->insert_rule(rule); - ruleset->manifest = manifest; ruleset->input_filters.emplace(filter->get_id(), filter); ddwaf::timer deadline{2s}; @@ -1561,9 +1506,8 @@ TEST(TestContext, InputFilterExcludeRule) TEST(TestContext, InputFilterWithCondition) { - ddwaf::manifest manifest; - condition::target_type client_ip{manifest.insert("http.client_ip"), "http.client_ip", {}}; - condition::target_type usr_id{manifest.insert("usr.id"), "usr.id", {}}; + condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}}; + condition::target_type usr_id{get_target_index("usr.id"), "usr.id", {}}; auto ruleset = std::make_shared(); { @@ -1585,7 +1529,7 @@ TEST(TestContext, InputFilterWithCondition) { auto obj_filter = std::make_shared(); - obj_filter->insert(client_ip.root); + obj_filter->insert(client_ip.root, client_ip.name); std::vector> conditions; std::vector targets{usr_id}; @@ -1600,8 +1544,6 @@ TEST(TestContext, InputFilterWithCondition) ruleset->input_filters.emplace(filter->get_id(), filter); } - ruleset->manifest = manifest; - // Without usr.id, nothing should be excluded { ddwaf::timer deadline{2s}; @@ -1658,9 +1600,8 @@ TEST(TestContext, InputFilterWithCondition) TEST(TestContext, InputFilterMultipleRules) { - ddwaf::manifest manifest; - condition::target_type client_ip{manifest.insert("http.client_ip"), "http.client_ip", {}}; - condition::target_type usr_id{manifest.insert("usr.id"), "usr.id", {}}; + condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}}; + condition::target_type usr_id{get_target_index("usr.id"), "usr.id", {}}; auto ruleset = std::make_shared(); { @@ -1698,8 +1639,8 @@ TEST(TestContext, InputFilterMultipleRules) { auto obj_filter = std::make_shared(); - obj_filter->insert(client_ip.root); - obj_filter->insert(usr_id.root); + obj_filter->insert(client_ip.root, client_ip.name); + obj_filter->insert(usr_id.root, usr_id.name); std::vector> conditions; std::set filter_rules{ruleset->rules[0].get(), ruleset->rules[1].get()}; @@ -1709,8 +1650,6 @@ TEST(TestContext, InputFilterMultipleRules) ruleset->input_filters.emplace(filter->get_id(), filter); } - ruleset->manifest = manifest; - // Without usr.id, nothing should be excluded { ddwaf::timer deadline{2s}; @@ -1773,9 +1712,8 @@ TEST(TestContext, InputFilterMultipleRules) TEST(TestContext, InputFilterMultipleRulesMultipleFilters) { - ddwaf::manifest manifest; - condition::target_type client_ip{manifest.insert("http.client_ip"), "http.client_ip", {}}; - condition::target_type usr_id{manifest.insert("usr.id"), "usr.id", {}}; + condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}}; + condition::target_type usr_id{get_target_index("usr.id"), "usr.id", {}}; auto ruleset = std::make_shared(); { @@ -1813,7 +1751,7 @@ TEST(TestContext, InputFilterMultipleRulesMultipleFilters) { auto obj_filter = std::make_shared(); - obj_filter->insert(client_ip.root); + obj_filter->insert(client_ip.root, client_ip.name); std::vector> conditions; std::set filter_rules{ruleset->rules[0].get()}; @@ -1825,7 +1763,7 @@ TEST(TestContext, InputFilterMultipleRulesMultipleFilters) { auto obj_filter = std::make_shared(); - obj_filter->insert(usr_id.root); + obj_filter->insert(usr_id.root, usr_id.name); std::vector> conditions; std::set filter_rules{ruleset->rules[1].get()}; @@ -1835,8 +1773,6 @@ TEST(TestContext, InputFilterMultipleRulesMultipleFilters) ruleset->input_filters.emplace(filter->get_id(), filter); } - ruleset->manifest = manifest; - // Without usr.id, nothing should be excluded { ddwaf::timer deadline{2s}; @@ -1899,11 +1835,10 @@ TEST(TestContext, InputFilterMultipleRulesMultipleFilters) TEST(TestContext, InputFilterMultipleRulesMultipleFiltersMultipleObjects) { - ddwaf::manifest manifest; - condition::target_type client_ip{manifest.insert("http.client_ip"), "http.client_ip", {}}; - condition::target_type usr_id{manifest.insert("usr.id"), "usr.id", {}}; + condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}}; + condition::target_type usr_id{get_target_index("usr.id"), "usr.id", {}}; condition::target_type cookie_header{ - manifest.insert("server.request.headers"), "server.request.headers", {"cookie"}}; + get_target_index("server.request.headers"), "server.request.headers", {"cookie"}}; auto ruleset = std::make_shared(); { @@ -1960,8 +1895,8 @@ TEST(TestContext, InputFilterMultipleRulesMultipleFiltersMultipleObjects) auto cookie_rule = ruleset->rules[2]; { auto obj_filter = std::make_shared(); - obj_filter->insert(client_ip.root); - obj_filter->insert(cookie_header.root); + obj_filter->insert(client_ip.root, client_ip.name); + obj_filter->insert(cookie_header.root, cookie_header.name); std::vector> conditions; std::set filter_rules{ip_rule.get(), cookie_rule.get()}; @@ -1973,8 +1908,8 @@ TEST(TestContext, InputFilterMultipleRulesMultipleFiltersMultipleObjects) { auto obj_filter = std::make_shared(); - obj_filter->insert(usr_id.root); - obj_filter->insert(client_ip.root); + obj_filter->insert(usr_id.root, usr_id.name); + obj_filter->insert(client_ip.root, client_ip.name); std::vector> conditions; std::set filter_rules{usr_rule.get(), ip_rule.get()}; @@ -1986,8 +1921,8 @@ TEST(TestContext, InputFilterMultipleRulesMultipleFiltersMultipleObjects) { auto obj_filter = std::make_shared(); - obj_filter->insert(usr_id.root); - obj_filter->insert(cookie_header.root); + obj_filter->insert(usr_id.root, usr_id.name); + obj_filter->insert(cookie_header.root, cookie_header.name); std::vector> conditions; std::set filter_rules{usr_rule.get(), cookie_rule.get()}; @@ -1997,8 +1932,6 @@ TEST(TestContext, InputFilterMultipleRulesMultipleFiltersMultipleObjects) ruleset->input_filters.emplace(filter->get_id(), filter); } - ruleset->manifest = manifest; - { ddwaf::timer deadline{2s}; ddwaf::test::context ctx(ruleset); diff --git a/tests/input_filter_test.cpp b/tests/input_filter_test.cpp index b0ac616ea..643d030dc 100644 --- a/tests/input_filter_test.cpp +++ b/tests/input_filter_test.cpp @@ -12,10 +12,9 @@ using namespace ddwaf::exclusion; TEST(TestInputFilter, InputExclusionNoConditions) { - ddwaf::manifest manifest; - auto query = manifest.insert("query"); + auto query = get_target_index("query"); - object_store store(manifest); + object_store store; ddwaf_object root; ddwaf_object tmp; @@ -24,7 +23,7 @@ TEST(TestInputFilter, InputExclusionNoConditions) store.insert(root); auto obj_filter = std::make_shared(); - obj_filter->insert(query, {}); + obj_filter->insert(query, "query", {}); auto rule = std::make_shared(ddwaf::rule("", "", {}, {})); input_filter filter("filter", {}, {rule.get()}, std::move(obj_filter)); @@ -40,10 +39,9 @@ TEST(TestInputFilter, InputExclusionNoConditions) TEST(TestInputFilter, ObjectExclusionNoConditions) { - ddwaf::manifest manifest; - auto query = manifest.insert("query"); + auto query = get_target_index("query"); - object_store store(manifest); + object_store store; ddwaf_object root; ddwaf_object child; @@ -57,7 +55,7 @@ TEST(TestInputFilter, ObjectExclusionNoConditions) store.insert(root); auto obj_filter = std::make_shared(); - obj_filter->insert(query, {"params"}); + obj_filter->insert(query, "query", {"params"}); auto rule = std::make_shared(ddwaf::rule("", "", {}, {})); input_filter filter("filter", {}, {rule.get()}, std::move(obj_filter)); @@ -73,8 +71,7 @@ TEST(TestInputFilter, ObjectExclusionNoConditions) TEST(TestInputFilter, InputExclusionWithCondition) { - ddwaf::manifest manifest; - auto client_ip = manifest.insert("http.client_ip"); + auto client_ip = get_target_index("http.client_ip"); std::vector targets{{client_ip, "http.client_ip", {}, {}}}; auto cond = std::make_shared(std::move(targets), @@ -87,11 +84,11 @@ TEST(TestInputFilter, InputExclusionWithCondition) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); auto obj_filter = std::make_shared(); - obj_filter->insert(client_ip, {}); + obj_filter->insert(client_ip, "client_ip", {}); auto rule = std::make_shared(ddwaf::rule("", "", {}, {})); input_filter filter("filter", std::move(conditions), {rule.get()}, std::move(obj_filter)); @@ -107,8 +104,7 @@ TEST(TestInputFilter, InputExclusionWithCondition) TEST(TestInputFilter, InputExclusionWithConditionAndTransformers) { - ddwaf::manifest manifest; - auto client_ip = manifest.insert("usr.id"); + auto client_ip = get_target_index("usr.id"); std::vector targets{{client_ip, "usr.id", {}, {PWT_LOWERCASE}}}; auto cond = std::make_shared(std::move(targets), @@ -121,11 +117,11 @@ TEST(TestInputFilter, InputExclusionWithConditionAndTransformers) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "ADMIN")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); auto obj_filter = std::make_shared(); - obj_filter->insert(client_ip, {}); + obj_filter->insert(client_ip, "client_ip", {}); auto rule = std::make_shared(ddwaf::rule("", "", {}, {})); input_filter filter("filter", std::move(conditions), {rule.get()}, std::move(obj_filter)); @@ -141,8 +137,7 @@ TEST(TestInputFilter, InputExclusionWithConditionAndTransformers) TEST(TestInputFilter, InputExclusionFailedCondition) { - ddwaf::manifest manifest; - auto client_ip = manifest.insert("http.client_ip"); + auto client_ip = get_target_index("http.client_ip"); std::vector targets{{client_ip, "http.client_ip", {}, {}}}; auto cond = std::make_shared(std::move(targets), @@ -155,11 +150,11 @@ TEST(TestInputFilter, InputExclusionFailedCondition) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.2")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); auto obj_filter = std::make_shared(); - obj_filter->insert(client_ip, {}); + obj_filter->insert(client_ip, "client_ip", {}); auto rule = std::make_shared(ddwaf::rule("", "", {}, {})); input_filter filter("filter", std::move(conditions), {rule.get()}, std::move(obj_filter)); @@ -172,9 +167,8 @@ TEST(TestInputFilter, InputExclusionFailedCondition) TEST(TestInputFilter, ObjectExclusionWithCondition) { - ddwaf::manifest manifest; - auto client_ip = manifest.insert("http.client_ip"); - auto query = manifest.insert("query"); + auto client_ip = get_target_index("http.client_ip"); + auto query = get_target_index("query"); std::vector targets{{client_ip, "http.client_ip", {}, {}}}; auto cond = std::make_shared(std::move(targets), @@ -192,11 +186,11 @@ TEST(TestInputFilter, ObjectExclusionWithCondition) ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); ddwaf_object_map_add(&root, "query", &child); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); auto obj_filter = std::make_shared(); - obj_filter->insert(query, {"params"}); + obj_filter->insert(query, "query", {"params"}); auto rule = std::make_shared(ddwaf::rule("", "", {}, {})); input_filter filter("filter", std::move(conditions), {rule.get()}, std::move(obj_filter)); @@ -213,9 +207,8 @@ TEST(TestInputFilter, ObjectExclusionWithCondition) TEST(TestInputFilter, ObjectExclusionFailedCondition) { - ddwaf::manifest manifest; - auto client_ip = manifest.insert("http.client_ip"); - auto query = manifest.insert("query"); + auto client_ip = get_target_index("http.client_ip"); + auto query = get_target_index("query"); std::vector targets{{client_ip, "http.client_ip", {}, {}}}; auto cond = std::make_shared(std::move(targets), @@ -233,11 +226,11 @@ TEST(TestInputFilter, ObjectExclusionFailedCondition) ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.2")); ddwaf_object_map_add(&root, "query", &child); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); auto obj_filter = std::make_shared(); - obj_filter->insert(query, {"params"}); + obj_filter->insert(query, "query", {"params"}); auto rule = std::make_shared(ddwaf::rule("", "", {}, {})); input_filter filter("filter", std::move(conditions), {rule.get()}, std::move(obj_filter)); @@ -251,9 +244,8 @@ TEST(TestInputFilter, ObjectExclusionFailedCondition) TEST(TestInputFilter, InputValidateCachedMatch) { - ddwaf::manifest manifest; - auto client_ip = manifest.insert("http.client_ip"); - auto usr_id = manifest.insert("usr.id"); + auto client_ip = get_target_index("http.client_ip"); + auto usr_id = get_target_index("usr.id"); std::vector> conditions; { @@ -272,7 +264,7 @@ TEST(TestInputFilter, InputValidateCachedMatch) } auto obj_filter = std::make_shared(); - obj_filter->insert(usr_id); + obj_filter->insert(usr_id, "usr.id"); auto rule = std::make_shared(ddwaf::rule("", "", {}, {})); input_filter filter("filter", std::move(conditions), {rule.get()}, std::move(obj_filter)); @@ -286,7 +278,7 @@ TEST(TestInputFilter, InputValidateCachedMatch) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -299,7 +291,7 @@ TEST(TestInputFilter, InputValidateCachedMatch) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -313,9 +305,8 @@ TEST(TestInputFilter, InputValidateCachedMatch) TEST(TestInputFilter, InputMatchWithoutCache) { - ddwaf::manifest manifest; - auto client_ip = manifest.insert("http.client_ip"); - auto usr_id = manifest.insert("usr.id"); + auto client_ip = get_target_index("http.client_ip"); + auto usr_id = get_target_index("usr.id"); std::vector> conditions; { @@ -334,7 +325,7 @@ TEST(TestInputFilter, InputMatchWithoutCache) } auto obj_filter = std::make_shared(); - obj_filter->insert(client_ip); + obj_filter->insert(client_ip, "client_ip"); auto rule = std::make_shared(ddwaf::rule("", "", {}, {})); input_filter filter("filter", std::move(conditions), {rule.get()}, std::move(obj_filter)); @@ -346,7 +337,7 @@ TEST(TestInputFilter, InputMatchWithoutCache) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -360,7 +351,7 @@ TEST(TestInputFilter, InputMatchWithoutCache) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -371,9 +362,8 @@ TEST(TestInputFilter, InputMatchWithoutCache) TEST(TestInputFilter, InputNoMatchWithoutCache) { - ddwaf::manifest manifest; - auto client_ip = manifest.insert("http.client_ip"); - auto usr_id = manifest.insert("usr.id"); + auto client_ip = get_target_index("http.client_ip"); + auto usr_id = get_target_index("usr.id"); std::vector> conditions; { @@ -392,14 +382,14 @@ TEST(TestInputFilter, InputNoMatchWithoutCache) } auto obj_filter = std::make_shared(); - obj_filter->insert(client_ip); + obj_filter->insert(client_ip, "client_ip"); auto rule = std::make_shared(ddwaf::rule("", "", {}, {})); input_filter filter("filter", std::move(conditions), {rule.get()}, std::move(obj_filter)); // In this instance we pass a complete store with both addresses but an // empty cache on every run to ensure that both conditions are matched on // the second run when there isn't a cached match. - ddwaf::object_store store(manifest); + ddwaf::object_store store; { ddwaf_object root; @@ -436,9 +426,8 @@ TEST(TestInputFilter, InputNoMatchWithoutCache) TEST(TestInputFilter, InputCachedMatchSecondRun) { - ddwaf::manifest manifest; - auto client_ip = manifest.insert("http.client_ip"); - auto usr_id = manifest.insert("usr.id"); + auto client_ip = get_target_index("http.client_ip"); + auto usr_id = get_target_index("usr.id"); std::vector> conditions; { @@ -457,14 +446,14 @@ TEST(TestInputFilter, InputCachedMatchSecondRun) } auto obj_filter = std::make_shared(); - obj_filter->insert(client_ip); + obj_filter->insert(client_ip, "client_ip"); auto rule = std::make_shared(ddwaf::rule("", "", {}, {})); input_filter filter("filter", std::move(conditions), {rule.get()}, std::move(obj_filter)); // In this instance we pass a complete store with both addresses but an // empty cache on every run to ensure that both conditions are matched on // the second run when there isn't a cached match. - ddwaf::object_store store(manifest); + ddwaf::object_store store; input_filter::cache_type cache; { @@ -499,10 +488,9 @@ TEST(TestInputFilter, InputCachedMatchSecondRun) TEST(TestInputFilter, ObjectValidateCachedMatch) { - ddwaf::manifest manifest; - auto client_ip = manifest.insert("http.client_ip"); - auto usr_id = manifest.insert("usr.id"); - auto query = manifest.insert("query"); + auto client_ip = get_target_index("http.client_ip"); + auto usr_id = get_target_index("usr.id"); + auto query = get_target_index("query"); std::vector> conditions; { @@ -521,7 +509,7 @@ TEST(TestInputFilter, ObjectValidateCachedMatch) } auto obj_filter = std::make_shared(); - obj_filter->insert(query, {"params"}); + obj_filter->insert(query, "query", {"params"}); auto rule = std::make_shared(ddwaf::rule("", "", {}, {})); input_filter filter("filter", std::move(conditions), {rule.get()}, std::move(obj_filter)); @@ -540,7 +528,7 @@ TEST(TestInputFilter, ObjectValidateCachedMatch) ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); ddwaf_object_map_add(&root, "query", &object); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -558,7 +546,7 @@ TEST(TestInputFilter, ObjectValidateCachedMatch) ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); ddwaf_object_map_add(&root, "query", &object); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -571,10 +559,9 @@ TEST(TestInputFilter, ObjectValidateCachedMatch) TEST(TestInputFilter, ObjectMatchWithoutCache) { - ddwaf::manifest manifest; - auto client_ip = manifest.insert("http.client_ip"); - auto usr_id = manifest.insert("usr.id"); - auto query = manifest.insert("query"); + auto client_ip = get_target_index("http.client_ip"); + auto usr_id = get_target_index("usr.id"); + auto query = get_target_index("query"); std::vector> conditions; { @@ -593,7 +580,7 @@ TEST(TestInputFilter, ObjectMatchWithoutCache) } auto obj_filter = std::make_shared(); - obj_filter->insert(query, {"params"}); + obj_filter->insert(query, "query", {"params"}); auto rule = std::make_shared(ddwaf::rule("", "", {}, {})); input_filter filter("filter", std::move(conditions), {rule.get()}, std::move(obj_filter)); @@ -610,7 +597,7 @@ TEST(TestInputFilter, ObjectMatchWithoutCache) ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); ddwaf_object_map_add(&root, "query", &object); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -629,7 +616,7 @@ TEST(TestInputFilter, ObjectMatchWithoutCache) ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); ddwaf_object_map_add(&root, "query", &object); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -640,10 +627,9 @@ TEST(TestInputFilter, ObjectMatchWithoutCache) TEST(TestInputFilter, ObjectNoMatchWithoutCache) { - ddwaf::manifest manifest; - auto client_ip = manifest.insert("http.client_ip"); - auto usr_id = manifest.insert("usr.id"); - auto query = manifest.insert("query"); + auto client_ip = get_target_index("http.client_ip"); + auto usr_id = get_target_index("usr.id"); + auto query = get_target_index("query"); std::vector> conditions; { @@ -662,14 +648,14 @@ TEST(TestInputFilter, ObjectNoMatchWithoutCache) } auto obj_filter = std::make_shared(); - obj_filter->insert(query, {"params"}); + obj_filter->insert(query, "query", {"params"}); auto rule = std::make_shared(ddwaf::rule("", "", {}, {})); input_filter filter("filter", std::move(conditions), {rule.get()}, std::move(obj_filter)); // In this instance we pass a complete store with both addresses but an // empty cache on every run to ensure that both conditions are matched on // the second run when there isn't a cached match. - ddwaf::object_store store(manifest); + ddwaf::object_store store; { ddwaf_object root; @@ -708,10 +694,9 @@ TEST(TestInputFilter, ObjectNoMatchWithoutCache) TEST(TestInputFilter, ObjectCachedMatchSecondRun) { - ddwaf::manifest manifest; - auto client_ip = manifest.insert("http.client_ip"); - auto usr_id = manifest.insert("usr.id"); - auto query = manifest.insert("query"); + auto client_ip = get_target_index("http.client_ip"); + auto usr_id = get_target_index("usr.id"); + auto query = get_target_index("query"); std::vector> conditions; { @@ -730,14 +715,14 @@ TEST(TestInputFilter, ObjectCachedMatchSecondRun) } auto obj_filter = std::make_shared(); - obj_filter->insert(query, {"params"}); + obj_filter->insert(query, "query", {"params"}); auto rule = std::make_shared(ddwaf::rule("", "", {}, {})); input_filter filter("filter", std::move(conditions), {rule.get()}, std::move(obj_filter)); // In this instance we pass a complete store with both addresses but an // empty cache on every run to ensure that both conditions are matched on // the second run when there isn't a cached match. - ddwaf::object_store store(manifest); + ddwaf::object_store store; input_filter::cache_type cache; { diff --git a/tests/manifest_test.cpp b/tests/manifest_test.cpp deleted file mode 100644 index 86d3aaa82..000000000 --- a/tests/manifest_test.cpp +++ /dev/null @@ -1,134 +0,0 @@ -// Unless explicitly stated otherwise all files in this repository are -// dual-licensed under the Apache-2.0 License or BSD-3-Clause License. -// -// This product includes software developed at Datadog (https://www.datadoghq.com/). -// Copyright 2021 Datadog, Inc. - -#include "test.h" - -TEST(TestManifest, TestEmpty) -{ - ddwaf::manifest manifest; - auto opt_target = manifest.find("path"); - EXPECT_FALSE(opt_target); -} - -TEST(TestManifest, TestBasic) -{ - ddwaf::manifest manifest; - auto target = manifest.insert("path"); - - { - auto opt_target = manifest.find("path"); - EXPECT_TRUE(opt_target.has_value()); - EXPECT_EQ(*opt_target, target); - } - - // Test double insertion - EXPECT_EQ(target, manifest.insert("path")); - - const auto &addresses = manifest.get_root_addresses(); - EXPECT_EQ(addresses.size(), 1); - EXPECT_STREQ(addresses[0], "path"); -} - -TEST(TestManifest, TestMultipleAddrs) -{ - ddwaf::manifest manifest; - - std::map targets; - for (const std::string str : {"path0", "path1", "path2", "path3"}) { - auto target = manifest.insert(str); - targets[str] = target; - - // Test double insertion - EXPECT_EQ(target, manifest.insert(str)); - - auto opt_target = manifest.find(str); - EXPECT_TRUE(opt_target.has_value()); - EXPECT_EQ(*opt_target, target); - } - - { - // The first call should generate the root addresses - const auto &addresses = manifest.get_root_addresses(); - EXPECT_EQ(addresses.size(), 4); - - for (const std::string str : {"path0", "path1", "path2", "path3"}) { - EXPECT_NE(find(addresses.begin(), addresses.end(), str), addresses.end()); - } - } -} - -TEST(TestManifest, TestUpdateTargets) -{ - ddwaf::manifest manifest; - for (const std::string str : {"path0", "path1", "path2", "path3"}) { manifest.insert(str); } - - { - std::unordered_set targets; - targets.emplace(*manifest.find("path0")); - targets.emplace(*manifest.find("path1")); - targets.emplace(*manifest.find("path2")); - targets.emplace(*manifest.find("path3")); - - // After this, no targets should be removed - manifest.remove_unused(targets); - - EXPECT_TRUE(manifest.find("path0")); - EXPECT_TRUE(manifest.find("path1")); - EXPECT_TRUE(manifest.find("path2")); - EXPECT_TRUE(manifest.find("path3")); - } - - { - std::unordered_set targets; - targets.emplace(*manifest.find("path0")); - targets.emplace(*manifest.find("path2")); - - // After this, only path0 and path2 should be in the manifest - manifest.remove_unused(targets); - - EXPECT_TRUE(manifest.find("path0")); - EXPECT_FALSE(manifest.find("path1")); - EXPECT_TRUE(manifest.find("path2")); - EXPECT_FALSE(manifest.find("path3")); - } - - { - // After this, the manifest should be empty - manifest.remove_unused({}); - - EXPECT_FALSE(manifest.find("path0")); - EXPECT_FALSE(manifest.find("path1")); - EXPECT_FALSE(manifest.find("path2")); - EXPECT_FALSE(manifest.find("path3")); - } -} - -TEST(TestManifest, TestRootAddresses) -{ - ddwaf::manifest manifest; - - for (const std::string str : {"path0", "path1", "path2", "path3"}) { manifest.insert(str); } - - { - // The first call should generate the root addresses - const auto &addresses = manifest.get_root_addresses(); - EXPECT_EQ(addresses.size(), 4); - - for (const std::string str : {"path0", "path1", "path2", "path3"}) { - EXPECT_NE(find(addresses.begin(), addresses.end(), str), addresses.end()); - } - } - - { - // The second call should reuse the generated array - const auto &addresses = manifest.get_root_addresses(); - EXPECT_EQ(addresses.size(), 4); - - for (const std::string str : {"path0", "path1", "path2", "path3"}) { - EXPECT_NE(find(addresses.begin(), addresses.end(), str), addresses.end()); - } - } -} diff --git a/tests/object_filter_test.cpp b/tests/object_filter_test.cpp index 8b68a1073..b54b539cf 100644 --- a/tests/object_filter_test.cpp +++ b/tests/object_filter_test.cpp @@ -12,10 +12,9 @@ using namespace ddwaf::exclusion; TEST(TestObjectFilter, RootTarget) { - ddwaf::manifest manifest; - auto query = manifest.insert("query"); + auto query = get_target_index("query"); - object_store store(manifest); + object_store store; ddwaf_object root, child, tmp; ddwaf_object_map(&child); @@ -27,7 +26,7 @@ TEST(TestObjectFilter, RootTarget) store.insert(root); object_filter filter; - filter.insert(query, {}); + filter.insert(query, "query", {}); ddwaf::timer deadline{2s}; object_filter::cache_type cache; @@ -39,10 +38,9 @@ TEST(TestObjectFilter, RootTarget) TEST(TestObjectFilter, SingleTarget) { - ddwaf::manifest manifest; - auto query = manifest.insert("query"); + auto query = get_target_index("query"); - object_store store(manifest); + object_store store; ddwaf_object root, child, tmp; ddwaf_object_map(&child); @@ -54,7 +52,7 @@ TEST(TestObjectFilter, SingleTarget) store.insert(root); object_filter filter; - filter.insert(query, {"params"}); + filter.insert(query, "query", {"params"}); ddwaf::timer deadline{2s}; object_filter::cache_type cache; @@ -66,11 +64,10 @@ TEST(TestObjectFilter, SingleTarget) TEST(TestObjectFilter, MultipleTargets) { - ddwaf::manifest manifest; - auto query = manifest.insert("query"); - auto path_params = manifest.insert("path_params"); + auto query = get_target_index("query"); + auto path_params = get_target_index("path_params"); - object_store store(manifest); + object_store store; ddwaf_object root, child, sibling, object, tmp; @@ -96,8 +93,8 @@ TEST(TestObjectFilter, MultipleTargets) store.insert(root); object_filter filter; - filter.insert(query, {"uri"}); - filter.insert(path_params, {"token", "value"}); + filter.insert(query, "query", {"uri"}); + filter.insert(path_params, "path_params", {"token", "value"}); ddwaf::timer deadline{2s}; object_filter::cache_type cache; @@ -110,12 +107,11 @@ TEST(TestObjectFilter, MultipleTargets) TEST(TestObjectFilter, MissingTarget) { - ddwaf::manifest manifest; - manifest.insert("query"); - manifest.insert("path_params"); - auto status = manifest.insert("status"); + get_target_index("query"); + get_target_index("path_params"); + auto status = get_target_index("status"); - object_store store(manifest); + object_store store; ddwaf_object root, child, sibling, object, tmp; @@ -141,7 +137,7 @@ TEST(TestObjectFilter, MissingTarget) store.insert(root); object_filter filter; - filter.insert(status, {"value"}); + filter.insert(status, "status", {"value"}); ddwaf::timer deadline{2s}; object_filter::cache_type cache; @@ -151,10 +147,9 @@ TEST(TestObjectFilter, MissingTarget) TEST(TestObjectFilter, SingleTargetCache) { - ddwaf::manifest manifest; - auto query = manifest.insert("query"); + auto query = get_target_index("query"); - object_store store(manifest); + object_store store; ddwaf_object root, child, tmp; ddwaf_object_map(&child); @@ -166,7 +161,7 @@ TEST(TestObjectFilter, SingleTargetCache) store.insert(root); object_filter filter; - filter.insert(query, {"params"}); + filter.insert(query, "query", {"params"}); ddwaf::timer deadline{2s}; object_filter::cache_type cache; @@ -184,15 +179,14 @@ TEST(TestObjectFilter, SingleTargetCache) TEST(TestObjectFilter, MultipleTargetsCache) { - ddwaf::manifest manifest; - auto query = manifest.insert("query"); - auto path_params = manifest.insert("path_params"); + auto query = get_target_index("query"); + auto path_params = get_target_index("path_params"); - object_store store(manifest); + object_store store; object_filter filter; - filter.insert(query, {"uri"}); - filter.insert(path_params, {"token", "value"}); + filter.insert(query, "query", {"uri"}); + filter.insert(path_params, "path_params", {"token", "value"}); ddwaf::timer deadline{2s}; object_filter::cache_type cache; @@ -245,15 +239,14 @@ TEST(TestObjectFilter, MultipleTargetsCache) TEST(TestObjectFilter, SingleGlobTarget) { - ddwaf::manifest manifest; - auto query = manifest.insert("query"); + auto query = get_target_index("query"); object_filter filter; - filter.insert(query, {"*"}); + filter.insert(query, "query", {"*"}); ddwaf::timer deadline{2s}; { - object_store store(manifest); + object_store store; object_filter::cache_type cache; ddwaf_object root, child, tmp; // Query @@ -274,7 +267,7 @@ TEST(TestObjectFilter, SingleGlobTarget) } { - object_store store(manifest); + object_store store; object_filter::cache_type cache; ddwaf_object root, child, grandchild, tmp; // Query @@ -298,7 +291,7 @@ TEST(TestObjectFilter, SingleGlobTarget) } { - object_store store(manifest); + object_store store; object_filter::cache_type cache; ddwaf_object root, tmp; // Root object @@ -314,16 +307,15 @@ TEST(TestObjectFilter, SingleGlobTarget) TEST(TestObjectFilter, GlobAndKeyTarget) { - ddwaf::manifest manifest; - auto query = manifest.insert("query"); + auto query = get_target_index("query"); object_filter filter; - filter.insert(query, {"*"}); - filter.insert(query, {"uri"}); + filter.insert(query, "query", {"*"}); + filter.insert(query, "query", {"uri"}); ddwaf::timer deadline{2s}; { - object_store store(manifest); + object_store store; object_filter::cache_type cache; ddwaf_object root, child, tmp; // Query @@ -344,7 +336,7 @@ TEST(TestObjectFilter, GlobAndKeyTarget) } { - object_store store(manifest); + object_store store; object_filter::cache_type cache; ddwaf_object root, child, grandchild, tmp; // Query @@ -368,7 +360,7 @@ TEST(TestObjectFilter, GlobAndKeyTarget) } { - object_store store(manifest); + object_store store; object_filter::cache_type cache; ddwaf_object root, tmp; // Root object @@ -384,17 +376,16 @@ TEST(TestObjectFilter, GlobAndKeyTarget) TEST(TestObjectFilter, MultipleComponentsGlobAndKeyTargets) { - ddwaf::manifest manifest; - auto query = manifest.insert("query"); + auto query = get_target_index("query"); object_filter filter; - filter.insert(query, {"*", "value"}); - filter.insert(query, {"uri", "other"}); + filter.insert(query, "query", {"*", "value"}); + filter.insert(query, "query", {"uri", "other"}); ddwaf::timer deadline{2s}; { - object_store store(manifest); + object_store store; object_filter::cache_type cache; ddwaf_object root, child, grandchild, grandnephew, tmp; // Query @@ -420,7 +411,7 @@ TEST(TestObjectFilter, MultipleComponentsGlobAndKeyTargets) } { - object_store store(manifest); + object_store store; object_filter::cache_type cache; ddwaf_object root, child, grandchild, grandnephew, tmp; // Query @@ -447,7 +438,7 @@ TEST(TestObjectFilter, MultipleComponentsGlobAndKeyTargets) } { - object_store store(manifest); + object_store store; object_filter::cache_type cache; ddwaf_object root, child, grandchild, grandnephew, tmp; // Query @@ -472,7 +463,7 @@ TEST(TestObjectFilter, MultipleComponentsGlobAndKeyTargets) } { - object_store store(manifest); + object_store store; object_filter::cache_type cache; ddwaf_object root, child, tmp; @@ -492,16 +483,15 @@ TEST(TestObjectFilter, MultipleComponentsGlobAndKeyTargets) TEST(TestObjectFilter, MultipleGlobsTargets) { - ddwaf::manifest manifest; - auto query = manifest.insert("query"); + auto query = get_target_index("query"); object_filter filter; - filter.insert(query, {"*", "*", "*"}); + filter.insert(query, "query", {"*", "*", "*"}); ddwaf::timer deadline{2s}; { - object_store store(manifest); + object_store store; object_filter::cache_type cache; ddwaf_object root, child, grandchild, grandnephew, greatgrandchild, greatgrandnephew, tmp; @@ -540,7 +530,7 @@ TEST(TestObjectFilter, MultipleGlobsTargets) } { - object_store store(manifest); + object_store store; object_filter::cache_type cache; ddwaf_object root, child, grandchild, grandnephew, tmp; @@ -565,7 +555,7 @@ TEST(TestObjectFilter, MultipleGlobsTargets) } { - object_store store(manifest); + object_store store; object_filter::cache_type cache; ddwaf_object root, child, tmp; @@ -586,14 +576,13 @@ TEST(TestObjectFilter, MultipleGlobsTargets) TEST(TestObjectFilter, MultipleComponentsMultipleGlobAndKeyTargets) { - ddwaf::manifest manifest; - auto query = manifest.insert("query"); + auto query = get_target_index("query"); object_filter filter; - filter.insert(query, {"a", "b", "c"}); - filter.insert(query, {"a", "*", "d", "e"}); - filter.insert(query, {"a", "*", "e", "*"}); - filter.insert(query, {"a", "*", "f", "*", "g"}); + filter.insert(query, "query", {"a", "b", "c"}); + filter.insert(query, "query", {"a", "*", "d", "e"}); + filter.insert(query, "query", {"a", "*", "e", "*"}); + filter.insert(query, "query", {"a", "*", "f", "*", "g"}); // Successful tests { @@ -611,7 +600,7 @@ TEST(TestObjectFilter, MultipleComponentsMultipleGlobAndKeyTargets) }; for (auto &[object, result] : tests) { - object_store store(manifest); + object_store store; object_filter::cache_type cache; ddwaf_object root = json_to_object(object); store.insert(root); @@ -637,7 +626,7 @@ TEST(TestObjectFilter, MultipleComponentsMultipleGlobAndKeyTargets) }; for (auto &object : tests) { - object_store store(manifest); + object_store store; object_filter::cache_type cache; ddwaf_object root = json_to_object(object); store.insert(root); @@ -651,14 +640,13 @@ TEST(TestObjectFilter, MultipleComponentsMultipleGlobAndKeyTargets) TEST(TestObjectFilter, ArrayWithGlobTargets) { - ddwaf::manifest manifest; - auto query = manifest.insert("query"); + auto query = get_target_index("query"); object_filter filter; - filter.insert(query, {"a", "*", "c", "d"}); + filter.insert(query, "query", {"a", "*", "c", "d"}); { - object_store store(manifest); + object_store store; object_filter::cache_type cache; ddwaf_object root, a, b, c, d, tmp; diff --git a/tests/object_store_test.cpp b/tests/object_store_test.cpp index 629e5248a..ff24617d5 100644 --- a/tests/object_store_test.cpp +++ b/tests/object_store_test.cpp @@ -10,11 +10,10 @@ using namespace ddwaf; TEST(TestObjectStore, InsertInvalidObject) { - ddwaf::manifest manifest; - auto query = manifest.insert("query"); - auto url = manifest.insert("url"); + auto query = get_target_index("query"); + auto url = get_target_index("url"); - object_store store(manifest); + object_store store; ddwaf_object root = DDWAF_OBJECT_INVALID; @@ -30,9 +29,8 @@ TEST(TestObjectStore, InsertInvalidObject) TEST(TestObjectStore, InsertMalformedMap) { - ddwaf::manifest manifest; - object_store store(manifest); + object_store store; ddwaf_object root = DDWAF_OBJECT_MAP; root.nbEntries = 30; @@ -44,10 +42,9 @@ TEST(TestObjectStore, InsertMalformedMap) TEST(TestObjectStore, InsertMalformedMapKey) { - ddwaf::manifest manifest; - manifest.insert("key"); + get_target_index("key"); - object_store store(manifest); + object_store store; ddwaf_object tmp; ddwaf_object root = DDWAF_OBJECT_MAP; @@ -62,11 +59,10 @@ TEST(TestObjectStore, InsertMalformedMapKey) TEST(TestObjectStore, InsertStringObject) { - ddwaf::manifest manifest; - auto query = manifest.insert("query"); - auto url = manifest.insert("url"); + auto query = get_target_index("query"); + auto url = get_target_index("url"); - object_store store(manifest); + object_store store; ddwaf_object root; ddwaf_object_string(&root, "hello"); @@ -83,11 +79,10 @@ TEST(TestObjectStore, InsertStringObject) TEST(TestObjectStore, InsertAndGetObject) { - ddwaf::manifest manifest; - auto query = manifest.insert("query"); - auto url = manifest.insert("url"); + auto query = get_target_index("query"); + auto url = get_target_index("url"); - object_store store(manifest); + object_store store; ddwaf_object root; ddwaf_object tmp; @@ -106,11 +101,10 @@ TEST(TestObjectStore, InsertAndGetObject) TEST(TestObjectStore, InsertMultipleUniqueObjects) { - ddwaf::manifest manifest; - auto query = manifest.insert("query"); - auto url = manifest.insert("url"); + auto query = get_target_index("query"); + auto url = get_target_index("url"); - object_store store(manifest); + object_store store; ddwaf_object first; ddwaf_object second; @@ -152,11 +146,10 @@ TEST(TestObjectStore, InsertMultipleUniqueObjects) TEST(TestObjectStore, InsertMultipleOverlappingObjects) { - ddwaf::manifest manifest; - auto query = manifest.insert("query"); - auto url = manifest.insert("url"); + auto query = get_target_index("query"); + auto url = get_target_index("url"); - object_store store(manifest); + object_store store; ddwaf_object first; ddwaf_object second; diff --git a/tests/parser_v2_input_filters.cpp b/tests/parser_v2_input_filters.cpp index 60fd6b473..08423e4e1 100644 --- a/tests/parser_v2_input_filters.cpp +++ b/tests/parser_v2_input_filters.cpp @@ -8,16 +8,15 @@ TEST(TestParserV2InputFilters, ParseEmpty) { - ddwaf::manifest manifest; ddwaf::object_limits limits; - manifest.insert("http.client_ip"); - manifest.insert("usr.id"); + get_target_index("http.client_ip"); + get_target_index("usr.id"); auto object = readRule(R"([{id: 1, inputs: []}])"); ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { @@ -51,14 +50,13 @@ TEST(TestParserV2InputFilters, ParseEmpty) TEST(TestParserV2InputFilters, ParseFilterWithoutID) { - ddwaf::manifest manifest; ddwaf::object_limits limits; auto object = readRule(R"([{inputs: [{address: http.client_ip}]}])"); ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { @@ -92,17 +90,16 @@ TEST(TestParserV2InputFilters, ParseFilterWithoutID) TEST(TestParserV2InputFilters, ParseDuplicateFilters) { - ddwaf::manifest manifest; ddwaf::object_limits limits; - manifest.insert("http.client_ip"); - manifest.insert("usr.id"); + get_target_index("http.client_ip"); + get_target_index("usr.id"); auto object = readRule( R"([{id: 1, inputs: [{address: http.client_ip}]}, {id: 1, inputs: [{address: usr.id}]}])"); ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { @@ -137,16 +134,15 @@ TEST(TestParserV2InputFilters, ParseDuplicateFilters) TEST(TestParserV2InputFilters, ParseUnconditionalNoTargets) { - ddwaf::manifest manifest; ddwaf::object_limits limits; - manifest.insert("http.client_ip"); - manifest.insert("usr.id"); + get_target_index("http.client_ip"); + get_target_index("usr.id"); auto object = readRule(R"([{id: 1, inputs: [{address: http.client_ip}]}])"); ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { @@ -182,17 +178,16 @@ TEST(TestParserV2InputFilters, ParseUnconditionalNoTargets) TEST(TestParserV2InputFilters, ParseUnconditionalTargetID) { - ddwaf::manifest manifest; ddwaf::object_limits limits; - manifest.insert("http.client_ip"); - manifest.insert("usr.id"); + get_target_index("http.client_ip"); + get_target_index("usr.id"); auto object = readRule( R"([{id: 1, inputs: [{address: http.client_ip}], rules_target: [{rule_id: 2939}]}])"); ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { @@ -233,17 +228,16 @@ TEST(TestParserV2InputFilters, ParseUnconditionalTargetID) TEST(TestParserV2InputFilters, ParseUnconditionalTargetTags) { - ddwaf::manifest manifest; ddwaf::object_limits limits; - manifest.insert("http.client_ip"); - manifest.insert("usr.id"); + get_target_index("http.client_ip"); + get_target_index("usr.id"); auto object = readRule( R"([{id: 1, inputs: [{address: http.client_ip}], rules_target: [{tags: {type: rule, category: unknown}}]}])"); ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { @@ -286,17 +280,16 @@ TEST(TestParserV2InputFilters, ParseUnconditionalTargetTags) TEST(TestParserV2InputFilters, ParseUnconditionalTargetPriority) { - ddwaf::manifest manifest; ddwaf::object_limits limits; - manifest.insert("http.client_ip"); - manifest.insert("usr.id"); + get_target_index("http.client_ip"); + get_target_index("usr.id"); auto object = readRule( R"([{id: 1, inputs: [{address: http.client_ip}], rules_target: [{rule_id: 2939, tags: {type: rule, category: unknown}}]}])"); ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { @@ -337,17 +330,16 @@ TEST(TestParserV2InputFilters, ParseUnconditionalTargetPriority) TEST(TestParserV2InputFilters, ParseUnconditionalMultipleTargets) { - ddwaf::manifest manifest; ddwaf::object_limits limits; - manifest.insert("http.client_ip"); - manifest.insert("usr.id"); + get_target_index("http.client_ip"); + get_target_index("usr.id"); auto object = readRule( R"([{id: 1, inputs: [{address: http.client_ip}], rules_target: [{rule_id: 2939}, {tags: {type: rule, category: unknown}}]}])"); ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { @@ -399,17 +391,16 @@ TEST(TestParserV2InputFilters, ParseUnconditionalMultipleTargets) TEST(TestParserV2InputFilters, ParseMultipleUnconditional) { - ddwaf::manifest manifest; ddwaf::object_limits limits; - manifest.insert("http.client_ip"); - manifest.insert("usr.id"); + get_target_index("http.client_ip"); + get_target_index("usr.id"); auto object = readRule( R"([{id: 1, inputs: [{address: http.client_ip}], rules_target: [{rule_id: 2939}]}, {id: 2, inputs: [{address: usr.id}], rules_target: [{tags: {type: rule, category: unknown}}]}])"); ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { @@ -470,17 +461,16 @@ TEST(TestParserV2InputFilters, ParseMultipleUnconditional) TEST(TestParserV2InputFilters, ParseConditionalSingleCondition) { - ddwaf::manifest manifest; ddwaf::object_limits limits; - manifest.insert("http.client_ip"); - manifest.insert("usr.id"); + get_target_index("http.client_ip"); + get_target_index("usr.id"); auto object = readRule( R"([{id: 1, inputs: [{address: http.client_ip}], rules_target: [{rule_id: 2939}], conditions: [{operator: match_regex, parameters: {inputs: [{address: arg1}], regex: .*}}]}])"); ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { @@ -521,17 +511,13 @@ TEST(TestParserV2InputFilters, ParseConditionalSingleCondition) TEST(TestParserV2InputFilters, ParseConditionalMultipleConditions) { - ddwaf::manifest manifest; ddwaf::object_limits limits; - manifest.insert("http.client_ip"); - manifest.insert("usr.id"); - auto object = readRule( R"([{id: 1, inputs: [{address: http.client_ip}], rules_target: [{rule_id: 2939}], conditions: [{operator: match_regex, parameters: {inputs: [{address: arg1}], regex: .*}}, {operator: match_regex, parameters: {inputs: [{address: arg2, key_path: [x]}], regex: .*}}, {operator: match_regex, parameters: {inputs: [{address: arg2, key_path: [y]}], regex: .*}}]}])"); ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { diff --git a/tests/parser_v2_rule_filters.cpp b/tests/parser_v2_rule_filters.cpp index db9bb1787..55c651b6a 100644 --- a/tests/parser_v2_rule_filters.cpp +++ b/tests/parser_v2_rule_filters.cpp @@ -9,14 +9,13 @@ TEST(TestParserV2RuleFilters, ParseEmptyFilter) { - ddwaf::manifest manifest; ddwaf::object_limits limits; auto object = readRule(R"([{id: 1}])"); ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { @@ -50,14 +49,13 @@ TEST(TestParserV2RuleFilters, ParseEmptyFilter) TEST(TestParserV2RuleFilters, ParseFilterWithoutID) { - ddwaf::manifest manifest; ddwaf::object_limits limits; auto object = readRule(R"([{rules_target: [{rule_id: 2939}]}])"); ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { @@ -91,7 +89,6 @@ TEST(TestParserV2RuleFilters, ParseFilterWithoutID) TEST(TestParserV2RuleFilters, ParseDuplicateUnconditional) { - ddwaf::manifest manifest; ddwaf::object_limits limits; auto object = readRule( @@ -99,7 +96,7 @@ TEST(TestParserV2RuleFilters, ParseDuplicateUnconditional) ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { @@ -134,14 +131,13 @@ TEST(TestParserV2RuleFilters, ParseDuplicateUnconditional) TEST(TestParserV2RuleFilters, ParseUnconditionalTargetID) { - ddwaf::manifest manifest; ddwaf::object_limits limits; auto object = readRule(R"([{id: 1, rules_target: [{rule_id: 2939}]}])"); ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { @@ -181,14 +177,13 @@ TEST(TestParserV2RuleFilters, ParseUnconditionalTargetID) TEST(TestParserV2RuleFilters, ParseUnconditionalTargetTags) { - ddwaf::manifest manifest; ddwaf::object_limits limits; auto object = readRule(R"([{id: 1, rules_target: [{tags: {type: rule, category: unknown}}]}])"); ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { @@ -230,7 +225,6 @@ TEST(TestParserV2RuleFilters, ParseUnconditionalTargetTags) TEST(TestParserV2RuleFilters, ParseUnconditionalTargetPriority) { - ddwaf::manifest manifest; ddwaf::object_limits limits; auto object = readRule( @@ -238,7 +232,7 @@ TEST(TestParserV2RuleFilters, ParseUnconditionalTargetPriority) ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { @@ -278,7 +272,6 @@ TEST(TestParserV2RuleFilters, ParseUnconditionalTargetPriority) TEST(TestParserV2RuleFilters, ParseUnconditionalMultipleTargets) { - ddwaf::manifest manifest; ddwaf::object_limits limits; auto object = readRule( @@ -286,7 +279,7 @@ TEST(TestParserV2RuleFilters, ParseUnconditionalMultipleTargets) ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { @@ -337,7 +330,6 @@ TEST(TestParserV2RuleFilters, ParseUnconditionalMultipleTargets) TEST(TestParserV2RuleFilters, ParseMultipleUnconditional) { - ddwaf::manifest manifest; ddwaf::object_limits limits; auto object = readRule( @@ -345,7 +337,7 @@ TEST(TestParserV2RuleFilters, ParseMultipleUnconditional) ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { @@ -404,7 +396,6 @@ TEST(TestParserV2RuleFilters, ParseMultipleUnconditional) TEST(TestParserV2RuleFilters, ParseDuplicateConditional) { - ddwaf::manifest manifest; ddwaf::object_limits limits; auto object = readRule( @@ -412,7 +403,7 @@ TEST(TestParserV2RuleFilters, ParseDuplicateConditional) ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); EXPECT_EQ(filters.rule_filters.size(), 1); @@ -421,7 +412,6 @@ TEST(TestParserV2RuleFilters, ParseDuplicateConditional) TEST(TestParserV2RuleFilters, ParseConditionalSingleCondition) { - ddwaf::manifest manifest; ddwaf::object_limits limits; auto object = readRule( @@ -429,7 +419,7 @@ TEST(TestParserV2RuleFilters, ParseConditionalSingleCondition) ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { @@ -469,7 +459,6 @@ TEST(TestParserV2RuleFilters, ParseConditionalSingleCondition) TEST(TestParserV2RuleFilters, ParseConditionalGlobal) { - ddwaf::manifest manifest; ddwaf::object_limits limits; auto object = readRule( @@ -477,7 +466,7 @@ TEST(TestParserV2RuleFilters, ParseConditionalGlobal) ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { @@ -512,7 +501,6 @@ TEST(TestParserV2RuleFilters, ParseConditionalGlobal) TEST(TestParserV2RuleFilters, ParseConditionalMultipleConditions) { - ddwaf::manifest manifest; ddwaf::object_limits limits; auto object = readRule( @@ -520,7 +508,7 @@ TEST(TestParserV2RuleFilters, ParseConditionalMultipleConditions) ddwaf::ruleset_info::section_info section; auto filters_array = static_cast(parameter(object)); - auto filters = parser::v2::parse_filters(filters_array, section, manifest, limits); + auto filters = parser::v2::parse_filters(filters_array, section, limits); ddwaf_object_free(&object); { diff --git a/tests/parser_v2_rules_test.cpp b/tests/parser_v2_rules_test.cpp index 0570e9981..4ea8b3168 100644 --- a/tests/parser_v2_rules_test.cpp +++ b/tests/parser_v2_rules_test.cpp @@ -10,14 +10,13 @@ TEST(TestParserV2Rules, ParseRule) { ddwaf::object_limits limits; ddwaf::ruleset_info::section_info section; - ddwaf::manifest manifest; std::unordered_map rule_data_ids; auto rule_object = readRule( R"([{id: 1, name: rule1, tags: {type: flow1, category: category1}, conditions: [{operator: match_regex, parameters: {inputs: [{address: arg1}], regex: .*}}, {operator: match_regex, parameters: {inputs: [{address: arg2, key_path: [x]}], regex: .*}}, {operator: match_regex, parameters: {inputs: [{address: arg2, key_path: [y]}], regex: .*}}]}])"); auto rule_array = static_cast(parameter(rule_object)); - auto rules = parser::v2::parse_rules(rule_array, section, manifest, rule_data_ids, limits); + auto rules = parser::v2::parse_rules(rule_array, section, rule_data_ids, limits); ddwaf_object_free(&rule_object); { @@ -56,14 +55,13 @@ TEST(TestParserV2Rules, ParseRuleWithoutType) { ddwaf::object_limits limits; ddwaf::ruleset_info::section_info section; - ddwaf::manifest manifest; std::unordered_map rule_data_ids; auto rule_object = readRule( R"([{id: 1, name: rule1, tags: {category: category1}, conditions: [{operator: match_regex, parameters: {inputs: [{address: arg1}], regex: .*}}, {operator: match_regex, parameters: {inputs: [{address: arg2, key_path: [x]}], regex: .*}}, {operator: match_regex, parameters: {inputs: [{address: arg2, key_path: [y]}], regex: .*}}]}])"); auto rule_array = static_cast(parameter(rule_object)); - auto rules = parser::v2::parse_rules(rule_array, section, manifest, rule_data_ids, limits); + auto rules = parser::v2::parse_rules(rule_array, section, rule_data_ids, limits); ddwaf_object_free(&rule_object); { @@ -98,14 +96,13 @@ TEST(TestParserV2Rules, ParseRuleWithoutID) { ddwaf::object_limits limits; ddwaf::ruleset_info::section_info section; - ddwaf::manifest manifest; std::unordered_map rule_data_ids; auto rule_object = readRule( R"([{name: rule1, tags: {type: type1, category: category1}, conditions: [{operator: match_regex, parameters: {inputs: [{address: arg1}], regex: .*}}, {operator: match_regex, parameters: {inputs: [{address: arg2, key_path: [x]}], regex: .*}}, {operator: match_regex, parameters: {inputs: [{address: arg2, key_path: [y]}], regex: .*}}]}])"); auto rule_array = static_cast(parameter(rule_object)); - auto rules = parser::v2::parse_rules(rule_array, section, manifest, rule_data_ids, limits); + auto rules = parser::v2::parse_rules(rule_array, section, rule_data_ids, limits); ddwaf_object_free(&rule_object); { @@ -140,7 +137,6 @@ TEST(TestParserV2Rules, ParseMultipleRules) { ddwaf::object_limits limits; ddwaf::ruleset_info::section_info section; - ddwaf::manifest manifest; std::unordered_map rule_data_ids; auto rule_object = readRule( @@ -149,7 +145,7 @@ TEST(TestParserV2Rules, ParseMultipleRules) auto rule_array = static_cast(parameter(rule_object)); EXPECT_EQ(rule_array.size(), 2); - auto rules = parser::v2::parse_rules(rule_array, section, manifest, rule_data_ids, limits); + auto rules = parser::v2::parse_rules(rule_array, section, rule_data_ids, limits); ddwaf_object_free(&rule_object); { @@ -205,7 +201,6 @@ TEST(TestParserV2Rules, ParseMultipleRulesOneInvalid) { ddwaf::object_limits limits; ddwaf::ruleset_info::section_info section; - ddwaf::manifest manifest; std::unordered_map rule_data_ids; auto rule_object = readRule( @@ -213,7 +208,7 @@ TEST(TestParserV2Rules, ParseMultipleRulesOneInvalid) auto rule_array = static_cast(parameter(rule_object)); - auto rules = parser::v2::parse_rules(rule_array, section, manifest, rule_data_ids, limits); + auto rules = parser::v2::parse_rules(rule_array, section, rule_data_ids, limits); ddwaf_object_free(&rule_object); { @@ -276,7 +271,6 @@ TEST(TestParserV2Rules, ParseMultipleRulesOneDuplicate) { ddwaf::object_limits limits; ddwaf::ruleset_info::section_info section; - ddwaf::manifest manifest; std::unordered_map rule_data_ids; auto rule_object = readRule( @@ -285,7 +279,7 @@ TEST(TestParserV2Rules, ParseMultipleRulesOneDuplicate) auto rule_array = static_cast(parameter(rule_object)); EXPECT_EQ(rule_array.size(), 2); - auto rules = parser::v2::parse_rules(rule_array, section, manifest, rule_data_ids, limits); + auto rules = parser::v2::parse_rules(rule_array, section, rule_data_ids, limits); ddwaf_object_free(&rule_object); { diff --git a/tests/rule_filter_test.cpp b/tests/rule_filter_test.cpp index 0c053578d..b16cd1fb8 100644 --- a/tests/rule_filter_test.cpp +++ b/tests/rule_filter_test.cpp @@ -12,8 +12,7 @@ TEST(TestRuleFilter, Match) { std::vector targets; - ddwaf::manifest manifest; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"192.168.0.1"})); @@ -27,7 +26,7 @@ TEST(TestRuleFilter, Match) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -40,8 +39,7 @@ TEST(TestRuleFilter, NoMatch) { std::vector targets; - ddwaf::manifest manifest; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{})); @@ -54,7 +52,7 @@ TEST(TestRuleFilter, NoMatch) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -65,12 +63,11 @@ TEST(TestRuleFilter, NoMatch) TEST(TestRuleFilter, ValidateCachedMatch) { - ddwaf::manifest manifest; std::vector> conditions; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( std::vector{"192.168.0.1"})); @@ -79,7 +76,7 @@ TEST(TestRuleFilter, ValidateCachedMatch) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); conditions.push_back(std::move(cond)); @@ -98,7 +95,7 @@ TEST(TestRuleFilter, ValidateCachedMatch) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -110,7 +107,7 @@ TEST(TestRuleFilter, ValidateCachedMatch) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -120,12 +117,11 @@ TEST(TestRuleFilter, ValidateCachedMatch) TEST(TestRuleFilter, MatchWithoutCache) { - ddwaf::manifest manifest; std::vector> conditions; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( std::vector{"192.168.0.1"})); @@ -134,7 +130,7 @@ TEST(TestRuleFilter, MatchWithoutCache) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); conditions.push_back(std::move(cond)); @@ -146,7 +142,7 @@ TEST(TestRuleFilter, MatchWithoutCache) // In this instance we pass a complete store with both addresses but an // empty cache on every run to ensure that both conditions are matched on // the second run when there isn't a cached match. - ddwaf::object_store store(manifest); + ddwaf::object_store store; { ddwaf::exclusion::rule_filter::cache_type cache; ddwaf_object root, tmp; @@ -174,12 +170,11 @@ TEST(TestRuleFilter, MatchWithoutCache) TEST(TestRuleFilter, NoMatchWithoutCache) { - ddwaf::manifest manifest; std::vector> conditions; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( std::vector{"192.168.0.1"})); @@ -188,7 +183,7 @@ TEST(TestRuleFilter, NoMatchWithoutCache) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); conditions.push_back(std::move(cond)); @@ -205,7 +200,7 @@ TEST(TestRuleFilter, NoMatchWithoutCache) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -218,7 +213,7 @@ TEST(TestRuleFilter, NoMatchWithoutCache) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -228,12 +223,11 @@ TEST(TestRuleFilter, NoMatchWithoutCache) TEST(TestRuleFilter, FullCachedMatchSecondRun) { - ddwaf::manifest manifest; std::vector> conditions; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( std::vector{"192.168.0.1"})); @@ -242,7 +236,7 @@ TEST(TestRuleFilter, FullCachedMatchSecondRun) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); conditions.push_back(std::move(cond)); @@ -251,7 +245,7 @@ TEST(TestRuleFilter, FullCachedMatchSecondRun) auto rule = std::make_shared(ddwaf::rule("", "", {}, {})); ddwaf::exclusion::rule_filter filter{"filter", std::move(conditions), {rule.get()}}; - ddwaf::object_store store(manifest); + ddwaf::object_store store; ddwaf::exclusion::rule_filter::cache_type cache; // In this test we validate that when a match has already occurred, the diff --git a/tests/rule_test.cpp b/tests/rule_test.cpp index 482d9ae75..e92d922bd 100644 --- a/tests/rule_test.cpp +++ b/tests/rule_test.cpp @@ -12,8 +12,7 @@ TEST(TestRule, Match) { std::vector targets; - ddwaf::manifest manifest; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"192.168.0.1"})); @@ -28,7 +27,7 @@ TEST(TestRule, Match) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -58,8 +57,7 @@ TEST(TestRule, NoMatch) { std::vector targets; - ddwaf::manifest manifest; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{})); @@ -72,7 +70,7 @@ TEST(TestRule, NoMatch) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -84,12 +82,11 @@ TEST(TestRule, NoMatch) TEST(TestRule, ValidateCachedMatch) { - ddwaf::manifest manifest; std::vector> conditions; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( std::vector{"192.168.0.1"})); @@ -98,7 +95,7 @@ TEST(TestRule, ValidateCachedMatch) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); conditions.push_back(std::move(cond)); @@ -117,7 +114,7 @@ TEST(TestRule, ValidateCachedMatch) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -130,7 +127,7 @@ TEST(TestRule, ValidateCachedMatch) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -166,12 +163,11 @@ TEST(TestRule, ValidateCachedMatch) TEST(TestRule, MatchWithoutCache) { - ddwaf::manifest manifest; std::vector> conditions; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( std::vector{"192.168.0.1"})); @@ -180,7 +176,7 @@ TEST(TestRule, MatchWithoutCache) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); conditions.push_back(std::move(cond)); @@ -193,7 +189,7 @@ TEST(TestRule, MatchWithoutCache) // In this instance we pass a complete store with both addresses but an // empty cache on every run to ensure that both conditions are matched on // the second run when there isn't a cached match. - ddwaf::object_store store(manifest); + ddwaf::object_store store; { ddwaf_object root, tmp; ddwaf_object_map(&root); @@ -242,12 +238,11 @@ TEST(TestRule, MatchWithoutCache) TEST(TestRule, NoMatchWithoutCache) { - ddwaf::manifest manifest; std::vector> conditions; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( std::vector{"192.168.0.1"})); @@ -256,7 +251,7 @@ TEST(TestRule, NoMatchWithoutCache) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); conditions.push_back(std::move(cond)); @@ -273,7 +268,7 @@ TEST(TestRule, NoMatchWithoutCache) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -287,7 +282,7 @@ TEST(TestRule, NoMatchWithoutCache) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -299,12 +294,11 @@ TEST(TestRule, NoMatchWithoutCache) TEST(TestRule, FullCachedMatchSecondRun) { - ddwaf::manifest manifest; std::vector> conditions; { std::vector targets; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared( std::move(targets), std::make_unique( std::vector{"192.168.0.1"})); @@ -313,7 +307,7 @@ TEST(TestRule, FullCachedMatchSecondRun) { std::vector targets; - targets.push_back({manifest.insert("usr.id"), "usr.id", {}, {}}); + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"admin"})); conditions.push_back(std::move(cond)); @@ -333,7 +327,7 @@ TEST(TestRule, FullCachedMatchSecondRun) ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -347,7 +341,7 @@ TEST(TestRule, FullCachedMatchSecondRun) ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; @@ -360,8 +354,7 @@ TEST(TestRule, ExcludeObject) { std::vector targets; - ddwaf::manifest manifest; - targets.push_back({manifest.insert("http.client_ip"), "http.client_ip", {}, {}}); + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); auto cond = std::make_shared(std::move(targets), std::make_unique(std::vector{"192.168.0.1"})); @@ -376,7 +369,7 @@ TEST(TestRule, ExcludeObject) ddwaf_object_map(&root); ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf::object_store store(manifest); + ddwaf::object_store store; store.insert(root); ddwaf::timer deadline{2s}; diff --git a/tests/waf_test.cpp b/tests/waf_test.cpp index ca0a26af5..4f1c7d4d5 100644 --- a/tests/waf_test.cpp +++ b/tests/waf_test.cpp @@ -65,3 +65,59 @@ TEST(TestWaf, RuleDisabledInRuleset) delete ctx; } } + +TEST(TestWaf, AddressUniqueness) +{ + std::unordered_set indices; + + { + std::size_t hash = std::hash()("grpc.server.request.message"); + EXPECT_EQ(indices.find(hash), indices.end()); + indices.insert(hash); + } + { + std::size_t hash = std::hash()("grpc.server.request.metadata"); + EXPECT_EQ(indices.find(hash), indices.end()); + indices.insert(hash); + } + { + std::size_t hash = std::hash()("http.client_ip"); + EXPECT_EQ(indices.find(hash), indices.end()); + indices.insert(hash); + } + { + std::size_t hash = std::hash()("server.request.body"); + EXPECT_EQ(indices.find(hash), indices.end()); + indices.insert(hash); + } + { + std::size_t hash = std::hash()("server.request.headers.no_cookies"); + EXPECT_EQ(indices.find(hash), indices.end()); + indices.insert(hash); + } + { + std::size_t hash = std::hash()("server.request.path_params"); + EXPECT_EQ(indices.find(hash), indices.end()); + indices.insert(hash); + } + { + std::size_t hash = std::hash()("server.request.query"); + EXPECT_EQ(indices.find(hash), indices.end()); + indices.insert(hash); + } + { + std::size_t hash = std::hash()("server.request.uri.raw"); + EXPECT_EQ(indices.find(hash), indices.end()); + indices.insert(hash); + } + { + std::size_t hash = std::hash()("server.response.status"); + EXPECT_EQ(indices.find(hash), indices.end()); + indices.insert(hash); + } + { + std::size_t hash = std::hash()("usr.id"); + EXPECT_EQ(indices.find(hash), indices.end()); + indices.insert(hash); + } +} From bc8bdcf53b8341334f91a8d59ffaba66c767cf57 Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Mon, 26 Jun 2023 14:21:19 +0100 Subject: [PATCH 02/28] Minor fix --- src/utils.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/utils.hpp b/src/utils.hpp index 3ac19eae4..01adbb621 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include // Convert numbers to strings @@ -34,7 +35,7 @@ namespace ddwaf { using target_index = std::size_t; inline target_index get_target_index(const std::string &address) { - return std::hash()(address); + return std::hash{}(address); } namespace object { From ef0a5c83dc3cbc04a74a64a8ccad76eb9a3a4cfc Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Mon, 26 Jun 2023 14:22:29 +0100 Subject: [PATCH 03/28] Format --- src/context.hpp | 3 +-- src/exclusion/input_filter.hpp | 12 +++++------- src/exclusion/object_filter.hpp | 3 ++- src/exclusion/rule_filter.hpp | 8 ++++---- src/object_store.cpp | 3 +-- src/parser/parser.hpp | 8 ++++---- src/parser/parser_v1.cpp | 6 ++++-- src/parser/parser_v2.cpp | 25 +++++++++++++++---------- src/rule.hpp | 7 +++---- src/ruleset.hpp | 4 +--- src/ruleset_builder.cpp | 10 ++++------ src/utils.hpp | 3 ++- 12 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/context.hpp b/src/context.hpp index 693b0c559..cc92dfe23 100644 --- a/src/context.hpp +++ b/src/context.hpp @@ -27,8 +27,7 @@ class context { public: using object_set = std::unordered_set; - explicit context(ruleset::ptr ruleset) - : ruleset_(std::move(ruleset)), store_(ruleset_->free_fn) + explicit context(ruleset::ptr ruleset) : ruleset_(std::move(ruleset)), store_(ruleset_->free_fn) { rule_filter_cache_.reserve(ruleset_->rule_filters.size()); input_filter_cache_.reserve(ruleset_->input_filters.size()); diff --git a/src/exclusion/input_filter.hpp b/src/exclusion/input_filter.hpp index 7d8adf703..b184b4a21 100644 --- a/src/exclusion/input_filter.hpp +++ b/src/exclusion/input_filter.hpp @@ -40,17 +40,15 @@ class input_filter { std::string_view get_id() { return id_; } - void get_addresses(std::unordered_set &addresses) const { + void get_addresses(std::unordered_set &addresses) const + { for (const auto &cond : conditions_) { - for (const auto &target : cond->get_targets()) { - addresses.emplace(target.name); - } + for (const auto &target : cond->get_targets()) { addresses.emplace(target.name); } } - for (const auto &[name, target] : filter_->get_targets()) { - addresses.emplace(name); - } + for (const auto &[name, target] : filter_->get_targets()) { addresses.emplace(name); } } + protected: std::string id_; std::vector conditions_; diff --git a/src/exclusion/object_filter.hpp b/src/exclusion/object_filter.hpp index b3e73af84..c84aec1bc 100644 --- a/src/exclusion/object_filter.hpp +++ b/src/exclusion/object_filter.hpp @@ -241,7 +241,8 @@ class object_filter { explicit object_filter(const ddwaf::object_limits &limits = {}) : limits_(limits) {} - void insert(target_index target, std::string name, const std::vector &key_path = {}) + void insert( + target_index target, std::string name, const std::vector &key_path = {}) { target_paths_[target].insert(key_path); targets_.emplace(std::move(name), target); diff --git a/src/exclusion/rule_filter.hpp b/src/exclusion/rule_filter.hpp index 358efedd5..877e8e251 100644 --- a/src/exclusion/rule_filter.hpp +++ b/src/exclusion/rule_filter.hpp @@ -32,13 +32,13 @@ class rule_filter { std::string_view get_id() { return id_; } - void get_addresses(std::unordered_set &addresses) const { + void get_addresses(std::unordered_set &addresses) const + { for (const auto &cond : conditions_) { - for (const auto &target : cond->get_targets()) { - addresses.emplace(target.name); - } + for (const auto &target : cond->get_targets()) { addresses.emplace(target.name); } } } + protected: std::string id_; std::vector conditions_; diff --git a/src/object_store.cpp b/src/object_store.cpp index 098e5c6ac..411d8b1ab 100644 --- a/src/object_store.cpp +++ b/src/object_store.cpp @@ -10,8 +10,7 @@ namespace ddwaf { -object_store::object_store(ddwaf_object_free_fn free_fn) - : obj_free_(free_fn) +object_store::object_store(ddwaf_object_free_fn free_fn) : obj_free_(free_fn) { if (obj_free_ != nullptr) { objects_to_free_.reserve(default_num_objects); diff --git a/src/parser/parser.hpp b/src/parser/parser.hpp index d39ce92bd..59c9a20a7 100644 --- a/src/parser/parser.hpp +++ b/src/parser/parser.hpp @@ -28,16 +28,16 @@ void parse( namespace v2 { rule_spec_container parse_rules(parameter::vector &rule_array, base_section_info &info, - std::unordered_map &rule_data_ids, - const object_limits &limits, rule::source_type source = rule::source_type::base); + std::unordered_map &rule_data_ids, const object_limits &limits, + rule::source_type source = rule::source_type::base); rule_data_container parse_rule_data(parameter::vector &rule_data, base_section_info &info, std::unordered_map &rule_data_ids); override_spec_container parse_overrides(parameter::vector &override_array, base_section_info &info); -filter_spec_container parse_filters(parameter::vector &filter_array, - base_section_info &info, const object_limits &limits); +filter_spec_container parse_filters( + parameter::vector &filter_array, base_section_info &info, const object_limits &limits); } // namespace v2 } // namespace ddwaf::parser diff --git a/src/parser/parser_v1.cpp b/src/parser/parser_v1.cpp index e44483405..3d9983130 100644 --- a/src/parser/parser_v1.cpp +++ b/src/parser/parser_v1.cpp @@ -27,7 +27,8 @@ namespace ddwaf::parser::v1 { namespace { -condition::ptr parseCondition(parameter::map &rule, std::vector transformers, ddwaf::object_limits limits) +condition::ptr parseCondition( + parameter::map &rule, std::vector transformers, ddwaf::object_limits limits) { auto operation = at(rule, "operation"); auto params = at(rule, "parameters"); @@ -106,7 +107,8 @@ condition::ptr parseCondition(parameter::map &rule, std::vector std::move(targets), std::move(processor), std::string{}, limits); } -void parseRule(parameter::map &rule, base_section_info &info, std::unordered_set &rule_ids, ddwaf::ruleset &rs, ddwaf::object_limits limits) +void parseRule(parameter::map &rule, base_section_info &info, + std::unordered_set &rule_ids, ddwaf::ruleset &rs, ddwaf::object_limits limits) { auto id = at(rule, "id"); if (rule_ids.find(id) != rule_ids.end()) { diff --git a/src/parser/parser_v2.cpp b/src/parser/parser_v2.cpp index 96ba74129..3d75a0232 100644 --- a/src/parser/parser_v2.cpp +++ b/src/parser/parser_v2.cpp @@ -129,7 +129,9 @@ std::vector parse_transformers( return transformers; } -condition::ptr parse_rule_condition(const parameter::map &root, std::unordered_map &rule_data_ids, condition::data_source source, const std::vector &transformers, const object_limits &limits) +condition::ptr parse_rule_condition(const parameter::map &root, + std::unordered_map &rule_data_ids, condition::data_source source, + const std::vector &transformers, const object_limits &limits) { auto operation = at(root, "operator"); auto params = at(root, "parameters"); @@ -180,7 +182,9 @@ condition::ptr parse_rule_condition(const parameter::map &root, std::unordered_m std::move(targets), std::move(processor), std::move(rule_data_id), limits); } -rule_spec parse_rule(parameter::map &rule, std::unordered_map &rule_data_ids, const object_limits &limits, rule::source_type source) +rule_spec parse_rule(parameter::map &rule, + std::unordered_map &rule_data_ids, const object_limits &limits, + rule::source_type source) { std::vector rule_transformers; auto data_source = ddwaf::condition::data_source::values; @@ -193,8 +197,8 @@ rule_spec parse_rule(parameter::map &rule, std::unordered_map(cond_param); - conditions.push_back(parse_rule_condition( - cond, rule_data_ids, data_source, rule_transformers, limits)); + conditions.push_back( + parse_rule_condition(cond, rule_data_ids, data_source, rule_transformers, limits)); } std::unordered_map tags; @@ -337,8 +341,7 @@ input_filter_spec parse_input_filter(const parameter::map &filter, const object_ conditions.reserve(conditions_array.size()); for (const auto &cond : conditions_array) { - conditions.push_back( - parse_filter_condition(static_cast(cond), limits)); + conditions.push_back(parse_filter_condition(static_cast(cond), limits)); } } @@ -383,8 +386,7 @@ rule_filter_spec parse_rule_filter(const parameter::map &filter, const object_li conditions.reserve(conditions_array.size()); for (const auto &cond : conditions_array) { - conditions.push_back( - parse_filter_condition(static_cast(cond), limits)); + conditions.push_back(parse_filter_condition(static_cast(cond), limits)); } } @@ -409,7 +411,9 @@ std::string index_to_id(unsigned idx) { return "index:" + std::to_string(idx); } } // namespace -rule_spec_container parse_rules(parameter::vector &rule_array, base_section_info &info, std::unordered_map &rule_data_ids, const object_limits &limits, rule::source_type source) +rule_spec_container parse_rules(parameter::vector &rule_array, base_section_info &info, + std::unordered_map &rule_data_ids, const object_limits &limits, + rule::source_type source) { rule_spec_container rules; for (unsigned i = 0; i < rule_array.size(); ++i) { @@ -535,7 +539,8 @@ override_spec_container parse_overrides(parameter::vector &override_array, base_ return overrides; } -filter_spec_container parse_filters(parameter::vector &filter_array, base_section_info &info, const object_limits &limits) +filter_spec_container parse_filters( + parameter::vector &filter_array, base_section_info &info, const object_limits &limits) { filter_spec_container filters; for (unsigned i = 0; i < filter_array.size(); i++) { diff --git a/src/rule.hpp b/src/rule.hpp index af3be1757..b0a8cf7f2 100644 --- a/src/rule.hpp +++ b/src/rule.hpp @@ -86,11 +86,10 @@ class rule { const std::vector &get_actions() const { return actions_; } - void get_addresses(std::unordered_set &addresses) const { + void get_addresses(std::unordered_set &addresses) const + { for (const auto &cond : conditions_) { - for (const auto &target : cond->get_targets()) { - addresses.emplace(target.name); - } + for (const auto &target : cond->get_targets()) { addresses.emplace(target.name); } } } diff --git a/src/ruleset.hpp b/src/ruleset.hpp index f963289ce..a7d8edd96 100644 --- a/src/ruleset.hpp +++ b/src/ruleset.hpp @@ -54,9 +54,7 @@ struct ruleset { [[nodiscard]] const std::vector &get_root_addresses() { if (root_addresses.empty()) { - for (const auto &rule : rules) { - rule->get_addresses(unique_root_addresses); - } + for (const auto &rule : rules) { rule->get_addresses(unique_root_addresses); } for (const auto &[id, filter] : rule_filters) { filter->get_addresses(unique_root_addresses); diff --git a/src/ruleset_builder.cpp b/src/ruleset_builder.cpp index 32971df3a..7eae23afe 100644 --- a/src/ruleset_builder.cpp +++ b/src/ruleset_builder.cpp @@ -194,8 +194,7 @@ ruleset_builder::change_state ruleset_builder::load(parameter::map &root, base_r rule_data_ids_.clear(); if (!rules.empty()) { - base_rules_ = parser::v2::parse_rules( - rules, section, rule_data_ids_, limits_); + base_rules_ = parser::v2::parse_rules(rules, section, rule_data_ids_, limits_); } else { DDWAF_DEBUG("Clearing all base rules"); base_rules_.clear(); @@ -218,8 +217,8 @@ ruleset_builder::change_state ruleset_builder::load(parameter::map &root, base_r // be discarded after decltype(rule_data_ids_) rule_data_ids; - auto new_user_rules = parser::v2::parse_rules(rules, section, - rule_data_ids, limits_, rule::source_type::user); + auto new_user_rules = parser::v2::parse_rules( + rules, section, rule_data_ids, limits_, rule::source_type::user); user_rules_ = std::move(new_user_rules); } else { DDWAF_DEBUG("Clearing all custom rules"); @@ -292,8 +291,7 @@ ruleset_builder::change_state ruleset_builder::load(parameter::map &root, base_r try { auto exclusions = static_cast(it->second); if (!exclusions.empty()) { - exclusions_ = - parser::v2::parse_filters(exclusions, section, limits_); + exclusions_ = parser::v2::parse_filters(exclusions, section, limits_); } else { DDWAF_DEBUG("Clearing all exclusions"); exclusions_.clear(); diff --git a/src/utils.hpp b/src/utils.hpp index 01adbb621..0f434c34e 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -34,7 +34,8 @@ namespace ddwaf { using target_index = std::size_t; -inline target_index get_target_index(const std::string &address) { +inline target_index get_target_index(const std::string &address) +{ return std::hash{}(address); } From 336fcb68033e8a439951f80e9f13dbbdb229773a Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Mon, 26 Jun 2023 19:36:23 +0100 Subject: [PATCH 04/28] Chained evaluation - expression --- src/expression.hpp | 85 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 src/expression.hpp diff --git a/src/expression.hpp b/src/expression.hpp new file mode 100644 index 000000000..edcde16da --- /dev/null +++ b/src/expression.hpp @@ -0,0 +1,85 @@ +// Unless explicitly stated otherwise all files in this repository are +// dual-licensed under the Apache-2.0 License or BSD-3-Clause License. +// +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2021 Datadog, Inc. + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace ddwaf { + +class expression { +public: + enum class data_source : uint8_t { values, keys }; + enum class address_scope : uint8_t { global, local }; + enum class match_type : uint8_t {resolved, scalar, object}; + + struct target_type { + address_scope scope{address_scope::global}; + + // Global scope + target_index root; + std::string name; + + // Local scope + std::size_t condition_index; + match_type match{match_type::object}; + + std::vector key_path{}; + + // Transformers + std::vector transformers{}; + data_source source{data_source::values}; + }; + + struct condition { + struct cache_type { + memory::unordered_set targets_evaluated; + std::string resolved{}; + ddwaf_object *scalar{nullptr}; + ddwaf_object *object{nullptr}; + }; + + std::vector targets_; + std::shared_ptr processor_; + std::string data_id_; + }; + + struct cache_type { + explicit cache_type(std::size_t num_conditions) { + conditions.reserve(num_conditions); + } + + std::vector conditions; + }; + + + explicit expression(std::vector &&conditions, ddwaf::object_limits limits = ddwaf::object_limits()): + limits_(limits), conditions_(std::move(conditions)) {} + + bool eval(const object_store &store, + const std::unordered_set &objects_excluded, + const std::unordered_map &dynamic_processors, + ddwaf::timer &deadline) const; + +protected: + ddwaf::object_limits limits_; + std::vector conditions_; +}; + +} // namespace ddwaf From c5cf73c92a0c1a3230db02799ed84a11fbcc4ccc Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Tue, 27 Jun 2023 07:35:33 +0100 Subject: [PATCH 05/28] Minor changes --- src/expression.cpp | 34 ++++++++++++++++++++++++++ src/expression.hpp | 59 ++++++++++++++++++++++++++++++---------------- 2 files changed, 73 insertions(+), 20 deletions(-) create mode 100644 src/expression.cpp diff --git a/src/expression.cpp b/src/expression.cpp new file mode 100644 index 000000000..63e1c9b90 --- /dev/null +++ b/src/expression.cpp @@ -0,0 +1,34 @@ +// Unless explicitly stated otherwise all files in this repository are +// dual-licensed under the Apache-2.0 License or BSD-3-Clause License. +// +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2021 Datadog, Inc. + +#include +#include +#include +#include + +namespace ddwaf { + +namespace { + +bool evaluate_condition() +{ + +} + +} + +bool expression::eval(cache_type &cache, const object_store &store, + const std::unordered_set &objects_excluded, + ddwaf::timer &deadline) const +{ + for (unsigned i = 0; i < conditions_.size(); ++i) { + + + } +} + + +} // namespace ddwaf diff --git a/src/expression.hpp b/src/expression.hpp index edcde16da..3e56951f0 100644 --- a/src/expression.hpp +++ b/src/expression.hpp @@ -27,20 +27,23 @@ class expression { public: enum class data_source : uint8_t { values, keys }; enum class address_scope : uint8_t { global, local }; - enum class match_type : uint8_t {resolved, scalar, object}; + enum class eval_target : uint8_t {resolved, scalar, object}; struct target_type { address_scope scope{address_scope::global}; + std::string name; // Global scope - target_index root; - std::string name; + struct { + target_index root; + std::vector key_path{}; + } global; // Local scope - std::size_t condition_index; - match_type match{match_type::object}; - - std::vector key_path{}; + struct { + std::size_t index; + eval_target target{eval_target::object}; + } local; // Transformers std::vector transformers{}; @@ -49,32 +52,48 @@ class expression { struct condition { struct cache_type { - memory::unordered_set targets_evaluated; - std::string resolved{}; - ddwaf_object *scalar{nullptr}; - ddwaf_object *object{nullptr}; + bool result{false}; + memory::unordered_set evaluated_targets; }; - std::vector targets_; - std::shared_ptr processor_; - std::string data_id_; + std::vector targets; + std::shared_ptr processor; + }; + + struct eval_result { + std::string resolved; + const ddwaf_object *scalar; + const ddwaf_object *object; }; struct cache_type { - explicit cache_type(std::size_t num_conditions) { - conditions.reserve(num_conditions); + std::vector results; + memory::vector condition_cache{}; + + // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) + void cache_result(std::size_t index, target_index target, std::optional &result) { + if (index >= condition_cache.size()) { return; } + + if (result.has_value()) { + results[index] = std::move(*result); + condition_cache[index].result = true; + } + condition_cache[index].evaluated_targets.emplace(target); } - std::vector conditions; - }; + void invalidate(std::size_t index) { + if (index >= condition_cache.size()) { return; } + condition_cache[index].result = false; + results[index] = {}; + } + }; explicit expression(std::vector &&conditions, ddwaf::object_limits limits = ddwaf::object_limits()): limits_(limits), conditions_(std::move(conditions)) {} - bool eval(const object_store &store, + bool eval(cache_type &cache, const object_store &store, const std::unordered_set &objects_excluded, - const std::unordered_map &dynamic_processors, ddwaf::timer &deadline) const; protected: From 0a90b596638761227a6f9de8fbb10eeb371db588 Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Tue, 27 Jun 2023 18:36:34 +0100 Subject: [PATCH 06/28] Minor changes --- src/expression.cpp | 101 ++++++++++++++++++++++++++++++++++++++++++--- src/expression.hpp | 77 ++++++++++++++++++++-------------- 2 files changed, 143 insertions(+), 35 deletions(-) diff --git a/src/expression.cpp b/src/expression.cpp index 63e1c9b90..4a805926d 100644 --- a/src/expression.cpp +++ b/src/expression.cpp @@ -11,22 +11,113 @@ namespace ddwaf { -namespace { - -bool evaluate_condition() +template +std::optional expression::eval_target(condition &cond, cache_type &cache, T &it, + const rule_processor::base::ptr &processor, const std::vector & /*transformers*/, + ddwaf::timer &deadline) const { - + for (; it; ++it) { + if (deadline.expired()) { + throw ddwaf::timeout_exception(); + } + + if (it.type() != DDWAF_OBJ_STRING) { + continue; + } + + auto optional_match = processor->match_object(*it); + if (!optional_match.has_value()) { + continue; + } + + if (!cond.dependents.scalar.empty()) { + for (auto index : cond.dependents.scalar) { + + optional_match->key_path = std::move(it.get_current_path()); + // If this target matched, we can stop processing + return optional_match; + } + + return std::nullopt; } + +bool expression::eval_condition(std::size_t index, cache_type &cache, const object_store &store, + const std::unordered_set &objects_excluded, + ddwaf::timer &deadline) const +{ + const auto &cond = conditions_[index]; + auto &cond_cache = cache.condition_cache[index]; + + for (const auto &target : cond.targets) { + if (deadline.expired()) { + throw ddwaf::timeout_exception(); + } + + if (target.scope == eval_scope::local || + cond_cache.targets.find(target.root) != cond_cache.targets.end()) { + continue; + } + + // TODO: iterators could be cached to avoid reinitialisation + const auto *object = store.get_target(target.root); + if (object == nullptr) { + continue; + } + + std::optional optional_match; + if (target.source == data_source::keys) { + object::key_iterator it(object, target.key_path, objects_excluded, limits_); + optional_match = eval_target(it, cond.processor, target.transformers, deadline); + } else { + object::value_iterator it(object, target.key_path, objects_excluded, limits_); + optional_match = eval_target(it, cond.processor, target.transformers, deadline); + } + + if (optional_match.has_value()) { + optional_match->address = target.name; + + DDWAF_TRACE("Target %s matched parameter value %s", + target.name.c_str(), optional_match->resolved.c_str()); + + cond_cache.result = optional_match; + return true; + } + } + + return false; } bool expression::eval(cache_type &cache, const object_store &store, const std::unordered_set &objects_excluded, ddwaf::timer &deadline) const { - for (unsigned i = 0; i < conditions_.size(); ++i) { + for (std::size_t i = 0; i < conditions_.size(); ++i) { + auto res = eval_condition(i, cache, store, objects_excluded, deadline); + } + + return true; +} + +expression::condition::condition(std::vector targets_, + std::shared_ptr processor_): + targets(std::move(targets_)), processor(std::move(processor_)) +{ + for (const auto &target : targets) { + if (target.scope == expression::eval_scope::global) { continue; } + switch(target.entity) { + case expression::eval_entity::resolved: + dependents.resolved.emplace(target.condition_index); + break; + case expression::eval_entity::scalar: + dependents.scalar.emplace(target.condition_index); + break; + case expression::eval_entity::object: + dependents.object.emplace(target.condition_index); + break; + } } } diff --git a/src/expression.hpp b/src/expression.hpp index 3e56951f0..b83f39f3f 100644 --- a/src/expression.hpp +++ b/src/expression.hpp @@ -25,25 +25,25 @@ namespace ddwaf { class expression { public: + using ptr = std::shared_ptr; + enum class data_source : uint8_t { values, keys }; - enum class address_scope : uint8_t { global, local }; - enum class eval_target : uint8_t {resolved, scalar, object}; + enum class eval_scope : uint8_t { global, local }; + enum class eval_entity : uint8_t {resolved, scalar, object}; struct target_type { - address_scope scope{address_scope::global}; + eval_scope scope{eval_scope::global}; std::string name; // Global scope - struct { - target_index root; - std::vector key_path{}; - } global; + target_index root; // Local scope - struct { - std::size_t index; - eval_target target{eval_target::object}; - } local; + std::size_t condition_index; + eval_entity entity{eval_entity::object}; + + // Applicable to either scope + std::vector key_path{}; // Transformers std::vector transformers{}; @@ -52,12 +52,20 @@ class expression { struct condition { struct cache_type { - bool result{false}; - memory::unordered_set evaluated_targets; + memory::unordered_set targets; + std::optional result; }; + condition(std::vector targets, + std::shared_ptr processor); + std::vector targets; std::shared_ptr processor; + struct { + std::unordered_set resolved{}; + std::unordered_set scalar{}; + std::unordered_set object{}; + } dependents; }; struct eval_result { @@ -67,26 +75,25 @@ class expression { }; struct cache_type { - std::vector results; memory::vector condition_cache{}; // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) - void cache_result(std::size_t index, target_index target, std::optional &result) { - if (index >= condition_cache.size()) { return; } - - if (result.has_value()) { - results[index] = std::move(*result); - condition_cache[index].result = true; - } - condition_cache[index].evaluated_targets.emplace(target); - } - - void invalidate(std::size_t index) { - if (index >= condition_cache.size()) { return; } - - condition_cache[index].result = false; - results[index] = {}; - } +/* void cache_result(std::size_t index, target_index target, std::optional &result) {*/ + /*if (index >= condition_cache.size()) { return; }*/ + + /*if (result.has_value()) {*/ + /*results[index] = std::move(*result);*/ + /*condition_cache[index].result = true;*/ + /*}*/ + /*condition_cache[index].targets.emplace(target);*/ + /*}*/ + + /*void invalidate(std::size_t index) {*/ + /*if (index >= condition_cache.size()) { return; }*/ + + /*condition_cache[index].result = false;*/ + /*results[index] = {};*/ + /*}*/ }; explicit expression(std::vector &&conditions, ddwaf::object_limits limits = ddwaf::object_limits()): @@ -97,6 +104,16 @@ class expression { ddwaf::timer &deadline) const; protected: + + template + std::optional eval_target(condition &cond, cache_type &cache, T &it, + const rule_processor::base::ptr &processor, const std::vector &transformers, + ddwaf::timer &deadline) const; + + bool eval_condition(std::size_t index, cache_type &cache, const object_store &store, + const std::unordered_set &objects_excluded, + ddwaf::timer &deadline) const; + ddwaf::object_limits limits_; std::vector conditions_; }; From 0832bf19574b44e7df684494217554761e47ec71 Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Tue, 27 Jun 2023 21:55:51 +0100 Subject: [PATCH 07/28] Functional expression? --- CMakeLists.txt | 1 + src/expression.cpp | 143 ++++++++++++++++++++++++++++----------------- src/expression.hpp | 141 ++++++++++++++++++++++++++++---------------- src/iterator.hpp | 1 + 4 files changed, 184 insertions(+), 102 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b8875ad38..6f7fc9750 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -73,6 +73,7 @@ set(LIBDDWAF_SOURCE ${libddwaf_SOURCE_DIR}/src/object_store.cpp ${libddwaf_SOURCE_DIR}/src/collection.cpp ${libddwaf_SOURCE_DIR}/src/condition.cpp + ${libddwaf_SOURCE_DIR}/src/expression.cpp ${libddwaf_SOURCE_DIR}/src/rule.cpp ${libddwaf_SOURCE_DIR}/src/ruleset_info.cpp ${libddwaf_SOURCE_DIR}/src/ip_utils.cpp diff --git a/src/expression.cpp b/src/expression.cpp index 4a805926d..4440e9451 100644 --- a/src/expression.cpp +++ b/src/expression.cpp @@ -9,13 +9,15 @@ #include #include -namespace ddwaf { +namespace ddwaf::experimental { template -std::optional expression::eval_target(condition &cond, cache_type &cache, T &it, - const rule_processor::base::ptr &processor, const std::vector & /*transformers*/, - ddwaf::timer &deadline) const +std::optional expression::evaluator::eval_target(const condition &cond, T &it, + const rule_processor::base::ptr &processor, + const std::vector & /*transformers*/) { + std::optional last_result = std::nullopt; + for (; it; ++it) { if (deadline.expired()) { throw ddwaf::timeout_exception(); @@ -25,101 +27,136 @@ std::optional expression::eval_target(condition &cond, cache_type continue; } - auto optional_match = processor->match_object(*it); - if (!optional_match.has_value()) { + { + auto optional_match = processor->match_object(*it); + if (!optional_match.has_value()) { + continue; + } + last_result = std::move(optional_match); + } + + last_result->key_path = std::move(it.get_current_path()); + // TODO set the root object only after returning + cache.set_eval_entities(cond.index, *it, it.get_root_object(), last_result->resolved); + + bool chain_result = true; + for (condition::index_type i = 0; i < cond.dependents.scalar.size(); ++i) { + const auto &next_cond = conditions[i]; + if (!eval_condition(next_cond)) { + chain_result = false; + break; + } + } + + if (!chain_result) { continue; } - if (!cond.dependents.scalar.empty()) { - for (auto index : cond.dependents.scalar) { - - optional_match->key_path = std::move(it.get_current_path()); - // If this target matched, we can stop processing - return optional_match; + break; } - return std::nullopt; + return last_result; } - -bool expression::eval_condition(std::size_t index, cache_type &cache, const object_store &store, - const std::unordered_set &objects_excluded, - ddwaf::timer &deadline) const +bool expression::evaluator::eval_condition(const condition &cond) { - const auto &cond = conditions_[index]; - auto &cond_cache = cache.condition_cache[index]; + auto &cond_cache = cache.get_condition_cache(cond.index); for (const auto &target : cond.targets) { if (deadline.expired()) { throw ddwaf::timeout_exception(); } - if (target.scope == eval_scope::local || - cond_cache.targets.find(target.root) != cond_cache.targets.end()) { + if (cond_cache.targets.find(target.root) != cond_cache.targets.end()) { continue; } // TODO: iterators could be cached to avoid reinitialisation - const auto *object = store.get_target(target.root); - if (object == nullptr) { - continue; + const ddwaf_object *object = nullptr; + if (target.scope == condition::eval_scope::global) { + object = store.get_target(target.root); + if (object == nullptr) { + continue; + } + } else { + object = cache.get_eval_entity(target.condition_index, target.entity); } std::optional optional_match; - if (target.source == data_source::keys) { - object::key_iterator it(object, target.key_path, objects_excluded, limits_); - optional_match = eval_target(it, cond.processor, target.transformers, deadline); + if (target.source == condition::data_source::keys) { + object::key_iterator it(object, target.key_path, objects_excluded, limits); + optional_match = eval_target(cond, it, cond.processor, target.transformers); } else { - object::value_iterator it(object, target.key_path, objects_excluded, limits_); - optional_match = eval_target(it, cond.processor, target.transformers, deadline); + object::value_iterator it(object, target.key_path, objects_excluded, limits); + optional_match = eval_target(cond, it, cond.processor, target.transformers); } - if (optional_match.has_value()) { - optional_match->address = target.name; + if (!optional_match.has_value()) { + continue; + } + + optional_match->address = target.name; + cond_cache.result = optional_match; - DDWAF_TRACE("Target %s matched parameter value %s", - target.name.c_str(), optional_match->resolved.c_str()); + bool chain_result = true; + for (condition::index_type i = 0; i < cond.dependents.object.size(); ++i) { + const auto &next_cond = conditions[i]; + if (!eval_condition(next_cond)) { + chain_result = false; + break; + } + } - cond_cache.result = optional_match; - return true; + if (!chain_result) { + continue; } + + DDWAF_TRACE("Target %s matched parameter value %s", target.name.c_str(), + optional_match->resolved.c_str()); + + return true; } return false; } -bool expression::eval(cache_type &cache, const object_store &store, - const std::unordered_set &objects_excluded, - ddwaf::timer &deadline) const +bool expression::evaluator::eval() { - for (std::size_t i = 0; i < conditions_.size(); ++i) { - auto res = eval_condition(i, cache, store, objects_excluded, deadline); + for (const auto &cond : conditions) { + if (!eval_condition(cond)) { + return false; + } } - return true; } +bool expression::eval(cache_type &cache, const object_store &store, + const std::unordered_set &objects_excluded, ddwaf::timer &deadline) const +{ + evaluator runner{deadline, limits_, conditions_, store, objects_excluded, cache}; + runner.eval(); + return true; +} -expression::condition::condition(std::vector targets_, - std::shared_ptr processor_): - targets(std::move(targets_)), processor(std::move(processor_)) +condition::condition(index_type index_, std::vector targets_, + std::shared_ptr processor_) + : index(index_), targets(std::move(targets_)), processor(std::move(processor_)) { for (const auto &target : targets) { - if (target.scope == expression::eval_scope::global) { continue; } + if (target.scope == eval_scope::global) { + continue; + } - switch(target.entity) { - case expression::eval_entity::resolved: - dependents.resolved.emplace(target.condition_index); - break; - case expression::eval_entity::scalar: + switch (target.entity) { + case eval_entity::resolved: + case eval_entity::scalar: dependents.scalar.emplace(target.condition_index); break; - case expression::eval_entity::object: + case eval_entity::object: dependents.object.emplace(target.condition_index); break; } } } - -} // namespace ddwaf +} // namespace ddwaf::experimental diff --git a/src/expression.hpp b/src/expression.hpp index b83f39f3f..6138d3ca4 100644 --- a/src/expression.hpp +++ b/src/expression.hpp @@ -21,15 +21,20 @@ #include #include -namespace ddwaf { +namespace ddwaf::experimental { -class expression { -public: - using ptr = std::shared_ptr; +struct condition { + using ptr = std::shared_ptr; + using index_type = std::size_t; + + struct cache_type { + std::unordered_set targets; + std::optional result; + }; enum class data_source : uint8_t { values, keys }; enum class eval_scope : uint8_t { global, local }; - enum class eval_entity : uint8_t {resolved, scalar, object}; + enum class eval_entity : uint8_t { resolved, scalar, object }; struct target_type { eval_scope scope{eval_scope::global}; @@ -50,65 +55,103 @@ class expression { data_source source{data_source::values}; }; - struct condition { - struct cache_type { - memory::unordered_set targets; - std::optional result; - }; - - condition(std::vector targets, - std::shared_ptr processor); - - std::vector targets; - std::shared_ptr processor; - struct { - std::unordered_set resolved{}; - std::unordered_set scalar{}; - std::unordered_set object{}; - } dependents; - }; + condition(index_type index_, std::vector targets_, + std::shared_ptr processor_); + + index_type index; + std::vector targets; + std::shared_ptr processor; + struct { + std::unordered_set scalar{}; + std::unordered_set object{}; + } dependents; +}; + +class expression { +public: + using ptr = std::shared_ptr; struct eval_result { - std::string resolved; - const ddwaf_object *scalar; - const ddwaf_object *object; + bool valid{false}; + ddwaf_object resolved{nullptr, 0, {nullptr}, 0, DDWAF_OBJ_INVALID}; + const ddwaf_object *scalar{nullptr}; + const ddwaf_object *object{nullptr}; }; struct cache_type { - memory::vector condition_cache{}; + std::vector conditions{}; + std::vector store{}; + + condition::cache_type &get_condition_cache(condition::index_type index) + { + return conditions[index]; + } // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) -/* void cache_result(std::size_t index, target_index target, std::optional &result) {*/ - /*if (index >= condition_cache.size()) { return; }*/ - - /*if (result.has_value()) {*/ - /*results[index] = std::move(*result);*/ - /*condition_cache[index].result = true;*/ - /*}*/ - /*condition_cache[index].targets.emplace(target);*/ - /*}*/ - - /*void invalidate(std::size_t index) {*/ - /*if (index >= condition_cache.size()) { return; }*/ - - /*condition_cache[index].result = false;*/ - /*results[index] = {};*/ - /*}*/ + void set_eval_entities(condition::index_type index, const ddwaf_object *scalar, + const ddwaf_object *object, const memory::string &resolved) + { + auto &eval_res = store[index]; + eval_res.valid = true; + eval_res.scalar = scalar; + eval_res.object = object; + ddwaf_object_stringl_nc(&eval_res.resolved, resolved.c_str(), resolved.size()); + } + + const ddwaf_object *get_eval_entity( + condition::index_type index, condition::eval_entity entity) + { + auto &result = store[index]; + if (!result.valid) { + return nullptr; + } + + if (entity == condition::eval_entity::resolved) { + return &result.resolved; + } + + if (entity == condition::eval_entity::scalar) { + return result.scalar; + } + + if (entity == condition::eval_entity::object) { + return result.object; + } + + return nullptr; + } }; - explicit expression(std::vector &&conditions, ddwaf::object_limits limits = ddwaf::object_limits()): - limits_(limits), conditions_(std::move(conditions)) {} + struct evaluator { + bool eval(); + bool eval_condition(const condition &cond); + + template + std::optional eval_target(const condition &cond, T &it, + const rule_processor::base::ptr &processor, + const std::vector & /*transformers*/); + + ddwaf::timer &deadline; + const ddwaf::object_limits &limits; + const std::vector &conditions; + const object_store &store; + const std::unordered_set &objects_excluded; + cache_type &cache; + }; + + explicit expression( + std::vector &&conditions, ddwaf::object_limits limits = ddwaf::object_limits()) + : limits_(limits), conditions_(std::move(conditions)) + {} bool eval(cache_type &cache, const object_store &store, const std::unordered_set &objects_excluded, ddwaf::timer &deadline) const; protected: - template - std::optional eval_target(condition &cond, cache_type &cache, T &it, - const rule_processor::base::ptr &processor, const std::vector &transformers, - ddwaf::timer &deadline) const; + std::optional eval_target(T &it, const rule_processor::base::ptr &processor, + const std::vector &transformers, ddwaf::timer &deadline) const; bool eval_condition(std::size_t index, cache_type &cache, const object_store &store, const std::unordered_set &objects_excluded, @@ -118,4 +161,4 @@ class expression { std::vector conditions_; }; -} // namespace ddwaf +} // namespace ddwaf::experimental diff --git a/src/iterator.hpp b/src/iterator.hpp index b693ce031..3e3bb46c3 100644 --- a/src/iterator.hpp +++ b/src/iterator.hpp @@ -38,6 +38,7 @@ template class iterator_base { [[nodiscard]] size_t depth() { return stack_.size() + path_.size(); } [[nodiscard]] memory::vector get_current_path() const; [[nodiscard]] const ddwaf_object *get_underlying_object() { return current_; } + [[nodiscard]] const ddwaf_object *get_root_object() { return stack_.front().first; } protected: bool should_exclude(const ddwaf_object *obj) const From 4ad13340ae4f296c43490081a55694ec02abc017 Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Wed, 28 Jun 2023 15:14:15 +0100 Subject: [PATCH 08/28] Expression tests --- src/expression.cpp | 75 ++--- src/expression.hpp | 62 ++-- tests/expression_test.cpp | 578 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 652 insertions(+), 63 deletions(-) create mode 100644 tests/expression_test.cpp diff --git a/src/expression.cpp b/src/expression.cpp index 4440e9451..355b81232 100644 --- a/src/expression.cpp +++ b/src/expression.cpp @@ -36,13 +36,13 @@ std::optional expression::evaluator::eval_target(const condition & } last_result->key_path = std::move(it.get_current_path()); - // TODO set the root object only after returning - cache.set_eval_entities(cond.index, *it, it.get_root_object(), last_result->resolved); + cache.set_eval_resolved(cond.index, last_result->resolved); + cache.set_eval_scalar(cond.index, *it); bool chain_result = true; - for (condition::index_type i = 0; i < cond.dependents.scalar.size(); ++i) { - const auto &next_cond = conditions[i]; - if (!eval_condition(next_cond)) { + for (auto index : cond.dependents.scalar) { + const auto &next_cond = conditions[index]; + if (!eval_condition(next_cond, condition::eval_scope::local)) { chain_result = false; break; } @@ -58,16 +58,22 @@ std::optional expression::evaluator::eval_target(const condition & return last_result; } -bool expression::evaluator::eval_condition(const condition &cond) +// NOLINTNEXTLINE(misc-no-recursion) +bool expression::evaluator::eval_condition(const condition &cond, condition::eval_scope scope) { auto &cond_cache = cache.get_condition_cache(cond.index); + if (cond_cache.result.has_value()) { + return true; + } + for (const auto &target : cond.targets) { if (deadline.expired()) { throw ddwaf::timeout_exception(); } - if (cond_cache.targets.find(target.root) != cond_cache.targets.end()) { + if (scope != target.scope || + cond_cache.targets.find(target.root) != cond_cache.targets.end()) { continue; } @@ -75,13 +81,17 @@ bool expression::evaluator::eval_condition(const condition &cond) const ddwaf_object *object = nullptr; if (target.scope == condition::eval_scope::global) { object = store.get_target(target.root); - if (object == nullptr) { - continue; - } } else { object = cache.get_eval_entity(target.condition_index, target.entity); } + if (object == nullptr) { + DDWAF_TRACE("No object found for target %s", target.name.c_str()); + continue; + } + + DDWAF_TRACE("Original object %p", object); + std::optional optional_match; if (target.source == condition::data_source::keys) { object::key_iterator it(object, target.key_path, objects_excluded, limits); @@ -91,6 +101,8 @@ bool expression::evaluator::eval_condition(const condition &cond) optional_match = eval_target(cond, it, cond.processor, target.transformers); } + cond_cache.targets.emplace(target.root); + if (!optional_match.has_value()) { continue; } @@ -98,10 +110,14 @@ bool expression::evaluator::eval_condition(const condition &cond) optional_match->address = target.name; cond_cache.result = optional_match; + cache.set_eval_object(cond.index, object); + + DDWAF_TRACE("Match! Checking chain"); bool chain_result = true; - for (condition::index_type i = 0; i < cond.dependents.object.size(); ++i) { - const auto &next_cond = conditions[i]; - if (!eval_condition(next_cond)) { + for (auto index : cond.dependents.object) { + const auto &next_cond = conditions[index]; + if (!eval_condition(next_cond, condition::eval_scope::local)) { + DDWAF_TRACE("Chain %lu didn't match", index) chain_result = false; break; } @@ -122,8 +138,10 @@ bool expression::evaluator::eval_condition(const condition &cond) bool expression::evaluator::eval() { + // NOLINTNEXTLINE(readability-use-anyofallof) for (const auto &cond : conditions) { - if (!eval_condition(cond)) { + DDWAF_TRACE("Condition %lu", cond.index); + if (!eval_condition(cond, condition::eval_scope::global)) { return false; } } @@ -133,30 +151,13 @@ bool expression::evaluator::eval() bool expression::eval(cache_type &cache, const object_store &store, const std::unordered_set &objects_excluded, ddwaf::timer &deadline) const { - evaluator runner{deadline, limits_, conditions_, store, objects_excluded, cache}; - runner.eval(); - return true; -} - -condition::condition(index_type index_, std::vector targets_, - std::shared_ptr processor_) - : index(index_), targets(std::move(targets_)), processor(std::move(processor_)) -{ - for (const auto &target : targets) { - if (target.scope == eval_scope::global) { - continue; - } - - switch (target.entity) { - case eval_entity::resolved: - case eval_entity::scalar: - dependents.scalar.emplace(target.condition_index); - break; - case eval_entity::object: - dependents.object.emplace(target.condition_index); - break; - } + if (cache.conditions.size() != conditions_.size()) { + cache.conditions.reserve(conditions_.size()); + cache.store.reserve(conditions_.size()); } + + evaluator runner{deadline, limits_, conditions_, store, objects_excluded, cache}; + return runner.eval(); } } // namespace ddwaf::experimental diff --git a/src/expression.hpp b/src/expression.hpp index 6138d3ca4..40f5995ff 100644 --- a/src/expression.hpp +++ b/src/expression.hpp @@ -6,6 +6,7 @@ #pragma once +#include "log.hpp" #include #include #include @@ -28,8 +29,8 @@ struct condition { using index_type = std::size_t; struct cache_type { - std::unordered_set targets; - std::optional result; + std::unordered_set targets{}; + std::optional result{std::nullopt}; }; enum class data_source : uint8_t { values, keys }; @@ -44,7 +45,7 @@ struct condition { target_index root; // Local scope - std::size_t condition_index; + std::size_t condition_index{0}; eval_entity entity{eval_entity::object}; // Applicable to either scope @@ -55,9 +56,6 @@ struct condition { data_source source{data_source::values}; }; - condition(index_type index_, std::vector targets_, - std::shared_ptr processor_); - index_type index; std::vector targets; std::shared_ptr processor; @@ -72,28 +70,42 @@ class expression { using ptr = std::shared_ptr; struct eval_result { - bool valid{false}; ddwaf_object resolved{nullptr, 0, {nullptr}, 0, DDWAF_OBJ_INVALID}; const ddwaf_object *scalar{nullptr}; const ddwaf_object *object{nullptr}; }; struct cache_type { - std::vector conditions{}; - std::vector store{}; + std::unordered_map conditions{}; + std::unordered_map store{}; condition::cache_type &get_condition_cache(condition::index_type index) { return conditions[index]; } + void set_eval_resolved(condition::index_type index, const memory::string &str) + { + ddwaf_object_stringl_nc(&store[index].resolved, str.c_str(), str.size()); + } + + void set_eval_scalar(condition::index_type index, const ddwaf_object *obj) + { + store[index].scalar = obj; + } + + void set_eval_object(condition::index_type index, const ddwaf_object *obj) + { + store[index].object = obj; + } + // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) void set_eval_entities(condition::index_type index, const ddwaf_object *scalar, const ddwaf_object *object, const memory::string &resolved) { auto &eval_res = store[index]; - eval_res.valid = true; eval_res.scalar = scalar; + DDWAF_TRACE("Object %p", object); eval_res.object = object; ddwaf_object_stringl_nc(&eval_res.resolved, resolved.c_str(), resolved.size()); } @@ -101,21 +113,19 @@ class expression { const ddwaf_object *get_eval_entity( condition::index_type index, condition::eval_entity entity) { - auto &result = store[index]; - if (!result.valid) { - return nullptr; - } - - if (entity == condition::eval_entity::resolved) { - return &result.resolved; - } - - if (entity == condition::eval_entity::scalar) { - return result.scalar; - } - - if (entity == condition::eval_entity::object) { - return result.object; + auto it = store.find(index); + if (it != store.end()) { + if (entity == condition::eval_entity::resolved) { + return &it->second.resolved; + } + + if (entity == condition::eval_entity::scalar) { + return it->second.scalar; + } + + if (entity == condition::eval_entity::object) { + return it->second.object; + } } return nullptr; @@ -124,7 +134,7 @@ class expression { struct evaluator { bool eval(); - bool eval_condition(const condition &cond); + bool eval_condition(const condition &cond, condition::eval_scope scope); template std::optional eval_target(const condition &cond, T &it, diff --git a/tests/expression_test.cpp b/tests/expression_test.cpp new file mode 100644 index 000000000..d7a327748 --- /dev/null +++ b/tests/expression_test.cpp @@ -0,0 +1,578 @@ +// Unless explicitly stated otherwise all files in this repository are +// dual-licensed under the Apache-2.0 License or BSD-3-Clause License. +// +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2021 Datadog, Inc. + +#include "PWTransformer.h" +#include "expression.hpp" +#include "test.h" + +using namespace ddwaf; + +TEST(TestExpression, SimpleMatch) +{ + std::vector conditions; + + { + experimental::condition::target_type target; + target.name = "server.request.query"; + target.root = get_target_index(target.name); + + experimental::condition cond; + cond.targets.emplace_back(std::move(target)); + cond.processor = std::make_unique(".*", 0, true); + conditions.emplace_back(std::move(cond)); + } + + experimental::expression expr(std::move(conditions)); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "value")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + experimental::expression::cache_type cache; + EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); +} + +TEST(TestExpression, MultiInputMatchOnSecond) +{ + std::vector conditions; + + { + experimental::condition cond; + + { + experimental::condition::target_type target; + target.name = "server.request.query"; + target.root = get_target_index(target.name); + cond.targets.emplace_back(std::move(target)); + } + + { + experimental::condition::target_type target; + target.name = "server.request.body"; + target.root = get_target_index(target.name); + cond.targets.emplace_back(std::move(target)); + } + + cond.index = 0; + cond.processor = std::make_unique("^value$", 0, true); + conditions.emplace_back(std::move(cond)); + } + + experimental::expression expr(std::move(conditions)); + + ddwaf::object_store store; + experimental::expression::cache_type cache; + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "bad")); + + store.insert(root); + + ddwaf::timer deadline{2s}; + + EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.body", ddwaf_object_string(&tmp, "value")); + + store.insert(root); + + ddwaf::timer deadline{2s}; + + EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); + } +} + +TEST(TestExpression, DuplicateInput) +{ + std::vector conditions; + + { + experimental::condition::target_type target; + target.name = "server.request.query"; + target.root = get_target_index(target.name); + + experimental::condition cond; + cond.targets.emplace_back(std::move(target)); + + cond.index = 0; + cond.processor = std::make_unique("^value$", 0, true); + conditions.emplace_back(std::move(cond)); + } + + experimental::expression expr(std::move(conditions)); + + experimental::expression::cache_type cache; + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "bad")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "value")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); + } +} + +TEST(TestExpression, MatchDuplicateInputNoCache) +{ + std::vector conditions; + + { + experimental::condition::target_type target; + target.name = "server.request.query"; + target.root = get_target_index(target.name); + + experimental::condition cond; + cond.targets.emplace_back(std::move(target)); + + cond.index = 0; + cond.processor = std::make_unique("^value$", 0, true); + conditions.emplace_back(std::move(cond)); + } + + experimental::expression expr(std::move(conditions)); + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "bad")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + experimental::expression::cache_type cache; + EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "value")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + experimental::expression::cache_type cache; + EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); + } +} + +TEST(TestExpression, TwoConditionsSingleInputNoMatch) +{ + std::vector conditions; + + { + experimental::condition::target_type target; + target.name = "server.request.query"; + target.root = get_target_index(target.name); + + experimental::condition cond; + cond.targets.emplace_back(std::move(target)); + + cond.index = 0; + cond.processor = std::make_unique("value", 0, true); + conditions.emplace_back(std::move(cond)); + } + + { + + experimental::condition::target_type target; + target.name = "server.request.query"; + target.root = get_target_index(target.name); + + experimental::condition cond; + cond.targets.emplace_back(std::move(target)); + + cond.index = 1; + cond.processor = std::make_unique("^value$", 0, true); + conditions.emplace_back(std::move(cond)); + } + + experimental::expression expr(std::move(conditions)); + + experimental::expression::cache_type cache; + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "bad_value")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "value")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); + } +} + +TEST(TestExpression, TwoConditionsSingleInputMatch) +{ + std::vector conditions; + + { + experimental::condition::target_type target; + target.name = "server.request.query"; + target.root = get_target_index(target.name); + + experimental::condition cond; + cond.targets.emplace_back(std::move(target)); + + cond.index = 0; + cond.processor = std::make_unique("value", 0, true); + conditions.emplace_back(std::move(cond)); + } + + { + + experimental::condition::target_type target; + target.name = "server.request.query"; + target.root = get_target_index(target.name); + + experimental::condition cond; + cond.targets.emplace_back(std::move(target)); + + cond.index = 1; + cond.processor = std::make_unique("^value$", 0, true); + conditions.emplace_back(std::move(cond)); + } + + experimental::expression expr(std::move(conditions)); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "value")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + experimental::expression::cache_type cache; + EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); +} + +TEST(TestExpression, TwoConditionsMultiInputSingleEvalMatch) +{ + std::vector conditions; + + { + experimental::condition::target_type target; + target.name = "server.request.query"; + target.root = get_target_index(target.name); + + experimental::condition cond; + cond.targets.emplace_back(std::move(target)); + + cond.index = 0; + cond.processor = std::make_unique("query", 0, true); + conditions.emplace_back(std::move(cond)); + } + + { + + experimental::condition::target_type target; + target.name = "server.request.body"; + target.root = get_target_index(target.name); + + experimental::condition cond; + cond.targets.emplace_back(std::move(target)); + + cond.index = 1; + cond.processor = std::make_unique("body", 0, true); + conditions.emplace_back(std::move(cond)); + } + + experimental::expression expr(std::move(conditions)); + + ddwaf::object_store store; + experimental::expression::cache_type cache; + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "query")); + ddwaf_object_map_add(&root, "server.request.body", ddwaf_object_string(&tmp, "body")); + + store.insert(root); + + ddwaf::timer deadline{2s}; + + EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); +} + +TEST(TestExpression, TwoConditionsMultiInputMultiEvalMatch) +{ + std::vector conditions; + + { + experimental::condition::target_type target; + target.name = "server.request.query"; + target.root = get_target_index(target.name); + + experimental::condition cond; + cond.targets.emplace_back(std::move(target)); + + cond.index = 0; + cond.processor = std::make_unique("query", 0, true); + conditions.emplace_back(std::move(cond)); + } + + { + + experimental::condition::target_type target; + target.name = "server.request.body"; + target.root = get_target_index(target.name); + + experimental::condition cond; + cond.targets.emplace_back(std::move(target)); + + cond.index = 1; + cond.processor = std::make_unique("body", 0, true); + conditions.emplace_back(std::move(cond)); + } + + experimental::expression expr(std::move(conditions)); + + ddwaf::object_store store; + experimental::expression::cache_type cache; + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "query")); + + store.insert(root); + + ddwaf::timer deadline{2s}; + + EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.body", ddwaf_object_string(&tmp, "body")); + ddwaf_object_map_add( + &root, "server.request.query", ddwaf_object_string(&tmp, "red-herring")); + + store.insert(root); + + ddwaf::timer deadline{2s}; + + EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); + } +} + +TEST(TestExpression, SingleObjectChain) +{ + std::vector conditions; + + { + experimental::condition::target_type target; + target.name = "server.request.query"; + target.root = get_target_index(target.name); + + experimental::condition cond; + cond.targets.emplace_back(std::move(target)); + + cond.index = 0; + cond.processor = std::make_unique("query", 0, true); + cond.dependents.object.emplace(1); + conditions.emplace_back(std::move(cond)); + } + + { + + experimental::condition::target_type target; + target.scope = experimental::condition::eval_scope::local; + target.condition_index = 0; + target.entity = experimental::condition::eval_entity::object; + target.name = "match.0.object"; + target.root = get_target_index(target.name); + + experimental::condition cond; + cond.targets.emplace_back(std::move(target)); + + cond.index = 1; + cond.processor = std::make_unique("^thermometer$", 0, true); + conditions.emplace_back(std::move(cond)); + } + + experimental::expression expr(std::move(conditions)); + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add( + &root, "server.request.query", ddwaf_object_string(&tmp, "some query")); + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + experimental::expression::cache_type cache; + EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object query; + ddwaf_object_map(&query); + ddwaf_object_map_add(&query, "value1", ddwaf_object_string(&tmp, "some query")); + ddwaf_object_map_add(&query, "value2", ddwaf_object_string(&tmp, "thermometer")); + + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", &query); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + experimental::expression::cache_type cache; + EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); + } +} + +TEST(TestExpression, SingleScalarChain) +{ + std::vector conditions; + + { + experimental::condition::target_type target; + target.name = "server.request.query"; + target.root = get_target_index(target.name); + + experimental::condition cond; + cond.targets.emplace_back(std::move(target)); + + cond.index = 0; + cond.processor = std::make_unique("query", 0, true); + cond.dependents.object.emplace(1); + conditions.emplace_back(std::move(cond)); + } + + { + + experimental::condition::target_type target; + target.scope = experimental::condition::eval_scope::local; + target.condition_index = 0; + target.entity = experimental::condition::eval_entity::scalar; + target.name = "match.0.object"; + target.root = get_target_index(target.name); + + experimental::condition cond; + cond.targets.emplace_back(std::move(target)); + + cond.index = 1; + cond.processor = std::make_unique("^query$", 0, true); + conditions.emplace_back(std::move(cond)); + } + + experimental::expression expr(std::move(conditions)); + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object query; + + ddwaf_object_map(&query); + ddwaf_object_map_add(&query, "value1", ddwaf_object_string(&tmp, "some query")); + ddwaf_object_map_add(&query, "value2", ddwaf_object_string(&tmp, "query")); + + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", &query); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + experimental::expression::cache_type cache; + EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object query; + + ddwaf_object_map(&query); + ddwaf_object_map_add(&query, "value1", ddwaf_object_string(&tmp, "query")); + ddwaf_object_map_add(&query, "value2", ddwaf_object_string(&tmp, "some query")); + + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", &query); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + experimental::expression::cache_type cache; + EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); + } +} From 7bffec3d7cdd231bf6840d69fdb3d156e6f87b93 Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Wed, 28 Jun 2023 16:08:15 +0100 Subject: [PATCH 09/28] Replace resolved with higlight and add test --- src/expression.cpp | 3 ++- src/expression.hpp | 23 +++++------------ tests/expression_test.cpp | 53 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 60 insertions(+), 19 deletions(-) diff --git a/src/expression.cpp b/src/expression.cpp index 355b81232..221dbaaf9 100644 --- a/src/expression.cpp +++ b/src/expression.cpp @@ -36,7 +36,7 @@ std::optional expression::evaluator::eval_target(const condition & } last_result->key_path = std::move(it.get_current_path()); - cache.set_eval_resolved(cond.index, last_result->resolved); + cache.set_eval_highlight(cond.index, last_result->matched); cache.set_eval_scalar(cond.index, *it); bool chain_result = true; @@ -91,6 +91,7 @@ bool expression::evaluator::eval_condition(const condition &cond, condition::eva } DDWAF_TRACE("Original object %p", object); + DDWAF_TRACE("Value %.*s", (int)object->nbEntries, object->stringValue); std::optional optional_match; if (target.source == condition::data_source::keys) { diff --git a/src/expression.hpp b/src/expression.hpp index 40f5995ff..8e3b2d25b 100644 --- a/src/expression.hpp +++ b/src/expression.hpp @@ -35,7 +35,7 @@ struct condition { enum class data_source : uint8_t { values, keys }; enum class eval_scope : uint8_t { global, local }; - enum class eval_entity : uint8_t { resolved, scalar, object }; + enum class eval_entity : uint8_t { highlight, scalar, object }; struct target_type { eval_scope scope{eval_scope::global}; @@ -70,7 +70,7 @@ class expression { using ptr = std::shared_ptr; struct eval_result { - ddwaf_object resolved{nullptr, 0, {nullptr}, 0, DDWAF_OBJ_INVALID}; + ddwaf_object highlight{nullptr, 0, {nullptr}, 0, DDWAF_OBJ_INVALID}; const ddwaf_object *scalar{nullptr}; const ddwaf_object *object{nullptr}; }; @@ -84,9 +84,9 @@ class expression { return conditions[index]; } - void set_eval_resolved(condition::index_type index, const memory::string &str) + void set_eval_highlight(condition::index_type index, const memory::string &str) { - ddwaf_object_stringl_nc(&store[index].resolved, str.c_str(), str.size()); + ddwaf_object_stringl(&store[index].highlight, str.c_str(), str.size()); } void set_eval_scalar(condition::index_type index, const ddwaf_object *obj) @@ -99,24 +99,13 @@ class expression { store[index].object = obj; } - // NOLINTNEXTLINE(bugprone-easily-swappable-parameters) - void set_eval_entities(condition::index_type index, const ddwaf_object *scalar, - const ddwaf_object *object, const memory::string &resolved) - { - auto &eval_res = store[index]; - eval_res.scalar = scalar; - DDWAF_TRACE("Object %p", object); - eval_res.object = object; - ddwaf_object_stringl_nc(&eval_res.resolved, resolved.c_str(), resolved.size()); - } - const ddwaf_object *get_eval_entity( condition::index_type index, condition::eval_entity entity) { auto it = store.find(index); if (it != store.end()) { - if (entity == condition::eval_entity::resolved) { - return &it->second.resolved; + if (entity == condition::eval_entity::highlight) { + return &it->second.highlight; } if (entity == condition::eval_entity::scalar) { diff --git a/tests/expression_test.cpp b/tests/expression_test.cpp index d7a327748..06ae4b42b 100644 --- a/tests/expression_test.cpp +++ b/tests/expression_test.cpp @@ -521,7 +521,7 @@ TEST(TestExpression, SingleScalarChain) target.scope = experimental::condition::eval_scope::local; target.condition_index = 0; target.entity = experimental::condition::eval_entity::scalar; - target.name = "match.0.object"; + target.name = "match.0.scalar"; target.root = get_target_index(target.name); experimental::condition cond; @@ -576,3 +576,54 @@ TEST(TestExpression, SingleScalarChain) EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); } } + +TEST(TestExpression, SingleHighlightChain) +{ + std::vector conditions; + + { + experimental::condition::target_type target; + target.name = "server.request.query"; + target.root = get_target_index(target.name); + + experimental::condition cond; + cond.targets.emplace_back(std::move(target)); + + cond.index = 0; + cond.processor = std::make_unique("(query).*", 0, true); + cond.dependents.object.emplace(1); + conditions.emplace_back(std::move(cond)); + } + + { + + experimental::condition::target_type target; + target.scope = experimental::condition::eval_scope::local; + target.condition_index = 0; + target.entity = experimental::condition::eval_entity::highlight; + target.name = "match.0.highlight"; + target.root = get_target_index(target.name); + + experimental::condition cond; + cond.targets.emplace_back(std::move(target)); + + cond.index = 1; + cond.processor = std::make_unique("^query$", 0, true); + conditions.emplace_back(std::move(cond)); + } + + experimental::expression expr(std::move(conditions)); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "some query")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + experimental::expression::cache_type cache; + EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); +} From 2c2bba01e4f132df0e1d629a91127cf2d60b544e Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Wed, 28 Jun 2023 17:26:02 +0100 Subject: [PATCH 10/28] Minor changes --- src/expression.cpp | 5 ++++- src/expression.hpp | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/expression.cpp b/src/expression.cpp index 221dbaaf9..41aee27ca 100644 --- a/src/expression.cpp +++ b/src/expression.cpp @@ -102,7 +102,10 @@ bool expression::evaluator::eval_condition(const condition &cond, condition::eva optional_match = eval_target(cond, it, cond.processor, target.transformers); } - cond_cache.targets.emplace(target.root); + // Only cache global targets + if (target.scope == condition::eval_scope::global) { + cond_cache.targets.emplace(target.root); + } if (!optional_match.has_value()) { continue; diff --git a/src/expression.hpp b/src/expression.hpp index 8e3b2d25b..3338bf04f 100644 --- a/src/expression.hpp +++ b/src/expression.hpp @@ -160,4 +160,13 @@ class expression { std::vector conditions_; }; +class expression_builder +{ +public: + expression_builder() = default; + +protected: + +}; + } // namespace ddwaf::experimental From 61a0814f140f95494c2ba6dbae228eb6650a80c4 Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Wed, 28 Jun 2023 20:30:46 +0100 Subject: [PATCH 11/28] Refactor and use pointers as map keys --- src/expression.cpp | 37 +++---- src/expression.hpp | 123 +++++++++----------- tests/expression_test.cpp | 228 ++++++++++++++++++-------------------- 3 files changed, 175 insertions(+), 213 deletions(-) diff --git a/src/expression.cpp b/src/expression.cpp index 41aee27ca..8ad542180 100644 --- a/src/expression.cpp +++ b/src/expression.cpp @@ -36,13 +36,12 @@ std::optional expression::evaluator::eval_target(const condition & } last_result->key_path = std::move(it.get_current_path()); - cache.set_eval_highlight(cond.index, last_result->matched); - cache.set_eval_scalar(cond.index, *it); + cache.set_eval_highlight(&cond, last_result->matched); + cache.set_eval_scalar(&cond, *it); bool chain_result = true; - for (auto index : cond.dependents.scalar) { - const auto &next_cond = conditions[index]; - if (!eval_condition(next_cond, condition::eval_scope::local)) { + for (const auto *next_cond : cond.children.scalar) { + if (!eval_condition(*next_cond, eval_scope::local)) { chain_result = false; break; } @@ -59,9 +58,9 @@ std::optional expression::evaluator::eval_target(const condition & } // NOLINTNEXTLINE(misc-no-recursion) -bool expression::evaluator::eval_condition(const condition &cond, condition::eval_scope scope) +bool expression::evaluator::eval_condition(const condition &cond, eval_scope scope) { - auto &cond_cache = cache.get_condition_cache(cond.index); + auto &cond_cache = cache.get_condition_cache(cond); if (cond_cache.result.has_value()) { return true; @@ -79,22 +78,18 @@ bool expression::evaluator::eval_condition(const condition &cond, condition::eva // TODO: iterators could be cached to avoid reinitialisation const ddwaf_object *object = nullptr; - if (target.scope == condition::eval_scope::global) { + if (target.scope == eval_scope::global) { object = store.get_target(target.root); } else { - object = cache.get_eval_entity(target.condition_index, target.entity); + object = cache.get_eval_entity(target.parent, target.entity); } if (object == nullptr) { - DDWAF_TRACE("No object found for target %s", target.name.c_str()); continue; } - DDWAF_TRACE("Original object %p", object); - DDWAF_TRACE("Value %.*s", (int)object->nbEntries, object->stringValue); - std::optional optional_match; - if (target.source == condition::data_source::keys) { + if (target.source == data_source::keys) { object::key_iterator it(object, target.key_path, objects_excluded, limits); optional_match = eval_target(cond, it, cond.processor, target.transformers); } else { @@ -103,7 +98,7 @@ bool expression::evaluator::eval_condition(const condition &cond, condition::eva } // Only cache global targets - if (target.scope == condition::eval_scope::global) { + if (target.scope == eval_scope::global) { cond_cache.targets.emplace(target.root); } @@ -114,14 +109,11 @@ bool expression::evaluator::eval_condition(const condition &cond, condition::eva optional_match->address = target.name; cond_cache.result = optional_match; - cache.set_eval_object(cond.index, object); + cache.set_eval_object(&cond, object); - DDWAF_TRACE("Match! Checking chain"); bool chain_result = true; - for (auto index : cond.dependents.object) { - const auto &next_cond = conditions[index]; - if (!eval_condition(next_cond, condition::eval_scope::local)) { - DDWAF_TRACE("Chain %lu didn't match", index) + for (const auto *next_cond : cond.children.object) { + if (!eval_condition(*next_cond, eval_scope::local)) { chain_result = false; break; } @@ -144,8 +136,7 @@ bool expression::evaluator::eval() { // NOLINTNEXTLINE(readability-use-anyofallof) for (const auto &cond : conditions) { - DDWAF_TRACE("Condition %lu", cond.index); - if (!eval_condition(cond, condition::eval_scope::global)) { + if (!eval_condition(*cond, eval_scope::global)) { return false; } } diff --git a/src/expression.hpp b/src/expression.hpp index 3338bf04f..b0d10effc 100644 --- a/src/expression.hpp +++ b/src/expression.hpp @@ -24,50 +24,48 @@ namespace ddwaf::experimental { -struct condition { - using ptr = std::shared_ptr; - using index_type = std::size_t; - - struct cache_type { - std::unordered_set targets{}; - std::optional result{std::nullopt}; - }; +class expression { +public: + using ptr = std::shared_ptr; enum class data_source : uint8_t { values, keys }; enum class eval_scope : uint8_t { global, local }; enum class eval_entity : uint8_t { highlight, scalar, object }; - struct target_type { - eval_scope scope{eval_scope::global}; - std::string name; + struct condition { + using ptr = std::shared_ptr; - // Global scope - target_index root; + struct cache_type { + std::unordered_set targets{}; + std::optional result{std::nullopt}; + }; - // Local scope - std::size_t condition_index{0}; - eval_entity entity{eval_entity::object}; + struct target_type { + eval_scope scope{eval_scope::global}; + std::string name; - // Applicable to either scope - std::vector key_path{}; + // Global scope + target_index root; - // Transformers - std::vector transformers{}; - data_source source{data_source::values}; - }; + // Local scope + const condition *parent{nullptr}; + eval_entity entity{eval_entity::object}; - index_type index; - std::vector targets; - std::shared_ptr processor; - struct { - std::unordered_set scalar{}; - std::unordered_set object{}; - } dependents; -}; + // Applicable to either scope + std::vector key_path{}; -class expression { -public: - using ptr = std::shared_ptr; + // Transformers + std::vector transformers{}; + data_source source{data_source::values}; + }; + + std::vector targets; + std::shared_ptr processor; + struct { + std::unordered_set scalar{}; + std::unordered_set object{}; + } children; + }; struct eval_result { ddwaf_object highlight{nullptr, 0, {nullptr}, 0, DDWAF_OBJ_INVALID}; @@ -76,54 +74,49 @@ class expression { }; struct cache_type { - std::unordered_map conditions{}; - std::unordered_map store{}; + std::unordered_map conditions{}; + std::unordered_map store{}; - condition::cache_type &get_condition_cache(condition::index_type index) + condition::cache_type &get_condition_cache(const condition &cond) { - return conditions[index]; + return conditions[&cond]; } - void set_eval_highlight(condition::index_type index, const memory::string &str) + void set_eval_highlight(const condition *cond, const memory::string &str) { - ddwaf_object_stringl(&store[index].highlight, str.c_str(), str.size()); + ddwaf_object_stringl(&store[cond].highlight, str.c_str(), str.size()); } - void set_eval_scalar(condition::index_type index, const ddwaf_object *obj) + void set_eval_scalar(const condition *cond, const ddwaf_object *obj) { - store[index].scalar = obj; + store[cond].scalar = obj; } - void set_eval_object(condition::index_type index, const ddwaf_object *obj) + void set_eval_object(const condition *cond, const ddwaf_object *obj) { - store[index].object = obj; + store[cond].object = obj; } - const ddwaf_object *get_eval_entity( - condition::index_type index, condition::eval_entity entity) + const ddwaf_object *get_eval_entity(const condition *cond, eval_entity entity) { - auto it = store.find(index); + auto it = store.find(cond); if (it != store.end()) { - if (entity == condition::eval_entity::highlight) { + switch (entity) { + case eval_entity::highlight: return &it->second.highlight; - } - - if (entity == condition::eval_entity::scalar) { + case eval_entity::scalar: return it->second.scalar; - } - - if (entity == condition::eval_entity::object) { + case eval_entity::object: return it->second.object; } } - return nullptr; } }; struct evaluator { bool eval(); - bool eval_condition(const condition &cond, condition::eval_scope scope); + bool eval_condition(const condition &cond, eval_scope scope); template std::optional eval_target(const condition &cond, T &it, @@ -132,14 +125,14 @@ class expression { ddwaf::timer &deadline; const ddwaf::object_limits &limits; - const std::vector &conditions; + const std::vector &conditions; const object_store &store; const std::unordered_set &objects_excluded; cache_type &cache; }; - explicit expression( - std::vector &&conditions, ddwaf::object_limits limits = ddwaf::object_limits()) + explicit expression(std::vector &&conditions, + ddwaf::object_limits limits = ddwaf::object_limits()) : limits_(limits), conditions_(std::move(conditions)) {} @@ -148,25 +141,15 @@ class expression { ddwaf::timer &deadline) const; protected: - template - std::optional eval_target(T &it, const rule_processor::base::ptr &processor, - const std::vector &transformers, ddwaf::timer &deadline) const; - - bool eval_condition(std::size_t index, cache_type &cache, const object_store &store, - const std::unordered_set &objects_excluded, - ddwaf::timer &deadline) const; - ddwaf::object_limits limits_; - std::vector conditions_; + std::vector conditions_; }; -class expression_builder -{ +class expression_builder { public: expression_builder() = default; protected: - }; } // namespace ddwaf::experimental diff --git a/tests/expression_test.cpp b/tests/expression_test.cpp index 06ae4b42b..afc3e8131 100644 --- a/tests/expression_test.cpp +++ b/tests/expression_test.cpp @@ -10,22 +10,24 @@ using namespace ddwaf; +using expression = experimental::expression; + TEST(TestExpression, SimpleMatch) { - std::vector conditions; + std::vector conditions; { - experimental::condition::target_type target; + expression::condition::target_type target; target.name = "server.request.query"; target.root = get_target_index(target.name); - experimental::condition cond; + expression::condition cond; cond.targets.emplace_back(std::move(target)); cond.processor = std::make_unique(".*", 0, true); - conditions.emplace_back(std::move(cond)); + conditions.emplace_back(std::make_shared(std::move(cond))); } - experimental::expression expr(std::move(conditions)); + expression expr(std::move(conditions)); ddwaf_object root; ddwaf_object tmp; @@ -37,40 +39,39 @@ TEST(TestExpression, SimpleMatch) ddwaf::timer deadline{2s}; - experimental::expression::cache_type cache; + expression::cache_type cache; EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); } TEST(TestExpression, MultiInputMatchOnSecond) { - std::vector conditions; + std::vector conditions; { - experimental::condition cond; + expression::condition cond; { - experimental::condition::target_type target; + expression::condition::target_type target; target.name = "server.request.query"; target.root = get_target_index(target.name); cond.targets.emplace_back(std::move(target)); } { - experimental::condition::target_type target; + expression::condition::target_type target; target.name = "server.request.body"; target.root = get_target_index(target.name); cond.targets.emplace_back(std::move(target)); } - cond.index = 0; cond.processor = std::make_unique("^value$", 0, true); - conditions.emplace_back(std::move(cond)); + conditions.emplace_back(std::make_shared(std::move(cond))); } - experimental::expression expr(std::move(conditions)); + expression expr(std::move(conditions)); ddwaf::object_store store; - experimental::expression::cache_type cache; + expression::cache_type cache; { ddwaf_object root; @@ -101,24 +102,23 @@ TEST(TestExpression, MultiInputMatchOnSecond) TEST(TestExpression, DuplicateInput) { - std::vector conditions; + std::vector conditions; { - experimental::condition::target_type target; + expression::condition::target_type target; target.name = "server.request.query"; target.root = get_target_index(target.name); - experimental::condition cond; + expression::condition cond; cond.targets.emplace_back(std::move(target)); - cond.index = 0; cond.processor = std::make_unique("^value$", 0, true); - conditions.emplace_back(std::move(cond)); + conditions.emplace_back(std::make_shared(std::move(cond))); } - experimental::expression expr(std::move(conditions)); + expression expr(std::move(conditions)); - experimental::expression::cache_type cache; + expression::cache_type cache; { ddwaf_object root; @@ -151,22 +151,21 @@ TEST(TestExpression, DuplicateInput) TEST(TestExpression, MatchDuplicateInputNoCache) { - std::vector conditions; + std::vector conditions; { - experimental::condition::target_type target; + expression::condition::target_type target; target.name = "server.request.query"; target.root = get_target_index(target.name); - experimental::condition cond; + expression::condition cond; cond.targets.emplace_back(std::move(target)); - cond.index = 0; cond.processor = std::make_unique("^value$", 0, true); - conditions.emplace_back(std::move(cond)); + conditions.emplace_back(std::make_shared(std::move(cond))); } - experimental::expression expr(std::move(conditions)); + expression expr(std::move(conditions)); { ddwaf_object root; @@ -179,7 +178,7 @@ TEST(TestExpression, MatchDuplicateInputNoCache) ddwaf::timer deadline{2s}; - experimental::expression::cache_type cache; + expression::cache_type cache; EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); } @@ -194,45 +193,43 @@ TEST(TestExpression, MatchDuplicateInputNoCache) ddwaf::timer deadline{2s}; - experimental::expression::cache_type cache; + expression::cache_type cache; EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); } } TEST(TestExpression, TwoConditionsSingleInputNoMatch) { - std::vector conditions; + std::vector conditions; { - experimental::condition::target_type target; + expression::condition::target_type target; target.name = "server.request.query"; target.root = get_target_index(target.name); - experimental::condition cond; + expression::condition cond; cond.targets.emplace_back(std::move(target)); - cond.index = 0; cond.processor = std::make_unique("value", 0, true); - conditions.emplace_back(std::move(cond)); + conditions.emplace_back(std::make_shared(std::move(cond))); } { - experimental::condition::target_type target; + expression::condition::target_type target; target.name = "server.request.query"; target.root = get_target_index(target.name); - experimental::condition cond; + expression::condition cond; cond.targets.emplace_back(std::move(target)); - cond.index = 1; cond.processor = std::make_unique("^value$", 0, true); - conditions.emplace_back(std::move(cond)); + conditions.emplace_back(std::make_shared(std::move(cond))); } - experimental::expression expr(std::move(conditions)); + expression expr(std::move(conditions)); - experimental::expression::cache_type cache; + expression::cache_type cache; { ddwaf_object root; @@ -265,36 +262,34 @@ TEST(TestExpression, TwoConditionsSingleInputNoMatch) TEST(TestExpression, TwoConditionsSingleInputMatch) { - std::vector conditions; + std::vector conditions; { - experimental::condition::target_type target; + expression::condition::target_type target; target.name = "server.request.query"; target.root = get_target_index(target.name); - experimental::condition cond; + expression::condition cond; cond.targets.emplace_back(std::move(target)); - cond.index = 0; cond.processor = std::make_unique("value", 0, true); - conditions.emplace_back(std::move(cond)); + conditions.emplace_back(std::make_shared(std::move(cond))); } { - experimental::condition::target_type target; + expression::condition::target_type target; target.name = "server.request.query"; target.root = get_target_index(target.name); - experimental::condition cond; + expression::condition cond; cond.targets.emplace_back(std::move(target)); - cond.index = 1; cond.processor = std::make_unique("^value$", 0, true); - conditions.emplace_back(std::move(cond)); + conditions.emplace_back(std::make_shared(std::move(cond))); } - experimental::expression expr(std::move(conditions)); + expression expr(std::move(conditions)); ddwaf_object root; ddwaf_object tmp; @@ -306,45 +301,43 @@ TEST(TestExpression, TwoConditionsSingleInputMatch) ddwaf::timer deadline{2s}; - experimental::expression::cache_type cache; + expression::cache_type cache; EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); } TEST(TestExpression, TwoConditionsMultiInputSingleEvalMatch) { - std::vector conditions; + std::vector conditions; { - experimental::condition::target_type target; + expression::condition::target_type target; target.name = "server.request.query"; target.root = get_target_index(target.name); - experimental::condition cond; + expression::condition cond; cond.targets.emplace_back(std::move(target)); - cond.index = 0; cond.processor = std::make_unique("query", 0, true); - conditions.emplace_back(std::move(cond)); + conditions.emplace_back(std::make_shared(std::move(cond))); } { - experimental::condition::target_type target; + expression::condition::target_type target; target.name = "server.request.body"; target.root = get_target_index(target.name); - experimental::condition cond; + expression::condition cond; cond.targets.emplace_back(std::move(target)); - cond.index = 1; cond.processor = std::make_unique("body", 0, true); - conditions.emplace_back(std::move(cond)); + conditions.emplace_back(std::make_shared(std::move(cond))); } - experimental::expression expr(std::move(conditions)); + expression expr(std::move(conditions)); ddwaf::object_store store; - experimental::expression::cache_type cache; + expression::cache_type cache; ddwaf_object root; ddwaf_object tmp; @@ -361,39 +354,37 @@ TEST(TestExpression, TwoConditionsMultiInputSingleEvalMatch) TEST(TestExpression, TwoConditionsMultiInputMultiEvalMatch) { - std::vector conditions; + std::vector conditions; { - experimental::condition::target_type target; + expression::condition::target_type target; target.name = "server.request.query"; target.root = get_target_index(target.name); - experimental::condition cond; + expression::condition cond; cond.targets.emplace_back(std::move(target)); - cond.index = 0; cond.processor = std::make_unique("query", 0, true); - conditions.emplace_back(std::move(cond)); + conditions.emplace_back(std::make_shared(std::move(cond))); } { - experimental::condition::target_type target; + expression::condition::target_type target; target.name = "server.request.body"; target.root = get_target_index(target.name); - experimental::condition cond; + expression::condition cond; cond.targets.emplace_back(std::move(target)); - cond.index = 1; cond.processor = std::make_unique("body", 0, true); - conditions.emplace_back(std::move(cond)); + conditions.emplace_back(std::make_shared(std::move(cond))); } - experimental::expression expr(std::move(conditions)); + expression expr(std::move(conditions)); ddwaf::object_store store; - experimental::expression::cache_type cache; + expression::cache_type cache; { ddwaf_object root; @@ -426,40 +417,39 @@ TEST(TestExpression, TwoConditionsMultiInputMultiEvalMatch) TEST(TestExpression, SingleObjectChain) { - std::vector conditions; + std::vector conditions; { - experimental::condition::target_type target; + expression::condition::target_type target; target.name = "server.request.query"; target.root = get_target_index(target.name); - experimental::condition cond; + expression::condition cond; cond.targets.emplace_back(std::move(target)); - cond.index = 0; cond.processor = std::make_unique("query", 0, true); - cond.dependents.object.emplace(1); - conditions.emplace_back(std::move(cond)); + conditions.emplace_back(std::make_shared(std::move(cond))); } { - experimental::condition::target_type target; - target.scope = experimental::condition::eval_scope::local; - target.condition_index = 0; - target.entity = experimental::condition::eval_entity::object; + expression::condition::target_type target; + target.scope = expression::eval_scope::local; + target.parent = conditions[0].get(); + target.entity = expression::eval_entity::object; target.name = "match.0.object"; target.root = get_target_index(target.name); - experimental::condition cond; + expression::condition cond; cond.targets.emplace_back(std::move(target)); - cond.index = 1; cond.processor = std::make_unique("^thermometer$", 0, true); - conditions.emplace_back(std::move(cond)); + conditions.emplace_back(std::make_shared(std::move(cond))); + + conditions[0]->children.object.emplace(conditions.back().get()); } - experimental::expression expr(std::move(conditions)); + expression expr(std::move(conditions)); { ddwaf_object root; @@ -472,7 +462,7 @@ TEST(TestExpression, SingleObjectChain) ddwaf::timer deadline{2s}; - experimental::expression::cache_type cache; + expression::cache_type cache; EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); } @@ -492,47 +482,46 @@ TEST(TestExpression, SingleObjectChain) ddwaf::timer deadline{2s}; - experimental::expression::cache_type cache; + expression::cache_type cache; EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); } } TEST(TestExpression, SingleScalarChain) { - std::vector conditions; + std::vector conditions; { - experimental::condition::target_type target; + expression::condition::target_type target; target.name = "server.request.query"; target.root = get_target_index(target.name); - experimental::condition cond; + expression::condition cond; cond.targets.emplace_back(std::move(target)); - cond.index = 0; cond.processor = std::make_unique("query", 0, true); - cond.dependents.object.emplace(1); - conditions.emplace_back(std::move(cond)); + conditions.emplace_back(std::make_shared(std::move(cond))); } { - experimental::condition::target_type target; - target.scope = experimental::condition::eval_scope::local; - target.condition_index = 0; - target.entity = experimental::condition::eval_entity::scalar; + expression::condition::target_type target; + target.scope = expression::eval_scope::local; + target.parent = conditions[0].get(); + target.entity = expression::eval_entity::scalar; target.name = "match.0.scalar"; target.root = get_target_index(target.name); - experimental::condition cond; + expression::condition cond; cond.targets.emplace_back(std::move(target)); - cond.index = 1; cond.processor = std::make_unique("^query$", 0, true); - conditions.emplace_back(std::move(cond)); + conditions.emplace_back(std::make_shared(std::move(cond))); + + conditions[0]->children.object.emplace(conditions.back().get()); } - experimental::expression expr(std::move(conditions)); + expression expr(std::move(conditions)); { ddwaf_object root; @@ -551,7 +540,7 @@ TEST(TestExpression, SingleScalarChain) ddwaf::timer deadline{2s}; - experimental::expression::cache_type cache; + expression::cache_type cache; EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); } @@ -572,47 +561,46 @@ TEST(TestExpression, SingleScalarChain) ddwaf::timer deadline{2s}; - experimental::expression::cache_type cache; + expression::cache_type cache; EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); } } TEST(TestExpression, SingleHighlightChain) { - std::vector conditions; + std::vector conditions; { - experimental::condition::target_type target; + expression::condition::target_type target; target.name = "server.request.query"; target.root = get_target_index(target.name); - experimental::condition cond; + expression::condition cond; cond.targets.emplace_back(std::move(target)); - cond.index = 0; cond.processor = std::make_unique("(query).*", 0, true); - cond.dependents.object.emplace(1); - conditions.emplace_back(std::move(cond)); + conditions.emplace_back(std::make_shared(std::move(cond))); } { - experimental::condition::target_type target; - target.scope = experimental::condition::eval_scope::local; - target.condition_index = 0; - target.entity = experimental::condition::eval_entity::highlight; + expression::condition::target_type target; + target.scope = expression::eval_scope::local; + target.parent = conditions[0].get(); + target.entity = expression::eval_entity::highlight; target.name = "match.0.highlight"; target.root = get_target_index(target.name); - experimental::condition cond; + expression::condition cond; cond.targets.emplace_back(std::move(target)); - cond.index = 1; cond.processor = std::make_unique("^query$", 0, true); - conditions.emplace_back(std::move(cond)); + conditions.emplace_back(std::make_shared(std::move(cond))); + + conditions[0]->children.object.emplace(conditions.back().get()); } - experimental::expression expr(std::move(conditions)); + expression expr(std::move(conditions)); ddwaf_object root; ddwaf_object tmp; @@ -624,6 +612,6 @@ TEST(TestExpression, SingleHighlightChain) ddwaf::timer deadline{2s}; - experimental::expression::cache_type cache; + expression::cache_type cache; EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); } From fda389f4b8577b8addd92c941b22a15636a5f330 Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Wed, 28 Jun 2023 21:03:27 +0100 Subject: [PATCH 12/28] Minor change --- src/expression.cpp | 1 + src/expression.hpp | 3 ++- tests/expression_test.cpp | 7 +++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/expression.cpp b/src/expression.cpp index 8ad542180..85c346bd1 100644 --- a/src/expression.cpp +++ b/src/expression.cpp @@ -36,6 +36,7 @@ std::optional expression::evaluator::eval_target(const condition & } last_result->key_path = std::move(it.get_current_path()); + cache.set_eval_highlight(&cond, last_result->matched); cache.set_eval_scalar(&cond, *it); diff --git a/src/expression.hpp b/src/expression.hpp index b0d10effc..cd3ee2aec 100644 --- a/src/expression.hpp +++ b/src/expression.hpp @@ -84,7 +84,8 @@ class expression { void set_eval_highlight(const condition *cond, const memory::string &str) { - ddwaf_object_stringl(&store[cond].highlight, str.c_str(), str.size()); + auto &res = store[cond]; + ddwaf_object_stringl_nc(&res.highlight, str.c_str(), str.size()); } void set_eval_scalar(const condition *cond, const ddwaf_object *obj) diff --git a/tests/expression_test.cpp b/tests/expression_test.cpp index afc3e8131..64d4fb560 100644 --- a/tests/expression_test.cpp +++ b/tests/expression_test.cpp @@ -518,7 +518,7 @@ TEST(TestExpression, SingleScalarChain) cond.processor = std::make_unique("^query$", 0, true); conditions.emplace_back(std::make_shared(std::move(cond))); - conditions[0]->children.object.emplace(conditions.back().get()); + conditions[0]->children.scalar.emplace(conditions.back().get()); } expression expr(std::move(conditions)); @@ -530,7 +530,6 @@ TEST(TestExpression, SingleScalarChain) ddwaf_object_map(&query); ddwaf_object_map_add(&query, "value1", ddwaf_object_string(&tmp, "some query")); - ddwaf_object_map_add(&query, "value2", ddwaf_object_string(&tmp, "query")); ddwaf_object_map(&root); ddwaf_object_map_add(&root, "server.request.query", &query); @@ -550,8 +549,8 @@ TEST(TestExpression, SingleScalarChain) ddwaf_object query; ddwaf_object_map(&query); - ddwaf_object_map_add(&query, "value1", ddwaf_object_string(&tmp, "query")); ddwaf_object_map_add(&query, "value2", ddwaf_object_string(&tmp, "some query")); + ddwaf_object_map_add(&query, "value1", ddwaf_object_string(&tmp, "query")); ddwaf_object_map(&root); ddwaf_object_map_add(&root, "server.request.query", &query); @@ -597,7 +596,7 @@ TEST(TestExpression, SingleHighlightChain) cond.processor = std::make_unique("^query$", 0, true); conditions.emplace_back(std::make_shared(std::move(cond))); - conditions[0]->children.object.emplace(conditions.back().get()); + conditions[0]->children.scalar.emplace(conditions.back().get()); } expression expr(std::move(conditions)); From 7889fd457200f91dc8a7bb8475f141d9bc39f472 Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Wed, 28 Jun 2023 22:23:35 +0100 Subject: [PATCH 13/28] Add expression builder and tests --- src/expression.cpp | 64 ++++- src/expression.hpp | 79 +++++- tests/expression_builder_test.cpp | 422 ++++++++++++++++++++++++++++++ 3 files changed, 549 insertions(+), 16 deletions(-) create mode 100644 tests/expression_builder_test.cpp diff --git a/src/expression.cpp b/src/expression.cpp index 85c346bd1..248a7c93d 100644 --- a/src/expression.cpp +++ b/src/expression.cpp @@ -11,10 +11,54 @@ namespace ddwaf::experimental { +std::optional expression::evaluator::eval_object(const ddwaf_object *object, + const rule_processor::base::ptr &processor, + const std::vector &transformers) const +{ + const bool has_transform = !transformers.empty(); + bool transform_required = false; + + if (has_transform) { + // This codepath is shared with the mutable path. The structure can't be const :/ + transform_required = + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) + PWTransformer::doesNeedTransform(transformers, const_cast(object)); + } + + const size_t length = + find_string_cutoff(object->stringValue, object->nbEntries, limits.max_string_length); + + // If we don't have transform to perform, or if they're irrelevant, no need to waste time + // copying and allocating data + if (!has_transform || !transform_required) { + return processor->match({object->stringValue, length}); + } + + ddwaf_object copy; + ddwaf_object_stringl(©, (const char *)object->stringValue, length); + + const std::unique_ptr scope( + ©, ddwaf_object_free); + + // Transform it and pick the pointer to process + bool transformFailed = false; + for (const PW_TRANSFORM_ID &transform : transformers) { + transformFailed = !PWTransformer::transform(transform, ©); + if (transformFailed || (copy.type == DDWAF_OBJ_STRING && copy.nbEntries == 0)) { + break; + } + } + + if (transformFailed) { + return processor->match({object->stringValue, length}); + } + + return processor->match_object(©); +} + template std::optional expression::evaluator::eval_target(const condition &cond, T &it, - const rule_processor::base::ptr &processor, - const std::vector & /*transformers*/) + const rule_processor::base::ptr &processor, const std::vector &transformers) { std::optional last_result = std::nullopt; @@ -27,14 +71,12 @@ std::optional expression::evaluator::eval_target(const condition & continue; } - { - auto optional_match = processor->match_object(*it); - if (!optional_match.has_value()) { - continue; - } - last_result = std::move(optional_match); + auto optional_match = eval_object(*it, processor, transformers); + if (!optional_match.has_value()) { + continue; } + last_result = std::move(optional_match); last_result->key_path = std::move(it.get_current_path()); cache.set_eval_highlight(&cond, last_result->matched); @@ -48,11 +90,9 @@ std::optional expression::evaluator::eval_target(const condition & } } - if (!chain_result) { - continue; + if (chain_result) { + break; } - - break; } return last_result; diff --git a/src/expression.hpp b/src/expression.hpp index cd3ee2aec..0647b951e 100644 --- a/src/expression.hpp +++ b/src/expression.hpp @@ -7,11 +7,13 @@ #pragma once #include "log.hpp" +#include "utils.hpp" #include #include #include #include #include +#include #include #include @@ -122,7 +124,11 @@ class expression { template std::optional eval_target(const condition &cond, T &it, const rule_processor::base::ptr &processor, - const std::vector & /*transformers*/); + const std::vector &transformers); + + std::optional eval_object(const ddwaf_object *object, + const rule_processor::base::ptr &processor, + const std::vector &transformers) const; ddwaf::timer &deadline; const ddwaf::object_limits &limits; @@ -132,8 +138,7 @@ class expression { cache_type &cache; }; - explicit expression(std::vector &&conditions, - ddwaf::object_limits limits = ddwaf::object_limits()) + explicit expression(std::vector &&conditions, ddwaf::object_limits limits = {}) : limits_(limits), conditions_(std::move(conditions)) {} @@ -148,9 +153,75 @@ class expression { class expression_builder { public: - expression_builder() = default; + explicit expression_builder(std::size_t num_conditions, ddwaf::object_limits limits = {}) + : limits_(limits) + { + conditions_.reserve(num_conditions); + } + + template void start_condition(Args... args) + { + auto cond = std::make_shared(); + cond->processor = std::make_unique(args...); + conditions_.emplace_back(std::move(cond)); + } + + void add_global_target(std::string name, std::vector key_path = {}, + std::vector transformers = {}, + expression::data_source source = expression::data_source::values) + { + expression::condition::target_type target; + target.scope = expression::eval_scope::global; + target.root = get_target_index(name); + target.key_path = std::move(key_path); + target.name = std::move(name); + target.transformers = std::move(transformers); + target.source = source; + + auto &cond = conditions_.back(); + cond->targets.emplace_back(std::move(target)); + } + + void add_local_target(std::string name, std::size_t cond_idx, expression::eval_entity entity, + std::vector key_path = {}, std::vector transformers = {}, + expression::data_source source = expression::data_source::values) + { + if (cond_idx >= (conditions_.size() - 1)) { + throw std::invalid_argument( + "local target references subsequent condition (or itself): current = " + + std::to_string(conditions_.size() - 1) + + ", referenced = " + std::to_string(cond_idx)); + } + + auto &parent = conditions_[cond_idx]; + auto &cond = conditions_.back(); + + if (entity == expression::eval_entity::object) { + parent->children.object.emplace(cond.get()); + } else { + parent->children.scalar.emplace(cond.get()); + } + + expression::condition::target_type target; + target.scope = expression::eval_scope::local; + target.parent = parent.get(); + target.entity = entity; + target.key_path = std::move(key_path); + target.name = std::move(name); + target.transformers = std::move(transformers); + target.source = source; + + cond->targets.emplace_back(std::move(target)); + } + + expression::ptr build() + { + return std::make_shared(std::move(conditions_), limits_); + } protected: + ddwaf::object_limits limits_; + std::vector conditions_; }; } // namespace ddwaf::experimental diff --git a/tests/expression_builder_test.cpp b/tests/expression_builder_test.cpp new file mode 100644 index 000000000..7db303eba --- /dev/null +++ b/tests/expression_builder_test.cpp @@ -0,0 +1,422 @@ +// Unless explicitly stated otherwise all files in this repository are +// dual-licensed under the Apache-2.0 License or BSD-3-Clause License. +// +// This product includes software developed at Datadog (https://www.datadoghq.com/). +// Copyright 2021 Datadog, Inc. + +#include "PWTransformer.h" +#include "expression.hpp" +#include "test.h" + +using namespace ddwaf; + +using expression = experimental::expression; +using expression_builder = experimental::expression_builder; + +TEST(TestExpressionBuilder, SimpleMatch) +{ + expression_builder builder(1); + builder.start_condition(".*", 0, true); + builder.add_global_target("server.request.query"); + + auto expr = builder.build(); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "value")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + expression::cache_type cache; + EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); +} + +TEST(TestExpressionBuilder, MultiInputMatchOnSecond) +{ + expression_builder builder(1); + builder.start_condition("^value$", 0, true); + builder.add_global_target("server.request.query"); + builder.add_global_target("server.request.body"); + + auto expr = builder.build(); + + ddwaf::object_store store; + expression::cache_type cache; + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "bad")); + + store.insert(root); + + ddwaf::timer deadline{2s}; + + EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.body", ddwaf_object_string(&tmp, "value")); + + store.insert(root); + + ddwaf::timer deadline{2s}; + + EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); + } +} + +TEST(TestExpressionBuilder, DuplicateInput) +{ + expression_builder builder(1); + builder.start_condition("^value$", 0, true); + builder.add_global_target("server.request.query"); + + auto expr = builder.build(); + + expression::cache_type cache; + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "bad")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "value")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); + } +} + +TEST(TestExpressionBuilder, MatchDuplicateInputNoCache) +{ + expression_builder builder(1); + builder.start_condition("^value$", 0, true); + builder.add_global_target("server.request.query"); + + auto expr = builder.build(); + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "bad")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + expression::cache_type cache; + EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "value")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + expression::cache_type cache; + EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); + } +} + +TEST(TestExpressionBuilder, TwoConditionsSingleInputNoMatch) +{ + expression_builder builder(2); + + builder.start_condition("value", 0, true); + builder.add_global_target("server.request.query"); + + builder.start_condition("^value$", 0, true); + builder.add_global_target("server.request.query"); + + auto expr = builder.build(); + + expression::cache_type cache; + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "bad_value")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "value")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); + } +} + +TEST(TestExpressionBuilder, TwoConditionsSingleInputMatch) +{ + expression_builder builder(2); + + builder.start_condition("value", 0, true); + builder.add_global_target("server.request.query"); + + builder.start_condition("^value$", 0, true); + builder.add_global_target("server.request.query"); + + auto expr = builder.build(); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "value")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + expression::cache_type cache; + EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); +} + +TEST(TestExpressionBuilder, TwoConditionsMultiInputSingleEvalMatch) +{ + expression_builder builder(2); + + builder.start_condition("query", 0, true); + builder.add_global_target("server.request.query"); + + builder.start_condition("body", 0, true); + builder.add_global_target("server.request.body"); + + auto expr = builder.build(); + + ddwaf::object_store store; + expression::cache_type cache; + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "query")); + ddwaf_object_map_add(&root, "server.request.body", ddwaf_object_string(&tmp, "body")); + + store.insert(root); + + ddwaf::timer deadline{2s}; + + EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); +} + +TEST(TestExpressionBuilder, TwoConditionsMultiInputMultiEvalMatch) +{ + expression_builder builder(2); + + builder.start_condition("query", 0, true); + builder.add_global_target("server.request.query"); + + builder.start_condition("body", 0, true); + builder.add_global_target("server.request.body"); + + auto expr = builder.build(); + + ddwaf::object_store store; + expression::cache_type cache; + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "query")); + + store.insert(root); + + ddwaf::timer deadline{2s}; + + EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.body", ddwaf_object_string(&tmp, "body")); + ddwaf_object_map_add( + &root, "server.request.query", ddwaf_object_string(&tmp, "red-herring")); + + store.insert(root); + + ddwaf::timer deadline{2s}; + + EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); + } +} + +TEST(TestExpressionBuilder, SingleObjectChain) +{ + expression_builder builder(2); + + builder.start_condition("query", 0, true); + builder.add_global_target("server.request.query"); + + builder.start_condition("^thermometer$", 0, true); + builder.add_local_target("match.0.object", 0, expression::eval_entity::object); + + auto expr = builder.build(); + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add( + &root, "server.request.query", ddwaf_object_string(&tmp, "some query")); + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + expression::cache_type cache; + EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object query; + ddwaf_object_map(&query); + ddwaf_object_map_add(&query, "value1", ddwaf_object_string(&tmp, "some query")); + ddwaf_object_map_add(&query, "value2", ddwaf_object_string(&tmp, "thermometer")); + + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", &query); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + expression::cache_type cache; + EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); + } +} + +TEST(TestExpressionBuilder, SingleScalarChain) +{ + expression_builder builder(2); + + builder.start_condition("query", 0, true); + builder.add_global_target("server.request.query"); + + builder.start_condition("^query$", 0, true); + builder.add_local_target("match.0.scalar", 0, expression::eval_entity::scalar); + + auto expr = builder.build(); + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object query; + + ddwaf_object_map(&query); + ddwaf_object_map_add(&query, "value1", ddwaf_object_string(&tmp, "some query")); + + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", &query); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + expression::cache_type cache; + EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object query; + + ddwaf_object_map(&query); + ddwaf_object_map_add(&query, "value2", ddwaf_object_string(&tmp, "some query")); + ddwaf_object_map_add(&query, "value1", ddwaf_object_string(&tmp, "query")); + + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", &query); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + expression::cache_type cache; + EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); + } +} + +TEST(TestExpressionBuilder, SingleHighlightChain) +{ + expression_builder builder(2); + + builder.start_condition("query", 0, true); + builder.add_global_target("server.request.query"); + + builder.start_condition("^query$", 0, true); + builder.add_local_target("match.0.highlight", 0, expression::eval_entity::highlight); + + auto expr = builder.build(); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "some query")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + expression::cache_type cache; + EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); +} From 0b2aa04d36c71c69a29463b2c7901db1f552637e Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Wed, 28 Jun 2023 22:34:48 +0100 Subject: [PATCH 14/28] Minor fix --- src/expression.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/expression.cpp b/src/expression.cpp index 248a7c93d..81d62d7b5 100644 --- a/src/expression.cpp +++ b/src/expression.cpp @@ -79,6 +79,10 @@ std::optional expression::evaluator::eval_target(const condition & last_result = std::move(optional_match); last_result->key_path = std::move(it.get_current_path()); + if (cond.children.scalar.empty()) { + break; + } + cache.set_eval_highlight(&cond, last_result->matched); cache.set_eval_scalar(&cond, *it); @@ -150,18 +154,20 @@ bool expression::evaluator::eval_condition(const condition &cond, eval_scope sco optional_match->address = target.name; cond_cache.result = optional_match; - cache.set_eval_object(&cond, object); + if (!cond.children.object.empty()) { + cache.set_eval_object(&cond, object); - bool chain_result = true; - for (const auto *next_cond : cond.children.object) { - if (!eval_condition(*next_cond, eval_scope::local)) { - chain_result = false; - break; + bool chain_result = true; + for (const auto *next_cond : cond.children.object) { + if (!eval_condition(*next_cond, eval_scope::local)) { + chain_result = false; + break; + } } - } - if (!chain_result) { - continue; + if (!chain_result) { + continue; + } } DDWAF_TRACE("Target %s matched parameter value %s", target.name.c_str(), From 27ff3af5e4fd31c9371dddfee04a072422013f28 Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Thu, 29 Jun 2023 13:45:10 +0100 Subject: [PATCH 15/28] Improve tests --- src/expression.cpp | 138 +++++++++- src/expression.hpp | 73 ++---- tests/expression_builder_test.cpp | 422 ------------------------------ tests/expression_test.cpp | 402 +++++++++------------------- tests/test_utils.cpp | 79 ++++++ tests/test_utils.hpp | 38 +++ 6 files changed, 409 insertions(+), 743 deletions(-) delete mode 100644 tests/expression_builder_test.cpp diff --git a/src/expression.cpp b/src/expression.cpp index 81d62d7b5..2d1769c6c 100644 --- a/src/expression.cpp +++ b/src/expression.cpp @@ -4,6 +4,7 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2021 Datadog, Inc. +#include #include #include #include @@ -198,8 +199,141 @@ bool expression::eval(cache_type &cache, const object_store &store, cache.store.reserve(conditions_.size()); } - evaluator runner{deadline, limits_, conditions_, store, objects_excluded, cache}; - return runner.eval(); + // TODO the cache result alone might be insufficient + if (!cache.result) { + evaluator runner{deadline, limits_, conditions_, store, objects_excluded, cache}; + cache.result = runner.eval(); + } + + return cache.result; +} + +memory::vector expression::get_matches(cache_type &cache) +{ + if (!cache.result) { + return {}; + } + + memory::vector matches; + + for (const auto &cond : conditions_) { + auto it = cache.conditions.find(cond.get()); + if (it == cache.conditions.end()) { + // Bug + return {}; + } + + auto &cond_cache = it->second; + + // clang-tidy has trouble with an optional after two levels of indirection + auto &result = cond_cache.result; + if (result.has_value()) { + matches.emplace_back(std::move(result.value())); + } else { + // Bug + return {}; + } + } + + return matches; +} + +namespace { +std::tuple explode_local_address(std::string_view str) +{ + constexpr std::string_view prefix = "match."; + auto pos = str.find(prefix); + if (pos == std::string_view::npos) { + return {false, 0, {}}; + } + str.remove_prefix(prefix.size()); + + // TODO everything below this point should throw instead of returning false + pos = str.find('.'); + if (pos == std::string_view::npos) { + return {false, 0, {}}; + } + + auto index_str = str.substr(0, pos); + std::size_t index = 0; + auto result = std::from_chars(index_str.data(), index_str.data() + index_str.size(), index); + if (result.ec == std::errc::invalid_argument) { + return {false, 0, {}}; + } + + expression::eval_entity entity; + auto entity_str = str.substr(pos + 1, str.size() - (pos + 1)); + if (entity_str == "object") { + entity = expression::eval_entity::object; + } else if (entity_str == "scalar") { + entity = expression::eval_entity::scalar; + } else if (entity_str == "highlight") { + entity = expression::eval_entity::highlight; + } else { + return {false, 0, {}}; + } + + return {true, index, entity}; +} + +} // namespace + // +void expression_builder::add_target(std::string name, std::vector key_path, + std::vector transformers, expression::data_source source) +{ + auto [res, index, entity] = explode_local_address(name); + if (res) { + add_local_target( + std::move(name), index, entity, std::move(key_path), std::move(transformers), source); + } else { + add_global_target(std::move(name), std::move(key_path), std::move(transformers), source); + } +} + +void expression_builder::add_global_target(std::string name, std::vector key_path, + std::vector transformers, expression::data_source source) +{ + expression::condition::target_type target; + target.scope = expression::eval_scope::global; + target.root = get_target_index(name); + target.key_path = std::move(key_path); + target.name = std::move(name); + target.transformers = std::move(transformers); + target.source = source; + + auto &cond = conditions_.back(); + cond->targets.emplace_back(std::move(target)); +} + +void expression_builder::add_local_target(std::string name, std::size_t cond_idx, + expression::eval_entity entity, std::vector key_path, + std::vector transformers, expression::data_source source) +{ + if (cond_idx >= (conditions_.size() - 1)) { + throw std::invalid_argument( + "local target references subsequent condition (or itself): current = " + + std::to_string(conditions_.size() - 1) + ", referenced = " + std::to_string(cond_idx)); + } + + auto &parent = conditions_[cond_idx]; + auto &cond = conditions_.back(); + + if (entity == expression::eval_entity::object) { + parent->children.object.emplace(cond.get()); + } else { + parent->children.scalar.emplace(cond.get()); + } + + expression::condition::target_type target; + target.scope = expression::eval_scope::local; + target.parent = parent.get(); + target.entity = entity; + target.key_path = std::move(key_path); + target.name = std::move(name); + target.transformers = std::move(transformers); + target.source = source; + + cond->targets.emplace_back(std::move(target)); } } // namespace ddwaf::experimental diff --git a/src/expression.hpp b/src/expression.hpp index 0647b951e..51a85607a 100644 --- a/src/expression.hpp +++ b/src/expression.hpp @@ -47,7 +47,7 @@ class expression { std::string name; // Global scope - target_index root; + target_index root{}; // Local scope const condition *parent{nullptr}; @@ -76,6 +76,7 @@ class expression { }; struct cache_type { + bool result{false}; std::unordered_map conditions{}; std::unordered_map store{}; @@ -146,6 +147,20 @@ class expression { const std::unordered_set &objects_excluded, ddwaf::timer &deadline) const; + memory::vector get_matches(cache_type &cache); + + void get_addresses(std::unordered_set &addresses) const + { + for (const auto &cond : conditions_) { + for (const auto &target : cond->targets) { + if (target.scope == eval_scope::global) { + addresses.emplace(target.name); + } + } + } + } + + protected: ddwaf::object_limits limits_; std::vector conditions_; @@ -166,53 +181,9 @@ class expression_builder { conditions_.emplace_back(std::move(cond)); } - void add_global_target(std::string name, std::vector key_path = {}, + void add_target(std::string name, std::vector key_path = {}, std::vector transformers = {}, - expression::data_source source = expression::data_source::values) - { - expression::condition::target_type target; - target.scope = expression::eval_scope::global; - target.root = get_target_index(name); - target.key_path = std::move(key_path); - target.name = std::move(name); - target.transformers = std::move(transformers); - target.source = source; - - auto &cond = conditions_.back(); - cond->targets.emplace_back(std::move(target)); - } - - void add_local_target(std::string name, std::size_t cond_idx, expression::eval_entity entity, - std::vector key_path = {}, std::vector transformers = {}, - expression::data_source source = expression::data_source::values) - { - if (cond_idx >= (conditions_.size() - 1)) { - throw std::invalid_argument( - "local target references subsequent condition (or itself): current = " + - std::to_string(conditions_.size() - 1) + - ", referenced = " + std::to_string(cond_idx)); - } - - auto &parent = conditions_[cond_idx]; - auto &cond = conditions_.back(); - - if (entity == expression::eval_entity::object) { - parent->children.object.emplace(cond.get()); - } else { - parent->children.scalar.emplace(cond.get()); - } - - expression::condition::target_type target; - target.scope = expression::eval_scope::local; - target.parent = parent.get(); - target.entity = entity; - target.key_path = std::move(key_path); - target.name = std::move(name); - target.transformers = std::move(transformers); - target.source = source; - - cond->targets.emplace_back(std::move(target)); - } + expression::data_source source = expression::data_source::values); expression::ptr build() { @@ -220,6 +191,14 @@ class expression_builder { } protected: + void add_global_target(std::string name, std::vector key_path = {}, + std::vector transformers = {}, + expression::data_source source = expression::data_source::values); + + void add_local_target(std::string name, std::size_t cond_idx, expression::eval_entity entity, + std::vector key_path = {}, std::vector transformers = {}, + expression::data_source source = expression::data_source::values); + ddwaf::object_limits limits_; std::vector conditions_; }; diff --git a/tests/expression_builder_test.cpp b/tests/expression_builder_test.cpp deleted file mode 100644 index 7db303eba..000000000 --- a/tests/expression_builder_test.cpp +++ /dev/null @@ -1,422 +0,0 @@ -// Unless explicitly stated otherwise all files in this repository are -// dual-licensed under the Apache-2.0 License or BSD-3-Clause License. -// -// This product includes software developed at Datadog (https://www.datadoghq.com/). -// Copyright 2021 Datadog, Inc. - -#include "PWTransformer.h" -#include "expression.hpp" -#include "test.h" - -using namespace ddwaf; - -using expression = experimental::expression; -using expression_builder = experimental::expression_builder; - -TEST(TestExpressionBuilder, SimpleMatch) -{ - expression_builder builder(1); - builder.start_condition(".*", 0, true); - builder.add_global_target("server.request.query"); - - auto expr = builder.build(); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "value")); - - ddwaf::object_store store; - store.insert(root); - - ddwaf::timer deadline{2s}; - - expression::cache_type cache; - EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); -} - -TEST(TestExpressionBuilder, MultiInputMatchOnSecond) -{ - expression_builder builder(1); - builder.start_condition("^value$", 0, true); - builder.add_global_target("server.request.query"); - builder.add_global_target("server.request.body"); - - auto expr = builder.build(); - - ddwaf::object_store store; - expression::cache_type cache; - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "bad")); - - store.insert(root); - - ddwaf::timer deadline{2s}; - - EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); - } - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "server.request.body", ddwaf_object_string(&tmp, "value")); - - store.insert(root); - - ddwaf::timer deadline{2s}; - - EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); - } -} - -TEST(TestExpressionBuilder, DuplicateInput) -{ - expression_builder builder(1); - builder.start_condition("^value$", 0, true); - builder.add_global_target("server.request.query"); - - auto expr = builder.build(); - - expression::cache_type cache; - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "bad")); - - ddwaf::object_store store; - store.insert(root); - - ddwaf::timer deadline{2s}; - - EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); - } - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "value")); - - ddwaf::object_store store; - store.insert(root); - - ddwaf::timer deadline{2s}; - - EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); - } -} - -TEST(TestExpressionBuilder, MatchDuplicateInputNoCache) -{ - expression_builder builder(1); - builder.start_condition("^value$", 0, true); - builder.add_global_target("server.request.query"); - - auto expr = builder.build(); - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "bad")); - - ddwaf::object_store store; - store.insert(root); - - ddwaf::timer deadline{2s}; - - expression::cache_type cache; - EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); - } - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "value")); - - ddwaf::object_store store; - store.insert(root); - - ddwaf::timer deadline{2s}; - - expression::cache_type cache; - EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); - } -} - -TEST(TestExpressionBuilder, TwoConditionsSingleInputNoMatch) -{ - expression_builder builder(2); - - builder.start_condition("value", 0, true); - builder.add_global_target("server.request.query"); - - builder.start_condition("^value$", 0, true); - builder.add_global_target("server.request.query"); - - auto expr = builder.build(); - - expression::cache_type cache; - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "bad_value")); - - ddwaf::object_store store; - store.insert(root); - - ddwaf::timer deadline{2s}; - - EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); - } - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "value")); - - ddwaf::object_store store; - store.insert(root); - - ddwaf::timer deadline{2s}; - - EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); - } -} - -TEST(TestExpressionBuilder, TwoConditionsSingleInputMatch) -{ - expression_builder builder(2); - - builder.start_condition("value", 0, true); - builder.add_global_target("server.request.query"); - - builder.start_condition("^value$", 0, true); - builder.add_global_target("server.request.query"); - - auto expr = builder.build(); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "value")); - - ddwaf::object_store store; - store.insert(root); - - ddwaf::timer deadline{2s}; - - expression::cache_type cache; - EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); -} - -TEST(TestExpressionBuilder, TwoConditionsMultiInputSingleEvalMatch) -{ - expression_builder builder(2); - - builder.start_condition("query", 0, true); - builder.add_global_target("server.request.query"); - - builder.start_condition("body", 0, true); - builder.add_global_target("server.request.body"); - - auto expr = builder.build(); - - ddwaf::object_store store; - expression::cache_type cache; - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "query")); - ddwaf_object_map_add(&root, "server.request.body", ddwaf_object_string(&tmp, "body")); - - store.insert(root); - - ddwaf::timer deadline{2s}; - - EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); -} - -TEST(TestExpressionBuilder, TwoConditionsMultiInputMultiEvalMatch) -{ - expression_builder builder(2); - - builder.start_condition("query", 0, true); - builder.add_global_target("server.request.query"); - - builder.start_condition("body", 0, true); - builder.add_global_target("server.request.body"); - - auto expr = builder.build(); - - ddwaf::object_store store; - expression::cache_type cache; - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "query")); - - store.insert(root); - - ddwaf::timer deadline{2s}; - - EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); - } - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "server.request.body", ddwaf_object_string(&tmp, "body")); - ddwaf_object_map_add( - &root, "server.request.query", ddwaf_object_string(&tmp, "red-herring")); - - store.insert(root); - - ddwaf::timer deadline{2s}; - - EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); - } -} - -TEST(TestExpressionBuilder, SingleObjectChain) -{ - expression_builder builder(2); - - builder.start_condition("query", 0, true); - builder.add_global_target("server.request.query"); - - builder.start_condition("^thermometer$", 0, true); - builder.add_local_target("match.0.object", 0, expression::eval_entity::object); - - auto expr = builder.build(); - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add( - &root, "server.request.query", ddwaf_object_string(&tmp, "some query")); - ddwaf::object_store store; - store.insert(root); - - ddwaf::timer deadline{2s}; - - expression::cache_type cache; - EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); - } - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object query; - ddwaf_object_map(&query); - ddwaf_object_map_add(&query, "value1", ddwaf_object_string(&tmp, "some query")); - ddwaf_object_map_add(&query, "value2", ddwaf_object_string(&tmp, "thermometer")); - - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "server.request.query", &query); - - ddwaf::object_store store; - store.insert(root); - - ddwaf::timer deadline{2s}; - - expression::cache_type cache; - EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); - } -} - -TEST(TestExpressionBuilder, SingleScalarChain) -{ - expression_builder builder(2); - - builder.start_condition("query", 0, true); - builder.add_global_target("server.request.query"); - - builder.start_condition("^query$", 0, true); - builder.add_local_target("match.0.scalar", 0, expression::eval_entity::scalar); - - auto expr = builder.build(); - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object query; - - ddwaf_object_map(&query); - ddwaf_object_map_add(&query, "value1", ddwaf_object_string(&tmp, "some query")); - - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "server.request.query", &query); - - ddwaf::object_store store; - store.insert(root); - - ddwaf::timer deadline{2s}; - - expression::cache_type cache; - EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); - } - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object query; - - ddwaf_object_map(&query); - ddwaf_object_map_add(&query, "value2", ddwaf_object_string(&tmp, "some query")); - ddwaf_object_map_add(&query, "value1", ddwaf_object_string(&tmp, "query")); - - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "server.request.query", &query); - - ddwaf::object_store store; - store.insert(root); - - ddwaf::timer deadline{2s}; - - expression::cache_type cache; - EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); - } -} - -TEST(TestExpressionBuilder, SingleHighlightChain) -{ - expression_builder builder(2); - - builder.start_condition("query", 0, true); - builder.add_global_target("server.request.query"); - - builder.start_condition("^query$", 0, true); - builder.add_local_target("match.0.highlight", 0, expression::eval_entity::highlight); - - auto expr = builder.build(); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "some query")); - - ddwaf::object_store store; - store.insert(root); - - ddwaf::timer deadline{2s}; - - expression::cache_type cache; - EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); -} diff --git a/tests/expression_test.cpp b/tests/expression_test.cpp index 64d4fb560..4cfffb474 100644 --- a/tests/expression_test.cpp +++ b/tests/expression_test.cpp @@ -11,23 +11,15 @@ using namespace ddwaf; using expression = experimental::expression; +using expression_builder = experimental::expression_builder; TEST(TestExpression, SimpleMatch) { - std::vector conditions; + expression_builder builder(1); + builder.start_condition(".*", 0, true); + builder.add_target("server.request.query"); - { - expression::condition::target_type target; - target.name = "server.request.query"; - target.root = get_target_index(target.name); - - expression::condition cond; - cond.targets.emplace_back(std::move(target)); - cond.processor = std::make_unique(".*", 0, true); - conditions.emplace_back(std::make_shared(std::move(cond))); - } - - expression expr(std::move(conditions)); + auto expr = builder.build(); ddwaf_object root; ddwaf_object tmp; @@ -40,35 +32,25 @@ TEST(TestExpression, SimpleMatch) ddwaf::timer deadline{2s}; expression::cache_type cache; - EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); + EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); + + auto matches = expr->get_matches(cache); + EXPECT_MATCHES(matches, {.op = "match_regex", + .op_value = ".*", + .address = "server.request.query", + .path = {}, + .value = "value", + .highlight = "value"}); } TEST(TestExpression, MultiInputMatchOnSecond) { - std::vector conditions; - - { - expression::condition cond; - - { - expression::condition::target_type target; - target.name = "server.request.query"; - target.root = get_target_index(target.name); - cond.targets.emplace_back(std::move(target)); - } - - { - expression::condition::target_type target; - target.name = "server.request.body"; - target.root = get_target_index(target.name); - cond.targets.emplace_back(std::move(target)); - } - - cond.processor = std::make_unique("^value$", 0, true); - conditions.emplace_back(std::make_shared(std::move(cond))); - } + expression_builder builder(1); + builder.start_condition("^value$", 0, true); + builder.add_target("server.request.query"); + builder.add_target("server.request.body"); - expression expr(std::move(conditions)); + auto expr = builder.build(); ddwaf::object_store store; expression::cache_type cache; @@ -83,7 +65,7 @@ TEST(TestExpression, MultiInputMatchOnSecond) ddwaf::timer deadline{2s}; - EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); + EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); } { @@ -96,27 +78,25 @@ TEST(TestExpression, MultiInputMatchOnSecond) ddwaf::timer deadline{2s}; - EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); + EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); + + auto matches = expr->get_matches(cache); + EXPECT_MATCHES(matches, {.op = "match_regex", + .op_value = "^value$", + .address = "server.request.body", + .path = {}, + .value = "value", + .highlight = "value"}); } } TEST(TestExpression, DuplicateInput) { - std::vector conditions; - - { - expression::condition::target_type target; - target.name = "server.request.query"; - target.root = get_target_index(target.name); + expression_builder builder(1); + builder.start_condition("^value$", 0, true); + builder.add_target("server.request.query"); - expression::condition cond; - cond.targets.emplace_back(std::move(target)); - - cond.processor = std::make_unique("^value$", 0, true); - conditions.emplace_back(std::make_shared(std::move(cond))); - } - - expression expr(std::move(conditions)); + auto expr = builder.build(); expression::cache_type cache; @@ -131,7 +111,7 @@ TEST(TestExpression, DuplicateInput) ddwaf::timer deadline{2s}; - EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); + EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); } { @@ -145,27 +125,17 @@ TEST(TestExpression, DuplicateInput) ddwaf::timer deadline{2s}; - EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); + EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); } } TEST(TestExpression, MatchDuplicateInputNoCache) { - std::vector conditions; - - { - expression::condition::target_type target; - target.name = "server.request.query"; - target.root = get_target_index(target.name); - - expression::condition cond; - cond.targets.emplace_back(std::move(target)); - - cond.processor = std::make_unique("^value$", 0, true); - conditions.emplace_back(std::make_shared(std::move(cond))); - } + expression_builder builder(1); + builder.start_condition("^value$", 0, true); + builder.add_target("server.request.query"); - expression expr(std::move(conditions)); + auto expr = builder.build(); { ddwaf_object root; @@ -179,7 +149,7 @@ TEST(TestExpression, MatchDuplicateInputNoCache) ddwaf::timer deadline{2s}; expression::cache_type cache; - EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); + EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); } { @@ -194,40 +164,29 @@ TEST(TestExpression, MatchDuplicateInputNoCache) ddwaf::timer deadline{2s}; expression::cache_type cache; - EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); + EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); + + auto matches = expr->get_matches(cache); + EXPECT_MATCHES(matches, {.op = "match_regex", + .op_value = "^value$", + .address = "server.request.query", + .path = {}, + .value = "value", + .highlight = "value"}); } } TEST(TestExpression, TwoConditionsSingleInputNoMatch) { - std::vector conditions; - - { - expression::condition::target_type target; - target.name = "server.request.query"; - target.root = get_target_index(target.name); - - expression::condition cond; - cond.targets.emplace_back(std::move(target)); + expression_builder builder(2); - cond.processor = std::make_unique("value", 0, true); - conditions.emplace_back(std::make_shared(std::move(cond))); - } - - { + builder.start_condition("value", 0, true); + builder.add_target("server.request.query"); - expression::condition::target_type target; - target.name = "server.request.query"; - target.root = get_target_index(target.name); - - expression::condition cond; - cond.targets.emplace_back(std::move(target)); - - cond.processor = std::make_unique("^value$", 0, true); - conditions.emplace_back(std::make_shared(std::move(cond))); - } + builder.start_condition("^value$", 0, true); + builder.add_target("server.request.query"); - expression expr(std::move(conditions)); + auto expr = builder.build(); expression::cache_type cache; @@ -242,7 +201,7 @@ TEST(TestExpression, TwoConditionsSingleInputNoMatch) ddwaf::timer deadline{2s}; - EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); + EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); } { @@ -256,40 +215,21 @@ TEST(TestExpression, TwoConditionsSingleInputNoMatch) ddwaf::timer deadline{2s}; - EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); + EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); } } TEST(TestExpression, TwoConditionsSingleInputMatch) { - std::vector conditions; + expression_builder builder(2); - { - expression::condition::target_type target; - target.name = "server.request.query"; - target.root = get_target_index(target.name); - - expression::condition cond; - cond.targets.emplace_back(std::move(target)); + builder.start_condition("value", 0, true); + builder.add_target("server.request.query"); - cond.processor = std::make_unique("value", 0, true); - conditions.emplace_back(std::make_shared(std::move(cond))); - } - - { + builder.start_condition("^value$", 0, true); + builder.add_target("server.request.query"); - expression::condition::target_type target; - target.name = "server.request.query"; - target.root = get_target_index(target.name); - - expression::condition cond; - cond.targets.emplace_back(std::move(target)); - - cond.processor = std::make_unique("^value$", 0, true); - conditions.emplace_back(std::make_shared(std::move(cond))); - } - - expression expr(std::move(conditions)); + auto expr = builder.build(); ddwaf_object root; ddwaf_object tmp; @@ -302,39 +242,20 @@ TEST(TestExpression, TwoConditionsSingleInputMatch) ddwaf::timer deadline{2s}; expression::cache_type cache; - EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); + EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); } TEST(TestExpression, TwoConditionsMultiInputSingleEvalMatch) { - std::vector conditions; - - { - expression::condition::target_type target; - target.name = "server.request.query"; - target.root = get_target_index(target.name); - - expression::condition cond; - cond.targets.emplace_back(std::move(target)); - - cond.processor = std::make_unique("query", 0, true); - conditions.emplace_back(std::make_shared(std::move(cond))); - } - - { - - expression::condition::target_type target; - target.name = "server.request.body"; - target.root = get_target_index(target.name); + expression_builder builder(2); - expression::condition cond; - cond.targets.emplace_back(std::move(target)); + builder.start_condition("query", 0, true); + builder.add_target("server.request.query"); - cond.processor = std::make_unique("body", 0, true); - conditions.emplace_back(std::make_shared(std::move(cond))); - } + builder.start_condition("body", 0, true); + builder.add_target("server.request.body"); - expression expr(std::move(conditions)); + auto expr = builder.build(); ddwaf::object_store store; expression::cache_type cache; @@ -349,39 +270,20 @@ TEST(TestExpression, TwoConditionsMultiInputSingleEvalMatch) ddwaf::timer deadline{2s}; - EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); + EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); } TEST(TestExpression, TwoConditionsMultiInputMultiEvalMatch) { - std::vector conditions; + expression_builder builder(2); - { - expression::condition::target_type target; - target.name = "server.request.query"; - target.root = get_target_index(target.name); - - expression::condition cond; - cond.targets.emplace_back(std::move(target)); + builder.start_condition("query", 0, true); + builder.add_target("server.request.query"); - cond.processor = std::make_unique("query", 0, true); - conditions.emplace_back(std::make_shared(std::move(cond))); - } + builder.start_condition("body", 0, true); + builder.add_target("server.request.body"); - { - - expression::condition::target_type target; - target.name = "server.request.body"; - target.root = get_target_index(target.name); - - expression::condition cond; - cond.targets.emplace_back(std::move(target)); - - cond.processor = std::make_unique("body", 0, true); - conditions.emplace_back(std::make_shared(std::move(cond))); - } - - expression expr(std::move(conditions)); + auto expr = builder.build(); ddwaf::object_store store; expression::cache_type cache; @@ -396,7 +298,7 @@ TEST(TestExpression, TwoConditionsMultiInputMultiEvalMatch) ddwaf::timer deadline{2s}; - EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); + EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); } { @@ -411,45 +313,21 @@ TEST(TestExpression, TwoConditionsMultiInputMultiEvalMatch) ddwaf::timer deadline{2s}; - EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); + EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); } } TEST(TestExpression, SingleObjectChain) { - std::vector conditions; - - { - expression::condition::target_type target; - target.name = "server.request.query"; - target.root = get_target_index(target.name); - - expression::condition cond; - cond.targets.emplace_back(std::move(target)); - - cond.processor = std::make_unique("query", 0, true); - conditions.emplace_back(std::make_shared(std::move(cond))); - } - - { - - expression::condition::target_type target; - target.scope = expression::eval_scope::local; - target.parent = conditions[0].get(); - target.entity = expression::eval_entity::object; - target.name = "match.0.object"; - target.root = get_target_index(target.name); - - expression::condition cond; - cond.targets.emplace_back(std::move(target)); + expression_builder builder(2); - cond.processor = std::make_unique("^thermometer$", 0, true); - conditions.emplace_back(std::make_shared(std::move(cond))); + builder.start_condition("query", 0, true); + builder.add_target("server.request.query"); - conditions[0]->children.object.emplace(conditions.back().get()); - } + builder.start_condition("^thermometer$", 0, true); + builder.add_target("match.0.object"); - expression expr(std::move(conditions)); + auto expr = builder.build(); { ddwaf_object root; @@ -463,7 +341,7 @@ TEST(TestExpression, SingleObjectChain) ddwaf::timer deadline{2s}; expression::cache_type cache; - EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); + EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); } { @@ -483,45 +361,21 @@ TEST(TestExpression, SingleObjectChain) ddwaf::timer deadline{2s}; expression::cache_type cache; - EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); + EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); } } TEST(TestExpression, SingleScalarChain) { - std::vector conditions; - - { - expression::condition::target_type target; - target.name = "server.request.query"; - target.root = get_target_index(target.name); + expression_builder builder(2); - expression::condition cond; - cond.targets.emplace_back(std::move(target)); + builder.start_condition("query", 0, true); + builder.add_target("server.request.query"); - cond.processor = std::make_unique("query", 0, true); - conditions.emplace_back(std::make_shared(std::move(cond))); - } - - { - - expression::condition::target_type target; - target.scope = expression::eval_scope::local; - target.parent = conditions[0].get(); - target.entity = expression::eval_entity::scalar; - target.name = "match.0.scalar"; - target.root = get_target_index(target.name); - - expression::condition cond; - cond.targets.emplace_back(std::move(target)); - - cond.processor = std::make_unique("^query$", 0, true); - conditions.emplace_back(std::make_shared(std::move(cond))); - - conditions[0]->children.scalar.emplace(conditions.back().get()); - } + builder.start_condition("^query$", 0, true); + builder.add_target("match.0.scalar"); - expression expr(std::move(conditions)); + auto expr = builder.build(); { ddwaf_object root; @@ -540,7 +394,7 @@ TEST(TestExpression, SingleScalarChain) ddwaf::timer deadline{2s}; expression::cache_type cache; - EXPECT_FALSE(expr.eval(cache, store, {}, deadline)); + EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); } { @@ -561,45 +415,35 @@ TEST(TestExpression, SingleScalarChain) ddwaf::timer deadline{2s}; expression::cache_type cache; - EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); + EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); + + auto matches = expr->get_matches(cache); + EXPECT_MATCHES(matches, {.op = "match_regex", + .op_value = "query", + .address = "server.request.query", + .path = {"value1"}, + .value = "query", + .highlight = "query"}, + {.op = "match_regex", + .op_value = "^query$", + .address = "match.0.scalar", + .path = {}, + .value = "query", + .highlight = "query"}); } } TEST(TestExpression, SingleHighlightChain) { - std::vector conditions; + expression_builder builder(2); - { - expression::condition::target_type target; - target.name = "server.request.query"; - target.root = get_target_index(target.name); - - expression::condition cond; - cond.targets.emplace_back(std::move(target)); - - cond.processor = std::make_unique("(query).*", 0, true); - conditions.emplace_back(std::make_shared(std::move(cond))); - } - - { - - expression::condition::target_type target; - target.scope = expression::eval_scope::local; - target.parent = conditions[0].get(); - target.entity = expression::eval_entity::highlight; - target.name = "match.0.highlight"; - target.root = get_target_index(target.name); - - expression::condition cond; - cond.targets.emplace_back(std::move(target)); + builder.start_condition("query", 0, true); + builder.add_target("server.request.query"); - cond.processor = std::make_unique("^query$", 0, true); - conditions.emplace_back(std::make_shared(std::move(cond))); - - conditions[0]->children.scalar.emplace(conditions.back().get()); - } + builder.start_condition("^query$", 0, true); + builder.add_target("match.0.highlight"); - expression expr(std::move(conditions)); + auto expr = builder.build(); ddwaf_object root; ddwaf_object tmp; @@ -612,5 +456,19 @@ TEST(TestExpression, SingleHighlightChain) ddwaf::timer deadline{2s}; expression::cache_type cache; - EXPECT_TRUE(expr.eval(cache, store, {}, deadline)); + EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); + + auto matches = expr->get_matches(cache); + EXPECT_MATCHES(matches, {.op = "match_regex", + .op_value = "query", + .address = "server.request.query", + .path = {}, + .value = "some query", + .highlight = "query"}, + {.op = "match_regex", + .op_value = "^query$", + .address = "match.0.highlight", + .path = {}, + .value = "query", + .highlight = "query"}); } diff --git a/tests/test_utils.cpp b/tests/test_utils.cpp index 4d06f2568..6db04b828 100644 --- a/tests/test_utils.cpp +++ b/tests/test_utils.cpp @@ -38,6 +38,33 @@ std::ostream &operator<<(std::ostream &os, const indent &offset) } // namespace + +std::ostream &operator<<(std::ostream &os, const event::match &m) +{ + os << indent(4) << "{\n" + << indent(8) << "operator: " << m.op << ",\n" + << indent(8) << "operator_value:" << m.op_value << ",\n" + << indent(8) << "address: " << m.address << ",\n" + << indent(8) << "path: ["; + + bool start = true; + for (const auto &p : m.path) { + if (!start) { + os << ", "; + } else { + start = false; + } + os << p; + } + + os << "],\n" + << indent(8) << "value: " << m.value << ",\n" + << indent(8) << "highlight: " << m.highlight << "\n" + << indent(4) << "}\n"; + + return os; +} + std::ostream &operator<<(std::ostream &os, const event &e) { os << "{\n" @@ -401,6 +428,12 @@ void PrintTo(const std::list &events, ::std::ostream *os) for (const auto &e : events) { *os << e; } } +void PrintTo(const std::list &matches, ::std::ostream *os) +{ + for (const auto &m : matches) { *os << m; } +} + + WafResultActionMatcher::WafResultActionMatcher(std::vector &&values) : expected_(std::move(values)) { @@ -463,6 +496,52 @@ bool WafResultDataMatcher::MatchAndExplain( return events.empty(); } +bool MatchMatcher::MatchAndExplain(std::list matches, ::testing::MatchResultListener * /*unused*/) const +{ + if (matches.size() != expected_matches_.size()) { + return false; + } + + for (const auto &expected : expected_matches_) { + bool found = false; + for (auto it = matches.begin(); it != matches.end(); ++it) { + auto &obtained = *it; + if (obtained == expected) { + matches.erase(it); + found = true; + break; + } + } + if (!found) { + return false; + } + } + + return matches.empty(); +} + + +std::list from_matches(const ddwaf::memory::vector &matches) +{ + std::list match_list; + + for (const auto &m : matches) { + ddwaf::test::event::match new_match; + new_match.value = m.resolved; + new_match.highlight = m.matched; + new_match.op = m.operator_name; + new_match.op_value = m.operator_value; + new_match.address = m.address; + for (const auto &k : m.key_path) { + new_match.path.emplace_back(k); + } + + match_list.emplace_back(std::move(new_match)); + } + + return match_list; +} + size_t getFileSize(const char *filename) { struct stat st; diff --git a/tests/test_utils.hpp b/tests/test_utils.hpp index b608ab5ba..9ed5b8365 100644 --- a/tests/test_utils.hpp +++ b/tests/test_utils.hpp @@ -33,6 +33,7 @@ bool operator==(const event::match &lhs, const event::match &rhs); bool operator==(const event &lhs, const event &rhs); std::ostream &operator<<(std::ostream &os, const event &e); +std::ostream &operator<<(std::ostream &os, const event::match &m); std::string object_to_json(const ddwaf_object &obj); @@ -88,6 +89,7 @@ ::testing::AssertionResult ValidateSchema(const std::string &result); // Required by gtest to pretty print relevant types void PrintTo(const ddwaf_object &actions, ::std::ostream *os); void PrintTo(const std::list &events, ::std::ostream *os); +void PrintTo(const std::list &matches, ::std::ostream *os); class WafResultActionMatcher { public: @@ -125,6 +127,28 @@ class WafResultDataMatcher { std::vector expected_events_; }; +class MatchMatcher { +public: + explicit MatchMatcher(std::vector expected_matches) + : expected_matches_(std::move(expected_matches)) + {} + + bool MatchAndExplain(std::list, ::testing::MatchResultListener *) const; + + void DescribeTo(::std::ostream *os) const + { + for (const auto &expected : expected_matches_) { *os << expected; } + } + + void DescribeNegationTo(::std::ostream *os) const + { + for (const auto &expected : expected_matches_) { *os << expected; } + } + +protected: + std::vector expected_matches_; +}; + inline ::testing::PolymorphicMatcher WithActions( std::vector &&values) { @@ -137,6 +161,15 @@ inline ::testing::PolymorphicMatcher WithEvents( return ::testing::MakePolymorphicMatcher(WafResultDataMatcher(std::move(expected))); } + +inline ::testing::PolymorphicMatcher WithMatches( + std::vector &&expected) +{ + return ::testing::MakePolymorphicMatcher(MatchMatcher(std::move(expected))); +} + +std::list from_matches(const ddwaf::memory::vector &matches); + // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define EXPECT_EVENTS(result, ...) \ { \ @@ -147,6 +180,11 @@ inline ::testing::PolymorphicMatcher WithEvents( EXPECT_THAT(events, WithEvents({__VA_ARGS__})); \ } +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define EXPECT_MATCHES(matches, ...) \ + EXPECT_THAT(from_matches(matches), WithMatches({__VA_ARGS__})); + + ddwaf_object readFile(std::string_view filename, std::string_view base = "./"); ddwaf_object readRule(const char *rule); From 92314ea1b2b928dccf477812ec26ca3e85907f83 Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Thu, 29 Jun 2023 15:05:52 +0100 Subject: [PATCH 16/28] Integrate expression on rule --- src/condition.cpp | 2 +- src/condition.hpp | 5 +- src/expression.cpp | 38 +++++++--- src/expression.hpp | 36 +++++++++- src/parser/parser_v1.cpp | 131 +++++++++++++++++------------------ src/parser/parser_v2.cpp | 101 +++++++++++++-------------- src/parser/specification.hpp | 2 +- src/rule.cpp | 37 +--------- src/rule.hpp | 20 +++--- src/ruleset_builder.cpp | 4 +- tests/expression_test.cpp | 83 +++++++++++----------- tests/test_utils.cpp | 13 ++-- tests/test_utils.hpp | 11 ++- 13 files changed, 243 insertions(+), 240 deletions(-) diff --git a/src/condition.cpp b/src/condition.cpp index 91b49ff09..197aa58bd 100644 --- a/src/condition.cpp +++ b/src/condition.cpp @@ -128,7 +128,7 @@ std::optional condition::match(const object_store &store, } std::optional optional_match; - if (source == data_source::keys) { + if (source == expression::data_source::keys) { object::key_iterator it(object, key_path, objects_excluded, limits_); optional_match = match_target(it, processor, transformers, deadline); } else { diff --git a/src/condition.hpp b/src/condition.hpp index 806f67a47..a1733e946 100644 --- a/src/condition.hpp +++ b/src/condition.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -27,14 +28,12 @@ class condition { public: using ptr = std::shared_ptr; - enum class data_source : uint8_t { values, keys }; - struct target_type { target_index root; std::string name; std::vector key_path{}; std::vector transformers{}; - data_source source{data_source::values}; + expression::data_source source{expression::data_source::values}; }; condition(std::vector targets, std::shared_ptr processor, diff --git a/src/expression.cpp b/src/expression.cpp index 2d1769c6c..ab7e1ec53 100644 --- a/src/expression.cpp +++ b/src/expression.cpp @@ -10,7 +10,7 @@ #include #include -namespace ddwaf::experimental { +namespace ddwaf { std::optional expression::evaluator::eval_object(const ddwaf_object *object, const rule_processor::base::ptr &processor, @@ -103,6 +103,20 @@ std::optional expression::evaluator::eval_target(const condition & return last_result; } +const rule_processor::base::ptr &expression::evaluator::get_processor(const condition &cond) const +{ + if (cond.processor || cond.data_id.empty()) { + return cond.processor; + } + + auto it = dynamic_processors.find(cond.data_id); + if (it == dynamic_processors.end()) { + return cond.processor; + } + + return it->second; +} + // NOLINTNEXTLINE(misc-no-recursion) bool expression::evaluator::eval_condition(const condition &cond, eval_scope scope) { @@ -112,13 +126,16 @@ bool expression::evaluator::eval_condition(const condition &cond, eval_scope sco return true; } - for (const auto &target : cond.targets) { + const auto &processor = get_processor(cond); + + for (std::size_t ti = 0; ti < cond.targets.size(); ++ti) { + const auto &target = cond.targets[ti]; + if (deadline.expired()) { throw ddwaf::timeout_exception(); } - if (scope != target.scope || - cond_cache.targets.find(target.root) != cond_cache.targets.end()) { + if (scope != target.scope || cond_cache.targets.find(ti) != cond_cache.targets.end()) { continue; } @@ -137,10 +154,10 @@ bool expression::evaluator::eval_condition(const condition &cond, eval_scope sco std::optional optional_match; if (target.source == data_source::keys) { object::key_iterator it(object, target.key_path, objects_excluded, limits); - optional_match = eval_target(cond, it, cond.processor, target.transformers); + optional_match = eval_target(cond, it, processor, target.transformers); } else { object::value_iterator it(object, target.key_path, objects_excluded, limits); - optional_match = eval_target(cond, it, cond.processor, target.transformers); + optional_match = eval_target(cond, it, processor, target.transformers); } // Only cache global targets @@ -192,7 +209,9 @@ bool expression::evaluator::eval() } bool expression::eval(cache_type &cache, const object_store &store, - const std::unordered_set &objects_excluded, ddwaf::timer &deadline) const + const std::unordered_set &objects_excluded, + const std::unordered_map &dynamic_processors, + ddwaf::timer &deadline) const { if (cache.conditions.size() != conditions_.size()) { cache.conditions.reserve(conditions_.size()); @@ -201,7 +220,8 @@ bool expression::eval(cache_type &cache, const object_store &store, // TODO the cache result alone might be insufficient if (!cache.result) { - evaluator runner{deadline, limits_, conditions_, store, objects_excluded, cache}; + evaluator runner{ + deadline, limits_, conditions_, store, objects_excluded, dynamic_processors, cache}; cache.result = runner.eval(); } @@ -336,4 +356,4 @@ void expression_builder::add_local_target(std::string name, std::size_t cond_idx cond->targets.emplace_back(std::move(target)); } -} // namespace ddwaf::experimental +} // namespace ddwaf diff --git a/src/expression.hpp b/src/expression.hpp index 51a85607a..46fb1d827 100644 --- a/src/expression.hpp +++ b/src/expression.hpp @@ -24,7 +24,7 @@ #include #include -namespace ddwaf::experimental { +namespace ddwaf { class expression { public: @@ -63,6 +63,7 @@ class expression { std::vector targets; std::shared_ptr processor; + std::string data_id; struct { std::unordered_set scalar{}; std::unordered_set object{}; @@ -131,11 +132,14 @@ class expression { const rule_processor::base::ptr &processor, const std::vector &transformers) const; + [[nodiscard]] const rule_processor::base::ptr &get_processor(const condition &cond) const; + ddwaf::timer &deadline; const ddwaf::object_limits &limits; const std::vector &conditions; const object_store &store; const std::unordered_set &objects_excluded; + const std::unordered_map &dynamic_processors; cache_type &cache; }; @@ -145,6 +149,7 @@ class expression { bool eval(cache_type &cache, const object_store &store, const std::unordered_set &objects_excluded, + const std::unordered_map &dynamic_processors, ddwaf::timer &deadline) const; memory::vector get_matches(cache_type &cache); @@ -160,7 +165,6 @@ class expression { } } - protected: ddwaf::object_limits limits_; std::vector conditions_; @@ -174,6 +178,7 @@ class expression_builder { conditions_.reserve(num_conditions); } + void start_condition() { conditions_.emplace_back(std::make_shared()); } template void start_condition(Args... args) { auto cond = std::make_shared(); @@ -181,6 +186,31 @@ class expression_builder { conditions_.emplace_back(std::move(cond)); } + void start_condition(std::string data_id) + { + auto cond = std::make_shared(); + cond->data_id = std::move(data_id); + conditions_.emplace_back(std::move(cond)); + } + + void set_data_id(std::string data_id) + { + auto &cond = conditions_.back(); + cond->data_id = std::move(data_id); + } + + template void set_processor(Args... args) + { + auto &cond = conditions_.back(); + cond->processor = std::make_unique(args...); + } + + void set_processor(rule_processor::base::ptr &&processor) + { + auto &cond = conditions_.back(); + cond->processor = std::move(processor); + } + void add_target(std::string name, std::vector key_path = {}, std::vector transformers = {}, expression::data_source source = expression::data_source::values); @@ -203,4 +233,4 @@ class expression_builder { std::vector conditions_; }; -} // namespace ddwaf::experimental +} // namespace ddwaf diff --git a/src/parser/parser_v1.cpp b/src/parser/parser_v1.cpp index 3d9983130..56f6b0c72 100644 --- a/src/parser/parser_v1.cpp +++ b/src/parser/parser_v1.cpp @@ -27,84 +27,84 @@ namespace ddwaf::parser::v1 { namespace { -condition::ptr parseCondition( - parameter::map &rule, std::vector transformers, ddwaf::object_limits limits) +expression::ptr parse_expression(parameter::vector &conditions_array, + const std::vector &transformers, ddwaf::object_limits limits) { - auto operation = at(rule, "operation"); - auto params = at(rule, "parameters"); + expression_builder builder(conditions_array.size(), limits); + for (const auto &cond_param : conditions_array) { + auto cond = static_cast(cond_param); - parameter::map options; - std::shared_ptr processor; - if (operation == "phrase_match") { - auto list = at(params, "list"); + builder.start_condition(); - std::vector patterns; - std::vector lengths; + auto operation = at(cond, "operation"); + auto params = at(cond, "parameters"); - patterns.reserve(list.size()); - lengths.reserve(list.size()); + parameter::map options; + std::shared_ptr processor; + if (operation == "phrase_match") { + auto list = at(params, "list"); - for (auto &pattern : list) { - if (pattern.type != DDWAF_OBJ_STRING) { - throw ddwaf::parsing_error("phrase_match list item not a string"); - } + std::vector patterns; + std::vector lengths; - patterns.push_back(pattern.stringValue); - lengths.push_back((uint32_t)pattern.nbEntries); - } + patterns.reserve(list.size()); + lengths.reserve(list.size()); - processor = std::make_shared(patterns, lengths); - } else if (operation == "match_regex") { - auto regex = at(params, "regex"); - options = at(params, "options", options); + for (auto &pattern : list) { + if (pattern.type != DDWAF_OBJ_STRING) { + throw ddwaf::parsing_error("phrase_match list item not a string"); + } - auto case_sensitive = at(options, "case_sensitive", false); - auto min_length = at(options, "min_length", 0); - if (min_length < 0) { - throw ddwaf::parsing_error("min_length is a negative number"); - } + patterns.push_back(pattern.stringValue); + lengths.push_back((uint32_t)pattern.nbEntries); + } - processor = - std::make_shared(regex, min_length, case_sensitive); - } else if (operation == "is_xss") { - processor = std::make_shared(); - } else if (operation == "is_sqli") { - processor = std::make_shared(); - } else { - throw ddwaf::parsing_error("unknown processor: " + std::string(operation)); - } + processor = std::make_shared(patterns, lengths); + } else if (operation == "match_regex") { + auto regex = at(params, "regex"); + options = at(params, "options", options); - std::vector targets; - auto inputs = at(params, "inputs"); - targets.reserve(inputs.size()); - for (const auto &input_param : inputs) { - auto input = static_cast(input_param); - if (input.empty()) { - throw ddwaf::parsing_error("empty address"); - } + auto case_sensitive = at(options, "case_sensitive", false); + auto min_length = at(options, "min_length", 0); + if (min_length < 0) { + throw ddwaf::parsing_error("min_length is a negative number"); + } - std::string root; - std::string key_path; - size_t pos = input.find(':', 0); - if (pos == std::string::npos || pos + 1 >= input.size()) { - root = input; + processor = + std::make_shared(regex, min_length, case_sensitive); + } else if (operation == "is_xss") { + processor = std::make_shared(); + } else if (operation == "is_sqli") { + processor = std::make_shared(); } else { - root = input.substr(0, pos); - key_path = input.substr(pos + 1, input.size()); + throw ddwaf::parsing_error("unknown processor: " + std::string(operation)); } + builder.set_processor(std::move(processor)); + + std::vector targets; + auto inputs = at(params, "inputs"); + targets.reserve(inputs.size()); + for (const auto &input_param : inputs) { + auto input = static_cast(input_param); + if (input.empty()) { + throw ddwaf::parsing_error("empty address"); + } - condition::target_type target; - target.root = get_target_index(root); - target.name = std::move(root); - if (!key_path.empty()) { - target.key_path.emplace_back(key_path); + std::string root; + std::vector key_path; + size_t pos = input.find(':', 0); + if (pos == std::string::npos || pos + 1 >= input.size()) { + root = input; + } else { + root = input.substr(0, pos); + key_path.emplace_back(input.substr(pos + 1, input.size())); + } + + builder.add_target(std::move(root), std::move(key_path), transformers); } - target.transformers = transformers; - targets.emplace_back(std::move(target)); } - return std::make_shared( - std::move(targets), std::move(processor), std::string{}, limits); + return builder.build(); } void parseRule(parameter::map &rule, base_section_info &info, @@ -129,13 +129,8 @@ void parseRule(parameter::map &rule, base_section_info &info, rule_transformers.push_back(transform_id); } - std::vector conditions; auto conditions_array = at(rule, "conditions"); - conditions.reserve(conditions_array.size()); - for (const auto &cond_param : conditions_array) { - auto cond = static_cast(cond_param); - conditions.push_back(parseCondition(cond, rule_transformers, limits)); - } + auto expression = parse_expression(conditions_array, rule_transformers, limits); std::unordered_map tags; for (auto &[key, value] : at(rule, "tags")) { @@ -151,7 +146,7 @@ void parseRule(parameter::map &rule, base_section_info &info, } auto rule_ptr = std::make_shared( - std::string(id), at(rule, "name"), std::move(tags), std::move(conditions)); + std::string(id), at(rule, "name"), std::move(tags), std::move(expression)); rule_ids.emplace(rule_ptr->get_id()); rs.insert_rule(rule_ptr); diff --git a/src/parser/parser_v2.cpp b/src/parser/parser_v2.cpp index 3d75a0232..5d2d94898 100644 --- a/src/parser/parser_v2.cpp +++ b/src/parser/parser_v2.cpp @@ -100,7 +100,7 @@ std::pair parse_processor( } std::vector parse_transformers( - const parameter::vector &root, condition::data_source &source) + const parameter::vector &root, expression::data_source &source) { if (root.empty()) { return {}; @@ -114,10 +114,10 @@ std::vector parse_transformers( PW_TRANSFORM_ID transform_id = PWTransformer::getIDForString(transformer); switch (transform_id) { case PWT_KEYS_ONLY: - source = ddwaf::condition::data_source::keys; + source = ddwaf::expression::data_source::keys; break; case PWT_VALUES_ONLY: - source = ddwaf::condition::data_source::values; + source = ddwaf::expression::data_source::values; break; case PWT_INVALID: throw ddwaf::parsing_error("invalid transformer " + std::string(transformer)); @@ -129,57 +129,60 @@ std::vector parse_transformers( return transformers; } -condition::ptr parse_rule_condition(const parameter::map &root, - std::unordered_map &rule_data_ids, condition::data_source source, +expression::ptr parse_expression(const parameter::vector &conditions_array, + std::unordered_map &rule_data_ids, expression::data_source source, const std::vector &transformers, const object_limits &limits) { - auto operation = at(root, "operator"); - auto params = at(root, "parameters"); + expression_builder builder(conditions_array.size(), limits); - auto [rule_data_id, processor] = parse_processor(operation, params); - if (!processor && !rule_data_id.empty()) { - rule_data_ids.emplace(rule_data_id, operation); - } - std::vector targets; - auto inputs = at(params, "inputs"); - if (inputs.empty()) { - throw ddwaf::parsing_error("empty inputs"); - } + for (const auto &cond_param : conditions_array) { + auto root = static_cast(cond_param); - for (const auto &input_param : inputs) { - auto input = static_cast(input_param); - auto address = at(input, "address"); + builder.start_condition(); - if (address.empty()) { - throw ddwaf::parsing_error("empty address"); + auto operation = at(root, "operator"); + auto params = at(root, "parameters"); + + auto [rule_data_id, processor] = parse_processor(operation, params); + builder.set_data_id(rule_data_id); + builder.set_processor(std::move(processor)); + if (!processor && !rule_data_id.empty()) { + rule_data_ids.emplace(rule_data_id, operation); } - auto kp = at>(input, "key_path", {}); - for (const auto &path : kp) { - if (path.empty()) { - throw ddwaf::parsing_error("empty key_path"); - } + std::vector targets; + auto inputs = at(params, "inputs"); + if (inputs.empty()) { + throw ddwaf::parsing_error("empty inputs"); } - condition::target_type target; - target.root = get_target_index(address); - target.name = address; - target.key_path = std::move(kp); + for (const auto &input_param : inputs) { + auto input = static_cast(input_param); + auto address = at(input, "address"); - auto it = input.find("transformers"); - if (it == input.end()) { - target.source = source; - target.transformers = transformers; - } else { - auto input_transformers = static_cast(it->second); - target.source = condition::data_source::values; - target.transformers = parse_transformers(input_transformers, target.source); + if (address.empty()) { + throw ddwaf::parsing_error("empty address"); + } + + auto kp = at>(input, "key_path", {}); + for (const auto &path : kp) { + if (path.empty()) { + throw ddwaf::parsing_error("empty key_path"); + } + } + + auto it = input.find("transformers"); + if (it == input.end()) { + builder.add_target(address, std::move(kp), transformers, source); + } else { + auto input_transformers = static_cast(it->second); + auto new_transformers = parse_transformers(input_transformers, source); + builder.add_target(address, std::move(kp), std::move(new_transformers), source); + } } - targets.emplace_back(target); } - return std::make_shared( - std::move(targets), std::move(processor), std::move(rule_data_id), limits); + return builder.build(); } rule_spec parse_rule(parameter::map &rule, @@ -187,19 +190,13 @@ rule_spec parse_rule(parameter::map &rule, rule::source_type source) { std::vector rule_transformers; - auto data_source = ddwaf::condition::data_source::values; + auto data_source = ddwaf::expression::data_source::values; auto transformers = at(rule, "transformers", {}); rule_transformers = parse_transformers(transformers, data_source); - std::vector conditions; auto conditions_array = at(rule, "conditions"); - conditions.reserve(conditions_array.size()); - - for (const auto &cond_param : conditions_array) { - auto cond = static_cast(cond_param); - conditions.push_back( - parse_rule_condition(cond, rule_data_ids, data_source, rule_transformers, limits)); - } + auto expression = + parse_expression(conditions_array, rule_data_ids, data_source, rule_transformers, limits); std::unordered_map tags; for (auto &[key, value] : at(rule, "tags")) { @@ -215,7 +212,7 @@ rule_spec parse_rule(parameter::map &rule, } return {at(rule, "enabled", true), source, at(rule, "name"), std::move(tags), - std::move(conditions), at>(rule, "on_match", {})}; + std::move(expression), at>(rule, "on_match", {})}; } rule_target_spec parse_rules_target(const parameter::map &target) @@ -317,7 +314,7 @@ condition::ptr parse_filter_condition(const parameter::map &root, const object_l target.root = get_target_index(address); target.name = address; target.key_path = std::move(key_path); - target.source = condition::data_source::values; + target.source = expression::data_source::values; auto it = input.find("transformers"); if (it != input.end()) { diff --git a/src/parser/specification.hpp b/src/parser/specification.hpp index 78aec3fd0..053710058 100644 --- a/src/parser/specification.hpp +++ b/src/parser/specification.hpp @@ -21,7 +21,7 @@ struct rule_spec { rule::source_type source; std::string name; std::unordered_map tags; - std::vector conditions; + expression::ptr expr; std::vector actions; }; diff --git a/src/rule.cpp b/src/rule.cpp index f8485f8d2..e8264f229 100644 --- a/src/rule.cpp +++ b/src/rule.cpp @@ -21,45 +21,14 @@ std::optional rule::match(const object_store &store, cache_type &cache, ddwaf::timer &deadline) const { // An event was already produced, so we skip the rule - if (cache.result) { + if (cache.result || !expression_->eval(cache.expr_cache, store, objects_excluded, + dynamic_processors, deadline)) { return std::nullopt; } - // On the first run, go through the conditions. Stop either at the first - // condition that didn't match and return no event or go through all - // and return an event. - // On subsequent runs, we can start at the first condition that did not - // match, because if the conditions matched with the data of the first - // run, then they having new data will make them match again. The condition - // that failed (and stopped the processing), we can run it again, but only - // on the new data. The subsequent conditions, we need to run with all data. - std::vector::const_iterator cond_iter; - bool run_on_new; - if (cache.last_cond.has_value()) { - cond_iter = *cache.last_cond; - run_on_new = true; - } else { - cond_iter = conditions_.cbegin(); - run_on_new = false; - } - - while (cond_iter != conditions_.cend()) { - auto &&cond = *cond_iter; - auto opt_match = - cond->match(store, objects_excluded, run_on_new, dynamic_processors, deadline); - if (!opt_match.has_value()) { - cache.last_cond = cond_iter; - return std::nullopt; - } - cache.matches.emplace_back(std::move(*opt_match)); - - run_on_new = false; - cond_iter++; - } - cache.result = true; - ddwaf::event evt{this, std::move(cache.matches)}; + ddwaf::event evt{this, expression_->get_matches(cache.expr_cache)}; return {std::move(evt)}; } diff --git a/src/rule.hpp b/src/rule.hpp index b0a8cf7f2..287ce82cf 100644 --- a/src/rule.hpp +++ b/src/rule.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -30,15 +31,14 @@ class rule { struct cache_type { bool result{false}; - memory::vector matches; - std::optional::const_iterator> last_cond{}; + expression::cache_type expr_cache; }; rule(std::string id, std::string name, std::unordered_map tags, - std::vector conditions, std::vector actions = {}, - bool enabled = true, source_type source = source_type::base) + expression::ptr expr, std::vector actions = {}, bool enabled = true, + source_type source = source_type::base) : enabled_(enabled), source_(source), id_(std::move(id)), name_(std::move(name)), - tags_(std::move(tags)), conditions_(std::move(conditions)), actions_(std::move(actions)) + tags_(std::move(tags)), expression_(std::move(expr)), actions_(std::move(actions)) {} rule(const rule &) = delete; @@ -47,7 +47,7 @@ class rule { rule(rule &&rhs) noexcept : enabled_(rhs.enabled_), source_(rhs.source_), id_(std::move(rhs.id_)), name_(std::move(rhs.name_)), tags_(std::move(rhs.tags_)), - conditions_(std::move(rhs.conditions_)), actions_(std::move(rhs.actions_)) + expression_(std::move(rhs.expression_)), actions_(std::move(rhs.actions_)) {} rule &operator=(rule &&rhs) noexcept @@ -57,7 +57,7 @@ class rule { id_ = std::move(rhs.id_); name_ = std::move(rhs.name_); tags_ = std::move(rhs.tags_); - conditions_ = std::move(rhs.conditions_); + expression_ = std::move(rhs.expression_); actions_ = std::move(rhs.actions_); return *this; } @@ -88,9 +88,7 @@ class rule { void get_addresses(std::unordered_set &addresses) const { - for (const auto &cond : conditions_) { - for (const auto &target : cond->get_targets()) { addresses.emplace(target.name); } - } + return expression_->get_addresses(addresses); } void set_actions(std::vector new_actions) { actions_ = std::move(new_actions); } @@ -101,7 +99,7 @@ class rule { std::string id_; std::string name_; std::unordered_map tags_; - std::vector conditions_; + expression::ptr expression_; std::vector actions_; }; diff --git a/src/ruleset_builder.cpp b/src/ruleset_builder.cpp index 7eae23afe..2b77c7ae2 100644 --- a/src/ruleset_builder.cpp +++ b/src/ruleset_builder.cpp @@ -82,7 +82,7 @@ std::shared_ptr ruleset_builder::build(parameter::map &root, base_rules // Initially, new rules are generated from their spec for (const auto &[id, spec] : base_rules_) { auto rule_ptr = std::make_shared( - id, spec.name, spec.tags, spec.conditions, spec.actions, spec.enabled, spec.source); + id, spec.name, spec.tags, spec.expr, spec.actions, spec.enabled, spec.source); // The string_view should be owned by the rule_ptr final_base_rules_.emplace(rule_ptr->get_id(), rule_ptr); @@ -125,7 +125,7 @@ std::shared_ptr ruleset_builder::build(parameter::map &root, base_rules // Initially, new rules are generated from their spec for (const auto &[id, spec] : user_rules_) { auto rule_ptr = std::make_shared( - id, spec.name, spec.tags, spec.conditions, spec.actions, spec.enabled, spec.source); + id, spec.name, spec.tags, spec.expr, spec.actions, spec.enabled, spec.source); // The string_view should be owned by the rule_ptr final_user_rules_.emplace(rule_ptr->get_id(), rule_ptr); diff --git a/tests/expression_test.cpp b/tests/expression_test.cpp index 4cfffb474..ffdd7f985 100644 --- a/tests/expression_test.cpp +++ b/tests/expression_test.cpp @@ -10,9 +10,6 @@ using namespace ddwaf; -using expression = experimental::expression; -using expression_builder = experimental::expression_builder; - TEST(TestExpression, SimpleMatch) { expression_builder builder(1); @@ -36,11 +33,11 @@ TEST(TestExpression, SimpleMatch) auto matches = expr->get_matches(cache); EXPECT_MATCHES(matches, {.op = "match_regex", - .op_value = ".*", - .address = "server.request.query", - .path = {}, - .value = "value", - .highlight = "value"}); + .op_value = ".*", + .address = "server.request.query", + .path = {}, + .value = "value", + .highlight = "value"}); } TEST(TestExpression, MultiInputMatchOnSecond) @@ -82,11 +79,11 @@ TEST(TestExpression, MultiInputMatchOnSecond) auto matches = expr->get_matches(cache); EXPECT_MATCHES(matches, {.op = "match_regex", - .op_value = "^value$", - .address = "server.request.body", - .path = {}, - .value = "value", - .highlight = "value"}); + .op_value = "^value$", + .address = "server.request.body", + .path = {}, + .value = "value", + .highlight = "value"}); } } @@ -168,11 +165,11 @@ TEST(TestExpression, MatchDuplicateInputNoCache) auto matches = expr->get_matches(cache); EXPECT_MATCHES(matches, {.op = "match_regex", - .op_value = "^value$", - .address = "server.request.query", - .path = {}, - .value = "value", - .highlight = "value"}); + .op_value = "^value$", + .address = "server.request.query", + .path = {}, + .value = "value", + .highlight = "value"}); } } @@ -418,18 +415,19 @@ TEST(TestExpression, SingleScalarChain) EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); auto matches = expr->get_matches(cache); - EXPECT_MATCHES(matches, {.op = "match_regex", - .op_value = "query", - .address = "server.request.query", - .path = {"value1"}, - .value = "query", - .highlight = "query"}, - {.op = "match_regex", - .op_value = "^query$", - .address = "match.0.scalar", - .path = {}, - .value = "query", - .highlight = "query"}); + EXPECT_MATCHES(matches, + {.op = "match_regex", + .op_value = "query", + .address = "server.request.query", + .path = {"value1"}, + .value = "query", + .highlight = "query"}, + {.op = "match_regex", + .op_value = "^query$", + .address = "match.0.scalar", + .path = {}, + .value = "query", + .highlight = "query"}); } } @@ -459,16 +457,17 @@ TEST(TestExpression, SingleHighlightChain) EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); auto matches = expr->get_matches(cache); - EXPECT_MATCHES(matches, {.op = "match_regex", - .op_value = "query", - .address = "server.request.query", - .path = {}, - .value = "some query", - .highlight = "query"}, - {.op = "match_regex", - .op_value = "^query$", - .address = "match.0.highlight", - .path = {}, - .value = "query", - .highlight = "query"}); + EXPECT_MATCHES(matches, + {.op = "match_regex", + .op_value = "query", + .address = "server.request.query", + .path = {}, + .value = "some query", + .highlight = "query"}, + {.op = "match_regex", + .op_value = "^query$", + .address = "match.0.highlight", + .path = {}, + .value = "query", + .highlight = "query"}); } diff --git a/tests/test_utils.cpp b/tests/test_utils.cpp index 6db04b828..e144a49c3 100644 --- a/tests/test_utils.cpp +++ b/tests/test_utils.cpp @@ -38,7 +38,6 @@ std::ostream &operator<<(std::ostream &os, const indent &offset) } // namespace - std::ostream &operator<<(std::ostream &os, const event::match &m) { os << indent(4) << "{\n" @@ -433,7 +432,6 @@ void PrintTo(const std::list &matches, ::std::ostream for (const auto &m : matches) { *os << m; } } - WafResultActionMatcher::WafResultActionMatcher(std::vector &&values) : expected_(std::move(values)) { @@ -496,7 +494,8 @@ bool WafResultDataMatcher::MatchAndExplain( return events.empty(); } -bool MatchMatcher::MatchAndExplain(std::list matches, ::testing::MatchResultListener * /*unused*/) const +bool MatchMatcher::MatchAndExplain( + std::list matches, ::testing::MatchResultListener * /*unused*/) const { if (matches.size() != expected_matches_.size()) { return false; @@ -520,8 +519,8 @@ bool MatchMatcher::MatchAndExplain(std::list matches, return matches.empty(); } - -std::list from_matches(const ddwaf::memory::vector &matches) +std::list from_matches( + const ddwaf::memory::vector &matches) { std::list match_list; @@ -532,9 +531,7 @@ std::list from_matches(const ddwaf::memory::vector
, ::testing::MatchResultListener *) const; + bool MatchAndExplain( + std::list, ::testing::MatchResultListener *) const; void DescribeTo(::std::ostream *os) const { @@ -161,14 +162,14 @@ inline ::testing::PolymorphicMatcher WithEvents( return ::testing::MakePolymorphicMatcher(WafResultDataMatcher(std::move(expected))); } - inline ::testing::PolymorphicMatcher WithMatches( std::vector &&expected) { return ::testing::MakePolymorphicMatcher(MatchMatcher(std::move(expected))); } -std::list from_matches(const ddwaf::memory::vector &matches); +std::list from_matches( + const ddwaf::memory::vector &matches); // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define EXPECT_EVENTS(result, ...) \ @@ -181,9 +182,7 @@ std::list from_matches(const ddwaf::memory::vector
Date: Thu, 29 Jun 2023 16:31:52 +0100 Subject: [PATCH 17/28] Update tests --- src/expression.cpp | 14 +- src/expression.hpp | 5 +- src/object_store.cpp | 1 + src/parser/parser_v2.cpp | 1 + tests/collection_test.cpp | 187 +- tests/condition_test.cpp | 4 +- tests/context_test.cpp | 3800 ++++++++++++++++---------------- tests/expression_test.cpp | 36 +- tests/mkmap_test.cpp | 4 +- tests/parser_v2_rules_test.cpp | 12 +- tests/rule_test.cpp | 142 +- tests/ruleset_test.cpp | 2 +- 12 files changed, 2049 insertions(+), 2159 deletions(-) diff --git a/src/expression.cpp b/src/expression.cpp index ab7e1ec53..26f555a2d 100644 --- a/src/expression.cpp +++ b/src/expression.cpp @@ -72,6 +72,7 @@ std::optional expression::evaluator::eval_target(const condition & continue; } + DDWAF_TRACE("Value %s", (*it)->stringValue); auto optional_match = eval_object(*it, processor, transformers); if (!optional_match.has_value()) { continue; @@ -127,6 +128,10 @@ bool expression::evaluator::eval_condition(const condition &cond, eval_scope sco } const auto &processor = get_processor(cond); + if (!processor) { + DDWAF_DEBUG("Condition doesn't have a valid processor"); + return false; + } for (std::size_t ti = 0; ti < cond.targets.size(); ++ti) { const auto &target = cond.targets[ti]; @@ -151,6 +156,8 @@ bool expression::evaluator::eval_condition(const condition &cond, eval_scope sco continue; } + DDWAF_TRACE("Evaluating target %s", target.name.c_str()); + std::optional optional_match; if (target.source == data_source::keys) { object::key_iterator it(object, target.key_path, objects_excluded, limits); @@ -160,15 +167,12 @@ bool expression::evaluator::eval_condition(const condition &cond, eval_scope sco optional_match = eval_target(cond, it, processor, target.transformers); } - // Only cache global targets - if (target.scope == eval_scope::global) { - cond_cache.targets.emplace(target.root); - } - if (!optional_match.has_value()) { continue; } + cond_cache.targets.emplace(ti); + optional_match->address = target.name; cond_cache.result = optional_match; diff --git a/src/expression.hpp b/src/expression.hpp index 46fb1d827..7ba030e9f 100644 --- a/src/expression.hpp +++ b/src/expression.hpp @@ -165,6 +165,9 @@ class expression { } } + // For testing + [[nodiscard]] constexpr std::size_t get_num_conditions() const { return conditions_.size(); } + protected: ddwaf::object_limits limits_; std::vector conditions_; @@ -182,7 +185,7 @@ class expression_builder { template void start_condition(Args... args) { auto cond = std::make_shared(); - cond->processor = std::make_unique(args...); + cond->processor = std::make_unique(std::forward(args)...); conditions_.emplace_back(std::move(cond)); } diff --git a/src/object_store.cpp b/src/object_store.cpp index 411d8b1ab..e746c589a 100644 --- a/src/object_store.cpp +++ b/src/object_store.cpp @@ -61,6 +61,7 @@ bool object_store::insert(const ddwaf_object &input) } std::string key(array[i].parameterName, length); + DDWAF_TRACE("Adding target %s", key.data()); auto target = get_target_index(key); objects_[target] = &array[i]; latest_batch_.emplace(target); diff --git a/src/parser/parser_v2.cpp b/src/parser/parser_v2.cpp index 5d2d94898..910b04bb5 100644 --- a/src/parser/parser_v2.cpp +++ b/src/parser/parser_v2.cpp @@ -176,6 +176,7 @@ expression::ptr parse_expression(const parameter::vector &conditions_array, builder.add_target(address, std::move(kp), transformers, source); } else { auto input_transformers = static_cast(it->second); + source = expression::data_source::values; auto new_transformers = parse_transformers(input_transformers, source); builder.add_target(address, std::move(kp), std::move(new_transformers), source); } diff --git a/tests/collection_test.cpp b/tests/collection_test.cpp index 4bee7ae66..11fa930ba 100644 --- a/tests/collection_test.cpp +++ b/tests/collection_test.cpp @@ -17,19 +17,13 @@ TYPED_TEST_SUITE(TestCollection, CollectionTypes); // Validate that a rule within the collection matches only once TYPED_TEST(TestCollection, SingleRuleMatch) { - std::vector targets; - - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"192.168.0.1"})); - - std::vector> conditions{std::move(cond)}; + expression_builder builder(1); + builder.start_condition(std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); std::unordered_map tags{{"type", "type"}, {"category", "category"}}; - auto rule = std::make_shared( - "id", "name", std::move(tags), std::move(conditions), std::vector{}); + auto rule = std::make_shared("id", "name", std::move(tags), builder.build()); TypeParam rule_collection; rule_collection.insert(rule); @@ -72,39 +66,29 @@ TYPED_TEST(TestCollection, MultipleRuleCachedMatch) std::vector rules; TypeParam rule_collection; { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); - - std::vector> conditions{std::move(cond)}; + expression_builder builder(1); + builder.start_condition( + std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); std::unordered_map tags{ {"type", "type"}, {"category", "category1"}}; - auto rule = std::make_shared( - "id1", "name1", std::move(tags), std::move(conditions), std::vector{}); + auto rule = std::make_shared("id1", "name1", std::move(tags), builder.build()); rules.emplace_back(rule); rule_collection.insert(rule); } { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); - - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); - - std::vector> conditions{std::move(cond)}; + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); std::unordered_map tags{ {"type", "type"}, {"category", "category2"}}; - auto rule = std::make_shared( - "id2", "name2", std::move(tags), std::move(conditions), std::vector{}); + auto rule = std::make_shared("id2", "name2", std::move(tags), builder.build()); rules.emplace_back(rule); rule_collection.insert(rule); @@ -149,37 +133,29 @@ TYPED_TEST(TestCollection, MultipleRuleFailAndMatch) std::vector rules; TypeParam rule_collection; { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); - - std::vector> conditions{std::move(cond)}; + expression_builder builder(1); + builder.start_condition( + std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); std::unordered_map tags{ {"type", "type"}, {"category", "category1"}}; - auto rule = std::make_shared( - "id1", "name1", std::move(tags), std::move(conditions), std::vector{}); + + auto rule = std::make_shared("id1", "name1", std::move(tags), builder.build()); rules.emplace_back(rule); rule_collection.insert(rule); } { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); - - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); - - std::vector> conditions{std::move(cond)}; + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); std::unordered_map tags{ {"type", "type"}, {"category", "category2"}}; - auto rule = std::make_shared( - "id2", "name2", std::move(tags), std::move(conditions), std::vector{}); + + auto rule = std::make_shared("id2", "name2", std::move(tags), builder.build()); rules.emplace_back(rule); rule_collection.insert(rule); @@ -221,28 +197,16 @@ TYPED_TEST(TestCollection, MultipleRuleFailAndMatch) // Validate that the rule cache is acted on TYPED_TEST(TestCollection, SingleRuleMultipleCalls) { - std::vector conditions; - { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - - conditions.emplace_back(std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"}))); - } - - { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); + expression_builder builder(2); + builder.start_condition(std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); - conditions.emplace_back(std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"}))); - } + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); std::unordered_map tags{{"type", "type"}, {"category", "category"}}; - auto rule = std::make_shared( - "id", "name", std::move(tags), std::move(conditions), std::vector{}); + auto rule = std::make_shared("id", "name", std::move(tags), builder.build()); TypeParam rule_collection; rule_collection.insert(rule); @@ -288,38 +252,30 @@ TEST(TestPriorityCollection, NoRegularMatchAfterPriorityMatch) collection regular; priority_collection priority; { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); - - std::vector> conditions{std::move(cond)}; + expression_builder builder(1); + builder.start_condition( + std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); std::unordered_map tags{ {"type", "type"}, {"category", "category1"}}; - auto rule = std::make_shared( - "id1", "name1", std::move(tags), std::move(conditions), std::vector{}); + + auto rule = std::make_shared("id1", "name1", std::move(tags), builder.build()); rules.emplace_back(rule); regular.insert(rule); } { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); - - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); - - std::vector> conditions{std::move(cond)}; + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); std::unordered_map tags{ {"type", "type"}, {"category", "category2"}}; - auto rule = std::make_shared("id2", "name2", std::move(tags), - std::move(conditions), std::vector{"redirect"}); + auto rule = std::make_shared( + "id2", "name2", std::move(tags), builder.build(), std::vector{"redirect"}); rules.emplace_back(rule); priority.insert(rule); @@ -367,38 +323,30 @@ TEST(TestPriorityCollection, PriorityMatchAfterRegularMatch) collection regular; priority_collection priority; { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); - - std::vector> conditions{std::move(cond)}; + expression_builder builder(1); + builder.start_condition( + std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); std::unordered_map tags{ {"type", "type"}, {"category", "category1"}}; - auto rule = std::make_shared( - "id1", "name1", std::move(tags), std::move(conditions), std::vector{}); + + auto rule = std::make_shared("id1", "name1", std::move(tags), builder.build()); rules.emplace_back(rule); regular.insert(rule); } { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); - - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); - - std::vector> conditions{std::move(cond)}; + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); std::unordered_map tags{ {"type", "type"}, {"category", "category2"}}; - auto rule = std::make_shared("id2", "name2", std::move(tags), - std::move(conditions), std::vector{"redirect"}); + auto rule = std::make_shared( + "id2", "name2", std::move(tags), builder.build(), std::vector{"redirect"}); rules.emplace_back(rule); priority.insert(rule); @@ -446,38 +394,31 @@ TEST(TestPriorityCollection, NoPriorityMatchAfterPriorityMatch) std::vector rules; priority_collection priority; { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); - - std::vector> conditions{std::move(cond)}; + expression_builder builder(1); + builder.start_condition( + std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); std::unordered_map tags{ {"type", "type"}, {"category", "category1"}}; - auto rule = std::make_shared("id1", "name1", std::move(tags), - std::move(conditions), std::vector{"block"}); + + auto rule = std::make_shared( + "id1", "name1", std::move(tags), builder.build(), std::vector{"block"}); rules.emplace_back(rule); priority.insert(rule); } { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); - - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); - - std::vector> conditions{std::move(cond)}; + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); std::unordered_map tags{ {"type", "type"}, {"category", "category2"}}; - auto rule = std::make_shared("id2", "name2", std::move(tags), - std::move(conditions), std::vector{"redirect"}); + auto rule = std::make_shared( + "id2", "name2", std::move(tags), builder.build(), std::vector{"redirect"}); rules.emplace_back(rule); priority.insert(rule); diff --git a/tests/condition_test.cpp b/tests/condition_test.cpp index df170cdfc..c14fa3c52 100644 --- a/tests/condition_test.cpp +++ b/tests/condition_test.cpp @@ -141,7 +141,7 @@ TEST(TestCondition, MatchOnKeys) std::vector targets; targets.push_back({get_target_index("server.request.query"), "server.request.query", {}, {}, - condition::data_source::keys}); + expression::data_source::keys}); auto cond = std::make_shared( std::move(targets), std::make_unique("value", 0, true)); @@ -176,7 +176,7 @@ TEST(TestCondition, MatchOnKeysWithTransformer) std::vector targets; targets.push_back({get_target_index("server.request.query"), "server.request.query", {}, - {PWT_LOWERCASE}, condition::data_source::keys}); + {PWT_LOWERCASE}, expression::data_source::keys}); auto cond = std::make_shared( std::move(targets), std::make_unique("value", 0, true)); diff --git a/tests/context_test.cpp b/tests/context_test.cpp index 457675783..df6f2a2a0 100644 --- a/tests/context_test.cpp +++ b/tests/context_test.cpp @@ -22,19 +22,13 @@ class context : public ddwaf::context { TEST(TestContext, MatchTimeout) { - std::vector targets; - - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"192.168.0.1"})); - - std::vector> conditions{std::move(cond)}; + expression_builder builder(1); + builder.start_condition(std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); std::unordered_map tags{{"type", "type"}, {"category", "category"}}; - auto rule = std::make_shared( - "id", "name", std::move(tags), std::move(conditions), std::vector{}); + auto rule = std::make_shared("id", "name", std::move(tags), builder.build()); auto ruleset = std::make_shared(); ruleset->insert_rule(rule); @@ -51,2030 +45,2030 @@ TEST(TestContext, MatchTimeout) EXPECT_THROW(ctx.match({}, {}, deadline), ddwaf::timeout_exception); } -TEST(TestContext, NoMatch) -{ - std::vector targets; - - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"192.168.0.1"})); - - std::vector> conditions{std::move(cond)}; - - std::unordered_map tags{{"type", "type"}, {"category", "category"}}; - - auto rule = std::make_shared( - "id", "name", std::move(tags), std::move(conditions), std::vector{}); - - auto ruleset = std::make_shared(); - ruleset->insert_rule(rule); - - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.2")); - ctx.insert(root); - - auto events = ctx.match({}, {}, deadline); - EXPECT_EQ(events.size(), 0); -} - -TEST(TestContext, Match) -{ - std::vector targets; - - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"192.168.0.1"})); - - std::vector> conditions{std::move(cond)}; - - std::unordered_map tags{{"type", "type"}, {"category", "category"}}; - - auto rule = std::make_shared( - "id", "name", std::move(tags), std::move(conditions), std::vector{}); - - auto ruleset = std::make_shared(); - ruleset->insert_rule(rule); - - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ctx.insert(root); - - auto events = ctx.match({}, {}, deadline); - EXPECT_EQ(events.size(), 1); -} - -TEST(TestContext, MatchMultipleRulesInCollectionSingleRun) -{ - auto ruleset = std::make_shared(); - { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); - - std::vector> conditions{std::move(cond)}; - - std::unordered_map tags{ - {"type", "type"}, {"category", "category1"}}; - - auto rule = std::make_shared( - "id1", "name1", std::move(tags), std::move(conditions), std::vector{}); - - ruleset->insert_rule(rule); - } - - { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); - - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); - - std::vector> conditions{std::move(cond)}; - - std::unordered_map tags{ - {"type", "type"}, {"category", "category2"}}; - - auto rule = std::make_shared( - "id2", "name2", std::move(tags), std::move(conditions), std::vector{}); - - ruleset->insert_rule(rule); - } - - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ctx.insert(root); - - auto events = ctx.match({}, {}, deadline); - EXPECT_EQ(events.size(), 1); - - auto &event = events[0]; - EXPECT_STREQ(event.rule->get_id().c_str(), "id1"); - EXPECT_STREQ(event.rule->get_name().c_str(), "name1"); - EXPECT_STREQ(event.rule->get_tag("type").data(), "type"); - EXPECT_STREQ(event.rule->get_tag("category").data(), "category1"); - std::vector expected_actions{}; - EXPECT_EQ(event.rule->get_actions(), expected_actions); - EXPECT_EQ(event.matches.size(), 1); - - auto &match = event.matches[0]; - EXPECT_STREQ(match.resolved.c_str(), "192.168.0.1"); - EXPECT_STREQ(match.matched.c_str(), "192.168.0.1"); - EXPECT_STREQ(match.operator_name.data(), "ip_match"); - EXPECT_STREQ(match.operator_value.data(), ""); - EXPECT_STREQ(match.address.data(), "http.client_ip"); - EXPECT_TRUE(match.key_path.empty()); -} - -TEST(TestContext, MatchMultipleRulesWithPrioritySingleRun) -{ - auto ruleset = std::make_shared(); - { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); - - std::vector> conditions{std::move(cond)}; - - std::unordered_map tags{ - {"type", "type"}, {"category", "category1"}}; - - auto rule = std::make_shared( - "id1", "name1", std::move(tags), std::move(conditions), std::vector{}); - - ruleset->insert_rule(rule); - } - - { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); - - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); - - std::vector> conditions{std::move(cond)}; - - std::unordered_map tags{ - {"type", "type"}, {"category", "category2"}}; - - // This rule has actions, so it'll be have priority - auto rule = std::make_shared("id2", "name2", std::move(tags), - std::move(conditions), std::vector{"block"}); - - ruleset->insert_rule(rule); - } - - { - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ctx.insert(root); - - ddwaf::timer deadline{2s}; - auto events = ctx.match({}, {}, deadline); - EXPECT_EQ(events.size(), 1); - - auto event = events[0]; - EXPECT_STREQ(event.rule->get_id().c_str(), "id2"); - EXPECT_EQ(event.rule->get_actions().size(), 1); - EXPECT_STREQ(event.rule->get_actions()[0].data(), "block"); - } - - { - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ctx.insert(root); - - ddwaf::timer deadline{2s}; - auto events = ctx.match({}, {}, deadline); - EXPECT_EQ(events.size(), 1); - - auto event = events[0]; - EXPECT_STREQ(event.rule->get_id().c_str(), "id2"); - EXPECT_EQ(event.rule->get_actions().size(), 1); - EXPECT_STREQ(event.rule->get_actions()[0].data(), "block"); - } -} - -TEST(TestContext, MatchMultipleRulesInCollectionDoubleRun) -{ - auto ruleset = std::make_shared(); - { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); +/*TEST(TestContext, NoMatch)*/ +/*{*/ +/*std::vector targets;*/ - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); +/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ - std::vector> conditions{std::move(cond)}; +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"192.168.0.1"}));*/ - std::unordered_map tags{ - {"type", "type"}, {"category", "category1"}}; +/*std::vector> conditions{std::move(cond)};*/ - auto rule = std::make_shared( - "id1", "name1", std::move(tags), std::move(conditions), std::vector{}); +/*std::unordered_map tags{{"type", "type"}, {"category", "category"}};*/ - ruleset->insert_rule(rule); - } +/*auto rule = std::make_shared(*/ +/*"id", "name", std::move(tags), std::move(conditions), std::vector{});*/ - { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); +/*auto ruleset = std::make_shared();*/ +/*ruleset->insert_rule(rule);*/ - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ - std::vector> conditions{std::move(cond)}; +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.2"));*/ +/*ctx.insert(root);*/ - std::unordered_map tags{ - {"type", "type"}, {"category", "category2"}}; +/*auto events = ctx.match({}, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 0);*/ +/*}*/ - auto rule = std::make_shared( - "id2", "name2", std::move(tags), std::move(conditions), std::vector{}); +/*TEST(TestContext, Match)*/ +/*{*/ +/*std::vector targets;*/ - ruleset->insert_rule(rule); - } +/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"192.168.0.1"}));*/ - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ctx.insert(root); - - auto events = ctx.match({}, {}, deadline); - EXPECT_EQ(events.size(), 1); - - auto &event = events[0]; - EXPECT_STREQ(event.rule->get_id().c_str(), "id1"); - EXPECT_STREQ(event.rule->get_name().c_str(), "name1"); - EXPECT_STREQ(event.rule->get_tag("type").data(), "type"); - EXPECT_STREQ(event.rule->get_tag("category").data(), "category1"); - std::vector expected_actions{}; - EXPECT_EQ(event.rule->get_actions(), expected_actions); - EXPECT_EQ(event.matches.size(), 1); - - auto &match = event.matches[0]; - EXPECT_STREQ(match.resolved.c_str(), "192.168.0.1"); - EXPECT_STREQ(match.matched.c_str(), "192.168.0.1"); - EXPECT_STREQ(match.operator_name.data(), "ip_match"); - EXPECT_STREQ(match.operator_value.data(), ""); - EXPECT_STREQ(match.address.data(), "http.client_ip"); - EXPECT_TRUE(match.key_path.empty()); - } - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ctx.insert(root); - - auto events = ctx.match({}, {}, deadline); - EXPECT_EQ(events.size(), 0); - } -} +/*std::vector> conditions{std::move(cond)};*/ -TEST(TestContext, MatchMultipleRulesWithPriorityDoubleRunPriorityLast) -{ - auto ruleset = std::make_shared(); - { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); +/*std::unordered_map tags{{"type", "type"}, {"category", "category"}};*/ - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); +/*auto rule = std::make_shared(*/ +/*"id", "name", std::move(tags), std::move(conditions), std::vector{});*/ - std::vector> conditions{std::move(cond)}; +/*auto ruleset = std::make_shared();*/ +/*ruleset->insert_rule(rule);*/ - std::unordered_map tags{ - {"type", "type"}, {"category", "category1"}}; +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ - auto rule = std::make_shared( - "id1", "name1", std::move(tags), std::move(conditions), std::vector{}); +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ctx.insert(root);*/ - ruleset->insert_rule(rule); - } +/*auto events = ctx.match({}, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 1);*/ +/*}*/ - { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); +/*TEST(TestContext, MatchMultipleRulesInCollectionSingleRun)*/ +/*{*/ +/*auto ruleset = std::make_shared();*/ +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); +/*auto cond = std::make_shared(*/ +/*std::move(targets), std::make_unique(*/ +/*std::vector{"192.168.0.1"}));*/ - std::vector> conditions{std::move(cond)}; +/*std::vector> conditions{std::move(cond)};*/ - std::unordered_map tags{ - {"type", "type"}, {"category", "category2"}}; +/*std::unordered_map tags{*/ +/*{"type", "type"}, {"category", "category1"}};*/ - auto rule = std::make_shared("id2", "name2", std::move(tags), - std::move(conditions), std::vector{"block"}); +/*auto rule = std::make_shared(*/ +/*"id1", "name1", std::move(tags), std::move(conditions), std::vector{});*/ - ruleset->insert_rule(rule); - } +/*ruleset->insert_rule(rule);*/ +/*}*/ - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ctx.insert(root); - - auto events = ctx.match({}, {}, deadline); - EXPECT_EQ(events.size(), 1); - - auto &event = events[0]; - EXPECT_STREQ(event.rule->get_id().c_str(), "id1"); - EXPECT_STREQ(event.rule->get_name().c_str(), "name1"); - EXPECT_STREQ(event.rule->get_tag("type").data(), "type"); - EXPECT_STREQ(event.rule->get_tag("category").data(), "category1"); - std::vector expected_actions{}; - EXPECT_EQ(event.rule->get_actions(), expected_actions); - EXPECT_EQ(event.matches.size(), 1); - - auto &match = event.matches[0]; - EXPECT_STREQ(match.resolved.c_str(), "192.168.0.1"); - EXPECT_STREQ(match.matched.c_str(), "192.168.0.1"); - EXPECT_STREQ(match.operator_name.data(), "ip_match"); - EXPECT_STREQ(match.operator_value.data(), ""); - EXPECT_STREQ(match.address.data(), "http.client_ip"); - EXPECT_TRUE(match.key_path.empty()); - } - - { - // An existing match in a collection will not inhibit a match in a - // priority collection. - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ctx.insert(root); - - auto events = ctx.match({}, {}, deadline); - EXPECT_EQ(events.size(), 1); - - auto &event = events[0]; - EXPECT_EQ(events.size(), 1); - EXPECT_STREQ(event.rule->get_id().c_str(), "id2"); - EXPECT_STREQ(event.rule->get_name().c_str(), "name2"); - EXPECT_STREQ(event.rule->get_tag("type").data(), "type"); - EXPECT_STREQ(event.rule->get_tag("category").data(), "category2"); - std::vector expected_actions{"block"}; - EXPECT_EQ(event.rule->get_actions(), expected_actions); - EXPECT_EQ(event.matches.size(), 1); - - auto &match = event.matches[0]; - EXPECT_STREQ(match.resolved.c_str(), "admin"); - EXPECT_STREQ(match.matched.c_str(), "admin"); - EXPECT_STREQ(match.operator_name.data(), "exact_match"); - EXPECT_STREQ(match.operator_value.data(), ""); - EXPECT_STREQ(match.address.data(), "usr.id"); - EXPECT_TRUE(match.key_path.empty()); - } -} +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"admin"}));*/ -TEST(TestContext, MatchMultipleRulesWithPriorityDoubleRunPriorityFirst) -{ - auto ruleset = std::make_shared(); - { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); +/*std::vector> conditions{std::move(cond)};*/ - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); +/*std::unordered_map tags{*/ +/*{"type", "type"}, {"category", "category2"}};*/ - std::vector> conditions{std::move(cond)}; +/*auto rule = std::make_shared(*/ +/*"id2", "name2", std::move(tags), std::move(conditions), std::vector{});*/ - std::unordered_map tags{ - {"type", "type"}, {"category", "category1"}}; +/*ruleset->insert_rule(rule);*/ +/*}*/ - auto rule = std::make_shared("id1", "name1", std::move(tags), - std::move(conditions), std::vector{"block"}); +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ - ruleset->insert_rule(rule); - } +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ctx.insert(root);*/ - { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); +/*auto events = ctx.match({}, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 1);*/ - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); +/*auto &event = events[0];*/ +/*EXPECT_STREQ(event.rule->get_id().c_str(), "id1");*/ +/*EXPECT_STREQ(event.rule->get_name().c_str(), "name1");*/ +/*EXPECT_STREQ(event.rule->get_tag("type").data(), "type");*/ +/*EXPECT_STREQ(event.rule->get_tag("category").data(), "category1");*/ +/*std::vector expected_actions{};*/ +/*EXPECT_EQ(event.rule->get_actions(), expected_actions);*/ +/*EXPECT_EQ(event.matches.size(), 1);*/ - std::vector> conditions{std::move(cond)}; +/*auto &match = event.matches[0];*/ +/*EXPECT_STREQ(match.resolved.c_str(), "192.168.0.1");*/ +/*EXPECT_STREQ(match.matched.c_str(), "192.168.0.1");*/ +/*EXPECT_STREQ(match.operator_name.data(), "ip_match");*/ +/*EXPECT_STREQ(match.operator_value.data(), "");*/ +/*EXPECT_STREQ(match.address.data(), "http.client_ip");*/ +/*EXPECT_TRUE(match.key_path.empty());*/ +/*}*/ - std::unordered_map tags{ - {"type", "type"}, {"category", "category2"}}; +/*TEST(TestContext, MatchMultipleRulesWithPrioritySingleRun)*/ +/*{*/ +/*auto ruleset = std::make_shared();*/ +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ - auto rule = std::make_shared( - "id2", "name2", std::move(tags), std::move(conditions), std::vector{}); +/*auto cond = std::make_shared(*/ +/*std::move(targets), std::make_unique(*/ +/*std::vector{"192.168.0.1"}));*/ - ruleset->insert_rule(rule); - } +/*std::vector> conditions{std::move(cond)};*/ - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); +/*std::unordered_map tags{*/ +/*{"type", "type"}, {"category", "category1"}};*/ - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ctx.insert(root); - - auto events = ctx.match({}, {}, deadline); - EXPECT_EQ(events.size(), 1); - - auto &event = events[0]; - EXPECT_STREQ(event.rule->get_id().c_str(), "id1"); - EXPECT_STREQ(event.rule->get_name().c_str(), "name1"); - EXPECT_STREQ(event.rule->get_tag("type").data(), "type"); - EXPECT_STREQ(event.rule->get_tag("category").data(), "category1"); - std::vector expected_actions{"block"}; - EXPECT_EQ(event.rule->get_actions(), expected_actions); - EXPECT_EQ(event.matches.size(), 1); - - auto &match = event.matches[0]; - EXPECT_STREQ(match.resolved.c_str(), "192.168.0.1"); - EXPECT_STREQ(match.matched.c_str(), "192.168.0.1"); - EXPECT_STREQ(match.operator_name.data(), "ip_match"); - EXPECT_STREQ(match.operator_value.data(), ""); - EXPECT_STREQ(match.address.data(), "http.client_ip"); - EXPECT_TRUE(match.key_path.empty()); - } - - { - // An existing match in a collection will not inhibit a match in a - // priority collection. - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ctx.insert(root); - - auto events = ctx.match({}, {}, deadline); - EXPECT_EQ(events.size(), 0); - } -} +/*auto rule = std::make_shared(*/ +/*"id1", "name1", std::move(tags), std::move(conditions), std::vector{});*/ -TEST(TestContext, MatchMultipleRulesWithPriorityUntilAllActionsMet) -{ - auto ruleset = std::make_shared(); - { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); +/*ruleset->insert_rule(rule);*/ +/*}*/ - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ - std::vector> conditions{std::move(cond)}; +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"admin"}));*/ - std::unordered_map tags{ - {"type", "type"}, {"category", "category1"}}; +/*std::vector> conditions{std::move(cond)};*/ - auto rule = std::make_shared( - "id1", "name1", std::move(tags), std::move(conditions), std::vector{}); +/*std::unordered_map tags{*/ +/*{"type", "type"}, {"category", "category2"}};*/ - ruleset->insert_rule(rule); - } +/*// This rule has actions, so it'll be have priority*/ +/*auto rule = std::make_shared("id2", "name2", std::move(tags),*/ +/*std::move(conditions), std::vector{"block"});*/ - { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); +/*ruleset->insert_rule(rule);*/ +/*}*/ - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); +/*{*/ +/*ddwaf::test::context ctx(ruleset);*/ - std::vector> conditions{std::move(cond)}; +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ctx.insert(root);*/ + +/*ddwaf::timer deadline{2s};*/ +/*auto events = ctx.match({}, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 1);*/ + +/*auto event = events[0];*/ +/*EXPECT_STREQ(event.rule->get_id().c_str(), "id2");*/ +/*EXPECT_EQ(event.rule->get_actions().size(), 1);*/ +/*EXPECT_STREQ(event.rule->get_actions()[0].data(), "block");*/ +/*}*/ + +/*{*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ctx.insert(root);*/ + +/*ddwaf::timer deadline{2s};*/ +/*auto events = ctx.match({}, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 1);*/ + +/*auto event = events[0];*/ +/*EXPECT_STREQ(event.rule->get_id().c_str(), "id2");*/ +/*EXPECT_EQ(event.rule->get_actions().size(), 1);*/ +/*EXPECT_STREQ(event.rule->get_actions()[0].data(), "block");*/ +/*}*/ +/*}*/ + +/*TEST(TestContext, MatchMultipleRulesInCollectionDoubleRun)*/ +/*{*/ +/*auto ruleset = std::make_shared();*/ +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ + +/*auto cond = std::make_shared(*/ +/*std::move(targets), std::make_unique(*/ +/*std::vector{"192.168.0.1"}));*/ + +/*std::vector> conditions{std::move(cond)};*/ + +/*std::unordered_map tags{*/ +/*{"type", "type"}, {"category", "category1"}};*/ + +/*auto rule = std::make_shared(*/ +/*"id1", "name1", std::move(tags), std::move(conditions), std::vector{});*/ + +/*ruleset->insert_rule(rule);*/ +/*}*/ - std::unordered_map tags{ - {"type", "type"}, {"category", "category2"}}; +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ - auto rule = std::make_shared("id2", "name2", std::move(tags), - std::move(conditions), std::vector{"redirect"}); +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"admin"}));*/ - ruleset->insert_rule(rule); - } +/*std::vector> conditions{std::move(cond)};*/ - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); +/*std::unordered_map tags{*/ +/*{"type", "type"}, {"category", "category2"}};*/ - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ctx.insert(root); - - auto events = ctx.match({}, {}, deadline); - EXPECT_EQ(events.size(), 1); - - auto &event = events[0]; - EXPECT_STREQ(event.rule->get_id().c_str(), "id1"); - EXPECT_STREQ(event.rule->get_name().c_str(), "name1"); - EXPECT_STREQ(event.rule->get_tag("type").data(), "type"); - EXPECT_STREQ(event.rule->get_tag("category").data(), "category1"); - EXPECT_TRUE(event.rule->get_actions().empty()); - - auto &match = event.matches[0]; - EXPECT_STREQ(match.resolved.c_str(), "192.168.0.1"); - EXPECT_STREQ(match.matched.c_str(), "192.168.0.1"); - EXPECT_STREQ(match.operator_name.data(), "ip_match"); - EXPECT_STREQ(match.operator_value.data(), ""); - EXPECT_STREQ(match.address.data(), "http.client_ip"); - EXPECT_TRUE(match.key_path.empty()); - } - - { - // An existing match in a collection will not inhibit a match in a - // priority collection. - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ctx.insert(root); - - auto events = ctx.match({}, {}, deadline); - EXPECT_EQ(events.size(), 1); - - auto &event = events[0]; - EXPECT_EQ(events.size(), 1); - EXPECT_STREQ(event.rule->get_id().c_str(), "id2"); - EXPECT_STREQ(event.rule->get_name().c_str(), "name2"); - EXPECT_STREQ(event.rule->get_tag("type").data(), "type"); - EXPECT_STREQ(event.rule->get_tag("category").data(), "category2"); - std::vector expected_actions{"redirect"}; - EXPECT_EQ(event.rule->get_actions(), expected_actions); - EXPECT_EQ(event.matches.size(), 1); - - auto &match = event.matches[0]; - EXPECT_STREQ(match.resolved.c_str(), "admin"); - EXPECT_STREQ(match.matched.c_str(), "admin"); - EXPECT_STREQ(match.operator_name.data(), "exact_match"); - EXPECT_STREQ(match.operator_value.data(), ""); - EXPECT_STREQ(match.address.data(), "usr.id"); - EXPECT_TRUE(match.key_path.empty()); - } -} +/*auto rule = std::make_shared(*/ +/*"id2", "name2", std::move(tags), std::move(conditions), std::vector{});*/ -TEST(TestContext, MatchMultipleCollectionsSingleRun) -{ - auto ruleset = std::make_shared(); - { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); +/*ruleset->insert_rule(rule);*/ +/*}*/ + +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*{*/ +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ctx.insert(root);*/ + +/*auto events = ctx.match({}, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 1);*/ + +/*auto &event = events[0];*/ +/*EXPECT_STREQ(event.rule->get_id().c_str(), "id1");*/ +/*EXPECT_STREQ(event.rule->get_name().c_str(), "name1");*/ +/*EXPECT_STREQ(event.rule->get_tag("type").data(), "type");*/ +/*EXPECT_STREQ(event.rule->get_tag("category").data(), "category1");*/ +/*std::vector expected_actions{};*/ +/*EXPECT_EQ(event.rule->get_actions(), expected_actions);*/ +/*EXPECT_EQ(event.matches.size(), 1);*/ + +/*auto &match = event.matches[0];*/ +/*EXPECT_STREQ(match.resolved.c_str(), "192.168.0.1");*/ +/*EXPECT_STREQ(match.matched.c_str(), "192.168.0.1");*/ +/*EXPECT_STREQ(match.operator_name.data(), "ip_match");*/ +/*EXPECT_STREQ(match.operator_value.data(), "");*/ +/*EXPECT_STREQ(match.address.data(), "http.client_ip");*/ +/*EXPECT_TRUE(match.key_path.empty());*/ +/*}*/ + +/*{*/ +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ctx.insert(root);*/ + +/*auto events = ctx.match({}, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 0);*/ +/*}*/ +/*}*/ + +/*TEST(TestContext, MatchMultipleRulesWithPriorityDoubleRunPriorityLast)*/ +/*{*/ +/*auto ruleset = std::make_shared();*/ +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ + +/*auto cond = std::make_shared(*/ +/*std::move(targets), std::make_unique(*/ +/*std::vector{"192.168.0.1"}));*/ + +/*std::vector> conditions{std::move(cond)};*/ + +/*std::unordered_map tags{*/ +/*{"type", "type"}, {"category", "category1"}};*/ + +/*auto rule = std::make_shared(*/ +/*"id1", "name1", std::move(tags), std::move(conditions), std::vector{});*/ + +/*ruleset->insert_rule(rule);*/ +/*}*/ + +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ + +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"admin"}));*/ + +/*std::vector> conditions{std::move(cond)};*/ + +/*std::unordered_map tags{*/ +/*{"type", "type"}, {"category", "category2"}};*/ + +/*auto rule = std::make_shared("id2", "name2", std::move(tags),*/ +/*std::move(conditions), std::vector{"block"});*/ + +/*ruleset->insert_rule(rule);*/ +/*}*/ + +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*{*/ +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ctx.insert(root);*/ + +/*auto events = ctx.match({}, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 1);*/ + +/*auto &event = events[0];*/ +/*EXPECT_STREQ(event.rule->get_id().c_str(), "id1");*/ +/*EXPECT_STREQ(event.rule->get_name().c_str(), "name1");*/ +/*EXPECT_STREQ(event.rule->get_tag("type").data(), "type");*/ +/*EXPECT_STREQ(event.rule->get_tag("category").data(), "category1");*/ +/*std::vector expected_actions{};*/ +/*EXPECT_EQ(event.rule->get_actions(), expected_actions);*/ +/*EXPECT_EQ(event.matches.size(), 1);*/ + +/*auto &match = event.matches[0];*/ +/*EXPECT_STREQ(match.resolved.c_str(), "192.168.0.1");*/ +/*EXPECT_STREQ(match.matched.c_str(), "192.168.0.1");*/ +/*EXPECT_STREQ(match.operator_name.data(), "ip_match");*/ +/*EXPECT_STREQ(match.operator_value.data(), "");*/ +/*EXPECT_STREQ(match.address.data(), "http.client_ip");*/ +/*EXPECT_TRUE(match.key_path.empty());*/ +/*}*/ + +/*{*/ +/*// An existing match in a collection will not inhibit a match in a*/ +/*// priority collection.*/ +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ctx.insert(root);*/ + +/*auto events = ctx.match({}, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 1);*/ + +/*auto &event = events[0];*/ +/*EXPECT_EQ(events.size(), 1);*/ +/*EXPECT_STREQ(event.rule->get_id().c_str(), "id2");*/ +/*EXPECT_STREQ(event.rule->get_name().c_str(), "name2");*/ +/*EXPECT_STREQ(event.rule->get_tag("type").data(), "type");*/ +/*EXPECT_STREQ(event.rule->get_tag("category").data(), "category2");*/ +/*std::vector expected_actions{"block"};*/ +/*EXPECT_EQ(event.rule->get_actions(), expected_actions);*/ +/*EXPECT_EQ(event.matches.size(), 1);*/ + +/*auto &match = event.matches[0];*/ +/*EXPECT_STREQ(match.resolved.c_str(), "admin");*/ +/*EXPECT_STREQ(match.matched.c_str(), "admin");*/ +/*EXPECT_STREQ(match.operator_name.data(), "exact_match");*/ +/*EXPECT_STREQ(match.operator_value.data(), "");*/ +/*EXPECT_STREQ(match.address.data(), "usr.id");*/ +/*EXPECT_TRUE(match.key_path.empty());*/ +/*}*/ +/*}*/ + +/*TEST(TestContext, MatchMultipleRulesWithPriorityDoubleRunPriorityFirst)*/ +/*{*/ +/*auto ruleset = std::make_shared();*/ +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ + +/*auto cond = std::make_shared(*/ +/*std::move(targets), std::make_unique(*/ +/*std::vector{"192.168.0.1"}));*/ + +/*std::vector> conditions{std::move(cond)};*/ + +/*std::unordered_map tags{*/ +/*{"type", "type"}, {"category", "category1"}};*/ + +/*auto rule = std::make_shared("id1", "name1", std::move(tags),*/ +/*std::move(conditions), std::vector{"block"});*/ + +/*ruleset->insert_rule(rule);*/ +/*}*/ + +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ + +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"admin"}));*/ + +/*std::vector> conditions{std::move(cond)};*/ + +/*std::unordered_map tags{*/ +/*{"type", "type"}, {"category", "category2"}};*/ + +/*auto rule = std::make_shared(*/ +/*"id2", "name2", std::move(tags), std::move(conditions), std::vector{});*/ + +/*ruleset->insert_rule(rule);*/ +/*}*/ + +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*{*/ +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ctx.insert(root);*/ + +/*auto events = ctx.match({}, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 1);*/ + +/*auto &event = events[0];*/ +/*EXPECT_STREQ(event.rule->get_id().c_str(), "id1");*/ +/*EXPECT_STREQ(event.rule->get_name().c_str(), "name1");*/ +/*EXPECT_STREQ(event.rule->get_tag("type").data(), "type");*/ +/*EXPECT_STREQ(event.rule->get_tag("category").data(), "category1");*/ +/*std::vector expected_actions{"block"};*/ +/*EXPECT_EQ(event.rule->get_actions(), expected_actions);*/ +/*EXPECT_EQ(event.matches.size(), 1);*/ + +/*auto &match = event.matches[0];*/ +/*EXPECT_STREQ(match.resolved.c_str(), "192.168.0.1");*/ +/*EXPECT_STREQ(match.matched.c_str(), "192.168.0.1");*/ +/*EXPECT_STREQ(match.operator_name.data(), "ip_match");*/ +/*EXPECT_STREQ(match.operator_value.data(), "");*/ +/*EXPECT_STREQ(match.address.data(), "http.client_ip");*/ +/*EXPECT_TRUE(match.key_path.empty());*/ +/*}*/ + +/*{*/ +/*// An existing match in a collection will not inhibit a match in a*/ +/*// priority collection.*/ +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ctx.insert(root);*/ + +/*auto events = ctx.match({}, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 0);*/ +/*}*/ +/*}*/ + +/*TEST(TestContext, MatchMultipleRulesWithPriorityUntilAllActionsMet)*/ +/*{*/ +/*auto ruleset = std::make_shared();*/ +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ + +/*auto cond = std::make_shared(*/ +/*std::move(targets), std::make_unique(*/ +/*std::vector{"192.168.0.1"}));*/ + +/*std::vector> conditions{std::move(cond)};*/ + +/*std::unordered_map tags{*/ +/*{"type", "type"}, {"category", "category1"}};*/ + +/*auto rule = std::make_shared(*/ +/*"id1", "name1", std::move(tags), std::move(conditions), std::vector{});*/ + +/*ruleset->insert_rule(rule);*/ +/*}*/ + +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ + +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"admin"}));*/ + +/*std::vector> conditions{std::move(cond)};*/ + +/*std::unordered_map tags{*/ +/*{"type", "type"}, {"category", "category2"}};*/ + +/*auto rule = std::make_shared("id2", "name2", std::move(tags),*/ +/*std::move(conditions), std::vector{"redirect"});*/ + +/*ruleset->insert_rule(rule);*/ +/*}*/ + +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*{*/ +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ctx.insert(root);*/ + +/*auto events = ctx.match({}, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 1);*/ + +/*auto &event = events[0];*/ +/*EXPECT_STREQ(event.rule->get_id().c_str(), "id1");*/ +/*EXPECT_STREQ(event.rule->get_name().c_str(), "name1");*/ +/*EXPECT_STREQ(event.rule->get_tag("type").data(), "type");*/ +/*EXPECT_STREQ(event.rule->get_tag("category").data(), "category1");*/ +/*EXPECT_TRUE(event.rule->get_actions().empty());*/ + +/*auto &match = event.matches[0];*/ +/*EXPECT_STREQ(match.resolved.c_str(), "192.168.0.1");*/ +/*EXPECT_STREQ(match.matched.c_str(), "192.168.0.1");*/ +/*EXPECT_STREQ(match.operator_name.data(), "ip_match");*/ +/*EXPECT_STREQ(match.operator_value.data(), "");*/ +/*EXPECT_STREQ(match.address.data(), "http.client_ip");*/ +/*EXPECT_TRUE(match.key_path.empty());*/ +/*}*/ + +/*{*/ +/*// An existing match in a collection will not inhibit a match in a*/ +/*// priority collection.*/ +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ctx.insert(root);*/ + +/*auto events = ctx.match({}, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 1);*/ + +/*auto &event = events[0];*/ +/*EXPECT_EQ(events.size(), 1);*/ +/*EXPECT_STREQ(event.rule->get_id().c_str(), "id2");*/ +/*EXPECT_STREQ(event.rule->get_name().c_str(), "name2");*/ +/*EXPECT_STREQ(event.rule->get_tag("type").data(), "type");*/ +/*EXPECT_STREQ(event.rule->get_tag("category").data(), "category2");*/ +/*std::vector expected_actions{"redirect"};*/ +/*EXPECT_EQ(event.rule->get_actions(), expected_actions);*/ +/*EXPECT_EQ(event.matches.size(), 1);*/ + +/*auto &match = event.matches[0];*/ +/*EXPECT_STREQ(match.resolved.c_str(), "admin");*/ +/*EXPECT_STREQ(match.matched.c_str(), "admin");*/ +/*EXPECT_STREQ(match.operator_name.data(), "exact_match");*/ +/*EXPECT_STREQ(match.operator_value.data(), "");*/ +/*EXPECT_STREQ(match.address.data(), "usr.id");*/ +/*EXPECT_TRUE(match.key_path.empty());*/ +/*}*/ +/*}*/ + +/*TEST(TestContext, MatchMultipleCollectionsSingleRun)*/ +/*{*/ +/*auto ruleset = std::make_shared();*/ +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ + +/*auto cond = std::make_shared(*/ +/*std::move(targets), std::make_unique(*/ +/*std::vector{"192.168.0.1"}));*/ + +/*std::vector> conditions{std::move(cond)};*/ + +/*std::unordered_map tags{*/ +/*{"type", "type1"}, {"category", "category1"}};*/ + +/*auto rule = std::make_shared(*/ +/*"id1", "name1", std::move(tags), std::move(conditions), std::vector{});*/ + +/*ruleset->insert_rule(rule);*/ +/*}*/ + +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ + +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"admin"}));*/ + +/*std::vector> conditions{std::move(cond)};*/ + +/*std::unordered_map tags{*/ +/*{"type", "type2"}, {"category", "category2"}};*/ + +/*auto rule = std::make_shared(*/ +/*"id2", "name2", std::move(tags), std::move(conditions), std::vector{});*/ + +/*ruleset->insert_rule(rule);*/ +/*}*/ + +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ctx.insert(root);*/ + +/*auto events = ctx.match({}, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 2);*/ +/*}*/ + +/*TEST(TestContext, MatchMultiplePriorityCollectionsSingleRun)*/ +/*{*/ +/*auto ruleset = std::make_shared();*/ +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ + +/*auto cond = std::make_shared(*/ +/*std::move(targets), std::make_unique(*/ +/*std::vector{"192.168.0.1"}));*/ - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); +/*std::vector> conditions{std::move(cond)};*/ - std::vector> conditions{std::move(cond)}; +/*std::unordered_map tags{*/ +/*{"type", "type1"}, {"category", "category1"}};*/ - std::unordered_map tags{ - {"type", "type1"}, {"category", "category1"}}; +/*auto rule = std::make_shared("id1", "name1", std::move(tags),*/ +/*std::move(conditions), std::vector{"block"});*/ - auto rule = std::make_shared( - "id1", "name1", std::move(tags), std::move(conditions), std::vector{}); +/*ruleset->insert_rule(rule);*/ +/*}*/ - ruleset->insert_rule(rule); - } +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ - { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"admin"}));*/ - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); +/*std::vector> conditions{std::move(cond)};*/ - std::vector> conditions{std::move(cond)}; +/*std::unordered_map tags{*/ +/*{"type", "type2"}, {"category", "category2"}};*/ - std::unordered_map tags{ - {"type", "type2"}, {"category", "category2"}}; +/*auto rule = std::make_shared("id2", "name2", std::move(tags),*/ +/*std::move(conditions), std::vector{"redirect"});*/ - auto rule = std::make_shared( - "id2", "name2", std::move(tags), std::move(conditions), std::vector{}); +/*ruleset->insert_rule(rule);*/ +/*}*/ - ruleset->insert_rule(rule); - } +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ctx.insert(root);*/ - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ctx.insert(root); - - auto events = ctx.match({}, {}, deadline); - EXPECT_EQ(events.size(), 2); -} - -TEST(TestContext, MatchMultiplePriorityCollectionsSingleRun) -{ - auto ruleset = std::make_shared(); - { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); +/*auto events = ctx.match({}, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 2);*/ +/*}*/ - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); +/*TEST(TestContext, MatchMultipleCollectionsDoubleRun)*/ +/*{*/ +/*auto ruleset = std::make_shared();*/ +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ - std::vector> conditions{std::move(cond)}; +/*auto cond = std::make_shared(*/ +/*std::move(targets), std::make_unique(*/ +/*std::vector{"192.168.0.1"}));*/ - std::unordered_map tags{ - {"type", "type1"}, {"category", "category1"}}; +/*std::vector> conditions{std::move(cond)};*/ - auto rule = std::make_shared("id1", "name1", std::move(tags), - std::move(conditions), std::vector{"block"}); +/*std::unordered_map tags{*/ +/*{"type", "type1"}, {"category", "category1"}};*/ - ruleset->insert_rule(rule); - } +/*auto rule = std::make_shared(*/ +/*"id1", "name1", std::move(tags), std::move(conditions), std::vector{});*/ - { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); +/*ruleset->insert_rule(rule);*/ +/*}*/ - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ - std::vector> conditions{std::move(cond)}; +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"admin"}));*/ - std::unordered_map tags{ - {"type", "type2"}, {"category", "category2"}}; +/*std::vector> conditions{std::move(cond)};*/ - auto rule = std::make_shared("id2", "name2", std::move(tags), - std::move(conditions), std::vector{"redirect"}); +/*std::unordered_map tags{*/ +/*{"type", "type2"}, {"category", "category2"}};*/ - ruleset->insert_rule(rule); - } +/*auto rule = std::make_shared(*/ +/*"id2", "name2", std::move(tags), std::move(conditions), std::vector{});*/ - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); +/*ruleset->insert_rule(rule);*/ +/*}*/ - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ctx.insert(root); +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ - auto events = ctx.match({}, {}, deadline); - EXPECT_EQ(events.size(), 2); -} +/*{*/ +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ctx.insert(root);*/ -TEST(TestContext, MatchMultipleCollectionsDoubleRun) -{ - auto ruleset = std::make_shared(); - { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); +/*auto events = ctx.match({}, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 1);*/ +/*}*/ - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); +/*{*/ +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ctx.insert(root);*/ - std::vector> conditions{std::move(cond)}; +/*auto events = ctx.match({}, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 1);*/ +/*}*/ +/*}*/ - std::unordered_map tags{ - {"type", "type1"}, {"category", "category1"}}; +/*TEST(TestContext, MatchMultiplePriorityCollectionsDoubleRun)*/ +/*{*/ +/*auto ruleset = std::make_shared();*/ +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ - auto rule = std::make_shared( - "id1", "name1", std::move(tags), std::move(conditions), std::vector{}); +/*auto cond = std::make_shared(*/ +/*std::move(targets), std::make_unique(*/ +/*std::vector{"192.168.0.1"}));*/ - ruleset->insert_rule(rule); - } +/*std::vector> conditions{std::move(cond)};*/ - { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); +/*std::unordered_map tags{*/ +/*{"type", "type1"}, {"category", "category1"}};*/ - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); +/*auto rule = std::make_shared("id1", "name1", std::move(tags),*/ +/*std::move(conditions), std::vector{"block"});*/ - std::vector> conditions{std::move(cond)}; +/*ruleset->insert_rule(rule);*/ +/*}*/ - std::unordered_map tags{ - {"type", "type2"}, {"category", "category2"}}; +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ - auto rule = std::make_shared( - "id2", "name2", std::move(tags), std::move(conditions), std::vector{}); +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"admin"}));*/ - ruleset->insert_rule(rule); - } +/*std::vector> conditions{std::move(cond)};*/ - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); +/*std::unordered_map tags{*/ +/*{"type", "type2"}, {"category", "category2"}};*/ - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ctx.insert(root); - - auto events = ctx.match({}, {}, deadline); - EXPECT_EQ(events.size(), 1); - } - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ctx.insert(root); - - auto events = ctx.match({}, {}, deadline); - EXPECT_EQ(events.size(), 1); - } -} +/*auto rule = std::make_shared("id2", "name2", std::move(tags),*/ +/*std::move(conditions), std::vector{"redirect"});*/ -TEST(TestContext, MatchMultiplePriorityCollectionsDoubleRun) -{ - auto ruleset = std::make_shared(); - { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); +/*ruleset->insert_rule(rule);*/ +/*}*/ - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ - std::vector> conditions{std::move(cond)}; +/*{*/ +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ctx.insert(root);*/ - std::unordered_map tags{ - {"type", "type1"}, {"category", "category1"}}; +/*auto events = ctx.match({}, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 1);*/ +/*}*/ - auto rule = std::make_shared("id1", "name1", std::move(tags), - std::move(conditions), std::vector{"block"}); +/*{*/ +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ctx.insert(root);*/ - ruleset->insert_rule(rule); - } +/*auto events = ctx.match({}, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 1);*/ +/*}*/ +/*}*/ - { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); +/*TEST(TestContext, RuleFilterWithCondition)*/ +/*{*/ +/*auto ruleset = std::make_shared();*/ - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); +/*// Generate rule*/ +/*ddwaf::rule::ptr rule;*/ +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ - std::vector> conditions{std::move(cond)}; +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"admin"}));*/ - std::unordered_map tags{ - {"type", "type2"}, {"category", "category2"}}; +/*std::vector> conditions{std::move(cond)};*/ - auto rule = std::make_shared("id2", "name2", std::move(tags), - std::move(conditions), std::vector{"redirect"}); +/*std::unordered_map tags{*/ +/*{"type", "type"}, {"category", "category"}};*/ - ruleset->insert_rule(rule); - } +/*rule = std::make_shared(*/ +/*"id", "name", std::move(tags), std::move(conditions), std::vector{});*/ - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); +/*ruleset->insert_rule(rule);*/ +/*}*/ - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ctx.insert(root); - - auto events = ctx.match({}, {}, deadline); - EXPECT_EQ(events.size(), 1); - } - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ctx.insert(root); - - auto events = ctx.match({}, {}, deadline); - EXPECT_EQ(events.size(), 1); - } -} +/*// Generate filter*/ +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ -TEST(TestContext, RuleFilterWithCondition) -{ - auto ruleset = std::make_shared(); +/*auto cond = std::make_shared(*/ +/*std::move(targets), std::make_unique(*/ +/*std::vector{"192.168.0.1"}));*/ - // Generate rule - ddwaf::rule::ptr rule; - { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); +/*std::vector> conditions{std::move(cond)};*/ - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); +/*auto filter = std::make_shared(*/ +/*"1", std::move(conditions), std::set{rule.get()});*/ +/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ +/*}*/ - std::vector> conditions{std::move(cond)}; +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ - std::unordered_map tags{ - {"type", "type"}, {"category", "category"}}; +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ctx.insert(root);*/ - rule = std::make_shared( - "id", "name", std::move(tags), std::move(conditions), std::vector{}); +/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ +/*EXPECT_EQ(rules_to_exclude.size(), 1);*/ +/*EXPECT_NE(rules_to_exclude.find(rule.get()), rules_to_exclude.end());*/ - ruleset->insert_rule(rule); - } +/*auto events = ctx.match(rules_to_exclude, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 0);*/ +/*}*/ - // Generate filter - { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); +/*TEST(TestContext, RuleFilterTimeout)*/ +/*{*/ +/*auto ruleset = std::make_shared();*/ - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); +/*// Generate rule*/ +/*ddwaf::rule::ptr rule;*/ +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ - std::vector> conditions{std::move(cond)}; +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"admin"}));*/ - auto filter = std::make_shared( - "1", std::move(conditions), std::set{rule.get()}); - ruleset->rule_filters.emplace(filter->get_id(), filter); - } +/*std::vector> conditions{std::move(cond)};*/ - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); +/*std::unordered_map tags{*/ +/*{"type", "type"}, {"category", "category"}};*/ - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ctx.insert(root); +/*rule = std::make_shared(*/ +/*"id", "name", std::move(tags), std::move(conditions), std::vector{});*/ - auto rules_to_exclude = ctx.filter_rules(deadline); - EXPECT_EQ(rules_to_exclude.size(), 1); - EXPECT_NE(rules_to_exclude.find(rule.get()), rules_to_exclude.end()); +/*ruleset->insert_rule(rule);*/ +/*}*/ - auto events = ctx.match(rules_to_exclude, {}, deadline); - EXPECT_EQ(events.size(), 0); -} +/*// Generate filter*/ +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ -TEST(TestContext, RuleFilterTimeout) -{ - auto ruleset = std::make_shared(); +/*auto cond = std::make_shared(*/ +/*std::move(targets), std::make_unique(*/ +/*std::vector{"192.168.0.1"}));*/ - // Generate rule - ddwaf::rule::ptr rule; - { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); +/*std::vector> conditions{std::move(cond)};*/ - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); +/*auto filter = std::make_shared(*/ +/*"1", std::move(conditions), std::set{rule.get()});*/ +/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ +/*}*/ - std::vector> conditions{std::move(cond)}; +/*ddwaf::timer deadline{0s};*/ +/*ddwaf::test::context ctx(ruleset);*/ - std::unordered_map tags{ - {"type", "type"}, {"category", "category"}}; +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ctx.insert(root);*/ - rule = std::make_shared( - "id", "name", std::move(tags), std::move(conditions), std::vector{}); +/*EXPECT_THROW(ctx.filter_rules(deadline), ddwaf::timeout_exception);*/ +/*}*/ - ruleset->insert_rule(rule); - } +/*TEST(TestContext, NoRuleFilterWithCondition)*/ +/*{*/ +/*auto ruleset = std::make_shared();*/ - // Generate filter - { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); - - std::vector> conditions{std::move(cond)}; - - auto filter = std::make_shared( - "1", std::move(conditions), std::set{rule.get()}); - ruleset->rule_filters.emplace(filter->get_id(), filter); - } - - ddwaf::timer deadline{0s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ctx.insert(root); - - EXPECT_THROW(ctx.filter_rules(deadline), ddwaf::timeout_exception); -} - -TEST(TestContext, NoRuleFilterWithCondition) -{ - auto ruleset = std::make_shared(); - - // Generate rule - ddwaf::rule::ptr rule; - { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); - - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); - - std::vector> conditions{std::move(cond)}; - - std::unordered_map tags{ - {"type", "type"}, {"category", "category"}}; - - rule = std::make_shared( - "id", "name", std::move(tags), std::move(conditions), std::vector{}); - - ruleset->insert_rule(rule); - } - - // Generate filter - { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); - - std::vector> conditions{std::move(cond)}; - - auto filter = std::make_shared( - "1", std::move(conditions), std::set{rule.get()}); - ruleset->rule_filters.emplace(filter->get_id(), filter); - } - - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.2")); - ctx.insert(root); - - auto rules_to_exclude = ctx.filter_rules(deadline); - EXPECT_TRUE(rules_to_exclude.empty()); - - auto events = ctx.match(rules_to_exclude, {}, deadline); - EXPECT_EQ(events.size(), 1); -} - -TEST(TestContext, MultipleRuleFiltersNonOverlappingRules) -{ - auto ruleset = std::make_shared(); - - // Generate rule - constexpr unsigned num_rules = 9; - std::vector rules; - rules.reserve(num_rules); - for (unsigned i = 0; i < num_rules; i++) { - - std::unordered_map tags{ - {"type", "type"}, {"category", "category"}}; - - rules.emplace_back(std::make_shared("id" + std::to_string(i), "name", - std::move(tags), std::vector{}, std::vector{})); - - ruleset->insert_rule(rules.back()); - } - - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - { - auto rules_to_exclude = ctx.filter_rules(deadline); - EXPECT_EQ(rules_to_exclude.size(), 0); - } - - { - auto filter = std::make_shared("1", std::vector{}, - std::set{rules[0].get(), rules[1].get(), rules[2].get()}); - ruleset->rule_filters.emplace(filter->get_id(), filter); - - auto rules_to_exclude = ctx.filter_rules(deadline); - EXPECT_EQ(rules_to_exclude.size(), 3); - EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); - } - - { - auto filter = std::make_shared("2", std::vector{}, - std::set{rules[3].get(), rules[4].get(), rules[5].get()}); - ruleset->rule_filters.emplace(filter->get_id(), filter); - - auto rules_to_exclude = ctx.filter_rules(deadline); - EXPECT_EQ(rules_to_exclude.size(), 6); - EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end()); - } - - { - auto filter = std::make_shared("3", std::vector{}, - std::set{rules[6].get(), rules[7].get(), rules[8].get()}); - ruleset->rule_filters.emplace(filter->get_id(), filter); - - auto rules_to_exclude = ctx.filter_rules(deadline); - EXPECT_EQ(rules_to_exclude.size(), 9); - EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end()); - } -} - -TEST(TestContext, MultipleRuleFiltersOverlappingRules) -{ - auto ruleset = std::make_shared(); - - // Generate rule - constexpr unsigned num_rules = 9; - std::vector rules; - rules.reserve(num_rules); - for (unsigned i = 0; i < num_rules; i++) { - std::string id = "id" + std::to_string(i); - - std::unordered_map tags{ - {"type", "type"}, {"category", "category"}}; - - rules.emplace_back(std::make_shared(std::string(id), "name", std::move(tags), - std::vector{}, std::vector{})); - - ruleset->insert_rule(rules.back()); - } - - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - { - auto rules_to_exclude = ctx.filter_rules(deadline); - EXPECT_EQ(rules_to_exclude.size(), 0); - } - - { - auto filter = std::make_shared("1", std::vector{}, - std::set{ - rules[0].get(), rules[1].get(), rules[2].get(), rules[3].get()}); - ruleset->rule_filters.emplace(filter->get_id(), filter); - - auto rules_to_exclude = ctx.filter_rules(deadline); - EXPECT_EQ(rules_to_exclude.size(), 4); - EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end()); - } - - { - auto filter = std::make_shared("2", std::vector{}, - std::set{rules[2].get(), rules[3].get(), rules[4].get()}); - ruleset->rule_filters.emplace(filter->get_id(), filter); - - auto rules_to_exclude = ctx.filter_rules(deadline); - EXPECT_EQ(rules_to_exclude.size(), 5); - EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end()); - } - - { - auto filter = std::make_shared("3", std::vector{}, - std::set{rules[0].get(), rules[5].get(), rules[6].get()}); - ruleset->rule_filters.emplace(filter->get_id(), filter); - - auto rules_to_exclude = ctx.filter_rules(deadline); - EXPECT_EQ(rules_to_exclude.size(), 7); - EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end()); - } - - { - auto filter = std::make_shared("4", std::vector{}, - std::set{rules[7].get(), rules[8].get(), rules[6].get()}); - ruleset->rule_filters.emplace(filter->get_id(), filter); - - auto rules_to_exclude = ctx.filter_rules(deadline); - EXPECT_EQ(rules_to_exclude.size(), 9); - EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end()); - } - - { - auto filter = std::make_shared("5", std::vector{}, - std::set{rules[0].get(), rules[1].get(), rules[2].get(), rules[3].get(), - rules[4].get(), rules[5].get(), rules[6].get(), rules[7].get(), rules[8].get()}); - ruleset->rule_filters.emplace(filter->get_id(), filter); - - auto rules_to_exclude = ctx.filter_rules(deadline); - EXPECT_EQ(rules_to_exclude.size(), 9); - EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end()); - } -} - -TEST(TestContext, MultipleRuleFiltersNonOverlappingRulesWithConditions) -{ - auto ruleset = std::make_shared(); - - // Generate rule - constexpr unsigned num_rules = 10; - std::vector rules; - rules.reserve(num_rules); - for (unsigned i = 0; i < num_rules; i++) { - std::string id = "id" + std::to_string(i); - - std::unordered_map tags{ - {"type", "type"}, {"category", "category"}}; - - rules.emplace_back(std::make_shared(std::string(id), "name", std::move(tags), - std::vector{}, std::vector{})); - - ruleset->insert_rule(rules.back()); - } - - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); - - std::vector> conditions{std::move(cond)}; - - auto filter = std::make_shared("1", std::move(conditions), - std::set{ - rules[0].get(), rules[1].get(), rules[2].get(), rules[3].get(), rules[4].get()}); - ruleset->rule_filters.emplace(filter->get_id(), filter); - } - - { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); - - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); - - std::vector> conditions{std::move(cond)}; - - auto filter = std::make_shared("2", std::move(conditions), - std::set{ - rules[5].get(), rules[6].get(), rules[7].get(), rules[8].get(), rules[9].get()}); - ruleset->rule_filters.emplace(filter->get_id(), filter); - } - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ctx.insert(root); - - auto rules_to_exclude = ctx.filter_rules(deadline); - EXPECT_EQ(rules_to_exclude.size(), 5); - EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[9].get()), rules_to_exclude.end()); - } - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ctx.insert(root); - - auto rules_to_exclude = ctx.filter_rules(deadline); - EXPECT_EQ(rules_to_exclude.size(), 10); - EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[9].get()), rules_to_exclude.end()); - } -} - -TEST(TestContext, MultipleRuleFiltersOverlappingRulesWithConditions) -{ - auto ruleset = std::make_shared(); - - // Generate rule - constexpr unsigned num_rules = 10; - std::vector rules; - rules.reserve(num_rules); - for (unsigned i = 0; i < num_rules; i++) { - std::string id = "id" + std::to_string(i); - - std::unordered_map tags{ - {"type", "type"}, {"category", "category"}}; - - rules.emplace_back(std::make_shared(std::string(id), "name", std::move(tags), - std::vector{}, std::vector{})); - - ruleset->insert_rule(rules.back()); - } - - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); - - std::vector> conditions{std::move(cond)}; - - auto filter = std::make_shared("1", std::move(conditions), - std::set{rules[0].get(), rules[1].get(), rules[2].get(), rules[3].get(), - rules[4].get(), rules[5].get(), rules[6].get()}); - ruleset->rule_filters.emplace(filter->get_id(), filter); - } - - { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); - - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); - - std::vector> conditions{std::move(cond)}; - - auto filter = std::make_shared("2", std::move(conditions), - std::set{rules[3].get(), rules[4].get(), rules[5].get(), rules[6].get(), - rules[7].get(), rules[8].get(), rules[9].get()}); - ruleset->rule_filters.emplace(filter->get_id(), filter); - } - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ctx.insert(root); - - auto rules_to_exclude = ctx.filter_rules(deadline); - EXPECT_EQ(rules_to_exclude.size(), 7); - EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end()); - } - - { - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ctx.insert(root); - - auto rules_to_exclude = ctx.filter_rules(deadline); - EXPECT_EQ(rules_to_exclude.size(), 10); - EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end()); - EXPECT_NE(rules_to_exclude.find(rules[9].get()), rules_to_exclude.end()); - } -} - -TEST(TestContext, InputFilterExclude) -{ - condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}}; - - std::vector targets{client_ip}; - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"192.168.0.1"})); - - std::vector> conditions{std::move(cond)}; - - std::unordered_map tags{{"type", "type"}, {"category", "category"}}; - - auto rule = std::make_shared( - "id", "name", std::move(tags), std::move(conditions), std::vector{}); - - auto obj_filter = std::make_shared(); - obj_filter->insert(client_ip.root, client_ip.name); - - std::vector filter_conditions; - std::set filter_rules{rule.get()}; - auto filter = std::make_shared( - "1", std::move(filter_conditions), std::move(filter_rules), std::move(obj_filter)); - - auto ruleset = std::make_shared(); - ruleset->insert_rule(rule); - ruleset->input_filters.emplace(filter->get_id(), filter); - - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ctx.insert(root); - - auto objects_to_exclude = ctx.filter_inputs({}, deadline); - EXPECT_EQ(objects_to_exclude.size(), 1); - auto events = ctx.match({}, objects_to_exclude, deadline); - EXPECT_EQ(events.size(), 0); -} - -TEST(TestContext, InputFilterExcludeRule) -{ - condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}}; - - std::vector targets{client_ip}; - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"192.168.0.1"})); - - std::vector> conditions{std::move(cond)}; - - std::unordered_map tags{{"type", "type"}, {"category", "category"}}; - - auto rule = std::make_shared( - "id", "name", std::move(tags), std::move(conditions), std::vector{}); - - auto obj_filter = std::make_shared(); - obj_filter->insert(client_ip.root, client_ip.name); - - std::vector filter_conditions; - std::set filter_rules{rule.get()}; - auto filter = std::make_shared( - "1", std::move(filter_conditions), std::move(filter_rules), std::move(obj_filter)); - - auto ruleset = std::make_shared(); - ruleset->insert_rule(rule); - ruleset->input_filters.emplace(filter->get_id(), filter); - - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ctx.insert(root); - - // The rule is added to the filter stage so that it's excluded from the - // final result, since we're not actually excluding the rule from the match - // stage we still get an event. - auto objects_to_exclude = ctx.filter_inputs({rule.get()}, deadline); - EXPECT_EQ(objects_to_exclude.size(), 0); - auto events = ctx.match({}, objects_to_exclude, deadline); - EXPECT_EQ(events.size(), 1); -} - -TEST(TestContext, InputFilterWithCondition) -{ - condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}}; - condition::target_type usr_id{get_target_index("usr.id"), "usr.id", {}}; - - auto ruleset = std::make_shared(); - { - std::vector> conditions; - std::vector targets{client_ip}; - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); - conditions.emplace_back(std::move(cond)); - - std::unordered_map tags{ - {"type", "type"}, {"category", "category"}}; - - auto rule = std::make_shared( - "id", "name", std::move(tags), std::move(conditions), std::vector{}); - - ruleset->insert_rule(rule); - } - - { - auto obj_filter = std::make_shared(); - obj_filter->insert(client_ip.root, client_ip.name); - - std::vector> conditions; - std::vector targets{usr_id}; - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); - conditions.emplace_back(std::move(cond)); - - std::set filter_rules{ruleset->rules[0].get()}; - auto filter = std::make_shared( - "1", std::move(conditions), std::move(filter_rules), std::move(obj_filter)); - - ruleset->input_filters.emplace(filter->get_id(), filter); - } - - // Without usr.id, nothing should be excluded - { - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ctx.insert(root); - - auto objects_to_exclude = ctx.filter_inputs({}, deadline); - EXPECT_EQ(objects_to_exclude.size(), 0); - auto events = ctx.match({}, objects_to_exclude, deadline); - EXPECT_EQ(events.size(), 1); - } - - // With usr.id != admin, nothing should be excluded - { - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admino")); - ctx.insert(root); - - auto objects_to_exclude = ctx.filter_inputs({}, deadline); - EXPECT_EQ(objects_to_exclude.size(), 0); - auto events = ctx.match({}, objects_to_exclude, deadline); - EXPECT_EQ(events.size(), 1); - } - - // With usr.id == admin, there should be no matches - { - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ctx.insert(root); - - auto objects_to_exclude = ctx.filter_inputs({}, deadline); - EXPECT_EQ(objects_to_exclude.size(), 1); - auto events = ctx.match({}, objects_to_exclude, deadline); - EXPECT_EQ(events.size(), 0); - } -} - -TEST(TestContext, InputFilterMultipleRules) -{ - condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}}; - condition::target_type usr_id{get_target_index("usr.id"), "usr.id", {}}; - - auto ruleset = std::make_shared(); - { - std::vector> conditions; - std::vector targets{client_ip}; - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); - conditions.emplace_back(std::move(cond)); - - std::unordered_map tags{ - {"type", "ip_type"}, {"category", "category"}}; - - auto rule = std::make_shared( - "ip_id", "name", std::move(tags), std::move(conditions), std::vector{}); - - ruleset->insert_rule(rule); - } - - { - std::vector> conditions; - std::vector targets{usr_id}; - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); - conditions.emplace_back(std::move(cond)); - - std::unordered_map tags{ - {"type", "usr_type"}, {"category", "category"}}; - - auto rule = std::make_shared( - "usr_id", "name", std::move(tags), std::move(conditions), std::vector{}); - - ruleset->insert_rule(rule); - } - - { - auto obj_filter = std::make_shared(); - obj_filter->insert(client_ip.root, client_ip.name); - obj_filter->insert(usr_id.root, usr_id.name); - - std::vector> conditions; - std::set filter_rules{ruleset->rules[0].get(), ruleset->rules[1].get()}; - auto filter = std::make_shared( - "1", std::move(conditions), std::move(filter_rules), std::move(obj_filter)); - - ruleset->input_filters.emplace(filter->get_id(), filter); - } - - // Without usr.id, nothing should be excluded - { - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ctx.insert(root); - - auto objects_to_exclude = ctx.filter_inputs({}, deadline); - EXPECT_EQ(objects_to_exclude.size(), 2); - for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 1); } - - auto events = ctx.match({}, objects_to_exclude, deadline); - EXPECT_EQ(events.size(), 0); - } - - // With usr.id != admin, nothing should be excluded - { - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admino")); - ctx.insert(root); - - auto objects_to_exclude = ctx.filter_inputs({}, deadline); - EXPECT_EQ(objects_to_exclude.size(), 2); - for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 2); } - - auto events = ctx.match({}, objects_to_exclude, deadline); - EXPECT_EQ(events.size(), 0); - } - - // With usr.id == admin, there should be no matches - { - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ctx.insert(root); - - auto objects_to_exclude = ctx.filter_inputs({}, deadline); - EXPECT_EQ(objects_to_exclude.size(), 2); - for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 2); } - - auto events = ctx.match({}, objects_to_exclude, deadline); - EXPECT_EQ(events.size(), 0); - } -} - -TEST(TestContext, InputFilterMultipleRulesMultipleFilters) -{ - condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}}; - condition::target_type usr_id{get_target_index("usr.id"), "usr.id", {}}; - - auto ruleset = std::make_shared(); - { - std::vector> conditions; - std::vector targets{client_ip}; - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); - conditions.emplace_back(std::move(cond)); - - std::unordered_map tags{ - {"type", "ip_type"}, {"category", "category"}}; - - auto rule = std::make_shared( - "ip_id", "name", std::move(tags), std::move(conditions), std::vector{}); - - ruleset->insert_rule(rule); - } - - { - std::vector> conditions; - std::vector targets{usr_id}; - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); - conditions.emplace_back(std::move(cond)); - - std::unordered_map tags{ - {"type", "usr_type"}, {"category", "category"}}; - - auto rule = std::make_shared( - "usr_id", "name", std::move(tags), std::move(conditions), std::vector{}); - - ruleset->insert_rule(rule); - } - - { - auto obj_filter = std::make_shared(); - obj_filter->insert(client_ip.root, client_ip.name); - - std::vector> conditions; - std::set filter_rules{ruleset->rules[0].get()}; - auto filter = std::make_shared( - "1", std::move(conditions), std::move(filter_rules), std::move(obj_filter)); - - ruleset->input_filters.emplace(filter->get_id(), filter); - } - - { - auto obj_filter = std::make_shared(); - obj_filter->insert(usr_id.root, usr_id.name); - - std::vector> conditions; - std::set filter_rules{ruleset->rules[1].get()}; - auto filter = std::make_shared( - "2", std::move(conditions), std::move(filter_rules), std::move(obj_filter)); - - ruleset->input_filters.emplace(filter->get_id(), filter); - } - - // Without usr.id, nothing should be excluded - { - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ctx.insert(root); - - auto objects_to_exclude = ctx.filter_inputs({}, deadline); - EXPECT_EQ(objects_to_exclude.size(), 1); - for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 1); } - - auto events = ctx.match({}, objects_to_exclude, deadline); - EXPECT_EQ(events.size(), 0); - } - - // With usr.id != admin, nothing should be excluded - { - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admino")); - ctx.insert(root); - - auto objects_to_exclude = ctx.filter_inputs({}, deadline); - EXPECT_EQ(objects_to_exclude.size(), 2); - for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 1); } - - auto events = ctx.match({}, objects_to_exclude, deadline); - EXPECT_EQ(events.size(), 0); - } - - // With usr.id == admin, there should be no matches - { - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ctx.insert(root); - - auto objects_to_exclude = ctx.filter_inputs({}, deadline); - EXPECT_EQ(objects_to_exclude.size(), 2); - for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 1); } - - auto events = ctx.match({}, objects_to_exclude, deadline); - EXPECT_EQ(events.size(), 0); - } -} - -TEST(TestContext, InputFilterMultipleRulesMultipleFiltersMultipleObjects) -{ - condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}}; - condition::target_type usr_id{get_target_index("usr.id"), "usr.id", {}}; - condition::target_type cookie_header{ - get_target_index("server.request.headers"), "server.request.headers", {"cookie"}}; - - auto ruleset = std::make_shared(); - { - std::vector> conditions; - std::vector targets{client_ip}; - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); - conditions.emplace_back(std::move(cond)); - - std::unordered_map tags{ - {"type", "ip_type"}, {"category", "category"}}; - - auto rule = std::make_shared( - "ip_id", "name", std::move(tags), std::move(conditions), std::vector{}); - - ruleset->insert_rule(rule); - } - - { - std::vector> conditions; - std::vector targets{usr_id}; - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); - conditions.emplace_back(std::move(cond)); - - std::unordered_map tags{ - {"type", "usr_type"}, {"category", "category"}}; - - auto rule = std::make_shared( - "usr_id", "name", std::move(tags), std::move(conditions), std::vector{}); - - ruleset->insert_rule(rule); - } - - { - std::vector> conditions; - std::vector targets{cookie_header}; - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"mycookie"})); - conditions.emplace_back(std::move(cond)); - - std::unordered_map tags{ - {"type", "cookie_type"}, {"category", "category"}}; - - auto rule = std::make_shared("cookie_id", "name", std::move(tags), - std::move(conditions), std::vector{}); - - ruleset->insert_rule(rule); - } - - auto ip_rule = ruleset->rules[0]; - auto usr_rule = ruleset->rules[1]; - auto cookie_rule = ruleset->rules[2]; - { - auto obj_filter = std::make_shared(); - obj_filter->insert(client_ip.root, client_ip.name); - obj_filter->insert(cookie_header.root, cookie_header.name); - - std::vector> conditions; - std::set filter_rules{ip_rule.get(), cookie_rule.get()}; - auto filter = std::make_shared( - "1", std::move(conditions), std::move(filter_rules), std::move(obj_filter)); - - ruleset->input_filters.emplace(filter->get_id(), filter); - } - - { - auto obj_filter = std::make_shared(); - obj_filter->insert(usr_id.root, usr_id.name); - obj_filter->insert(client_ip.root, client_ip.name); - - std::vector> conditions; - std::set filter_rules{usr_rule.get(), ip_rule.get()}; - auto filter = std::make_shared( - "2", std::move(conditions), std::move(filter_rules), std::move(obj_filter)); - - ruleset->input_filters.emplace(filter->get_id(), filter); - } - - { - auto obj_filter = std::make_shared(); - obj_filter->insert(usr_id.root, usr_id.name); - obj_filter->insert(cookie_header.root, cookie_header.name); - - std::vector> conditions; - std::set filter_rules{usr_rule.get(), cookie_rule.get()}; - auto filter = std::make_shared( - "3", std::move(conditions), std::move(filter_rules), std::move(obj_filter)); - - ruleset->input_filters.emplace(filter->get_id(), filter); - } - - { - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ctx.insert(root); - - auto objects_to_exclude = ctx.filter_inputs({}, deadline); - EXPECT_EQ(objects_to_exclude.size(), 3); - for (const auto &[rule, objects] : objects_to_exclude) { - EXPECT_EQ(objects.size(), 1); - EXPECT_NE(objects.find(&root.array[0]), objects.end()); - } - - auto events = ctx.match({}, objects_to_exclude, deadline); - EXPECT_EQ(events.size(), 0); - } - - { - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ctx.insert(root); - - auto objects_to_exclude = ctx.filter_inputs({}, deadline); - EXPECT_EQ(objects_to_exclude.size(), 3); - for (const auto &[rule, objects] : objects_to_exclude) { - EXPECT_EQ(objects.size(), 1); - EXPECT_NE(objects.find(&root.array[0]), objects.end()); - } - - auto events = ctx.match({}, objects_to_exclude, deadline); - EXPECT_EQ(events.size(), 0); - } - - { - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object headers; - ddwaf_object tmp; - ddwaf_object_map(&headers); - ddwaf_object_map_add(&headers, "cookie", ddwaf_object_string(&tmp, "mycookie")); - - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "server.request.headers", &headers); - - ctx.insert(root); - - auto objects_to_exclude = ctx.filter_inputs({}, deadline); - EXPECT_EQ(objects_to_exclude.size(), 3); - for (const auto &[rule, objects] : objects_to_exclude) { - EXPECT_EQ(objects.size(), 1); - EXPECT_NE(objects.find(&root.array[0]), objects.end()); - } - - auto events = ctx.match({}, objects_to_exclude, deadline); - EXPECT_EQ(events.size(), 0); - } - - { - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object tmp; - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ctx.insert(root); - - auto objects_to_exclude = ctx.filter_inputs({}, deadline); - EXPECT_EQ(objects_to_exclude.size(), 3); - for (const auto &[rule, objects] : objects_to_exclude) { - EXPECT_EQ(objects.size(), 2); - EXPECT_NE(objects.find(&root.array[0]), objects.end()); - EXPECT_NE(objects.find(&root.array[1]), objects.end()); - } - auto events = ctx.match({}, objects_to_exclude, deadline); - EXPECT_EQ(events.size(), 0); - } - - { - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object headers; - ddwaf_object tmp; - ddwaf_object_map(&headers); - ddwaf_object_map_add(&headers, "cookie", ddwaf_object_string(&tmp, "mycookie")); - - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ddwaf_object_map_add(&root, "server.request.headers", &headers); - - ctx.insert(root); - - auto objects_to_exclude = ctx.filter_inputs({}, deadline); - EXPECT_EQ(objects_to_exclude.size(), 3); - for (const auto &[rule, objects] : objects_to_exclude) { - EXPECT_EQ(objects.size(), 2); - EXPECT_NE(objects.find(&root.array[0]), objects.end()); - EXPECT_NE(objects.find(&root.array[1]), objects.end()); - } - auto events = ctx.match({}, objects_to_exclude, deadline); - EXPECT_EQ(events.size(), 0); - } - - { - ddwaf::timer deadline{2s}; - ddwaf::test::context ctx(ruleset); - - ddwaf_object root; - ddwaf_object headers; - ddwaf_object tmp; - ddwaf_object_map(&headers); - ddwaf_object_map_add(&headers, "cookie", ddwaf_object_string(&tmp, "mycookie")); - - ddwaf_object_map(&root); - ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); - ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); - ddwaf_object_map_add(&root, "server.request.headers", &headers); - - ctx.insert(root); - - auto objects_to_exclude = ctx.filter_inputs({}, deadline); - EXPECT_EQ(objects_to_exclude.size(), 3); - for (const auto &[rule, objects] : objects_to_exclude) { - EXPECT_EQ(objects.size(), 3); - EXPECT_NE(objects.find(&root.array[0]), objects.end()); - EXPECT_NE(objects.find(&root.array[1]), objects.end()); - EXPECT_NE(objects.find(&root.array[2]), objects.end()); - } - auto events = ctx.match({}, objects_to_exclude, deadline); - EXPECT_EQ(events.size(), 0); - } -} +/*// Generate rule*/ +/*ddwaf::rule::ptr rule;*/ +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ + +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"admin"}));*/ + +/*std::vector> conditions{std::move(cond)};*/ + +/*std::unordered_map tags{*/ +/*{"type", "type"}, {"category", "category"}};*/ + +/*rule = std::make_shared(*/ +/*"id", "name", std::move(tags), std::move(conditions), std::vector{});*/ + +/*ruleset->insert_rule(rule);*/ +/*}*/ + +/*// Generate filter*/ +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ + +/*auto cond = std::make_shared(*/ +/*std::move(targets), std::make_unique(*/ +/*std::vector{"192.168.0.1"}));*/ + +/*std::vector> conditions{std::move(cond)};*/ + +/*auto filter = std::make_shared(*/ +/*"1", std::move(conditions), std::set{rule.get()});*/ +/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ +/*}*/ + +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.2"));*/ +/*ctx.insert(root);*/ + +/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ +/*EXPECT_TRUE(rules_to_exclude.empty());*/ + +/*auto events = ctx.match(rules_to_exclude, {}, deadline);*/ +/*EXPECT_EQ(events.size(), 1);*/ +/*}*/ + +/*TEST(TestContext, MultipleRuleFiltersNonOverlappingRules)*/ +/*{*/ +/*auto ruleset = std::make_shared();*/ + +/*// Generate rule*/ +/*constexpr unsigned num_rules = 9;*/ +/*std::vector rules;*/ +/*rules.reserve(num_rules);*/ +/*for (unsigned i = 0; i < num_rules; i++) {*/ + +/*std::unordered_map tags{*/ +/*{"type", "type"}, {"category", "category"}};*/ + +/*rules.emplace_back(std::make_shared("id" + std::to_string(i), "name",*/ +/*std::move(tags), std::vector{}, std::vector{}));*/ + +/*ruleset->insert_rule(rules.back());*/ +/*}*/ + +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*{*/ +/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ +/*EXPECT_EQ(rules_to_exclude.size(), 0);*/ +/*}*/ + +/*{*/ +/*auto filter = std::make_shared("1", std::vector{},*/ +/*std::set{rules[0].get(), rules[1].get(), rules[2].get()});*/ +/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ + +/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ +/*EXPECT_EQ(rules_to_exclude.size(), 3);*/ +/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ +/*}*/ + +/*{*/ +/*auto filter = std::make_shared("2", std::vector{},*/ +/*std::set{rules[3].get(), rules[4].get(), rules[5].get()});*/ +/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ + +/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ +/*EXPECT_EQ(rules_to_exclude.size(), 6);*/ +/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end());*/ +/*}*/ + +/*{*/ +/*auto filter = std::make_shared("3", std::vector{},*/ +/*std::set{rules[6].get(), rules[7].get(), rules[8].get()});*/ +/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ + +/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ +/*EXPECT_EQ(rules_to_exclude.size(), 9);*/ +/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end());*/ +/*}*/ +/*}*/ + +/*TEST(TestContext, MultipleRuleFiltersOverlappingRules)*/ +/*{*/ +/*auto ruleset = std::make_shared();*/ + +/*// Generate rule*/ +/*constexpr unsigned num_rules = 9;*/ +/*std::vector rules;*/ +/*rules.reserve(num_rules);*/ +/*for (unsigned i = 0; i < num_rules; i++) {*/ +/*std::string id = "id" + std::to_string(i);*/ + +/*std::unordered_map tags{*/ +/*{"type", "type"}, {"category", "category"}};*/ + +/*rules.emplace_back(std::make_shared(std::string(id), "name", std::move(tags),*/ +/*std::vector{}, std::vector{}));*/ + +/*ruleset->insert_rule(rules.back());*/ +/*}*/ + +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*{*/ +/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ +/*EXPECT_EQ(rules_to_exclude.size(), 0);*/ +/*}*/ + +/*{*/ +/*auto filter = std::make_shared("1", std::vector{},*/ +/*std::set{*/ +/*rules[0].get(), rules[1].get(), rules[2].get(), rules[3].get()});*/ +/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ + +/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ +/*EXPECT_EQ(rules_to_exclude.size(), 4);*/ +/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end());*/ +/*}*/ + +/*{*/ +/*auto filter = std::make_shared("2", std::vector{},*/ +/*std::set{rules[2].get(), rules[3].get(), rules[4].get()});*/ +/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ + +/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ +/*EXPECT_EQ(rules_to_exclude.size(), 5);*/ +/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end());*/ +/*}*/ + +/*{*/ +/*auto filter = std::make_shared("3", std::vector{},*/ +/*std::set{rules[0].get(), rules[5].get(), rules[6].get()});*/ +/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ + +/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ +/*EXPECT_EQ(rules_to_exclude.size(), 7);*/ +/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end());*/ +/*}*/ + +/*{*/ +/*auto filter = std::make_shared("4", std::vector{},*/ +/*std::set{rules[7].get(), rules[8].get(), rules[6].get()});*/ +/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ + +/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ +/*EXPECT_EQ(rules_to_exclude.size(), 9);*/ +/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end());*/ +/*}*/ + +/*{*/ +/*auto filter = std::make_shared("5", std::vector{},*/ +/*std::set{rules[0].get(), rules[1].get(), rules[2].get(), rules[3].get(),*/ +/*rules[4].get(), rules[5].get(), rules[6].get(), rules[7].get(), rules[8].get()});*/ +/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ + +/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ +/*EXPECT_EQ(rules_to_exclude.size(), 9);*/ +/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end());*/ +/*}*/ +/*}*/ + +/*TEST(TestContext, MultipleRuleFiltersNonOverlappingRulesWithConditions)*/ +/*{*/ +/*auto ruleset = std::make_shared();*/ + +/*// Generate rule*/ +/*constexpr unsigned num_rules = 10;*/ +/*std::vector rules;*/ +/*rules.reserve(num_rules);*/ +/*for (unsigned i = 0; i < num_rules; i++) {*/ +/*std::string id = "id" + std::to_string(i);*/ + +/*std::unordered_map tags{*/ +/*{"type", "type"}, {"category", "category"}};*/ + +/*rules.emplace_back(std::make_shared(std::string(id), "name", std::move(tags),*/ +/*std::vector{}, std::vector{}));*/ + +/*ruleset->insert_rule(rules.back());*/ +/*}*/ + +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ + +/*auto cond = std::make_shared(*/ +/*std::move(targets), std::make_unique(*/ +/*std::vector{"192.168.0.1"}));*/ + +/*std::vector> conditions{std::move(cond)};*/ + +/*auto filter = std::make_shared("1", std::move(conditions),*/ +/*std::set{*/ +/*rules[0].get(), rules[1].get(), rules[2].get(), rules[3].get(), rules[4].get()});*/ +/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ +/*}*/ + +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ + +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"admin"}));*/ + +/*std::vector> conditions{std::move(cond)};*/ + +/*auto filter = std::make_shared("2", std::move(conditions),*/ +/*std::set{*/ +/*rules[5].get(), rules[6].get(), rules[7].get(), rules[8].get(), rules[9].get()});*/ +/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ +/*}*/ + +/*{*/ +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ctx.insert(root);*/ + +/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ +/*EXPECT_EQ(rules_to_exclude.size(), 5);*/ +/*EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[9].get()), rules_to_exclude.end());*/ +/*}*/ + +/*{*/ +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ctx.insert(root);*/ + +/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ +/*EXPECT_EQ(rules_to_exclude.size(), 10);*/ +/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[9].get()), rules_to_exclude.end());*/ +/*}*/ +/*}*/ + +/*TEST(TestContext, MultipleRuleFiltersOverlappingRulesWithConditions)*/ +/*{*/ +/*auto ruleset = std::make_shared();*/ + +/*// Generate rule*/ +/*constexpr unsigned num_rules = 10;*/ +/*std::vector rules;*/ +/*rules.reserve(num_rules);*/ +/*for (unsigned i = 0; i < num_rules; i++) {*/ +/*std::string id = "id" + std::to_string(i);*/ + +/*std::unordered_map tags{*/ +/*{"type", "type"}, {"category", "category"}};*/ + +/*rules.emplace_back(std::make_shared(std::string(id), "name", std::move(tags),*/ +/*std::vector{}, std::vector{}));*/ + +/*ruleset->insert_rule(rules.back());*/ +/*}*/ + +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ + +/*auto cond = std::make_shared(*/ +/*std::move(targets), std::make_unique(*/ +/*std::vector{"192.168.0.1"}));*/ + +/*std::vector> conditions{std::move(cond)};*/ + +/*auto filter = std::make_shared("1", std::move(conditions),*/ +/*std::set{rules[0].get(), rules[1].get(), rules[2].get(), rules[3].get(),*/ +/*rules[4].get(), rules[5].get(), rules[6].get()});*/ +/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ +/*}*/ + +/*{*/ +/*std::vector targets;*/ +/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ + +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"admin"}));*/ + +/*std::vector> conditions{std::move(cond)};*/ + +/*auto filter = std::make_shared("2", std::move(conditions),*/ +/*std::set{rules[3].get(), rules[4].get(), rules[5].get(), rules[6].get(),*/ +/*rules[7].get(), rules[8].get(), rules[9].get()});*/ +/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ +/*}*/ + +/*{*/ +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ctx.insert(root);*/ + +/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ +/*EXPECT_EQ(rules_to_exclude.size(), 7);*/ +/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end());*/ +/*}*/ + +/*{*/ +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ctx.insert(root);*/ + +/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ +/*EXPECT_EQ(rules_to_exclude.size(), 10);*/ +/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end());*/ +/*EXPECT_NE(rules_to_exclude.find(rules[9].get()), rules_to_exclude.end());*/ +/*}*/ +/*}*/ + +/*TEST(TestContext, InputFilterExclude)*/ +/*{*/ +/*condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}};*/ + +/*std::vector targets{client_ip};*/ +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"192.168.0.1"}));*/ + +/*std::vector> conditions{std::move(cond)};*/ + +/*std::unordered_map tags{{"type", "type"}, {"category", "category"}};*/ + +/*auto rule = std::make_shared(*/ +/*"id", "name", std::move(tags), std::move(conditions), std::vector{});*/ + +/*auto obj_filter = std::make_shared();*/ +/*obj_filter->insert(client_ip.root, client_ip.name);*/ + +/*std::vector filter_conditions;*/ +/*std::set filter_rules{rule.get()};*/ +/*auto filter = std::make_shared(*/ +/*"1", std::move(filter_conditions), std::move(filter_rules), std::move(obj_filter));*/ + +/*auto ruleset = std::make_shared();*/ +/*ruleset->insert_rule(rule);*/ +/*ruleset->input_filters.emplace(filter->get_id(), filter);*/ + +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ctx.insert(root);*/ + +/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ +/*EXPECT_EQ(objects_to_exclude.size(), 1);*/ +/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ +/*EXPECT_EQ(events.size(), 0);*/ +/*}*/ + +/*TEST(TestContext, InputFilterExcludeRule)*/ +/*{*/ +/*condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}};*/ + +/*std::vector targets{client_ip};*/ +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"192.168.0.1"}));*/ + +/*std::vector> conditions{std::move(cond)};*/ + +/*std::unordered_map tags{{"type", "type"}, {"category", "category"}};*/ + +/*auto rule = std::make_shared(*/ +/*"id", "name", std::move(tags), std::move(conditions), std::vector{});*/ + +/*auto obj_filter = std::make_shared();*/ +/*obj_filter->insert(client_ip.root, client_ip.name);*/ + +/*std::vector filter_conditions;*/ +/*std::set filter_rules{rule.get()};*/ +/*auto filter = std::make_shared(*/ +/*"1", std::move(filter_conditions), std::move(filter_rules), std::move(obj_filter));*/ + +/*auto ruleset = std::make_shared();*/ +/*ruleset->insert_rule(rule);*/ +/*ruleset->input_filters.emplace(filter->get_id(), filter);*/ + +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ctx.insert(root);*/ + +/*// The rule is added to the filter stage so that it's excluded from the*/ +/*// final result, since we're not actually excluding the rule from the match*/ +/*// stage we still get an event.*/ +/*auto objects_to_exclude = ctx.filter_inputs({rule.get()}, deadline);*/ +/*EXPECT_EQ(objects_to_exclude.size(), 0);*/ +/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ +/*EXPECT_EQ(events.size(), 1);*/ +/*}*/ + +/*TEST(TestContext, InputFilterWithCondition)*/ +/*{*/ +/*condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}};*/ +/*condition::target_type usr_id{get_target_index("usr.id"), "usr.id", {}};*/ + +/*auto ruleset = std::make_shared();*/ +/*{*/ +/*std::vector> conditions;*/ +/*std::vector targets{client_ip};*/ +/*auto cond = std::make_shared(*/ +/*std::move(targets), std::make_unique(*/ +/*std::vector{"192.168.0.1"}));*/ +/*conditions.emplace_back(std::move(cond));*/ + +/*std::unordered_map tags{*/ +/*{"type", "type"}, {"category", "category"}};*/ + +/*auto rule = std::make_shared(*/ +/*"id", "name", std::move(tags), std::move(conditions), std::vector{});*/ + +/*ruleset->insert_rule(rule);*/ +/*}*/ + +/*{*/ +/*auto obj_filter = std::make_shared();*/ +/*obj_filter->insert(client_ip.root, client_ip.name);*/ + +/*std::vector> conditions;*/ +/*std::vector targets{usr_id};*/ +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"admin"}));*/ +/*conditions.emplace_back(std::move(cond));*/ + +/*std::set filter_rules{ruleset->rules[0].get()};*/ +/*auto filter = std::make_shared(*/ +/*"1", std::move(conditions), std::move(filter_rules), std::move(obj_filter));*/ + +/*ruleset->input_filters.emplace(filter->get_id(), filter);*/ +/*}*/ + +/*// Without usr.id, nothing should be excluded*/ +/*{*/ +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ctx.insert(root);*/ + +/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ +/*EXPECT_EQ(objects_to_exclude.size(), 0);*/ +/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ +/*EXPECT_EQ(events.size(), 1);*/ +/*}*/ + +/*// With usr.id != admin, nothing should be excluded*/ +/*{*/ +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admino"));*/ +/*ctx.insert(root);*/ + +/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ +/*EXPECT_EQ(objects_to_exclude.size(), 0);*/ +/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ +/*EXPECT_EQ(events.size(), 1);*/ +/*}*/ + +/*// With usr.id == admin, there should be no matches*/ +/*{*/ +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ctx.insert(root);*/ + +/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ +/*EXPECT_EQ(objects_to_exclude.size(), 1);*/ +/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ +/*EXPECT_EQ(events.size(), 0);*/ +/*}*/ +/*}*/ + +/*TEST(TestContext, InputFilterMultipleRules)*/ +/*{*/ +/*condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}};*/ +/*condition::target_type usr_id{get_target_index("usr.id"), "usr.id", {}};*/ + +/*auto ruleset = std::make_shared();*/ +/*{*/ +/*std::vector> conditions;*/ +/*std::vector targets{client_ip};*/ +/*auto cond = std::make_shared(*/ +/*std::move(targets), std::make_unique(*/ +/*std::vector{"192.168.0.1"}));*/ +/*conditions.emplace_back(std::move(cond));*/ + +/*std::unordered_map tags{*/ +/*{"type", "ip_type"}, {"category", "category"}};*/ + +/*auto rule = std::make_shared(*/ +/*"ip_id", "name", std::move(tags), std::move(conditions), std::vector{});*/ + +/*ruleset->insert_rule(rule);*/ +/*}*/ + +/*{*/ +/*std::vector> conditions;*/ +/*std::vector targets{usr_id};*/ +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"admin"}));*/ +/*conditions.emplace_back(std::move(cond));*/ + +/*std::unordered_map tags{*/ +/*{"type", "usr_type"}, {"category", "category"}};*/ + +/*auto rule = std::make_shared(*/ +/*"usr_id", "name", std::move(tags), std::move(conditions), std::vector{});*/ + +/*ruleset->insert_rule(rule);*/ +/*}*/ + +/*{*/ +/*auto obj_filter = std::make_shared();*/ +/*obj_filter->insert(client_ip.root, client_ip.name);*/ +/*obj_filter->insert(usr_id.root, usr_id.name);*/ + +/*std::vector> conditions;*/ +/*std::set filter_rules{ruleset->rules[0].get(), ruleset->rules[1].get()};*/ +/*auto filter = std::make_shared(*/ +/*"1", std::move(conditions), std::move(filter_rules), std::move(obj_filter));*/ + +/*ruleset->input_filters.emplace(filter->get_id(), filter);*/ +/*}*/ + +/*// Without usr.id, nothing should be excluded*/ +/*{*/ +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ctx.insert(root);*/ + +/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ +/*EXPECT_EQ(objects_to_exclude.size(), 2);*/ +/*for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 1); }*/ + +/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ +/*EXPECT_EQ(events.size(), 0);*/ +/*}*/ + +/*// With usr.id != admin, nothing should be excluded*/ +/*{*/ +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admino"));*/ +/*ctx.insert(root);*/ + +/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ +/*EXPECT_EQ(objects_to_exclude.size(), 2);*/ +/*for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 2); }*/ + +/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ +/*EXPECT_EQ(events.size(), 0);*/ +/*}*/ + +/*// With usr.id == admin, there should be no matches*/ +/*{*/ +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ctx.insert(root);*/ + +/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ +/*EXPECT_EQ(objects_to_exclude.size(), 2);*/ +/*for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 2); }*/ + +/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ +/*EXPECT_EQ(events.size(), 0);*/ +/*}*/ +/*}*/ + +/*TEST(TestContext, InputFilterMultipleRulesMultipleFilters)*/ +/*{*/ +/*condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}};*/ +/*condition::target_type usr_id{get_target_index("usr.id"), "usr.id", {}};*/ + +/*auto ruleset = std::make_shared();*/ +/*{*/ +/*std::vector> conditions;*/ +/*std::vector targets{client_ip};*/ +/*auto cond = std::make_shared(*/ +/*std::move(targets), std::make_unique(*/ +/*std::vector{"192.168.0.1"}));*/ +/*conditions.emplace_back(std::move(cond));*/ + +/*std::unordered_map tags{*/ +/*{"type", "ip_type"}, {"category", "category"}};*/ + +/*auto rule = std::make_shared(*/ +/*"ip_id", "name", std::move(tags), std::move(conditions), std::vector{});*/ + +/*ruleset->insert_rule(rule);*/ +/*}*/ + +/*{*/ +/*std::vector> conditions;*/ +/*std::vector targets{usr_id};*/ +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"admin"}));*/ +/*conditions.emplace_back(std::move(cond));*/ + +/*std::unordered_map tags{*/ +/*{"type", "usr_type"}, {"category", "category"}};*/ + +/*auto rule = std::make_shared(*/ +/*"usr_id", "name", std::move(tags), std::move(conditions), std::vector{});*/ + +/*ruleset->insert_rule(rule);*/ +/*}*/ + +/*{*/ +/*auto obj_filter = std::make_shared();*/ +/*obj_filter->insert(client_ip.root, client_ip.name);*/ + +/*std::vector> conditions;*/ +/*std::set filter_rules{ruleset->rules[0].get()};*/ +/*auto filter = std::make_shared(*/ +/*"1", std::move(conditions), std::move(filter_rules), std::move(obj_filter));*/ + +/*ruleset->input_filters.emplace(filter->get_id(), filter);*/ +/*}*/ + +/*{*/ +/*auto obj_filter = std::make_shared();*/ +/*obj_filter->insert(usr_id.root, usr_id.name);*/ + +/*std::vector> conditions;*/ +/*std::set filter_rules{ruleset->rules[1].get()};*/ +/*auto filter = std::make_shared(*/ +/*"2", std::move(conditions), std::move(filter_rules), std::move(obj_filter));*/ + +/*ruleset->input_filters.emplace(filter->get_id(), filter);*/ +/*}*/ + +/*// Without usr.id, nothing should be excluded*/ +/*{*/ +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ctx.insert(root);*/ + +/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ +/*EXPECT_EQ(objects_to_exclude.size(), 1);*/ +/*for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 1); }*/ + +/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ +/*EXPECT_EQ(events.size(), 0);*/ +/*}*/ + +/*// With usr.id != admin, nothing should be excluded*/ +/*{*/ +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admino"));*/ +/*ctx.insert(root);*/ + +/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ +/*EXPECT_EQ(objects_to_exclude.size(), 2);*/ +/*for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 1); }*/ + +/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ +/*EXPECT_EQ(events.size(), 0);*/ +/*}*/ + +/*// With usr.id == admin, there should be no matches*/ +/*{*/ +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ctx.insert(root);*/ + +/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ +/*EXPECT_EQ(objects_to_exclude.size(), 2);*/ +/*for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 1); }*/ + +/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ +/*EXPECT_EQ(events.size(), 0);*/ +/*}*/ +/*}*/ + +/*TEST(TestContext, InputFilterMultipleRulesMultipleFiltersMultipleObjects)*/ +/*{*/ +/*condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}};*/ +/*condition::target_type usr_id{get_target_index("usr.id"), "usr.id", {}};*/ +/*condition::target_type cookie_header{*/ +/*get_target_index("server.request.headers"), "server.request.headers", {"cookie"}};*/ + +/*auto ruleset = std::make_shared();*/ +/*{*/ +/*std::vector> conditions;*/ +/*std::vector targets{client_ip};*/ +/*auto cond = std::make_shared(*/ +/*std::move(targets), std::make_unique(*/ +/*std::vector{"192.168.0.1"}));*/ +/*conditions.emplace_back(std::move(cond));*/ + +/*std::unordered_map tags{*/ +/*{"type", "ip_type"}, {"category", "category"}};*/ + +/*auto rule = std::make_shared(*/ +/*"ip_id", "name", std::move(tags), std::move(conditions), std::vector{});*/ + +/*ruleset->insert_rule(rule);*/ +/*}*/ + +/*{*/ +/*std::vector> conditions;*/ +/*std::vector targets{usr_id};*/ +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"admin"}));*/ +/*conditions.emplace_back(std::move(cond));*/ + +/*std::unordered_map tags{*/ +/*{"type", "usr_type"}, {"category", "category"}};*/ + +/*auto rule = std::make_shared(*/ +/*"usr_id", "name", std::move(tags), std::move(conditions), std::vector{});*/ + +/*ruleset->insert_rule(rule);*/ +/*}*/ + +/*{*/ +/*std::vector> conditions;*/ +/*std::vector targets{cookie_header};*/ +/*auto cond = std::make_shared(std::move(targets),*/ +/*std::make_unique(std::vector{"mycookie"}));*/ +/*conditions.emplace_back(std::move(cond));*/ + +/*std::unordered_map tags{*/ +/*{"type", "cookie_type"}, {"category", "category"}};*/ + +/*auto rule = std::make_shared("cookie_id", "name", std::move(tags),*/ +/*std::move(conditions), std::vector{});*/ + +/*ruleset->insert_rule(rule);*/ +/*}*/ + +/*auto ip_rule = ruleset->rules[0];*/ +/*auto usr_rule = ruleset->rules[1];*/ +/*auto cookie_rule = ruleset->rules[2];*/ +/*{*/ +/*auto obj_filter = std::make_shared();*/ +/*obj_filter->insert(client_ip.root, client_ip.name);*/ +/*obj_filter->insert(cookie_header.root, cookie_header.name);*/ + +/*std::vector> conditions;*/ +/*std::set filter_rules{ip_rule.get(), cookie_rule.get()};*/ +/*auto filter = std::make_shared(*/ +/*"1", std::move(conditions), std::move(filter_rules), std::move(obj_filter));*/ + +/*ruleset->input_filters.emplace(filter->get_id(), filter);*/ +/*}*/ + +/*{*/ +/*auto obj_filter = std::make_shared();*/ +/*obj_filter->insert(usr_id.root, usr_id.name);*/ +/*obj_filter->insert(client_ip.root, client_ip.name);*/ + +/*std::vector> conditions;*/ +/*std::set filter_rules{usr_rule.get(), ip_rule.get()};*/ +/*auto filter = std::make_shared(*/ +/*"2", std::move(conditions), std::move(filter_rules), std::move(obj_filter));*/ + +/*ruleset->input_filters.emplace(filter->get_id(), filter);*/ +/*}*/ + +/*{*/ +/*auto obj_filter = std::make_shared();*/ +/*obj_filter->insert(usr_id.root, usr_id.name);*/ +/*obj_filter->insert(cookie_header.root, cookie_header.name);*/ + +/*std::vector> conditions;*/ +/*std::set filter_rules{usr_rule.get(), cookie_rule.get()};*/ +/*auto filter = std::make_shared(*/ +/*"3", std::move(conditions), std::move(filter_rules), std::move(obj_filter));*/ + +/*ruleset->input_filters.emplace(filter->get_id(), filter);*/ +/*}*/ + +/*{*/ +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ctx.insert(root);*/ + +/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ +/*EXPECT_EQ(objects_to_exclude.size(), 3);*/ +/*for (const auto &[rule, objects] : objects_to_exclude) {*/ +/*EXPECT_EQ(objects.size(), 1);*/ +/*EXPECT_NE(objects.find(&root.array[0]), objects.end());*/ +/*}*/ + +/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ +/*EXPECT_EQ(events.size(), 0);*/ +/*}*/ + +/*{*/ +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ctx.insert(root);*/ + +/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ +/*EXPECT_EQ(objects_to_exclude.size(), 3);*/ +/*for (const auto &[rule, objects] : objects_to_exclude) {*/ +/*EXPECT_EQ(objects.size(), 1);*/ +/*EXPECT_NE(objects.find(&root.array[0]), objects.end());*/ +/*}*/ + +/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ +/*EXPECT_EQ(events.size(), 0);*/ +/*}*/ + +/*{*/ +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*ddwaf_object root;*/ +/*ddwaf_object headers;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&headers);*/ +/*ddwaf_object_map_add(&headers, "cookie", ddwaf_object_string(&tmp, "mycookie"));*/ + +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "server.request.headers", &headers);*/ + +/*ctx.insert(root);*/ + +/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ +/*EXPECT_EQ(objects_to_exclude.size(), 3);*/ +/*for (const auto &[rule, objects] : objects_to_exclude) {*/ +/*EXPECT_EQ(objects.size(), 1);*/ +/*EXPECT_NE(objects.find(&root.array[0]), objects.end());*/ +/*}*/ + +/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ +/*EXPECT_EQ(events.size(), 0);*/ +/*}*/ + +/*{*/ +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*ddwaf_object root;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ctx.insert(root);*/ + +/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ +/*EXPECT_EQ(objects_to_exclude.size(), 3);*/ +/*for (const auto &[rule, objects] : objects_to_exclude) {*/ +/*EXPECT_EQ(objects.size(), 2);*/ +/*EXPECT_NE(objects.find(&root.array[0]), objects.end());*/ +/*EXPECT_NE(objects.find(&root.array[1]), objects.end());*/ +/*}*/ +/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ +/*EXPECT_EQ(events.size(), 0);*/ +/*}*/ + +/*{*/ +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*ddwaf_object root;*/ +/*ddwaf_object headers;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&headers);*/ +/*ddwaf_object_map_add(&headers, "cookie", ddwaf_object_string(&tmp, "mycookie"));*/ + +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ddwaf_object_map_add(&root, "server.request.headers", &headers);*/ + +/*ctx.insert(root);*/ + +/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ +/*EXPECT_EQ(objects_to_exclude.size(), 3);*/ +/*for (const auto &[rule, objects] : objects_to_exclude) {*/ +/*EXPECT_EQ(objects.size(), 2);*/ +/*EXPECT_NE(objects.find(&root.array[0]), objects.end());*/ +/*EXPECT_NE(objects.find(&root.array[1]), objects.end());*/ +/*}*/ +/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ +/*EXPECT_EQ(events.size(), 0);*/ +/*}*/ + +/*{*/ +/*ddwaf::timer deadline{2s};*/ +/*ddwaf::test::context ctx(ruleset);*/ + +/*ddwaf_object root;*/ +/*ddwaf_object headers;*/ +/*ddwaf_object tmp;*/ +/*ddwaf_object_map(&headers);*/ +/*ddwaf_object_map_add(&headers, "cookie", ddwaf_object_string(&tmp, "mycookie"));*/ + +/*ddwaf_object_map(&root);*/ +/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ +/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ +/*ddwaf_object_map_add(&root, "server.request.headers", &headers);*/ + +/*ctx.insert(root);*/ + +/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ +/*EXPECT_EQ(objects_to_exclude.size(), 3);*/ +/*for (const auto &[rule, objects] : objects_to_exclude) {*/ +/*EXPECT_EQ(objects.size(), 3);*/ +/*EXPECT_NE(objects.find(&root.array[0]), objects.end());*/ +/*EXPECT_NE(objects.find(&root.array[1]), objects.end());*/ +/*EXPECT_NE(objects.find(&root.array[2]), objects.end());*/ +/*}*/ +/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ +/*EXPECT_EQ(events.size(), 0);*/ +/*}*/ +/*}*/ diff --git a/tests/expression_test.cpp b/tests/expression_test.cpp index ffdd7f985..90f75d98f 100644 --- a/tests/expression_test.cpp +++ b/tests/expression_test.cpp @@ -29,7 +29,7 @@ TEST(TestExpression, SimpleMatch) ddwaf::timer deadline{2s}; expression::cache_type cache; - EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); + EXPECT_TRUE(expr->eval(cache, store, {}, {}, deadline)); auto matches = expr->get_matches(cache); EXPECT_MATCHES(matches, {.op = "match_regex", @@ -62,7 +62,7 @@ TEST(TestExpression, MultiInputMatchOnSecond) ddwaf::timer deadline{2s}; - EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); + EXPECT_FALSE(expr->eval(cache, store, {}, {}, deadline)); } { @@ -75,7 +75,7 @@ TEST(TestExpression, MultiInputMatchOnSecond) ddwaf::timer deadline{2s}; - EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); + EXPECT_TRUE(expr->eval(cache, store, {}, {}, deadline)); auto matches = expr->get_matches(cache); EXPECT_MATCHES(matches, {.op = "match_regex", @@ -108,7 +108,7 @@ TEST(TestExpression, DuplicateInput) ddwaf::timer deadline{2s}; - EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); + EXPECT_FALSE(expr->eval(cache, store, {}, {}, deadline)); } { @@ -122,7 +122,7 @@ TEST(TestExpression, DuplicateInput) ddwaf::timer deadline{2s}; - EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); + EXPECT_TRUE(expr->eval(cache, store, {}, {}, deadline)); } } @@ -146,7 +146,7 @@ TEST(TestExpression, MatchDuplicateInputNoCache) ddwaf::timer deadline{2s}; expression::cache_type cache; - EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); + EXPECT_FALSE(expr->eval(cache, store, {}, {}, deadline)); } { @@ -161,7 +161,7 @@ TEST(TestExpression, MatchDuplicateInputNoCache) ddwaf::timer deadline{2s}; expression::cache_type cache; - EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); + EXPECT_TRUE(expr->eval(cache, store, {}, {}, deadline)); auto matches = expr->get_matches(cache); EXPECT_MATCHES(matches, {.op = "match_regex", @@ -198,7 +198,7 @@ TEST(TestExpression, TwoConditionsSingleInputNoMatch) ddwaf::timer deadline{2s}; - EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); + EXPECT_FALSE(expr->eval(cache, store, {}, {}, deadline)); } { @@ -212,7 +212,7 @@ TEST(TestExpression, TwoConditionsSingleInputNoMatch) ddwaf::timer deadline{2s}; - EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); + EXPECT_TRUE(expr->eval(cache, store, {}, {}, deadline)); } } @@ -239,7 +239,7 @@ TEST(TestExpression, TwoConditionsSingleInputMatch) ddwaf::timer deadline{2s}; expression::cache_type cache; - EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); + EXPECT_TRUE(expr->eval(cache, store, {}, {}, deadline)); } TEST(TestExpression, TwoConditionsMultiInputSingleEvalMatch) @@ -267,7 +267,7 @@ TEST(TestExpression, TwoConditionsMultiInputSingleEvalMatch) ddwaf::timer deadline{2s}; - EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); + EXPECT_TRUE(expr->eval(cache, store, {}, {}, deadline)); } TEST(TestExpression, TwoConditionsMultiInputMultiEvalMatch) @@ -295,7 +295,7 @@ TEST(TestExpression, TwoConditionsMultiInputMultiEvalMatch) ddwaf::timer deadline{2s}; - EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); + EXPECT_FALSE(expr->eval(cache, store, {}, {}, deadline)); } { @@ -310,7 +310,7 @@ TEST(TestExpression, TwoConditionsMultiInputMultiEvalMatch) ddwaf::timer deadline{2s}; - EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); + EXPECT_TRUE(expr->eval(cache, store, {}, {}, deadline)); } } @@ -338,7 +338,7 @@ TEST(TestExpression, SingleObjectChain) ddwaf::timer deadline{2s}; expression::cache_type cache; - EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); + EXPECT_FALSE(expr->eval(cache, store, {}, {}, deadline)); } { @@ -358,7 +358,7 @@ TEST(TestExpression, SingleObjectChain) ddwaf::timer deadline{2s}; expression::cache_type cache; - EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); + EXPECT_TRUE(expr->eval(cache, store, {}, {}, deadline)); } } @@ -391,7 +391,7 @@ TEST(TestExpression, SingleScalarChain) ddwaf::timer deadline{2s}; expression::cache_type cache; - EXPECT_FALSE(expr->eval(cache, store, {}, deadline)); + EXPECT_FALSE(expr->eval(cache, store, {}, {}, deadline)); } { @@ -412,7 +412,7 @@ TEST(TestExpression, SingleScalarChain) ddwaf::timer deadline{2s}; expression::cache_type cache; - EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); + EXPECT_TRUE(expr->eval(cache, store, {}, {}, deadline)); auto matches = expr->get_matches(cache); EXPECT_MATCHES(matches, @@ -454,7 +454,7 @@ TEST(TestExpression, SingleHighlightChain) ddwaf::timer deadline{2s}; expression::cache_type cache; - EXPECT_TRUE(expr->eval(cache, store, {}, deadline)); + EXPECT_TRUE(expr->eval(cache, store, {}, {}, deadline)); auto matches = expr->get_matches(cache); EXPECT_MATCHES(matches, diff --git a/tests/mkmap_test.cpp b/tests/mkmap_test.cpp index 7a8221712..b7b6b2468 100644 --- a/tests/mkmap_test.cpp +++ b/tests/mkmap_test.cpp @@ -33,7 +33,7 @@ TEST(TestMultiKeyMap, Find) tags.emplace("category", spec.category); auto rule_ptr = std::make_shared( - std::string(spec.id), "name", decltype(tags)(tags), std::vector{}); + std::string(spec.id), "name", decltype(tags)(tags), expression::ptr{}); rules.emplace_back(rule_ptr); ruledb.insert(rule_ptr->get_tags(), rule_ptr.get()); } @@ -98,7 +98,7 @@ TEST(TestMultiKeyMap, Multifind) tags.emplace("category", spec.category); auto rule_ptr = std::make_shared( - std::string(spec.id), "name", decltype(tags)(tags), std::vector{}); + std::string(spec.id), "name", decltype(tags)(tags), expression::ptr{}); rules.emplace_back(rule_ptr); ruledb.insert(rule_ptr->get_tags(), rule_ptr.get()); } diff --git a/tests/parser_v2_rules_test.cpp b/tests/parser_v2_rules_test.cpp index 4ea8b3168..76c9ff188 100644 --- a/tests/parser_v2_rules_test.cpp +++ b/tests/parser_v2_rules_test.cpp @@ -43,7 +43,7 @@ TEST(TestParserV2Rules, ParseRule) parser::rule_spec &rule = rules["1"]; EXPECT_TRUE(rule.enabled); - EXPECT_EQ(rule.conditions.size(), 3); + EXPECT_EQ(rule.expr->get_num_conditions(), 3); EXPECT_EQ(rule.actions.size(), 0); EXPECT_STR(rule.name, "rule1"); EXPECT_EQ(rule.tags.size(), 2); @@ -175,7 +175,7 @@ TEST(TestParserV2Rules, ParseMultipleRules) { parser::rule_spec &rule = rules["1"]; EXPECT_TRUE(rule.enabled); - EXPECT_EQ(rule.conditions.size(), 3); + EXPECT_EQ(rule.expr->get_num_conditions(), 3); EXPECT_EQ(rule.actions.size(), 0); EXPECT_STR(rule.name, "rule1"); EXPECT_EQ(rule.tags.size(), 2); @@ -186,7 +186,7 @@ TEST(TestParserV2Rules, ParseMultipleRules) { parser::rule_spec &rule = rules["secondrule"]; EXPECT_TRUE(rule.enabled); - EXPECT_EQ(rule.conditions.size(), 1); + EXPECT_EQ(rule.expr->get_num_conditions(), 1); EXPECT_EQ(rule.actions.size(), 1); EXPECT_STR(rule.actions[0], "block"); EXPECT_STR(rule.name, "rule2"); @@ -245,7 +245,7 @@ TEST(TestParserV2Rules, ParseMultipleRulesOneInvalid) { parser::rule_spec &rule = rules["1"]; EXPECT_TRUE(rule.enabled); - EXPECT_EQ(rule.conditions.size(), 3); + EXPECT_EQ(rule.expr->get_num_conditions(), 3); EXPECT_EQ(rule.actions.size(), 0); EXPECT_STR(rule.name, "rule1"); EXPECT_EQ(rule.tags.size(), 2); @@ -256,7 +256,7 @@ TEST(TestParserV2Rules, ParseMultipleRulesOneInvalid) { parser::rule_spec &rule = rules["secondrule"]; EXPECT_TRUE(rule.enabled); - EXPECT_EQ(rule.conditions.size(), 1); + EXPECT_EQ(rule.expr->get_num_conditions(), 1); EXPECT_EQ(rule.actions.size(), 1); EXPECT_STR(rule.actions[0], "block"); EXPECT_STR(rule.name, "rule2"); @@ -314,7 +314,7 @@ TEST(TestParserV2Rules, ParseMultipleRulesOneDuplicate) { parser::rule_spec &rule = rules["1"]; EXPECT_TRUE(rule.enabled); - EXPECT_EQ(rule.conditions.size(), 3); + EXPECT_EQ(rule.expr->get_num_conditions(), 3); EXPECT_EQ(rule.actions.size(), 0); EXPECT_STR(rule.name, "rule1"); EXPECT_EQ(rule.tags.size(), 2); diff --git a/tests/rule_test.cpp b/tests/rule_test.cpp index e92d922bd..c5c8a4c9e 100644 --- a/tests/rule_test.cpp +++ b/tests/rule_test.cpp @@ -10,20 +10,16 @@ using namespace ddwaf; TEST(TestRule, Match) { - std::vector targets; - - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"192.168.0.1"})); - - std::vector> conditions{std::move(cond)}; + expression_builder builder(1); + builder.start_condition(std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); std::unordered_map tags{{"type", "type"}, {"category", "category"}}; ddwaf::rule rule( - "id", "name", std::move(tags), std::move(conditions), {"update", "block", "passlist"}); + "id", "name", std::move(tags), builder.build(), {"update", "block", "passlist"}); - ddwaf_object root, tmp; + ddwaf_object root; + ddwaf_object tmp; ddwaf_object_map(&root); ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); @@ -55,18 +51,15 @@ TEST(TestRule, Match) TEST(TestRule, NoMatch) { - std::vector targets; + expression_builder builder(1); + builder.start_condition(std::vector{}); + builder.add_target("http.client_ip"); - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{})); - - std::vector> conditions{std::move(cond)}; std::unordered_map tags{{"type", "type"}, {"category", "category"}}; - ddwaf::rule rule("id", "name", std::move(tags), std::move(conditions)); + ddwaf::rule rule("id", "name", std::move(tags), builder.build()); - ddwaf_object root, tmp; + ddwaf_object root; + ddwaf_object tmp; ddwaf_object_map(&root); ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); @@ -82,35 +75,24 @@ TEST(TestRule, NoMatch) TEST(TestRule, ValidateCachedMatch) { - std::vector> conditions; + expression_builder builder(2); + builder.start_condition(std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); - { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); - conditions.push_back(std::move(cond)); - } - - { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); - conditions.push_back(std::move(cond)); - } + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); std::unordered_map tags{{"type", "type"}, {"category", "category"}}; - ddwaf::rule rule("id", "name", std::move(tags), std::move(conditions)); + ddwaf::rule rule("id", "name", std::move(tags), builder.build()); ddwaf::rule::cache_type cache; // To validate that the cache works, we pass an object store containing // only the latest address. This ensures that the IP condition can't be // matched on the second run. { - ddwaf_object root, tmp; + ddwaf_object root; + ddwaf_object tmp; ddwaf_object_map(&root); ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); @@ -123,7 +105,8 @@ TEST(TestRule, ValidateCachedMatch) } { - ddwaf_object root, tmp; + ddwaf_object root; + ddwaf_object tmp; ddwaf_object_map(&root); ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); @@ -163,28 +146,16 @@ TEST(TestRule, ValidateCachedMatch) TEST(TestRule, MatchWithoutCache) { - std::vector> conditions; + expression_builder builder(2); + builder.start_condition(std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); - { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); - conditions.push_back(std::move(cond)); - } - - { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); - conditions.push_back(std::move(cond)); - } + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); std::unordered_map tags{{"type", "type"}, {"category", "category"}}; - ddwaf::rule rule("id", "name", std::move(tags), std::move(conditions)); + ddwaf::rule rule("id", "name", std::move(tags), builder.build()); // In this instance we pass a complete store with both addresses but an // empty cache on every run to ensure that both conditions are matched on @@ -238,28 +209,16 @@ TEST(TestRule, MatchWithoutCache) TEST(TestRule, NoMatchWithoutCache) { - std::vector> conditions; - - { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); - conditions.push_back(std::move(cond)); - } + expression_builder builder(2); + builder.start_condition(std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); - { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); - conditions.push_back(std::move(cond)); - } + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); std::unordered_map tags{{"type", "type"}, {"category", "category"}}; - ddwaf::rule rule("id", "name", std::move(tags), std::move(conditions)); + ddwaf::rule rule("id", "name", std::move(tags), builder.build()); // In this test we validate that when the cache is empty and only one // address is passed, the filter doesn't match (as it should be). @@ -296,26 +255,16 @@ TEST(TestRule, FullCachedMatchSecondRun) { std::vector> conditions; - { - std::vector targets; - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - auto cond = std::make_shared( - std::move(targets), std::make_unique( - std::vector{"192.168.0.1"})); - conditions.push_back(std::move(cond)); - } + expression_builder builder(2); + builder.start_condition(std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); - { - std::vector targets; - targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"admin"})); - conditions.push_back(std::move(cond)); - } + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); std::unordered_map tags{{"type", "type"}, {"category", "category"}}; - ddwaf::rule rule("id", "name", std::move(tags), std::move(conditions)); + ddwaf::rule rule("id", "name", std::move(tags), builder.build()); // In this test we validate that when a match has already occurred, the // second run for the same rule returns no events regardless of input. @@ -352,18 +301,15 @@ TEST(TestRule, FullCachedMatchSecondRun) TEST(TestRule, ExcludeObject) { - std::vector targets; - - targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); - auto cond = std::make_shared(std::move(targets), - std::make_unique(std::vector{"192.168.0.1"})); + expression_builder builder(1); + builder.start_condition(std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); - std::vector> conditions{std::move(cond)}; std::unordered_map tags{{"type", "type"}, {"category", "category"}}; ddwaf::rule rule( - "id", "name", std::move(tags), std::move(conditions), {"update", "block", "passlist"}); + "id", "name", std::move(tags), builder.build(), {"update", "block", "passlist"}); ddwaf_object root, tmp; ddwaf_object_map(&root); diff --git a/tests/ruleset_test.cpp b/tests/ruleset_test.cpp index 8d81a0157..516038ad9 100644 --- a/tests/ruleset_test.cpp +++ b/tests/ruleset_test.cpp @@ -15,7 +15,7 @@ rule::ptr make_rule(std::string id, std::string name, rule::source_type source = rule::source_type::base) { return std::make_shared(std::move(id), std::move(name), std::move(tags), - std::vector{}, std::move(actions), true, source); + expression::ptr{}, std::move(actions), true, source); } } // namespace From 11bb35ec1cae29a54d83982bd9e03386d2a4ba15 Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Thu, 29 Jun 2023 16:40:02 +0100 Subject: [PATCH 18/28] Minor fix --- src/expression.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/expression.hpp b/src/expression.hpp index 7ba030e9f..caf83b327 100644 --- a/src/expression.hpp +++ b/src/expression.hpp @@ -166,7 +166,7 @@ class expression { } // For testing - [[nodiscard]] constexpr std::size_t get_num_conditions() const { return conditions_.size(); } + [[nodiscard]] std::size_t get_num_conditions() const { return conditions_.size(); } protected: ddwaf::object_limits limits_; From 07a4e98227251b4f3a49f0c8c8dbb83295741729 Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Thu, 29 Jun 2023 17:15:17 +0100 Subject: [PATCH 19/28] Add validator tests for chained eval --- .../chained_evaluation/001_scalar_chain.yaml | 31 ++++++ .../002_highlight_chain.yaml | 38 ++++++++ .../chained_evaluation/003_object_chain.yaml | 35 +++++++ .../rules/chained_evaluation/ruleset.yaml | 94 +++++++++++++++++++ 4 files changed, 198 insertions(+) create mode 100644 validator/tests/rules/chained_evaluation/001_scalar_chain.yaml create mode 100644 validator/tests/rules/chained_evaluation/002_highlight_chain.yaml create mode 100644 validator/tests/rules/chained_evaluation/003_object_chain.yaml create mode 100644 validator/tests/rules/chained_evaluation/ruleset.yaml diff --git a/validator/tests/rules/chained_evaluation/001_scalar_chain.yaml b/validator/tests/rules/chained_evaluation/001_scalar_chain.yaml new file mode 100644 index 000000000..6482a2e45 --- /dev/null +++ b/validator/tests/rules/chained_evaluation/001_scalar_chain.yaml @@ -0,0 +1,31 @@ +{ + name: "Basic run with match", + runs: [ + { + input: { + server.request.query: processbuilder.base64data + }, + rules: [ + { + exp-000-001: [ + { + address: server.request.query, + value: processbuilder.base64data, + highlight: [ + processbuilder + ] + }, + { + address: match.0.scalar, + value: processbuilder.base64data, + highlight: [ + base64data + ] + }, + ] + } + ], + code: match + } + ] +} diff --git a/validator/tests/rules/chained_evaluation/002_highlight_chain.yaml b/validator/tests/rules/chained_evaluation/002_highlight_chain.yaml new file mode 100644 index 000000000..03104e379 --- /dev/null +++ b/validator/tests/rules/chained_evaluation/002_highlight_chain.yaml @@ -0,0 +1,38 @@ +{ + name: "Basic run with match", + runs: [ + { + input: { + server.request.query: "evil_exploit:ZXhlYyh0YWtlX292ZXJfd29ybGQp" + }, + rules: [ + { + exp-000-002: [ + { + address: server.request.query, + value: "evil_exploit:ZXhlYyh0YWtlX292ZXJfd29ybGQp", + highlight: [ + "evil_exploit:ZXhlYyh0YWtlX292ZXJfd29ybGQp" + ] + }, + { + address: match.0.highlight, + value: "evil_exploit:ZXhlYyh0YWtlX292ZXJfd29ybGQp", + highlight: [ + ZXhlYyh0YWtlX292ZXJfd29ybGQp + ] + }, + { + address: match.1.highlight, + value: exec(take_over_world), + highlight: [ + exec + ] + } + ] + } + ], + code: match + } + ] +} diff --git a/validator/tests/rules/chained_evaluation/003_object_chain.yaml b/validator/tests/rules/chained_evaluation/003_object_chain.yaml new file mode 100644 index 000000000..77349b9ff --- /dev/null +++ b/validator/tests/rules/chained_evaluation/003_object_chain.yaml @@ -0,0 +1,35 @@ +{ + name: "Basic run with match", + runs: [ + { + input: { + server.request.query: { + comment : { + text: "we're going to try to exec() something" + } + } + }, + rules: [ + { + exp-000-003: [ + { + address: server.request.query, + value: "we're going to try to exec() something", + highlight: [ + exec( + ] + }, + { + address: match.0.object, + value: comment, + highlight: [ + comment + ] + }, + ] + } + ], + code: match + } + ] +} diff --git a/validator/tests/rules/chained_evaluation/ruleset.yaml b/validator/tests/rules/chained_evaluation/ruleset.yaml new file mode 100644 index 000000000..7fce8e6d7 --- /dev/null +++ b/validator/tests/rules/chained_evaluation/ruleset.yaml @@ -0,0 +1,94 @@ +version: '2.1' +rules: + - id: exp-000-001 + name: 'Chained scalar' + tags: + type: java_code_injection + crs_id: '944110' + category: attack_attempt + conditions: + - parameters: + inputs: + - address: server.request.query + - address: server.request.body + - address: server.request.path_params + - address: server.request.headers.no_cookies + - address: grpc.server.request.message + regex: (?:runtime|processbuilder) + options: + case_sensitive: true + min_length: 7 + operator: match_regex + - parameters: + inputs: + - address: match.0.scalar + regex: (?:unmarshaller|base64data|java\.) + options: + case_sensitive: true + min_length: 5 + operator: match_regex + transformers: + - lowercase + - id: exp-000-002 + name: 'Chained highlight' + tags: + type: java_code_injection + category: attack_attempt + conditions: + - parameters: + inputs: + - address: server.request.query + - address: server.request.body + - address: server.request.path_params + - address: server.request.headers.no_cookies + - address: grpc.server.request.message + regex: evil_exploit:[A-Za-z0-9+/=]+ + options: + case_sensitive: true + operator: match_regex + - parameters: + inputs: + - address: match.0.highlight + regex: "[A-Za-z0-9+/]+={0,3}$" + options: + case_sensitive: true + min_length: 4 + operator: match_regex + - parameters: + inputs: + - address: match.1.highlight + transformers: + - base64Decode + regex: \bexec\b + options: + case_sensitive: true + min_length: 5 + operator: match_regex + - id: exp-000-003 + name: 'Chained object' + tags: + type: java_code_injection + category: attack_attempt + conditions: + - parameters: + inputs: + - address: server.request.query + - address: server.request.body + - address: server.request.path_params + - address: server.request.headers.no_cookies + - address: grpc.server.request.message + regex: \bexec\( + options: + case_sensitive: true + min_length: 5 + operator: match_regex + - parameters: + inputs: + - address: match.0.object + transformers: + - keys_only + regex: \bcomment\b + options: + case_sensitive: true + min_length: 5 + operator: match_regex From d8dcae3a977f17a1d78857d30e0ebdf2f1b5e554 Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Thu, 29 Jun 2023 17:41:29 +0100 Subject: [PATCH 20/28] Fix more tests --- tests/context_test.cpp | 1132 ++++++++++++++++++---------------------- 1 file changed, 522 insertions(+), 610 deletions(-) diff --git a/tests/context_test.cpp b/tests/context_test.cpp index df6f2a2a0..690d385f4 100644 --- a/tests/context_test.cpp +++ b/tests/context_test.cpp @@ -45,702 +45,614 @@ TEST(TestContext, MatchTimeout) EXPECT_THROW(ctx.match({}, {}, deadline), ddwaf::timeout_exception); } -/*TEST(TestContext, NoMatch)*/ -/*{*/ -/*std::vector targets;*/ +TEST(TestContext, NoMatch) +{ + expression_builder builder(1); + builder.start_condition(std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); -/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ + std::unordered_map tags{{"type", "type"}, {"category", "category"}}; -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"192.168.0.1"}));*/ + auto rule = std::make_shared("id", "name", std::move(tags), builder.build()); -/*std::vector> conditions{std::move(cond)};*/ + auto ruleset = std::make_shared(); + ruleset->insert_rule(rule); -/*std::unordered_map tags{{"type", "type"}, {"category", "category"}};*/ + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); -/*auto rule = std::make_shared(*/ -/*"id", "name", std::move(tags), std::move(conditions), std::vector{});*/ + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.2")); + ctx.insert(root); -/*auto ruleset = std::make_shared();*/ -/*ruleset->insert_rule(rule);*/ + auto events = ctx.match({}, {}, deadline); + EXPECT_EQ(events.size(), 0); +} -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ +TEST(TestContext, Match) +{ + expression_builder builder(1); + builder.start_condition(std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.2"));*/ -/*ctx.insert(root);*/ + std::unordered_map tags{{"type", "type"}, {"category", "category"}}; -/*auto events = ctx.match({}, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 0);*/ -/*}*/ + auto rule = std::make_shared("id", "name", std::move(tags), builder.build()); -/*TEST(TestContext, Match)*/ -/*{*/ -/*std::vector targets;*/ + auto ruleset = std::make_shared(); + ruleset->insert_rule(rule); -/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"192.168.0.1"}));*/ + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ctx.insert(root); -/*std::vector> conditions{std::move(cond)};*/ + auto events = ctx.match({}, {}, deadline); + EXPECT_EQ(events.size(), 1); +} -/*std::unordered_map tags{{"type", "type"}, {"category", "category"}};*/ +TEST(TestContext, MatchMultipleRulesInCollectionSingleRun) +{ + auto ruleset = std::make_shared(); + { + expression_builder builder(1); + builder.start_condition( + std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); -/*auto rule = std::make_shared(*/ -/*"id", "name", std::move(tags), std::move(conditions), std::vector{});*/ + std::unordered_map tags{ + {"type", "type"}, {"category", "category1"}}; -/*auto ruleset = std::make_shared();*/ -/*ruleset->insert_rule(rule);*/ + auto rule = std::make_shared("id1", "name1", std::move(tags), builder.build()); -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ + ruleset->insert_rule(rule); + } -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ctx.insert(root);*/ + { + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); -/*auto events = ctx.match({}, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 1);*/ -/*}*/ + std::unordered_map tags{ + {"type", "type"}, {"category", "category2"}}; -/*TEST(TestContext, MatchMultipleRulesInCollectionSingleRun)*/ -/*{*/ -/*auto ruleset = std::make_shared();*/ -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ + auto rule = std::make_shared("id2", "name2", std::move(tags), builder.build()); -/*auto cond = std::make_shared(*/ -/*std::move(targets), std::make_unique(*/ -/*std::vector{"192.168.0.1"}));*/ + ruleset->insert_rule(rule); + } -/*std::vector> conditions{std::move(cond)};*/ + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); -/*std::unordered_map tags{*/ -/*{"type", "type"}, {"category", "category1"}};*/ + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ctx.insert(root); -/*auto rule = std::make_shared(*/ -/*"id1", "name1", std::move(tags), std::move(conditions), std::vector{});*/ + auto events = ctx.match({}, {}, deadline); + EXPECT_EQ(events.size(), 1); + + auto &event = events[0]; + EXPECT_STREQ(event.rule->get_id().c_str(), "id1"); + EXPECT_STREQ(event.rule->get_name().c_str(), "name1"); + EXPECT_STREQ(event.rule->get_tag("type").data(), "type"); + EXPECT_STREQ(event.rule->get_tag("category").data(), "category1"); + std::vector expected_actions{}; + EXPECT_EQ(event.rule->get_actions(), expected_actions); + EXPECT_EQ(event.matches.size(), 1); + + auto &match = event.matches[0]; + EXPECT_STREQ(match.resolved.c_str(), "192.168.0.1"); + EXPECT_STREQ(match.matched.c_str(), "192.168.0.1"); + EXPECT_STREQ(match.operator_name.data(), "ip_match"); + EXPECT_STREQ(match.operator_value.data(), ""); + EXPECT_STREQ(match.address.data(), "http.client_ip"); + EXPECT_TRUE(match.key_path.empty()); +} -/*ruleset->insert_rule(rule);*/ -/*}*/ +TEST(TestContext, MatchMultipleRulesWithPrioritySingleRun) +{ + auto ruleset = std::make_shared(); + { + expression_builder builder(1); + builder.start_condition( + std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); + + std::unordered_map tags{ + {"type", "type"}, {"category", "category1"}}; + + auto rule = std::make_shared("id1", "name1", std::move(tags), builder.build()); + + ruleset->insert_rule(rule); + } + + { + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); + + std::unordered_map tags{ + {"type", "type"}, {"category", "category2"}}; + + auto rule = std::make_shared( + "id2", "name2", std::move(tags), builder.build(), std::vector{"block"}); + + ruleset->insert_rule(rule); + } + + { + ddwaf::test::context ctx(ruleset); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ctx.insert(root); + + ddwaf::timer deadline{2s}; + auto events = ctx.match({}, {}, deadline); + EXPECT_EQ(events.size(), 1); + + auto event = events[0]; + EXPECT_STREQ(event.rule->get_id().c_str(), "id2"); + EXPECT_EQ(event.rule->get_actions().size(), 1); + EXPECT_STREQ(event.rule->get_actions()[0].data(), "block"); + } + + { + ddwaf::test::context ctx(ruleset); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ctx.insert(root); + + ddwaf::timer deadline{2s}; + auto events = ctx.match({}, {}, deadline); + EXPECT_EQ(events.size(), 1); + + auto event = events[0]; + EXPECT_STREQ(event.rule->get_id().c_str(), "id2"); + EXPECT_EQ(event.rule->get_actions().size(), 1); + EXPECT_STREQ(event.rule->get_actions()[0].data(), "block"); + } +} -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ +TEST(TestContext, MatchMultipleRulesInCollectionDoubleRun) +{ + auto ruleset = std::make_shared(); + { + expression_builder builder(1); + builder.start_condition( + std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"admin"}));*/ + std::unordered_map tags{ + {"type", "type"}, {"category", "category1"}}; -/*std::vector> conditions{std::move(cond)};*/ + auto rule = std::make_shared("id1", "name1", std::move(tags), builder.build()); -/*std::unordered_map tags{*/ -/*{"type", "type"}, {"category", "category2"}};*/ + ruleset->insert_rule(rule); + } -/*auto rule = std::make_shared(*/ -/*"id2", "name2", std::move(tags), std::move(conditions), std::vector{});*/ + { + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); -/*ruleset->insert_rule(rule);*/ -/*}*/ + std::unordered_map tags{ + {"type", "type"}, {"category", "category2"}}; -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ + auto rule = std::make_shared("id2", "name2", std::move(tags), builder.build()); -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ctx.insert(root);*/ + ruleset->insert_rule(rule); + } -/*auto events = ctx.match({}, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 1);*/ + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); -/*auto &event = events[0];*/ -/*EXPECT_STREQ(event.rule->get_id().c_str(), "id1");*/ -/*EXPECT_STREQ(event.rule->get_name().c_str(), "name1");*/ -/*EXPECT_STREQ(event.rule->get_tag("type").data(), "type");*/ -/*EXPECT_STREQ(event.rule->get_tag("category").data(), "category1");*/ -/*std::vector expected_actions{};*/ -/*EXPECT_EQ(event.rule->get_actions(), expected_actions);*/ -/*EXPECT_EQ(event.matches.size(), 1);*/ + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ctx.insert(root); + + auto events = ctx.match({}, {}, deadline); + EXPECT_EQ(events.size(), 1); + + auto &event = events[0]; + EXPECT_STREQ(event.rule->get_id().c_str(), "id1"); + EXPECT_STREQ(event.rule->get_name().c_str(), "name1"); + EXPECT_STREQ(event.rule->get_tag("type").data(), "type"); + EXPECT_STREQ(event.rule->get_tag("category").data(), "category1"); + std::vector expected_actions{}; + EXPECT_EQ(event.rule->get_actions(), expected_actions); + EXPECT_EQ(event.matches.size(), 1); + + auto &match = event.matches[0]; + EXPECT_STREQ(match.resolved.c_str(), "192.168.0.1"); + EXPECT_STREQ(match.matched.c_str(), "192.168.0.1"); + EXPECT_STREQ(match.operator_name.data(), "ip_match"); + EXPECT_STREQ(match.operator_value.data(), ""); + EXPECT_STREQ(match.address.data(), "http.client_ip"); + EXPECT_TRUE(match.key_path.empty()); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ctx.insert(root); + + auto events = ctx.match({}, {}, deadline); + EXPECT_EQ(events.size(), 0); + } +} -/*auto &match = event.matches[0];*/ -/*EXPECT_STREQ(match.resolved.c_str(), "192.168.0.1");*/ -/*EXPECT_STREQ(match.matched.c_str(), "192.168.0.1");*/ -/*EXPECT_STREQ(match.operator_name.data(), "ip_match");*/ -/*EXPECT_STREQ(match.operator_value.data(), "");*/ -/*EXPECT_STREQ(match.address.data(), "http.client_ip");*/ -/*EXPECT_TRUE(match.key_path.empty());*/ -/*}*/ +TEST(TestContext, MatchMultipleRulesWithPriorityDoubleRunPriorityLast) +{ + auto ruleset = std::make_shared(); + { + expression_builder builder(1); + builder.start_condition( + std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); -/*TEST(TestContext, MatchMultipleRulesWithPrioritySingleRun)*/ -/*{*/ -/*auto ruleset = std::make_shared();*/ -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ + std::unordered_map tags{ + {"type", "type"}, {"category", "category1"}}; -/*auto cond = std::make_shared(*/ -/*std::move(targets), std::make_unique(*/ -/*std::vector{"192.168.0.1"}));*/ + auto rule = std::make_shared("id1", "name1", std::move(tags), builder.build()); -/*std::vector> conditions{std::move(cond)};*/ + ruleset->insert_rule(rule); + } -/*std::unordered_map tags{*/ -/*{"type", "type"}, {"category", "category1"}};*/ + { + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); -/*auto rule = std::make_shared(*/ -/*"id1", "name1", std::move(tags), std::move(conditions), std::vector{});*/ + std::unordered_map tags{ + {"type", "type"}, {"category", "category2"}}; -/*ruleset->insert_rule(rule);*/ -/*}*/ + auto rule = std::make_shared( + "id2", "name2", std::move(tags), builder.build(), std::vector{"block"}); -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ + ruleset->insert_rule(rule); + } + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"admin"}));*/ + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ctx.insert(root); + + auto events = ctx.match({}, {}, deadline); + EXPECT_EQ(events.size(), 1); + + auto &event = events[0]; + EXPECT_STREQ(event.rule->get_id().c_str(), "id1"); + EXPECT_STREQ(event.rule->get_name().c_str(), "name1"); + EXPECT_STREQ(event.rule->get_tag("type").data(), "type"); + EXPECT_STREQ(event.rule->get_tag("category").data(), "category1"); + std::vector expected_actions{}; + EXPECT_EQ(event.rule->get_actions(), expected_actions); + EXPECT_EQ(event.matches.size(), 1); + + auto &match = event.matches[0]; + EXPECT_STREQ(match.resolved.c_str(), "192.168.0.1"); + EXPECT_STREQ(match.matched.c_str(), "192.168.0.1"); + EXPECT_STREQ(match.operator_name.data(), "ip_match"); + EXPECT_STREQ(match.operator_value.data(), ""); + EXPECT_STREQ(match.address.data(), "http.client_ip"); + EXPECT_TRUE(match.key_path.empty()); + } + + { + // An existing match in a collection will not inhibit a match in a + // priority collection. + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ctx.insert(root); + + auto events = ctx.match({}, {}, deadline); + EXPECT_EQ(events.size(), 1); + + auto &event = events[0]; + EXPECT_EQ(events.size(), 1); + EXPECT_STREQ(event.rule->get_id().c_str(), "id2"); + EXPECT_STREQ(event.rule->get_name().c_str(), "name2"); + EXPECT_STREQ(event.rule->get_tag("type").data(), "type"); + EXPECT_STREQ(event.rule->get_tag("category").data(), "category2"); + std::vector expected_actions{"block"}; + EXPECT_EQ(event.rule->get_actions(), expected_actions); + EXPECT_EQ(event.matches.size(), 1); + + auto &match = event.matches[0]; + EXPECT_STREQ(match.resolved.c_str(), "admin"); + EXPECT_STREQ(match.matched.c_str(), "admin"); + EXPECT_STREQ(match.operator_name.data(), "exact_match"); + EXPECT_STREQ(match.operator_value.data(), ""); + EXPECT_STREQ(match.address.data(), "usr.id"); + EXPECT_TRUE(match.key_path.empty()); + } +} -/*std::vector> conditions{std::move(cond)};*/ +TEST(TestContext, MatchMultipleRulesWithPriorityDoubleRunPriorityFirst) +{ + auto ruleset = std::make_shared(); + { + expression_builder builder(1); + builder.start_condition( + std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); -/*std::unordered_map tags{*/ -/*{"type", "type"}, {"category", "category2"}};*/ + std::unordered_map tags{ + {"type", "type"}, {"category", "category1"}}; -/*// This rule has actions, so it'll be have priority*/ -/*auto rule = std::make_shared("id2", "name2", std::move(tags),*/ -/*std::move(conditions), std::vector{"block"});*/ + auto rule = std::make_shared( + "id1", "name1", std::move(tags), builder.build(), std::vector{"block"}); -/*ruleset->insert_rule(rule);*/ -/*}*/ + ruleset->insert_rule(rule); + } -/*{*/ -/*ddwaf::test::context ctx(ruleset);*/ + { + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ctx.insert(root);*/ + std::unordered_map tags{ + {"type", "type"}, {"category", "category2"}}; -/*ddwaf::timer deadline{2s};*/ -/*auto events = ctx.match({}, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 1);*/ + auto rule = std::make_shared("id2", "name2", std::move(tags), builder.build()); -/*auto event = events[0];*/ -/*EXPECT_STREQ(event.rule->get_id().c_str(), "id2");*/ -/*EXPECT_EQ(event.rule->get_actions().size(), 1);*/ -/*EXPECT_STREQ(event.rule->get_actions()[0].data(), "block");*/ -/*}*/ + ruleset->insert_rule(rule); + } -/*{*/ -/*ddwaf::test::context ctx(ruleset);*/ + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ctx.insert(root);*/ + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ctx.insert(root); + + auto events = ctx.match({}, {}, deadline); + EXPECT_EQ(events.size(), 1); + + auto &event = events[0]; + EXPECT_STREQ(event.rule->get_id().c_str(), "id1"); + EXPECT_STREQ(event.rule->get_name().c_str(), "name1"); + EXPECT_STREQ(event.rule->get_tag("type").data(), "type"); + EXPECT_STREQ(event.rule->get_tag("category").data(), "category1"); + std::vector expected_actions{"block"}; + EXPECT_EQ(event.rule->get_actions(), expected_actions); + EXPECT_EQ(event.matches.size(), 1); + + auto &match = event.matches[0]; + EXPECT_STREQ(match.resolved.c_str(), "192.168.0.1"); + EXPECT_STREQ(match.matched.c_str(), "192.168.0.1"); + EXPECT_STREQ(match.operator_name.data(), "ip_match"); + EXPECT_STREQ(match.operator_value.data(), ""); + EXPECT_STREQ(match.address.data(), "http.client_ip"); + EXPECT_TRUE(match.key_path.empty()); + } + + { + // An existing match in a collection will not inhibit a match in a + // priority collection. + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ctx.insert(root); + + auto events = ctx.match({}, {}, deadline); + EXPECT_EQ(events.size(), 0); + } +} -/*ddwaf::timer deadline{2s};*/ -/*auto events = ctx.match({}, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 1);*/ +TEST(TestContext, MatchMultipleRulesWithPriorityUntilAllActionsMet) +{ + auto ruleset = std::make_shared(); + { + expression_builder builder(1); + builder.start_condition( + std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); -/*auto event = events[0];*/ -/*EXPECT_STREQ(event.rule->get_id().c_str(), "id2");*/ -/*EXPECT_EQ(event.rule->get_actions().size(), 1);*/ -/*EXPECT_STREQ(event.rule->get_actions()[0].data(), "block");*/ -/*}*/ -/*}*/ + std::unordered_map tags{ + {"type", "type"}, {"category", "category1"}}; -/*TEST(TestContext, MatchMultipleRulesInCollectionDoubleRun)*/ -/*{*/ -/*auto ruleset = std::make_shared();*/ -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ + auto rule = std::make_shared("id1", "name1", std::move(tags), builder.build()); -/*auto cond = std::make_shared(*/ -/*std::move(targets), std::make_unique(*/ -/*std::vector{"192.168.0.1"}));*/ + ruleset->insert_rule(rule); + } -/*std::vector> conditions{std::move(cond)};*/ + { + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); -/*std::unordered_map tags{*/ -/*{"type", "type"}, {"category", "category1"}};*/ + std::unordered_map tags{ + {"type", "type"}, {"category", "category2"}}; -/*auto rule = std::make_shared(*/ -/*"id1", "name1", std::move(tags), std::move(conditions), std::vector{});*/ + auto rule = std::make_shared( + "id2", "name2", std::move(tags), builder.build(), std::vector{"redirect"}); -/*ruleset->insert_rule(rule);*/ -/*}*/ + ruleset->insert_rule(rule); + } -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"admin"}));*/ + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ctx.insert(root); + + auto events = ctx.match({}, {}, deadline); + EXPECT_EQ(events.size(), 1); + + auto &event = events[0]; + EXPECT_STREQ(event.rule->get_id().c_str(), "id1"); + EXPECT_STREQ(event.rule->get_name().c_str(), "name1"); + EXPECT_STREQ(event.rule->get_tag("type").data(), "type"); + EXPECT_STREQ(event.rule->get_tag("category").data(), "category1"); + EXPECT_TRUE(event.rule->get_actions().empty()); + + auto &match = event.matches[0]; + EXPECT_STREQ(match.resolved.c_str(), "192.168.0.1"); + EXPECT_STREQ(match.matched.c_str(), "192.168.0.1"); + EXPECT_STREQ(match.operator_name.data(), "ip_match"); + EXPECT_STREQ(match.operator_value.data(), ""); + EXPECT_STREQ(match.address.data(), "http.client_ip"); + EXPECT_TRUE(match.key_path.empty()); + } + + { + // An existing match in a collection will not inhibit a match in a + // priority collection. + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ctx.insert(root); + + auto events = ctx.match({}, {}, deadline); + EXPECT_EQ(events.size(), 1); + + auto &event = events[0]; + EXPECT_EQ(events.size(), 1); + EXPECT_STREQ(event.rule->get_id().c_str(), "id2"); + EXPECT_STREQ(event.rule->get_name().c_str(), "name2"); + EXPECT_STREQ(event.rule->get_tag("type").data(), "type"); + EXPECT_STREQ(event.rule->get_tag("category").data(), "category2"); + std::vector expected_actions{"redirect"}; + EXPECT_EQ(event.rule->get_actions(), expected_actions); + EXPECT_EQ(event.matches.size(), 1); + + auto &match = event.matches[0]; + EXPECT_STREQ(match.resolved.c_str(), "admin"); + EXPECT_STREQ(match.matched.c_str(), "admin"); + EXPECT_STREQ(match.operator_name.data(), "exact_match"); + EXPECT_STREQ(match.operator_value.data(), ""); + EXPECT_STREQ(match.address.data(), "usr.id"); + EXPECT_TRUE(match.key_path.empty()); + } +} -/*std::vector> conditions{std::move(cond)};*/ +TEST(TestContext, MatchMultipleCollectionsSingleRun) +{ + auto ruleset = std::make_shared(); + { + expression_builder builder(1); + builder.start_condition( + std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); -/*std::unordered_map tags{*/ -/*{"type", "type"}, {"category", "category2"}};*/ + std::unordered_map tags{ + {"type", "type1"}, {"category", "category1"}}; -/*auto rule = std::make_shared(*/ -/*"id2", "name2", std::move(tags), std::move(conditions), std::vector{});*/ + auto rule = std::make_shared("id1", "name1", std::move(tags), builder.build()); -/*ruleset->insert_rule(rule);*/ -/*}*/ + ruleset->insert_rule(rule); + } -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ + { + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); -/*{*/ -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ctx.insert(root);*/ + std::unordered_map tags{ + {"type", "type2"}, {"category", "category2"}}; -/*auto events = ctx.match({}, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 1);*/ + auto rule = std::make_shared("id2", "name2", std::move(tags), builder.build()); -/*auto &event = events[0];*/ -/*EXPECT_STREQ(event.rule->get_id().c_str(), "id1");*/ -/*EXPECT_STREQ(event.rule->get_name().c_str(), "name1");*/ -/*EXPECT_STREQ(event.rule->get_tag("type").data(), "type");*/ -/*EXPECT_STREQ(event.rule->get_tag("category").data(), "category1");*/ -/*std::vector expected_actions{};*/ -/*EXPECT_EQ(event.rule->get_actions(), expected_actions);*/ -/*EXPECT_EQ(event.matches.size(), 1);*/ + ruleset->insert_rule(rule); + } -/*auto &match = event.matches[0];*/ -/*EXPECT_STREQ(match.resolved.c_str(), "192.168.0.1");*/ -/*EXPECT_STREQ(match.matched.c_str(), "192.168.0.1");*/ -/*EXPECT_STREQ(match.operator_name.data(), "ip_match");*/ -/*EXPECT_STREQ(match.operator_value.data(), "");*/ -/*EXPECT_STREQ(match.address.data(), "http.client_ip");*/ -/*EXPECT_TRUE(match.key_path.empty());*/ -/*}*/ + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); -/*{*/ -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ctx.insert(root);*/ + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ctx.insert(root); -/*auto events = ctx.match({}, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 0);*/ -/*}*/ -/*}*/ + auto events = ctx.match({}, {}, deadline); + EXPECT_EQ(events.size(), 2); +} -/*TEST(TestContext, MatchMultipleRulesWithPriorityDoubleRunPriorityLast)*/ -/*{*/ -/*auto ruleset = std::make_shared();*/ -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ +TEST(TestContext, MatchMultiplePriorityCollectionsSingleRun) +{ + auto ruleset = std::make_shared(); + { + expression_builder builder(1); + builder.start_condition( + std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); -/*auto cond = std::make_shared(*/ -/*std::move(targets), std::make_unique(*/ -/*std::vector{"192.168.0.1"}));*/ + std::unordered_map tags{ + {"type", "type1"}, {"category", "category1"}}; -/*std::vector> conditions{std::move(cond)};*/ + auto rule = std::make_shared( + "id1", "name1", std::move(tags), builder.build(), std::vector{"block"}); -/*std::unordered_map tags{*/ -/*{"type", "type"}, {"category", "category1"}};*/ + ruleset->insert_rule(rule); + } -/*auto rule = std::make_shared(*/ -/*"id1", "name1", std::move(tags), std::move(conditions), std::vector{});*/ + { + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); -/*ruleset->insert_rule(rule);*/ -/*}*/ + std::unordered_map tags{ + {"type", "type2"}, {"category", "category2"}}; -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ - -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"admin"}));*/ - -/*std::vector> conditions{std::move(cond)};*/ - -/*std::unordered_map tags{*/ -/*{"type", "type"}, {"category", "category2"}};*/ - -/*auto rule = std::make_shared("id2", "name2", std::move(tags),*/ -/*std::move(conditions), std::vector{"block"});*/ - -/*ruleset->insert_rule(rule);*/ -/*}*/ - -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*{*/ -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ctx.insert(root);*/ - -/*auto events = ctx.match({}, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 1);*/ - -/*auto &event = events[0];*/ -/*EXPECT_STREQ(event.rule->get_id().c_str(), "id1");*/ -/*EXPECT_STREQ(event.rule->get_name().c_str(), "name1");*/ -/*EXPECT_STREQ(event.rule->get_tag("type").data(), "type");*/ -/*EXPECT_STREQ(event.rule->get_tag("category").data(), "category1");*/ -/*std::vector expected_actions{};*/ -/*EXPECT_EQ(event.rule->get_actions(), expected_actions);*/ -/*EXPECT_EQ(event.matches.size(), 1);*/ - -/*auto &match = event.matches[0];*/ -/*EXPECT_STREQ(match.resolved.c_str(), "192.168.0.1");*/ -/*EXPECT_STREQ(match.matched.c_str(), "192.168.0.1");*/ -/*EXPECT_STREQ(match.operator_name.data(), "ip_match");*/ -/*EXPECT_STREQ(match.operator_value.data(), "");*/ -/*EXPECT_STREQ(match.address.data(), "http.client_ip");*/ -/*EXPECT_TRUE(match.key_path.empty());*/ -/*}*/ - -/*{*/ -/*// An existing match in a collection will not inhibit a match in a*/ -/*// priority collection.*/ -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ctx.insert(root);*/ - -/*auto events = ctx.match({}, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 1);*/ - -/*auto &event = events[0];*/ -/*EXPECT_EQ(events.size(), 1);*/ -/*EXPECT_STREQ(event.rule->get_id().c_str(), "id2");*/ -/*EXPECT_STREQ(event.rule->get_name().c_str(), "name2");*/ -/*EXPECT_STREQ(event.rule->get_tag("type").data(), "type");*/ -/*EXPECT_STREQ(event.rule->get_tag("category").data(), "category2");*/ -/*std::vector expected_actions{"block"};*/ -/*EXPECT_EQ(event.rule->get_actions(), expected_actions);*/ -/*EXPECT_EQ(event.matches.size(), 1);*/ - -/*auto &match = event.matches[0];*/ -/*EXPECT_STREQ(match.resolved.c_str(), "admin");*/ -/*EXPECT_STREQ(match.matched.c_str(), "admin");*/ -/*EXPECT_STREQ(match.operator_name.data(), "exact_match");*/ -/*EXPECT_STREQ(match.operator_value.data(), "");*/ -/*EXPECT_STREQ(match.address.data(), "usr.id");*/ -/*EXPECT_TRUE(match.key_path.empty());*/ -/*}*/ -/*}*/ - -/*TEST(TestContext, MatchMultipleRulesWithPriorityDoubleRunPriorityFirst)*/ -/*{*/ -/*auto ruleset = std::make_shared();*/ -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ - -/*auto cond = std::make_shared(*/ -/*std::move(targets), std::make_unique(*/ -/*std::vector{"192.168.0.1"}));*/ - -/*std::vector> conditions{std::move(cond)};*/ - -/*std::unordered_map tags{*/ -/*{"type", "type"}, {"category", "category1"}};*/ - -/*auto rule = std::make_shared("id1", "name1", std::move(tags),*/ -/*std::move(conditions), std::vector{"block"});*/ - -/*ruleset->insert_rule(rule);*/ -/*}*/ - -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ - -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"admin"}));*/ - -/*std::vector> conditions{std::move(cond)};*/ - -/*std::unordered_map tags{*/ -/*{"type", "type"}, {"category", "category2"}};*/ - -/*auto rule = std::make_shared(*/ -/*"id2", "name2", std::move(tags), std::move(conditions), std::vector{});*/ - -/*ruleset->insert_rule(rule);*/ -/*}*/ - -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*{*/ -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ctx.insert(root);*/ - -/*auto events = ctx.match({}, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 1);*/ - -/*auto &event = events[0];*/ -/*EXPECT_STREQ(event.rule->get_id().c_str(), "id1");*/ -/*EXPECT_STREQ(event.rule->get_name().c_str(), "name1");*/ -/*EXPECT_STREQ(event.rule->get_tag("type").data(), "type");*/ -/*EXPECT_STREQ(event.rule->get_tag("category").data(), "category1");*/ -/*std::vector expected_actions{"block"};*/ -/*EXPECT_EQ(event.rule->get_actions(), expected_actions);*/ -/*EXPECT_EQ(event.matches.size(), 1);*/ - -/*auto &match = event.matches[0];*/ -/*EXPECT_STREQ(match.resolved.c_str(), "192.168.0.1");*/ -/*EXPECT_STREQ(match.matched.c_str(), "192.168.0.1");*/ -/*EXPECT_STREQ(match.operator_name.data(), "ip_match");*/ -/*EXPECT_STREQ(match.operator_value.data(), "");*/ -/*EXPECT_STREQ(match.address.data(), "http.client_ip");*/ -/*EXPECT_TRUE(match.key_path.empty());*/ -/*}*/ - -/*{*/ -/*// An existing match in a collection will not inhibit a match in a*/ -/*// priority collection.*/ -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ctx.insert(root);*/ - -/*auto events = ctx.match({}, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 0);*/ -/*}*/ -/*}*/ - -/*TEST(TestContext, MatchMultipleRulesWithPriorityUntilAllActionsMet)*/ -/*{*/ -/*auto ruleset = std::make_shared();*/ -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ - -/*auto cond = std::make_shared(*/ -/*std::move(targets), std::make_unique(*/ -/*std::vector{"192.168.0.1"}));*/ - -/*std::vector> conditions{std::move(cond)};*/ - -/*std::unordered_map tags{*/ -/*{"type", "type"}, {"category", "category1"}};*/ + auto rule = std::make_shared( + "id2", "name2", std::move(tags), builder.build(), std::vector{"redirect"}); -/*auto rule = std::make_shared(*/ -/*"id1", "name1", std::move(tags), std::move(conditions), std::vector{});*/ - -/*ruleset->insert_rule(rule);*/ -/*}*/ - -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ + ruleset->insert_rule(rule); + } -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"admin"}));*/ - -/*std::vector> conditions{std::move(cond)};*/ - -/*std::unordered_map tags{*/ -/*{"type", "type"}, {"category", "category2"}};*/ - -/*auto rule = std::make_shared("id2", "name2", std::move(tags),*/ -/*std::move(conditions), std::vector{"redirect"});*/ - -/*ruleset->insert_rule(rule);*/ -/*}*/ - -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*{*/ -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ctx.insert(root);*/ - -/*auto events = ctx.match({}, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 1);*/ - -/*auto &event = events[0];*/ -/*EXPECT_STREQ(event.rule->get_id().c_str(), "id1");*/ -/*EXPECT_STREQ(event.rule->get_name().c_str(), "name1");*/ -/*EXPECT_STREQ(event.rule->get_tag("type").data(), "type");*/ -/*EXPECT_STREQ(event.rule->get_tag("category").data(), "category1");*/ -/*EXPECT_TRUE(event.rule->get_actions().empty());*/ - -/*auto &match = event.matches[0];*/ -/*EXPECT_STREQ(match.resolved.c_str(), "192.168.0.1");*/ -/*EXPECT_STREQ(match.matched.c_str(), "192.168.0.1");*/ -/*EXPECT_STREQ(match.operator_name.data(), "ip_match");*/ -/*EXPECT_STREQ(match.operator_value.data(), "");*/ -/*EXPECT_STREQ(match.address.data(), "http.client_ip");*/ -/*EXPECT_TRUE(match.key_path.empty());*/ -/*}*/ - -/*{*/ -/*// An existing match in a collection will not inhibit a match in a*/ -/*// priority collection.*/ -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ctx.insert(root);*/ - -/*auto events = ctx.match({}, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 1);*/ - -/*auto &event = events[0];*/ -/*EXPECT_EQ(events.size(), 1);*/ -/*EXPECT_STREQ(event.rule->get_id().c_str(), "id2");*/ -/*EXPECT_STREQ(event.rule->get_name().c_str(), "name2");*/ -/*EXPECT_STREQ(event.rule->get_tag("type").data(), "type");*/ -/*EXPECT_STREQ(event.rule->get_tag("category").data(), "category2");*/ -/*std::vector expected_actions{"redirect"};*/ -/*EXPECT_EQ(event.rule->get_actions(), expected_actions);*/ -/*EXPECT_EQ(event.matches.size(), 1);*/ - -/*auto &match = event.matches[0];*/ -/*EXPECT_STREQ(match.resolved.c_str(), "admin");*/ -/*EXPECT_STREQ(match.matched.c_str(), "admin");*/ -/*EXPECT_STREQ(match.operator_name.data(), "exact_match");*/ -/*EXPECT_STREQ(match.operator_value.data(), "");*/ -/*EXPECT_STREQ(match.address.data(), "usr.id");*/ -/*EXPECT_TRUE(match.key_path.empty());*/ -/*}*/ -/*}*/ - -/*TEST(TestContext, MatchMultipleCollectionsSingleRun)*/ -/*{*/ -/*auto ruleset = std::make_shared();*/ -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ - -/*auto cond = std::make_shared(*/ -/*std::move(targets), std::make_unique(*/ -/*std::vector{"192.168.0.1"}));*/ - -/*std::vector> conditions{std::move(cond)};*/ - -/*std::unordered_map tags{*/ -/*{"type", "type1"}, {"category", "category1"}};*/ - -/*auto rule = std::make_shared(*/ -/*"id1", "name1", std::move(tags), std::move(conditions), std::vector{});*/ - -/*ruleset->insert_rule(rule);*/ -/*}*/ - -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ - -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"admin"}));*/ - -/*std::vector> conditions{std::move(cond)};*/ - -/*std::unordered_map tags{*/ -/*{"type", "type2"}, {"category", "category2"}};*/ - -/*auto rule = std::make_shared(*/ -/*"id2", "name2", std::move(tags), std::move(conditions), std::vector{});*/ - -/*ruleset->insert_rule(rule);*/ -/*}*/ - -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ctx.insert(root);*/ - -/*auto events = ctx.match({}, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 2);*/ -/*}*/ - -/*TEST(TestContext, MatchMultiplePriorityCollectionsSingleRun)*/ -/*{*/ -/*auto ruleset = std::make_shared();*/ -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ - -/*auto cond = std::make_shared(*/ -/*std::move(targets), std::make_unique(*/ -/*std::vector{"192.168.0.1"}));*/ - -/*std::vector> conditions{std::move(cond)};*/ - -/*std::unordered_map tags{*/ -/*{"type", "type1"}, {"category", "category1"}};*/ - -/*auto rule = std::make_shared("id1", "name1", std::move(tags),*/ -/*std::move(conditions), std::vector{"block"});*/ - -/*ruleset->insert_rule(rule);*/ -/*}*/ - -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ - -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"admin"}));*/ - -/*std::vector> conditions{std::move(cond)};*/ - -/*std::unordered_map tags{*/ -/*{"type", "type2"}, {"category", "category2"}};*/ - -/*auto rule = std::make_shared("id2", "name2", std::move(tags),*/ -/*std::move(conditions), std::vector{"redirect"});*/ - -/*ruleset->insert_rule(rule);*/ -/*}*/ - -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ctx.insert(root);*/ + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ctx.insert(root); -/*auto events = ctx.match({}, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 2);*/ -/*}*/ + auto events = ctx.match({}, {}, deadline); + EXPECT_EQ(events.size(), 2); +} /*TEST(TestContext, MatchMultipleCollectionsDoubleRun)*/ /*{*/ From f45c5fb6514cd7c91ecd162f9312de9f9c427189 Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Thu, 29 Jun 2023 18:24:58 +0100 Subject: [PATCH 21/28] Reduce parallelism on docker builds --- docker/libddwaf/common/Makefile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docker/libddwaf/common/Makefile b/docker/libddwaf/common/Makefile index 079d72068..f884ce7ec 100644 --- a/docker/libddwaf/common/Makefile +++ b/docker/libddwaf/common/Makefile @@ -72,7 +72,7 @@ src/%/.finger: %-$(LLVM_VERSION).src.tar.xz AR=$(GCC_TOOL_PREFIX)ar \ RANLIB=$(GCC_TOOL_PREFIX)ranlib \ ../../src/musl/configure --prefix=$(MUSL_SYSROOT) && \ - $(MAKE) -j && \ + $(MAKE) -j $(shell nproc) && \ $(MAKE) install && \ popd && \ touch $@ @@ -110,7 +110,7 @@ COMMON_CMAKE_OPTIONS := -DCMAKE_BUILD_TYPE=$(RELTYPE) \ -DCOMPILER_RT_DEFAULT_TARGET_ONLY=ON \ -DCOMPILER_RT_BUILD_CRT=ON \ ../../src/compiler-rt && \ - $(MAKE) -j && $(MAKE) install && \ + $(MAKE) -j $(shell nproc) && $(MAKE) install && \ popd && \ touch $@ @@ -122,7 +122,7 @@ COMMON_CMAKE_OPTIONS := -DCMAKE_BUILD_TYPE=$(RELTYPE) \ -DLLVM_PATH=../../src/llvm \ -DLIBUNWIND_USE_COMPILER_RT=ON \ ../../src/libunwind && \ - $(MAKE) -j && $(MAKE) install && \ + $(MAKE) -j $(shell nproc) && $(MAKE) install && \ popd && \ touch $@ @@ -137,7 +137,7 @@ COMMON_CMAKE_OPTIONS := -DCMAKE_BUILD_TYPE=$(RELTYPE) \ -DLIBCXXABI_LIBUNWIND_PATH=../../src/libunwind \ -DLIBCXXABI_LIBCXX_INCLUDES=../../src/libcxx/include \ ../../src/libcxxabi && \ - $(MAKE) -j && $(MAKE) install && \ + $(MAKE) -j $(shell nproc) && $(MAKE) install && \ popd && \ touch $@ @@ -160,7 +160,7 @@ COMMON_CMAKE_OPTIONS := -DCMAKE_BUILD_TYPE=$(RELTYPE) \ -DLIBCXX_ENABLE_FILESYSTEM=0 \ -DLIBCXX_ENABLE_EXPERIMENTAL_LIBRARY=1 \ ../../src/libcxx && \ - $(MAKE) -j && $(MAKE) install && \ + $(MAKE) -j $(shell nproc) && $(MAKE) install && \ popd && \ touch $@ @@ -171,6 +171,6 @@ libddwaf: -DCMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE=PRE_TEST \ -DLIBDDWAF_TEST_COVERAGE=OFF \ ../../src/libddwaf && \ - make -j && make -j testPowerWAF && patchelf --remove-needed libc.so libddwaf.so && make package + make -j $(shell nproc) && make -j $(shell nproc) estPowerWAF && patchelf --remove-needed libc.so libddwaf.so && make package .PHONY: libddwaf From 36d523ab530fc5dcb3865ca6cb4c8bfab29ec0fe Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Thu, 29 Jun 2023 18:37:26 +0100 Subject: [PATCH 22/28] Fix typo --- docker/libddwaf/common/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/libddwaf/common/Makefile b/docker/libddwaf/common/Makefile index f884ce7ec..51c9f6337 100644 --- a/docker/libddwaf/common/Makefile +++ b/docker/libddwaf/common/Makefile @@ -171,6 +171,6 @@ libddwaf: -DCMAKE_GTEST_DISCOVER_TESTS_DISCOVERY_MODE=PRE_TEST \ -DLIBDDWAF_TEST_COVERAGE=OFF \ ../../src/libddwaf && \ - make -j $(shell nproc) && make -j $(shell nproc) estPowerWAF && patchelf --remove-needed libc.so libddwaf.so && make package + make -j $(shell nproc) && make -j $(shell nproc) testPowerWAF && patchelf --remove-needed libc.so libddwaf.so && make package .PHONY: libddwaf From e641cac31199e670a807bce835ed596eaa1fdfdc Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Thu, 29 Jun 2023 19:02:37 +0100 Subject: [PATCH 23/28] Enable all remaining tests --- tests/context_test.cpp | 2474 ++++++++++++++++++++-------------------- 1 file changed, 1208 insertions(+), 1266 deletions(-) diff --git a/tests/context_test.cpp b/tests/context_test.cpp index 690d385f4..eba4e9659 100644 --- a/tests/context_test.cpp +++ b/tests/context_test.cpp @@ -654,1333 +654,1275 @@ TEST(TestContext, MatchMultiplePriorityCollectionsSingleRun) EXPECT_EQ(events.size(), 2); } -/*TEST(TestContext, MatchMultipleCollectionsDoubleRun)*/ -/*{*/ -/*auto ruleset = std::make_shared();*/ -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ +TEST(TestContext, MatchMultipleCollectionsDoubleRun) +{ + auto ruleset = std::make_shared(); + { + expression_builder builder(1); + builder.start_condition( + std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); + + std::unordered_map tags{ + {"type", "type1"}, {"category", "category1"}}; + + auto rule = std::make_shared("id1", "name1", std::move(tags), builder.build()); + + ruleset->insert_rule(rule); + } + + { + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); + + std::unordered_map tags{ + {"type", "type2"}, {"category", "category2"}}; + + auto rule = std::make_shared("id2", "name2", std::move(tags), builder.build()); + + ruleset->insert_rule(rule); + } + + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ctx.insert(root); + + auto events = ctx.match({}, {}, deadline); + EXPECT_EQ(events.size(), 1); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ctx.insert(root); + + auto events = ctx.match({}, {}, deadline); + EXPECT_EQ(events.size(), 1); + } +} + +TEST(TestContext, MatchMultiplePriorityCollectionsDoubleRun) +{ + auto ruleset = std::make_shared(); + + { + expression_builder builder(1); + builder.start_condition( + std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); + + std::unordered_map tags{ + {"type", "type1"}, {"category", "category1"}}; + + auto rule = std::make_shared( + "id1", "name1", std::move(tags), builder.build(), std::vector{"block"}); + + ruleset->insert_rule(rule); + } + + { + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); + + std::unordered_map tags{ + {"type", "type2"}, {"category", "category2"}}; + + auto rule = std::make_shared( + "id2", "name2", std::move(tags), builder.build(), std::vector{"redirect"}); + + ruleset->insert_rule(rule); + } + + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ctx.insert(root); + + auto events = ctx.match({}, {}, deadline); + EXPECT_EQ(events.size(), 1); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ctx.insert(root); + + auto events = ctx.match({}, {}, deadline); + EXPECT_EQ(events.size(), 1); + } +} + +TEST(TestContext, RuleFilterWithCondition) +{ + auto ruleset = std::make_shared(); + + // Generate rule + ddwaf::rule::ptr rule; + { + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); + + std::unordered_map tags{ + {"type", "type"}, {"category", "category"}}; + + rule = std::make_shared("id", "name", std::move(tags), builder.build()); + + ruleset->insert_rule(rule); + } + + // Generate filter + { + std::vector targets; + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); + + auto cond = std::make_shared( + std::move(targets), std::make_unique( + std::vector{"192.168.0.1"})); + + std::vector> conditions{std::move(cond)}; + + auto filter = std::make_shared( + "1", std::move(conditions), std::set{rule.get()}); + ruleset->rule_filters.emplace(filter->get_id(), filter); + } + + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ctx.insert(root); + + auto rules_to_exclude = ctx.filter_rules(deadline); + EXPECT_EQ(rules_to_exclude.size(), 1); + EXPECT_NE(rules_to_exclude.find(rule.get()), rules_to_exclude.end()); + + auto events = ctx.match(rules_to_exclude, {}, deadline); + EXPECT_EQ(events.size(), 0); +} + +TEST(TestContext, RuleFilterTimeout) +{ + auto ruleset = std::make_shared(); + + // Generate rule + ddwaf::rule::ptr rule; + { + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); + + std::unordered_map tags{ + {"type", "type"}, {"category", "category"}}; + + rule = std::make_shared("id", "name", std::move(tags), builder.build()); + + ruleset->insert_rule(rule); + } + + // Generate filter + { + std::vector targets; + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); + + auto cond = std::make_shared( + std::move(targets), std::make_unique( + std::vector{"192.168.0.1"})); + + std::vector> conditions{std::move(cond)}; + + auto filter = std::make_shared( + "1", std::move(conditions), std::set{rule.get()}); + ruleset->rule_filters.emplace(filter->get_id(), filter); + } + + ddwaf::timer deadline{0s}; + ddwaf::test::context ctx(ruleset); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ctx.insert(root); + + EXPECT_THROW(ctx.filter_rules(deadline), ddwaf::timeout_exception); +} + +TEST(TestContext, NoRuleFilterWithCondition) +{ + auto ruleset = std::make_shared(); + + // Generate rule + ddwaf::rule::ptr rule; + { + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr.id"); + + std::unordered_map tags{ + {"type", "type"}, {"category", "category"}}; + + rule = std::make_shared("id", "name", std::move(tags), builder.build()); + + ruleset->insert_rule(rule); + } + + // Generate filter + { + std::vector targets; + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); + + auto cond = std::make_shared( + std::move(targets), std::make_unique( + std::vector{"192.168.0.1"})); + + std::vector> conditions{std::move(cond)}; + + auto filter = std::make_shared( + "1", std::move(conditions), std::set{rule.get()}); + ruleset->rule_filters.emplace(filter->get_id(), filter); + } + + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.2")); + ctx.insert(root); + + auto rules_to_exclude = ctx.filter_rules(deadline); + EXPECT_TRUE(rules_to_exclude.empty()); + + auto events = ctx.match(rules_to_exclude, {}, deadline); + EXPECT_EQ(events.size(), 1); +} + +TEST(TestContext, MultipleRuleFiltersNonOverlappingRules) +{ + auto ruleset = std::make_shared(); + + // Generate rule + constexpr unsigned num_rules = 9; + std::vector rules; + rules.reserve(num_rules); + for (unsigned i = 0; i < num_rules; i++) { + + std::unordered_map tags{ + {"type", "type"}, {"category", "category"}}; + + rules.emplace_back(std::make_shared("id" + std::to_string(i), "name", + std::move(tags), expression::ptr{}, std::vector{})); + + ruleset->insert_rule(rules.back()); + } + + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); + + { + auto rules_to_exclude = ctx.filter_rules(deadline); + EXPECT_EQ(rules_to_exclude.size(), 0); + } + + { + auto filter = std::make_shared("1", std::vector{}, + std::set{rules[0].get(), rules[1].get(), rules[2].get()}); + ruleset->rule_filters.emplace(filter->get_id(), filter); + + auto rules_to_exclude = ctx.filter_rules(deadline); + EXPECT_EQ(rules_to_exclude.size(), 3); + EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); + } + + { + auto filter = std::make_shared("2", std::vector{}, + std::set{rules[3].get(), rules[4].get(), rules[5].get()}); + ruleset->rule_filters.emplace(filter->get_id(), filter); + + auto rules_to_exclude = ctx.filter_rules(deadline); + EXPECT_EQ(rules_to_exclude.size(), 6); + EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end()); + } + + { + auto filter = std::make_shared("3", std::vector{}, + std::set{rules[6].get(), rules[7].get(), rules[8].get()}); + ruleset->rule_filters.emplace(filter->get_id(), filter); + + auto rules_to_exclude = ctx.filter_rules(deadline); + EXPECT_EQ(rules_to_exclude.size(), 9); + EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end()); + } +} + +TEST(TestContext, MultipleRuleFiltersOverlappingRules) +{ + auto ruleset = std::make_shared(); + + // Generate rule + constexpr unsigned num_rules = 9; + std::vector rules; + rules.reserve(num_rules); + for (unsigned i = 0; i < num_rules; i++) { + std::string id = "id" + std::to_string(i); + + std::unordered_map tags{ + {"type", "type"}, {"category", "category"}}; + + rules.emplace_back(std::make_shared(std::string(id), "name", std::move(tags), + expression::ptr{}, std::vector{})); + + ruleset->insert_rule(rules.back()); + } + + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); + + { + auto rules_to_exclude = ctx.filter_rules(deadline); + EXPECT_EQ(rules_to_exclude.size(), 0); + } + + { + auto filter = std::make_shared("1", std::vector{}, + std::set{ + rules[0].get(), rules[1].get(), rules[2].get(), rules[3].get()}); + ruleset->rule_filters.emplace(filter->get_id(), filter); + + auto rules_to_exclude = ctx.filter_rules(deadline); + EXPECT_EQ(rules_to_exclude.size(), 4); + EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end()); + } + + { + auto filter = std::make_shared("2", std::vector{}, + std::set{rules[2].get(), rules[3].get(), rules[4].get()}); + ruleset->rule_filters.emplace(filter->get_id(), filter); + + auto rules_to_exclude = ctx.filter_rules(deadline); + EXPECT_EQ(rules_to_exclude.size(), 5); + EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end()); + } + + { + auto filter = std::make_shared("3", std::vector{}, + std::set{rules[0].get(), rules[5].get(), rules[6].get()}); + ruleset->rule_filters.emplace(filter->get_id(), filter); + + auto rules_to_exclude = ctx.filter_rules(deadline); + EXPECT_EQ(rules_to_exclude.size(), 7); + EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end()); + } + + { + auto filter = std::make_shared("4", std::vector{}, + std::set{rules[7].get(), rules[8].get(), rules[6].get()}); + ruleset->rule_filters.emplace(filter->get_id(), filter); + + auto rules_to_exclude = ctx.filter_rules(deadline); + EXPECT_EQ(rules_to_exclude.size(), 9); + EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end()); + } + + { + auto filter = std::make_shared("5", std::vector{}, + std::set{rules[0].get(), rules[1].get(), rules[2].get(), rules[3].get(), + rules[4].get(), rules[5].get(), rules[6].get(), rules[7].get(), rules[8].get()}); + ruleset->rule_filters.emplace(filter->get_id(), filter); + + auto rules_to_exclude = ctx.filter_rules(deadline); + EXPECT_EQ(rules_to_exclude.size(), 9); + EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end()); + } +} + +TEST(TestContext, MultipleRuleFiltersNonOverlappingRulesWithConditions) +{ + auto ruleset = std::make_shared(); + + // Generate rule + constexpr unsigned num_rules = 10; + std::vector rules; + rules.reserve(num_rules); + for (unsigned i = 0; i < num_rules; i++) { + std::string id = "id" + std::to_string(i); + + std::unordered_map tags{ + {"type", "type"}, {"category", "category"}}; + + rules.emplace_back(std::make_shared(std::string(id), "name", std::move(tags), + expression::ptr{}, std::vector{})); + + ruleset->insert_rule(rules.back()); + } + + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); + + { + std::vector targets; + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); + + auto cond = std::make_shared( + std::move(targets), std::make_unique( + std::vector{"192.168.0.1"})); + + std::vector> conditions{std::move(cond)}; + + auto filter = std::make_shared("1", std::move(conditions), + std::set{ + rules[0].get(), rules[1].get(), rules[2].get(), rules[3].get(), rules[4].get()}); + ruleset->rule_filters.emplace(filter->get_id(), filter); + } + + { + std::vector targets; + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); + + auto cond = std::make_shared(std::move(targets), + std::make_unique(std::vector{"admin"})); + + std::vector> conditions{std::move(cond)}; + + auto filter = std::make_shared("2", std::move(conditions), + std::set{ + rules[5].get(), rules[6].get(), rules[7].get(), rules[8].get(), rules[9].get()}); + ruleset->rule_filters.emplace(filter->get_id(), filter); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ctx.insert(root); + + auto rules_to_exclude = ctx.filter_rules(deadline); + EXPECT_EQ(rules_to_exclude.size(), 5); + EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[9].get()), rules_to_exclude.end()); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ctx.insert(root); + + auto rules_to_exclude = ctx.filter_rules(deadline); + EXPECT_EQ(rules_to_exclude.size(), 10); + EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[9].get()), rules_to_exclude.end()); + } +} + +TEST(TestContext, MultipleRuleFiltersOverlappingRulesWithConditions) +{ + auto ruleset = std::make_shared(); + + // Generate rule + constexpr unsigned num_rules = 10; + std::vector rules; + rules.reserve(num_rules); + for (unsigned i = 0; i < num_rules; i++) { + std::string id = "id" + std::to_string(i); + + std::unordered_map tags{ + {"type", "type"}, {"category", "category"}}; + + rules.emplace_back(std::make_shared(std::string(id), "name", std::move(tags), + expression::ptr{}, std::vector{})); + + ruleset->insert_rule(rules.back()); + } + + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); + + { + std::vector targets; + targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}}); + + auto cond = std::make_shared( + std::move(targets), std::make_unique( + std::vector{"192.168.0.1"})); + + std::vector> conditions{std::move(cond)}; + + auto filter = std::make_shared("1", std::move(conditions), + std::set{rules[0].get(), rules[1].get(), rules[2].get(), rules[3].get(), + rules[4].get(), rules[5].get(), rules[6].get()}); + ruleset->rule_filters.emplace(filter->get_id(), filter); + } + + { + std::vector targets; + targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}}); + + auto cond = std::make_shared(std::move(targets), + std::make_unique(std::vector{"admin"})); + + std::vector> conditions{std::move(cond)}; + + auto filter = std::make_shared("2", std::move(conditions), + std::set{rules[3].get(), rules[4].get(), rules[5].get(), rules[6].get(), + rules[7].get(), rules[8].get(), rules[9].get()}); + ruleset->rule_filters.emplace(filter->get_id(), filter); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ctx.insert(root); + + auto rules_to_exclude = ctx.filter_rules(deadline); + EXPECT_EQ(rules_to_exclude.size(), 7); + EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end()); + } + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ctx.insert(root); + + auto rules_to_exclude = ctx.filter_rules(deadline); + EXPECT_EQ(rules_to_exclude.size(), 10); + EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end()); + EXPECT_NE(rules_to_exclude.find(rules[9].get()), rules_to_exclude.end()); + } +} + +TEST(TestContext, InputFilterExclude) +{ + expression_builder builder(1); + builder.start_condition(std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); + + std::unordered_map tags{{"type", "type"}, {"category", "category"}}; + + auto rule = std::make_shared("id", "name", std::move(tags), builder.build()); + + auto obj_filter = std::make_shared(); + obj_filter->insert(get_target_index("http.client_ip"), "http.client_ip"); + + std::vector filter_conditions; + std::set filter_rules{rule.get()}; + auto filter = std::make_shared( + "1", std::move(filter_conditions), std::move(filter_rules), std::move(obj_filter)); + + auto ruleset = std::make_shared(); + ruleset->insert_rule(rule); + ruleset->input_filters.emplace(filter->get_id(), filter); + + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ctx.insert(root); + + auto objects_to_exclude = ctx.filter_inputs({}, deadline); + EXPECT_EQ(objects_to_exclude.size(), 1); + auto events = ctx.match({}, objects_to_exclude, deadline); + EXPECT_EQ(events.size(), 0); +} + +TEST(TestContext, InputFilterExcludeRule) +{ + expression_builder builder(1); + builder.start_condition(std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); + + std::unordered_map tags{{"type", "type"}, {"category", "category"}}; + + auto rule = std::make_shared("id", "name", std::move(tags), builder.build()); + + auto obj_filter = std::make_shared(); + obj_filter->insert(get_target_index("http.client_ip"), "http.client_ip"); + + std::vector filter_conditions; + std::set filter_rules{rule.get()}; + auto filter = std::make_shared( + "1", std::move(filter_conditions), std::move(filter_rules), std::move(obj_filter)); + + auto ruleset = std::make_shared(); + ruleset->insert_rule(rule); + ruleset->input_filters.emplace(filter->get_id(), filter); + + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ctx.insert(root); + + // The rule is added to the filter stage so that it's excluded from the + // final result, since we're not actually excluding the rule from the match + // stage we still get an event. + auto objects_to_exclude = ctx.filter_inputs({rule.get()}, deadline); + EXPECT_EQ(objects_to_exclude.size(), 0); + auto events = ctx.match({}, objects_to_exclude, deadline); + EXPECT_EQ(events.size(), 1); +} + +TEST(TestContext, InputFilterWithCondition) +{ + auto ruleset = std::make_shared(); + { + expression_builder builder(1); + builder.start_condition( + std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); + + std::unordered_map tags{ + {"type", "type"}, {"category", "category"}}; + + auto rule = std::make_shared("id", "name", std::move(tags), builder.build()); + + ruleset->insert_rule(rule); + } + + { + condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}}; + condition::target_type usr_id{get_target_index("usr.id"), "usr.id", {}}; + + auto obj_filter = std::make_shared(); + obj_filter->insert(client_ip.root, client_ip.name); + + std::vector> conditions; + std::vector targets{usr_id}; + auto cond = std::make_shared(std::move(targets), + std::make_unique(std::vector{"admin"})); + conditions.emplace_back(std::move(cond)); + + std::set filter_rules{ruleset->rules[0].get()}; + auto filter = std::make_shared( + "1", std::move(conditions), std::move(filter_rules), std::move(obj_filter)); + + ruleset->input_filters.emplace(filter->get_id(), filter); + } + + // Without usr.id, nothing should be excluded + { + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ctx.insert(root); + + auto objects_to_exclude = ctx.filter_inputs({}, deadline); + EXPECT_EQ(objects_to_exclude.size(), 0); + auto events = ctx.match({}, objects_to_exclude, deadline); + EXPECT_EQ(events.size(), 1); + } -/*auto cond = std::make_shared(*/ -/*std::move(targets), std::make_unique(*/ -/*std::vector{"192.168.0.1"}));*/ + // With usr.id != admin, nothing should be excluded + { + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admino")); + ctx.insert(root); + + auto objects_to_exclude = ctx.filter_inputs({}, deadline); + EXPECT_EQ(objects_to_exclude.size(), 0); + auto events = ctx.match({}, objects_to_exclude, deadline); + EXPECT_EQ(events.size(), 1); + } + + // With usr.id == admin, there should be no matches + { + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ctx.insert(root); + + auto objects_to_exclude = ctx.filter_inputs({}, deadline); + EXPECT_EQ(objects_to_exclude.size(), 1); + auto events = ctx.match({}, objects_to_exclude, deadline); + EXPECT_EQ(events.size(), 0); + } +} + +TEST(TestContext, InputFilterMultipleRules) +{ + auto ruleset = std::make_shared(); + { + expression_builder builder(1); + builder.start_condition( + std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); + + std::unordered_map tags{ + {"type", "ip_type"}, {"category", "category"}}; + + auto rule = + std::make_shared("ip_id", "name", std::move(tags), builder.build()); + + ruleset->insert_rule(rule); + } + + { + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr_id"); + + std::unordered_map tags{ + {"type", "usr_type"}, {"category", "category"}}; + + auto rule = + std::make_shared("usr_id", "name", std::move(tags), builder.build()); + + ruleset->insert_rule(rule); + } + + { + condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}}; + condition::target_type usr_id{get_target_index("usr.id"), "usr.id", {}}; + + auto obj_filter = std::make_shared(); + obj_filter->insert(client_ip.root, client_ip.name); + obj_filter->insert(usr_id.root, usr_id.name); + + std::vector> conditions; + std::set filter_rules{ruleset->rules[0].get(), ruleset->rules[1].get()}; + auto filter = std::make_shared( + "1", std::move(conditions), std::move(filter_rules), std::move(obj_filter)); + + ruleset->input_filters.emplace(filter->get_id(), filter); + } + + // Without usr.id, nothing should be excluded + { + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ctx.insert(root); + + auto objects_to_exclude = ctx.filter_inputs({}, deadline); + EXPECT_EQ(objects_to_exclude.size(), 2); + for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 1); } + + auto events = ctx.match({}, objects_to_exclude, deadline); + EXPECT_EQ(events.size(), 0); + } + + // With usr.id != admin, nothing should be excluded + { + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admino")); + ctx.insert(root); + + auto objects_to_exclude = ctx.filter_inputs({}, deadline); + EXPECT_EQ(objects_to_exclude.size(), 2); + for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 2); } + + auto events = ctx.match({}, objects_to_exclude, deadline); + EXPECT_EQ(events.size(), 0); + } + + // With usr.id == admin, there should be no matches + { + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ctx.insert(root); + + auto objects_to_exclude = ctx.filter_inputs({}, deadline); + EXPECT_EQ(objects_to_exclude.size(), 2); + for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 2); } + + auto events = ctx.match({}, objects_to_exclude, deadline); + EXPECT_EQ(events.size(), 0); + } +} + +TEST(TestContext, InputFilterMultipleRulesMultipleFilters) +{ + auto ruleset = std::make_shared(); + { + expression_builder builder(1); + builder.start_condition( + std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); + + std::unordered_map tags{ + {"type", "ip_type"}, {"category", "category"}}; + + auto rule = + std::make_shared("ip_id", "name", std::move(tags), builder.build()); + + ruleset->insert_rule(rule); + } + + { + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr_id"); + + std::unordered_map tags{ + {"type", "usr_type"}, {"category", "category"}}; + + auto rule = + std::make_shared("usr_id", "name", std::move(tags), builder.build()); + + ruleset->insert_rule(rule); + } + + { + condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}}; + + auto obj_filter = std::make_shared(); + obj_filter->insert(client_ip.root, client_ip.name); -/*std::vector> conditions{std::move(cond)};*/ + std::vector> conditions; + std::set filter_rules{ruleset->rules[0].get()}; + auto filter = std::make_shared( + "1", std::move(conditions), std::move(filter_rules), std::move(obj_filter)); -/*std::unordered_map tags{*/ -/*{"type", "type1"}, {"category", "category1"}};*/ + ruleset->input_filters.emplace(filter->get_id(), filter); + } + + { + condition::target_type usr_id{get_target_index("usr.id"), "usr.id", {}}; + + auto obj_filter = std::make_shared(); + obj_filter->insert(usr_id.root, usr_id.name); -/*auto rule = std::make_shared(*/ -/*"id1", "name1", std::move(tags), std::move(conditions), std::vector{});*/ + std::vector> conditions; + std::set filter_rules{ruleset->rules[1].get()}; + auto filter = std::make_shared( + "2", std::move(conditions), std::move(filter_rules), std::move(obj_filter)); + + ruleset->input_filters.emplace(filter->get_id(), filter); + } + + // Without usr.id, nothing should be excluded + { + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); -/*ruleset->insert_rule(rule);*/ -/*}*/ + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ctx.insert(root); -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ + auto objects_to_exclude = ctx.filter_inputs({}, deadline); + EXPECT_EQ(objects_to_exclude.size(), 1); + for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 1); } -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"admin"}));*/ + auto events = ctx.match({}, objects_to_exclude, deadline); + EXPECT_EQ(events.size(), 0); + } -/*std::vector> conditions{std::move(cond)};*/ + // With usr.id != admin, nothing should be excluded + { + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); -/*std::unordered_map tags{*/ -/*{"type", "type2"}, {"category", "category2"}};*/ + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admino")); + ctx.insert(root); -/*auto rule = std::make_shared(*/ -/*"id2", "name2", std::move(tags), std::move(conditions), std::vector{});*/ + auto objects_to_exclude = ctx.filter_inputs({}, deadline); + EXPECT_EQ(objects_to_exclude.size(), 2); + for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 1); } -/*ruleset->insert_rule(rule);*/ -/*}*/ + auto events = ctx.match({}, objects_to_exclude, deadline); + EXPECT_EQ(events.size(), 0); + } -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ + // With usr.id == admin, there should be no matches + { + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); -/*{*/ -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ctx.insert(root);*/ + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ctx.insert(root); -/*auto events = ctx.match({}, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 1);*/ -/*}*/ + auto objects_to_exclude = ctx.filter_inputs({}, deadline); + EXPECT_EQ(objects_to_exclude.size(), 2); + for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 1); } -/*{*/ -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ctx.insert(root);*/ + auto events = ctx.match({}, objects_to_exclude, deadline); + EXPECT_EQ(events.size(), 0); + } +} -/*auto events = ctx.match({}, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 1);*/ -/*}*/ -/*}*/ +TEST(TestContext, InputFilterMultipleRulesMultipleFiltersMultipleObjects) +{ + auto ruleset = std::make_shared(); + { + expression_builder builder(1); + builder.start_condition( + std::vector{"192.168.0.1"}); + builder.add_target("http.client_ip"); -/*TEST(TestContext, MatchMultiplePriorityCollectionsDoubleRun)*/ -/*{*/ -/*auto ruleset = std::make_shared();*/ -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ + std::unordered_map tags{ + {"type", "ip_type"}, {"category", "category"}}; -/*auto cond = std::make_shared(*/ -/*std::move(targets), std::make_unique(*/ -/*std::vector{"192.168.0.1"}));*/ + auto rule = + std::make_shared("ip_id", "name", std::move(tags), builder.build()); -/*std::vector> conditions{std::move(cond)};*/ + ruleset->insert_rule(rule); + } -/*std::unordered_map tags{*/ -/*{"type", "type1"}, {"category", "category1"}};*/ + { + expression_builder builder(1); + builder.start_condition(std::vector{"admin"}); + builder.add_target("usr_id"); -/*auto rule = std::make_shared("id1", "name1", std::move(tags),*/ -/*std::move(conditions), std::vector{"block"});*/ + std::unordered_map tags{ + {"type", "usr_type"}, {"category", "category"}}; -/*ruleset->insert_rule(rule);*/ -/*}*/ + auto rule = + std::make_shared("usr_id", "name", std::move(tags), builder.build()); -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ + ruleset->insert_rule(rule); + } -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"admin"}));*/ + { + expression_builder builder(1); + builder.start_condition(std::vector{"mycookie"}); + builder.add_target("server.request.headers", {"cookie"}); -/*std::vector> conditions{std::move(cond)};*/ + std::unordered_map tags{ + {"type", "cookie_type"}, {"category", "category"}}; -/*std::unordered_map tags{*/ -/*{"type", "type2"}, {"category", "category2"}};*/ + auto rule = + std::make_shared("cookie_id", "name", std::move(tags), builder.build()); -/*auto rule = std::make_shared("id2", "name2", std::move(tags),*/ -/*std::move(conditions), std::vector{"redirect"});*/ + ruleset->insert_rule(rule); + } -/*ruleset->insert_rule(rule);*/ -/*}*/ + auto ip_rule = ruleset->rules[0]; + auto usr_rule = ruleset->rules[1]; + auto cookie_rule = ruleset->rules[2]; + condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}}; + condition::target_type usr_id{get_target_index("usr.id"), "usr.id", {}}; + condition::target_type cookie_header{ + get_target_index("server.request.headers"), "server.request.headers", {"cookie"}}; -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ + { + auto obj_filter = std::make_shared(); + obj_filter->insert(client_ip.root, client_ip.name); + obj_filter->insert(cookie_header.root, cookie_header.name); -/*{*/ -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ctx.insert(root);*/ + std::vector> conditions; + std::set filter_rules{ip_rule.get(), cookie_rule.get()}; + auto filter = std::make_shared( + "1", std::move(conditions), std::move(filter_rules), std::move(obj_filter)); -/*auto events = ctx.match({}, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 1);*/ -/*}*/ + ruleset->input_filters.emplace(filter->get_id(), filter); + } -/*{*/ -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ctx.insert(root);*/ + { + auto obj_filter = std::make_shared(); + obj_filter->insert(usr_id.root, usr_id.name); + obj_filter->insert(client_ip.root, client_ip.name); -/*auto events = ctx.match({}, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 1);*/ -/*}*/ -/*}*/ + std::vector> conditions; + std::set filter_rules{usr_rule.get(), ip_rule.get()}; + auto filter = std::make_shared( + "2", std::move(conditions), std::move(filter_rules), std::move(obj_filter)); -/*TEST(TestContext, RuleFilterWithCondition)*/ -/*{*/ -/*auto ruleset = std::make_shared();*/ + ruleset->input_filters.emplace(filter->get_id(), filter); + } -/*// Generate rule*/ -/*ddwaf::rule::ptr rule;*/ -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ + { + auto obj_filter = std::make_shared(); + obj_filter->insert(usr_id.root, usr_id.name); + obj_filter->insert(cookie_header.root, cookie_header.name); -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"admin"}));*/ + std::vector> conditions; + std::set filter_rules{usr_rule.get(), cookie_rule.get()}; + auto filter = std::make_shared( + "3", std::move(conditions), std::move(filter_rules), std::move(obj_filter)); -/*std::vector> conditions{std::move(cond)};*/ + ruleset->input_filters.emplace(filter->get_id(), filter); + } -/*std::unordered_map tags{*/ -/*{"type", "type"}, {"category", "category"}};*/ + { + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); -/*rule = std::make_shared(*/ -/*"id", "name", std::move(tags), std::move(conditions), std::vector{});*/ + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ctx.insert(root); -/*ruleset->insert_rule(rule);*/ -/*}*/ + auto objects_to_exclude = ctx.filter_inputs({}, deadline); + EXPECT_EQ(objects_to_exclude.size(), 3); + for (const auto &[rule, objects] : objects_to_exclude) { + EXPECT_EQ(objects.size(), 1); + EXPECT_NE(objects.find(&root.array[0]), objects.end()); + } -/*// Generate filter*/ -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ + auto events = ctx.match({}, objects_to_exclude, deadline); + EXPECT_EQ(events.size(), 0); + } -/*auto cond = std::make_shared(*/ -/*std::move(targets), std::make_unique(*/ -/*std::vector{"192.168.0.1"}));*/ + { + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); -/*std::vector> conditions{std::move(cond)};*/ + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ctx.insert(root); -/*auto filter = std::make_shared(*/ -/*"1", std::move(conditions), std::set{rule.get()});*/ -/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ -/*}*/ + auto objects_to_exclude = ctx.filter_inputs({}, deadline); + EXPECT_EQ(objects_to_exclude.size(), 3); + for (const auto &[rule, objects] : objects_to_exclude) { + EXPECT_EQ(objects.size(), 1); + EXPECT_NE(objects.find(&root.array[0]), objects.end()); + } -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ + auto events = ctx.match({}, objects_to_exclude, deadline); + EXPECT_EQ(events.size(), 0); + } -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ctx.insert(root);*/ + { + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); -/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ -/*EXPECT_EQ(rules_to_exclude.size(), 1);*/ -/*EXPECT_NE(rules_to_exclude.find(rule.get()), rules_to_exclude.end());*/ + ddwaf_object root; + ddwaf_object headers; + ddwaf_object tmp; + ddwaf_object_map(&headers); + ddwaf_object_map_add(&headers, "cookie", ddwaf_object_string(&tmp, "mycookie")); -/*auto events = ctx.match(rules_to_exclude, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 0);*/ -/*}*/ + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.headers", &headers); -/*TEST(TestContext, RuleFilterTimeout)*/ -/*{*/ -/*auto ruleset = std::make_shared();*/ + ctx.insert(root); -/*// Generate rule*/ -/*ddwaf::rule::ptr rule;*/ -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ + auto objects_to_exclude = ctx.filter_inputs({}, deadline); + EXPECT_EQ(objects_to_exclude.size(), 3); + for (const auto &[rule, objects] : objects_to_exclude) { + EXPECT_EQ(objects.size(), 1); + EXPECT_NE(objects.find(&root.array[0]), objects.end()); + } -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"admin"}));*/ + auto events = ctx.match({}, objects_to_exclude, deadline); + EXPECT_EQ(events.size(), 0); + } -/*std::vector> conditions{std::move(cond)};*/ + { + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); -/*std::unordered_map tags{*/ -/*{"type", "type"}, {"category", "category"}};*/ + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ctx.insert(root); -/*rule = std::make_shared(*/ -/*"id", "name", std::move(tags), std::move(conditions), std::vector{});*/ + auto objects_to_exclude = ctx.filter_inputs({}, deadline); + EXPECT_EQ(objects_to_exclude.size(), 3); + for (const auto &[rule, objects] : objects_to_exclude) { + EXPECT_EQ(objects.size(), 2); + EXPECT_NE(objects.find(&root.array[0]), objects.end()); + EXPECT_NE(objects.find(&root.array[1]), objects.end()); + } + auto events = ctx.match({}, objects_to_exclude, deadline); + EXPECT_EQ(events.size(), 0); + } -/*ruleset->insert_rule(rule);*/ -/*}*/ + { + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); -/*// Generate filter*/ -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ + ddwaf_object root; + ddwaf_object headers; + ddwaf_object tmp; + ddwaf_object_map(&headers); + ddwaf_object_map_add(&headers, "cookie", ddwaf_object_string(&tmp, "mycookie")); -/*auto cond = std::make_shared(*/ -/*std::move(targets), std::make_unique(*/ -/*std::vector{"192.168.0.1"}));*/ + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ddwaf_object_map_add(&root, "server.request.headers", &headers); -/*std::vector> conditions{std::move(cond)};*/ + ctx.insert(root); -/*auto filter = std::make_shared(*/ -/*"1", std::move(conditions), std::set{rule.get()});*/ -/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ -/*}*/ + auto objects_to_exclude = ctx.filter_inputs({}, deadline); + EXPECT_EQ(objects_to_exclude.size(), 3); + for (const auto &[rule, objects] : objects_to_exclude) { + EXPECT_EQ(objects.size(), 2); + EXPECT_NE(objects.find(&root.array[0]), objects.end()); + EXPECT_NE(objects.find(&root.array[1]), objects.end()); + } + auto events = ctx.match({}, objects_to_exclude, deadline); + EXPECT_EQ(events.size(), 0); + } -/*ddwaf::timer deadline{0s};*/ -/*ddwaf::test::context ctx(ruleset);*/ + { + ddwaf::timer deadline{2s}; + ddwaf::test::context ctx(ruleset); -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ctx.insert(root);*/ + ddwaf_object root; + ddwaf_object headers; + ddwaf_object tmp; + ddwaf_object_map(&headers); + ddwaf_object_map_add(&headers, "cookie", ddwaf_object_string(&tmp, "mycookie")); -/*EXPECT_THROW(ctx.filter_rules(deadline), ddwaf::timeout_exception);*/ -/*}*/ + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1")); + ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin")); + ddwaf_object_map_add(&root, "server.request.headers", &headers); -/*TEST(TestContext, NoRuleFilterWithCondition)*/ -/*{*/ -/*auto ruleset = std::make_shared();*/ + ctx.insert(root); -/*// Generate rule*/ -/*ddwaf::rule::ptr rule;*/ -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ - -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"admin"}));*/ - -/*std::vector> conditions{std::move(cond)};*/ - -/*std::unordered_map tags{*/ -/*{"type", "type"}, {"category", "category"}};*/ - -/*rule = std::make_shared(*/ -/*"id", "name", std::move(tags), std::move(conditions), std::vector{});*/ - -/*ruleset->insert_rule(rule);*/ -/*}*/ - -/*// Generate filter*/ -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ - -/*auto cond = std::make_shared(*/ -/*std::move(targets), std::make_unique(*/ -/*std::vector{"192.168.0.1"}));*/ - -/*std::vector> conditions{std::move(cond)};*/ - -/*auto filter = std::make_shared(*/ -/*"1", std::move(conditions), std::set{rule.get()});*/ -/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ -/*}*/ - -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.2"));*/ -/*ctx.insert(root);*/ - -/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ -/*EXPECT_TRUE(rules_to_exclude.empty());*/ - -/*auto events = ctx.match(rules_to_exclude, {}, deadline);*/ -/*EXPECT_EQ(events.size(), 1);*/ -/*}*/ - -/*TEST(TestContext, MultipleRuleFiltersNonOverlappingRules)*/ -/*{*/ -/*auto ruleset = std::make_shared();*/ - -/*// Generate rule*/ -/*constexpr unsigned num_rules = 9;*/ -/*std::vector rules;*/ -/*rules.reserve(num_rules);*/ -/*for (unsigned i = 0; i < num_rules; i++) {*/ - -/*std::unordered_map tags{*/ -/*{"type", "type"}, {"category", "category"}};*/ - -/*rules.emplace_back(std::make_shared("id" + std::to_string(i), "name",*/ -/*std::move(tags), std::vector{}, std::vector{}));*/ - -/*ruleset->insert_rule(rules.back());*/ -/*}*/ - -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*{*/ -/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ -/*EXPECT_EQ(rules_to_exclude.size(), 0);*/ -/*}*/ - -/*{*/ -/*auto filter = std::make_shared("1", std::vector{},*/ -/*std::set{rules[0].get(), rules[1].get(), rules[2].get()});*/ -/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ - -/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ -/*EXPECT_EQ(rules_to_exclude.size(), 3);*/ -/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ -/*}*/ - -/*{*/ -/*auto filter = std::make_shared("2", std::vector{},*/ -/*std::set{rules[3].get(), rules[4].get(), rules[5].get()});*/ -/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ - -/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ -/*EXPECT_EQ(rules_to_exclude.size(), 6);*/ -/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end());*/ -/*}*/ - -/*{*/ -/*auto filter = std::make_shared("3", std::vector{},*/ -/*std::set{rules[6].get(), rules[7].get(), rules[8].get()});*/ -/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ - -/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ -/*EXPECT_EQ(rules_to_exclude.size(), 9);*/ -/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end());*/ -/*}*/ -/*}*/ - -/*TEST(TestContext, MultipleRuleFiltersOverlappingRules)*/ -/*{*/ -/*auto ruleset = std::make_shared();*/ - -/*// Generate rule*/ -/*constexpr unsigned num_rules = 9;*/ -/*std::vector rules;*/ -/*rules.reserve(num_rules);*/ -/*for (unsigned i = 0; i < num_rules; i++) {*/ -/*std::string id = "id" + std::to_string(i);*/ - -/*std::unordered_map tags{*/ -/*{"type", "type"}, {"category", "category"}};*/ - -/*rules.emplace_back(std::make_shared(std::string(id), "name", std::move(tags),*/ -/*std::vector{}, std::vector{}));*/ - -/*ruleset->insert_rule(rules.back());*/ -/*}*/ - -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*{*/ -/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ -/*EXPECT_EQ(rules_to_exclude.size(), 0);*/ -/*}*/ - -/*{*/ -/*auto filter = std::make_shared("1", std::vector{},*/ -/*std::set{*/ -/*rules[0].get(), rules[1].get(), rules[2].get(), rules[3].get()});*/ -/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ - -/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ -/*EXPECT_EQ(rules_to_exclude.size(), 4);*/ -/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end());*/ -/*}*/ - -/*{*/ -/*auto filter = std::make_shared("2", std::vector{},*/ -/*std::set{rules[2].get(), rules[3].get(), rules[4].get()});*/ -/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ - -/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ -/*EXPECT_EQ(rules_to_exclude.size(), 5);*/ -/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end());*/ -/*}*/ - -/*{*/ -/*auto filter = std::make_shared("3", std::vector{},*/ -/*std::set{rules[0].get(), rules[5].get(), rules[6].get()});*/ -/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ - -/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ -/*EXPECT_EQ(rules_to_exclude.size(), 7);*/ -/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end());*/ -/*}*/ - -/*{*/ -/*auto filter = std::make_shared("4", std::vector{},*/ -/*std::set{rules[7].get(), rules[8].get(), rules[6].get()});*/ -/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ - -/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ -/*EXPECT_EQ(rules_to_exclude.size(), 9);*/ -/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end());*/ -/*}*/ - -/*{*/ -/*auto filter = std::make_shared("5", std::vector{},*/ -/*std::set{rules[0].get(), rules[1].get(), rules[2].get(), rules[3].get(),*/ -/*rules[4].get(), rules[5].get(), rules[6].get(), rules[7].get(), rules[8].get()});*/ -/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ - -/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ -/*EXPECT_EQ(rules_to_exclude.size(), 9);*/ -/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end());*/ -/*}*/ -/*}*/ - -/*TEST(TestContext, MultipleRuleFiltersNonOverlappingRulesWithConditions)*/ -/*{*/ -/*auto ruleset = std::make_shared();*/ - -/*// Generate rule*/ -/*constexpr unsigned num_rules = 10;*/ -/*std::vector rules;*/ -/*rules.reserve(num_rules);*/ -/*for (unsigned i = 0; i < num_rules; i++) {*/ -/*std::string id = "id" + std::to_string(i);*/ - -/*std::unordered_map tags{*/ -/*{"type", "type"}, {"category", "category"}};*/ - -/*rules.emplace_back(std::make_shared(std::string(id), "name", std::move(tags),*/ -/*std::vector{}, std::vector{}));*/ - -/*ruleset->insert_rule(rules.back());*/ -/*}*/ - -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ - -/*auto cond = std::make_shared(*/ -/*std::move(targets), std::make_unique(*/ -/*std::vector{"192.168.0.1"}));*/ - -/*std::vector> conditions{std::move(cond)};*/ - -/*auto filter = std::make_shared("1", std::move(conditions),*/ -/*std::set{*/ -/*rules[0].get(), rules[1].get(), rules[2].get(), rules[3].get(), rules[4].get()});*/ -/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ -/*}*/ - -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ - -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"admin"}));*/ - -/*std::vector> conditions{std::move(cond)};*/ - -/*auto filter = std::make_shared("2", std::move(conditions),*/ -/*std::set{*/ -/*rules[5].get(), rules[6].get(), rules[7].get(), rules[8].get(), rules[9].get()});*/ -/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ -/*}*/ - -/*{*/ -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ctx.insert(root);*/ - -/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ -/*EXPECT_EQ(rules_to_exclude.size(), 5);*/ -/*EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[9].get()), rules_to_exclude.end());*/ -/*}*/ - -/*{*/ -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ctx.insert(root);*/ - -/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ -/*EXPECT_EQ(rules_to_exclude.size(), 10);*/ -/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[9].get()), rules_to_exclude.end());*/ -/*}*/ -/*}*/ - -/*TEST(TestContext, MultipleRuleFiltersOverlappingRulesWithConditions)*/ -/*{*/ -/*auto ruleset = std::make_shared();*/ - -/*// Generate rule*/ -/*constexpr unsigned num_rules = 10;*/ -/*std::vector rules;*/ -/*rules.reserve(num_rules);*/ -/*for (unsigned i = 0; i < num_rules; i++) {*/ -/*std::string id = "id" + std::to_string(i);*/ - -/*std::unordered_map tags{*/ -/*{"type", "type"}, {"category", "category"}};*/ - -/*rules.emplace_back(std::make_shared(std::string(id), "name", std::move(tags),*/ -/*std::vector{}, std::vector{}));*/ - -/*ruleset->insert_rule(rules.back());*/ -/*}*/ - -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("http.client_ip"), "http.client_ip", {}, {}});*/ - -/*auto cond = std::make_shared(*/ -/*std::move(targets), std::make_unique(*/ -/*std::vector{"192.168.0.1"}));*/ - -/*std::vector> conditions{std::move(cond)};*/ - -/*auto filter = std::make_shared("1", std::move(conditions),*/ -/*std::set{rules[0].get(), rules[1].get(), rules[2].get(), rules[3].get(),*/ -/*rules[4].get(), rules[5].get(), rules[6].get()});*/ -/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ -/*}*/ - -/*{*/ -/*std::vector targets;*/ -/*targets.push_back({get_target_index("usr.id"), "usr.id", {}, {}});*/ - -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"admin"}));*/ - -/*std::vector> conditions{std::move(cond)};*/ - -/*auto filter = std::make_shared("2", std::move(conditions),*/ -/*std::set{rules[3].get(), rules[4].get(), rules[5].get(), rules[6].get(),*/ -/*rules[7].get(), rules[8].get(), rules[9].get()});*/ -/*ruleset->rule_filters.emplace(filter->get_id(), filter);*/ -/*}*/ - -/*{*/ -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ctx.insert(root);*/ - -/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ -/*EXPECT_EQ(rules_to_exclude.size(), 7);*/ -/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end());*/ -/*}*/ - -/*{*/ -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ctx.insert(root);*/ - -/*auto rules_to_exclude = ctx.filter_rules(deadline);*/ -/*EXPECT_EQ(rules_to_exclude.size(), 10);*/ -/*EXPECT_NE(rules_to_exclude.find(rules[0].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[1].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[2].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[3].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[4].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[5].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[6].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[7].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[8].get()), rules_to_exclude.end());*/ -/*EXPECT_NE(rules_to_exclude.find(rules[9].get()), rules_to_exclude.end());*/ -/*}*/ -/*}*/ - -/*TEST(TestContext, InputFilterExclude)*/ -/*{*/ -/*condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}};*/ - -/*std::vector targets{client_ip};*/ -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"192.168.0.1"}));*/ - -/*std::vector> conditions{std::move(cond)};*/ - -/*std::unordered_map tags{{"type", "type"}, {"category", "category"}};*/ - -/*auto rule = std::make_shared(*/ -/*"id", "name", std::move(tags), std::move(conditions), std::vector{});*/ - -/*auto obj_filter = std::make_shared();*/ -/*obj_filter->insert(client_ip.root, client_ip.name);*/ - -/*std::vector filter_conditions;*/ -/*std::set filter_rules{rule.get()};*/ -/*auto filter = std::make_shared(*/ -/*"1", std::move(filter_conditions), std::move(filter_rules), std::move(obj_filter));*/ - -/*auto ruleset = std::make_shared();*/ -/*ruleset->insert_rule(rule);*/ -/*ruleset->input_filters.emplace(filter->get_id(), filter);*/ - -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ctx.insert(root);*/ - -/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ -/*EXPECT_EQ(objects_to_exclude.size(), 1);*/ -/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ -/*EXPECT_EQ(events.size(), 0);*/ -/*}*/ - -/*TEST(TestContext, InputFilterExcludeRule)*/ -/*{*/ -/*condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}};*/ - -/*std::vector targets{client_ip};*/ -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"192.168.0.1"}));*/ - -/*std::vector> conditions{std::move(cond)};*/ - -/*std::unordered_map tags{{"type", "type"}, {"category", "category"}};*/ - -/*auto rule = std::make_shared(*/ -/*"id", "name", std::move(tags), std::move(conditions), std::vector{});*/ - -/*auto obj_filter = std::make_shared();*/ -/*obj_filter->insert(client_ip.root, client_ip.name);*/ - -/*std::vector filter_conditions;*/ -/*std::set filter_rules{rule.get()};*/ -/*auto filter = std::make_shared(*/ -/*"1", std::move(filter_conditions), std::move(filter_rules), std::move(obj_filter));*/ - -/*auto ruleset = std::make_shared();*/ -/*ruleset->insert_rule(rule);*/ -/*ruleset->input_filters.emplace(filter->get_id(), filter);*/ - -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ctx.insert(root);*/ - -/*// The rule is added to the filter stage so that it's excluded from the*/ -/*// final result, since we're not actually excluding the rule from the match*/ -/*// stage we still get an event.*/ -/*auto objects_to_exclude = ctx.filter_inputs({rule.get()}, deadline);*/ -/*EXPECT_EQ(objects_to_exclude.size(), 0);*/ -/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ -/*EXPECT_EQ(events.size(), 1);*/ -/*}*/ - -/*TEST(TestContext, InputFilterWithCondition)*/ -/*{*/ -/*condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}};*/ -/*condition::target_type usr_id{get_target_index("usr.id"), "usr.id", {}};*/ - -/*auto ruleset = std::make_shared();*/ -/*{*/ -/*std::vector> conditions;*/ -/*std::vector targets{client_ip};*/ -/*auto cond = std::make_shared(*/ -/*std::move(targets), std::make_unique(*/ -/*std::vector{"192.168.0.1"}));*/ -/*conditions.emplace_back(std::move(cond));*/ - -/*std::unordered_map tags{*/ -/*{"type", "type"}, {"category", "category"}};*/ - -/*auto rule = std::make_shared(*/ -/*"id", "name", std::move(tags), std::move(conditions), std::vector{});*/ - -/*ruleset->insert_rule(rule);*/ -/*}*/ - -/*{*/ -/*auto obj_filter = std::make_shared();*/ -/*obj_filter->insert(client_ip.root, client_ip.name);*/ - -/*std::vector> conditions;*/ -/*std::vector targets{usr_id};*/ -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"admin"}));*/ -/*conditions.emplace_back(std::move(cond));*/ - -/*std::set filter_rules{ruleset->rules[0].get()};*/ -/*auto filter = std::make_shared(*/ -/*"1", std::move(conditions), std::move(filter_rules), std::move(obj_filter));*/ - -/*ruleset->input_filters.emplace(filter->get_id(), filter);*/ -/*}*/ - -/*// Without usr.id, nothing should be excluded*/ -/*{*/ -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ctx.insert(root);*/ - -/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ -/*EXPECT_EQ(objects_to_exclude.size(), 0);*/ -/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ -/*EXPECT_EQ(events.size(), 1);*/ -/*}*/ - -/*// With usr.id != admin, nothing should be excluded*/ -/*{*/ -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admino"));*/ -/*ctx.insert(root);*/ - -/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ -/*EXPECT_EQ(objects_to_exclude.size(), 0);*/ -/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ -/*EXPECT_EQ(events.size(), 1);*/ -/*}*/ - -/*// With usr.id == admin, there should be no matches*/ -/*{*/ -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ctx.insert(root);*/ - -/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ -/*EXPECT_EQ(objects_to_exclude.size(), 1);*/ -/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ -/*EXPECT_EQ(events.size(), 0);*/ -/*}*/ -/*}*/ - -/*TEST(TestContext, InputFilterMultipleRules)*/ -/*{*/ -/*condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}};*/ -/*condition::target_type usr_id{get_target_index("usr.id"), "usr.id", {}};*/ - -/*auto ruleset = std::make_shared();*/ -/*{*/ -/*std::vector> conditions;*/ -/*std::vector targets{client_ip};*/ -/*auto cond = std::make_shared(*/ -/*std::move(targets), std::make_unique(*/ -/*std::vector{"192.168.0.1"}));*/ -/*conditions.emplace_back(std::move(cond));*/ - -/*std::unordered_map tags{*/ -/*{"type", "ip_type"}, {"category", "category"}};*/ - -/*auto rule = std::make_shared(*/ -/*"ip_id", "name", std::move(tags), std::move(conditions), std::vector{});*/ - -/*ruleset->insert_rule(rule);*/ -/*}*/ - -/*{*/ -/*std::vector> conditions;*/ -/*std::vector targets{usr_id};*/ -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"admin"}));*/ -/*conditions.emplace_back(std::move(cond));*/ - -/*std::unordered_map tags{*/ -/*{"type", "usr_type"}, {"category", "category"}};*/ - -/*auto rule = std::make_shared(*/ -/*"usr_id", "name", std::move(tags), std::move(conditions), std::vector{});*/ - -/*ruleset->insert_rule(rule);*/ -/*}*/ - -/*{*/ -/*auto obj_filter = std::make_shared();*/ -/*obj_filter->insert(client_ip.root, client_ip.name);*/ -/*obj_filter->insert(usr_id.root, usr_id.name);*/ - -/*std::vector> conditions;*/ -/*std::set filter_rules{ruleset->rules[0].get(), ruleset->rules[1].get()};*/ -/*auto filter = std::make_shared(*/ -/*"1", std::move(conditions), std::move(filter_rules), std::move(obj_filter));*/ - -/*ruleset->input_filters.emplace(filter->get_id(), filter);*/ -/*}*/ - -/*// Without usr.id, nothing should be excluded*/ -/*{*/ -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ctx.insert(root);*/ - -/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ -/*EXPECT_EQ(objects_to_exclude.size(), 2);*/ -/*for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 1); }*/ - -/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ -/*EXPECT_EQ(events.size(), 0);*/ -/*}*/ - -/*// With usr.id != admin, nothing should be excluded*/ -/*{*/ -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admino"));*/ -/*ctx.insert(root);*/ - -/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ -/*EXPECT_EQ(objects_to_exclude.size(), 2);*/ -/*for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 2); }*/ - -/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ -/*EXPECT_EQ(events.size(), 0);*/ -/*}*/ - -/*// With usr.id == admin, there should be no matches*/ -/*{*/ -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ctx.insert(root);*/ - -/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ -/*EXPECT_EQ(objects_to_exclude.size(), 2);*/ -/*for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 2); }*/ - -/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ -/*EXPECT_EQ(events.size(), 0);*/ -/*}*/ -/*}*/ - -/*TEST(TestContext, InputFilterMultipleRulesMultipleFilters)*/ -/*{*/ -/*condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}};*/ -/*condition::target_type usr_id{get_target_index("usr.id"), "usr.id", {}};*/ - -/*auto ruleset = std::make_shared();*/ -/*{*/ -/*std::vector> conditions;*/ -/*std::vector targets{client_ip};*/ -/*auto cond = std::make_shared(*/ -/*std::move(targets), std::make_unique(*/ -/*std::vector{"192.168.0.1"}));*/ -/*conditions.emplace_back(std::move(cond));*/ - -/*std::unordered_map tags{*/ -/*{"type", "ip_type"}, {"category", "category"}};*/ - -/*auto rule = std::make_shared(*/ -/*"ip_id", "name", std::move(tags), std::move(conditions), std::vector{});*/ - -/*ruleset->insert_rule(rule);*/ -/*}*/ - -/*{*/ -/*std::vector> conditions;*/ -/*std::vector targets{usr_id};*/ -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"admin"}));*/ -/*conditions.emplace_back(std::move(cond));*/ - -/*std::unordered_map tags{*/ -/*{"type", "usr_type"}, {"category", "category"}};*/ - -/*auto rule = std::make_shared(*/ -/*"usr_id", "name", std::move(tags), std::move(conditions), std::vector{});*/ - -/*ruleset->insert_rule(rule);*/ -/*}*/ - -/*{*/ -/*auto obj_filter = std::make_shared();*/ -/*obj_filter->insert(client_ip.root, client_ip.name);*/ - -/*std::vector> conditions;*/ -/*std::set filter_rules{ruleset->rules[0].get()};*/ -/*auto filter = std::make_shared(*/ -/*"1", std::move(conditions), std::move(filter_rules), std::move(obj_filter));*/ - -/*ruleset->input_filters.emplace(filter->get_id(), filter);*/ -/*}*/ - -/*{*/ -/*auto obj_filter = std::make_shared();*/ -/*obj_filter->insert(usr_id.root, usr_id.name);*/ - -/*std::vector> conditions;*/ -/*std::set filter_rules{ruleset->rules[1].get()};*/ -/*auto filter = std::make_shared(*/ -/*"2", std::move(conditions), std::move(filter_rules), std::move(obj_filter));*/ - -/*ruleset->input_filters.emplace(filter->get_id(), filter);*/ -/*}*/ - -/*// Without usr.id, nothing should be excluded*/ -/*{*/ -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ctx.insert(root);*/ - -/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ -/*EXPECT_EQ(objects_to_exclude.size(), 1);*/ -/*for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 1); }*/ - -/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ -/*EXPECT_EQ(events.size(), 0);*/ -/*}*/ - -/*// With usr.id != admin, nothing should be excluded*/ -/*{*/ -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admino"));*/ -/*ctx.insert(root);*/ - -/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ -/*EXPECT_EQ(objects_to_exclude.size(), 2);*/ -/*for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 1); }*/ - -/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ -/*EXPECT_EQ(events.size(), 0);*/ -/*}*/ - -/*// With usr.id == admin, there should be no matches*/ -/*{*/ -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ctx.insert(root);*/ - -/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ -/*EXPECT_EQ(objects_to_exclude.size(), 2);*/ -/*for (const auto &[rule, objects] : objects_to_exclude) { EXPECT_EQ(objects.size(), 1); }*/ - -/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ -/*EXPECT_EQ(events.size(), 0);*/ -/*}*/ -/*}*/ - -/*TEST(TestContext, InputFilterMultipleRulesMultipleFiltersMultipleObjects)*/ -/*{*/ -/*condition::target_type client_ip{get_target_index("http.client_ip"), "http.client_ip", {}};*/ -/*condition::target_type usr_id{get_target_index("usr.id"), "usr.id", {}};*/ -/*condition::target_type cookie_header{*/ -/*get_target_index("server.request.headers"), "server.request.headers", {"cookie"}};*/ - -/*auto ruleset = std::make_shared();*/ -/*{*/ -/*std::vector> conditions;*/ -/*std::vector targets{client_ip};*/ -/*auto cond = std::make_shared(*/ -/*std::move(targets), std::make_unique(*/ -/*std::vector{"192.168.0.1"}));*/ -/*conditions.emplace_back(std::move(cond));*/ - -/*std::unordered_map tags{*/ -/*{"type", "ip_type"}, {"category", "category"}};*/ - -/*auto rule = std::make_shared(*/ -/*"ip_id", "name", std::move(tags), std::move(conditions), std::vector{});*/ - -/*ruleset->insert_rule(rule);*/ -/*}*/ - -/*{*/ -/*std::vector> conditions;*/ -/*std::vector targets{usr_id};*/ -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"admin"}));*/ -/*conditions.emplace_back(std::move(cond));*/ - -/*std::unordered_map tags{*/ -/*{"type", "usr_type"}, {"category", "category"}};*/ - -/*auto rule = std::make_shared(*/ -/*"usr_id", "name", std::move(tags), std::move(conditions), std::vector{});*/ - -/*ruleset->insert_rule(rule);*/ -/*}*/ - -/*{*/ -/*std::vector> conditions;*/ -/*std::vector targets{cookie_header};*/ -/*auto cond = std::make_shared(std::move(targets),*/ -/*std::make_unique(std::vector{"mycookie"}));*/ -/*conditions.emplace_back(std::move(cond));*/ - -/*std::unordered_map tags{*/ -/*{"type", "cookie_type"}, {"category", "category"}};*/ - -/*auto rule = std::make_shared("cookie_id", "name", std::move(tags),*/ -/*std::move(conditions), std::vector{});*/ - -/*ruleset->insert_rule(rule);*/ -/*}*/ - -/*auto ip_rule = ruleset->rules[0];*/ -/*auto usr_rule = ruleset->rules[1];*/ -/*auto cookie_rule = ruleset->rules[2];*/ -/*{*/ -/*auto obj_filter = std::make_shared();*/ -/*obj_filter->insert(client_ip.root, client_ip.name);*/ -/*obj_filter->insert(cookie_header.root, cookie_header.name);*/ - -/*std::vector> conditions;*/ -/*std::set filter_rules{ip_rule.get(), cookie_rule.get()};*/ -/*auto filter = std::make_shared(*/ -/*"1", std::move(conditions), std::move(filter_rules), std::move(obj_filter));*/ - -/*ruleset->input_filters.emplace(filter->get_id(), filter);*/ -/*}*/ - -/*{*/ -/*auto obj_filter = std::make_shared();*/ -/*obj_filter->insert(usr_id.root, usr_id.name);*/ -/*obj_filter->insert(client_ip.root, client_ip.name);*/ - -/*std::vector> conditions;*/ -/*std::set filter_rules{usr_rule.get(), ip_rule.get()};*/ -/*auto filter = std::make_shared(*/ -/*"2", std::move(conditions), std::move(filter_rules), std::move(obj_filter));*/ - -/*ruleset->input_filters.emplace(filter->get_id(), filter);*/ -/*}*/ - -/*{*/ -/*auto obj_filter = std::make_shared();*/ -/*obj_filter->insert(usr_id.root, usr_id.name);*/ -/*obj_filter->insert(cookie_header.root, cookie_header.name);*/ - -/*std::vector> conditions;*/ -/*std::set filter_rules{usr_rule.get(), cookie_rule.get()};*/ -/*auto filter = std::make_shared(*/ -/*"3", std::move(conditions), std::move(filter_rules), std::move(obj_filter));*/ - -/*ruleset->input_filters.emplace(filter->get_id(), filter);*/ -/*}*/ - -/*{*/ -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ctx.insert(root);*/ - -/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ -/*EXPECT_EQ(objects_to_exclude.size(), 3);*/ -/*for (const auto &[rule, objects] : objects_to_exclude) {*/ -/*EXPECT_EQ(objects.size(), 1);*/ -/*EXPECT_NE(objects.find(&root.array[0]), objects.end());*/ -/*}*/ - -/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ -/*EXPECT_EQ(events.size(), 0);*/ -/*}*/ - -/*{*/ -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ctx.insert(root);*/ - -/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ -/*EXPECT_EQ(objects_to_exclude.size(), 3);*/ -/*for (const auto &[rule, objects] : objects_to_exclude) {*/ -/*EXPECT_EQ(objects.size(), 1);*/ -/*EXPECT_NE(objects.find(&root.array[0]), objects.end());*/ -/*}*/ - -/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ -/*EXPECT_EQ(events.size(), 0);*/ -/*}*/ - -/*{*/ -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*ddwaf_object root;*/ -/*ddwaf_object headers;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&headers);*/ -/*ddwaf_object_map_add(&headers, "cookie", ddwaf_object_string(&tmp, "mycookie"));*/ - -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "server.request.headers", &headers);*/ - -/*ctx.insert(root);*/ - -/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ -/*EXPECT_EQ(objects_to_exclude.size(), 3);*/ -/*for (const auto &[rule, objects] : objects_to_exclude) {*/ -/*EXPECT_EQ(objects.size(), 1);*/ -/*EXPECT_NE(objects.find(&root.array[0]), objects.end());*/ -/*}*/ - -/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ -/*EXPECT_EQ(events.size(), 0);*/ -/*}*/ - -/*{*/ -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*ddwaf_object root;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ctx.insert(root);*/ - -/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ -/*EXPECT_EQ(objects_to_exclude.size(), 3);*/ -/*for (const auto &[rule, objects] : objects_to_exclude) {*/ -/*EXPECT_EQ(objects.size(), 2);*/ -/*EXPECT_NE(objects.find(&root.array[0]), objects.end());*/ -/*EXPECT_NE(objects.find(&root.array[1]), objects.end());*/ -/*}*/ -/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ -/*EXPECT_EQ(events.size(), 0);*/ -/*}*/ - -/*{*/ -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*ddwaf_object root;*/ -/*ddwaf_object headers;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&headers);*/ -/*ddwaf_object_map_add(&headers, "cookie", ddwaf_object_string(&tmp, "mycookie"));*/ - -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ddwaf_object_map_add(&root, "server.request.headers", &headers);*/ - -/*ctx.insert(root);*/ - -/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ -/*EXPECT_EQ(objects_to_exclude.size(), 3);*/ -/*for (const auto &[rule, objects] : objects_to_exclude) {*/ -/*EXPECT_EQ(objects.size(), 2);*/ -/*EXPECT_NE(objects.find(&root.array[0]), objects.end());*/ -/*EXPECT_NE(objects.find(&root.array[1]), objects.end());*/ -/*}*/ -/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ -/*EXPECT_EQ(events.size(), 0);*/ -/*}*/ - -/*{*/ -/*ddwaf::timer deadline{2s};*/ -/*ddwaf::test::context ctx(ruleset);*/ - -/*ddwaf_object root;*/ -/*ddwaf_object headers;*/ -/*ddwaf_object tmp;*/ -/*ddwaf_object_map(&headers);*/ -/*ddwaf_object_map_add(&headers, "cookie", ddwaf_object_string(&tmp, "mycookie"));*/ - -/*ddwaf_object_map(&root);*/ -/*ddwaf_object_map_add(&root, "http.client_ip", ddwaf_object_string(&tmp, "192.168.0.1"));*/ -/*ddwaf_object_map_add(&root, "usr.id", ddwaf_object_string(&tmp, "admin"));*/ -/*ddwaf_object_map_add(&root, "server.request.headers", &headers);*/ - -/*ctx.insert(root);*/ - -/*auto objects_to_exclude = ctx.filter_inputs({}, deadline);*/ -/*EXPECT_EQ(objects_to_exclude.size(), 3);*/ -/*for (const auto &[rule, objects] : objects_to_exclude) {*/ -/*EXPECT_EQ(objects.size(), 3);*/ -/*EXPECT_NE(objects.find(&root.array[0]), objects.end());*/ -/*EXPECT_NE(objects.find(&root.array[1]), objects.end());*/ -/*EXPECT_NE(objects.find(&root.array[2]), objects.end());*/ -/*}*/ -/*auto events = ctx.match({}, objects_to_exclude, deadline);*/ -/*EXPECT_EQ(events.size(), 0);*/ -/*}*/ -/*}*/ + auto objects_to_exclude = ctx.filter_inputs({}, deadline); + EXPECT_EQ(objects_to_exclude.size(), 3); + for (const auto &[rule, objects] : objects_to_exclude) { + EXPECT_EQ(objects.size(), 3); + EXPECT_NE(objects.find(&root.array[0]), objects.end()); + EXPECT_NE(objects.find(&root.array[1]), objects.end()); + EXPECT_NE(objects.find(&root.array[2]), objects.end()); + } + auto events = ctx.match({}, objects_to_exclude, deadline); + EXPECT_EQ(events.size(), 0); + } +} From 3822348279e6c82cf49d18d65ab49e582fe85533 Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Fri, 30 Jun 2023 11:42:24 +0100 Subject: [PATCH 24/28] Fix bug on failed object-chain path --- src/expression.cpp | 2 +- tests/expression_test.cpp | 106 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 1 deletion(-) diff --git a/src/expression.cpp b/src/expression.cpp index 26f555a2d..cb4eff621 100644 --- a/src/expression.cpp +++ b/src/expression.cpp @@ -198,7 +198,7 @@ bool expression::evaluator::eval_condition(const condition &cond, eval_scope sco return true; } - return false; + return cond_cache.result.has_value(); } bool expression::evaluator::eval() diff --git a/tests/expression_test.cpp b/tests/expression_test.cpp index 90f75d98f..cb6247aa2 100644 --- a/tests/expression_test.cpp +++ b/tests/expression_test.cpp @@ -471,3 +471,109 @@ TEST(TestExpression, SingleHighlightChain) .value = "query", .highlight = "query"}); } + +TEST(TestExpression, HybridScalarChain) +{ + expression_builder builder(2); + + builder.start_condition("query", 0, true); + builder.add_target("server.request.query"); + + builder.start_condition("^query$", 0, true); + builder.add_target("match.0.scalar"); + builder.add_target("server.request.body"); + + auto expr = builder.build(); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "some query")); + ddwaf_object_map_add(&root, "server.request.body", ddwaf_object_string(&tmp, "query")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + expression::cache_type cache; + EXPECT_TRUE(expr->eval(cache, store, {}, {}, deadline)); + + auto matches = expr->get_matches(cache); + EXPECT_MATCHES(matches, + {.op = "match_regex", + .op_value = "query", + .address = "server.request.query", + .path = {}, + .value = "some query", + .highlight = "query"}, + {.op = "match_regex", + .op_value = "^query$", + .address = "server.request.body", + .path = {}, + .value = "query", + .highlight = "query"}); +} + +TEST(TestExpression, HybridObjectChain) +{ + expression_builder builder(2); + + builder.start_condition("query", 0, true); + builder.add_target("server.request.query"); + + builder.start_condition("^thermometer$", 0, true); + builder.add_target("match.0.object"); + builder.add_target("server.request.body"); + + auto expr = builder.build(); + + { + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add( + &root, "server.request.query", ddwaf_object_string(&tmp, "some query")); + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + expression::cache_type cache; + EXPECT_FALSE(expr->eval(cache, store, {}, {}, deadline)); + } + + { + ddwaf_object root; + ddwaf_object tmp; + + ddwaf_object_map(&root); + ddwaf_object_map_add( + &root, "server.request.query", ddwaf_object_string(&tmp, "some query")); + ddwaf_object_map_add( + &root, "server.request.body", ddwaf_object_string(&tmp, "thermometer")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + expression::cache_type cache; + EXPECT_TRUE(expr->eval(cache, store, {}, {}, deadline)); + + auto matches = expr->get_matches(cache); + EXPECT_MATCHES(matches, + {.op = "match_regex", + .op_value = "query", + .address = "server.request.query", + .path = {}, + .value = "some query", + .highlight = "query"}, + {.op = "match_regex", + .op_value = "^thermometer$", + .address = "server.request.body", + .path = {}, + .value = "thermometer", + .highlight = "thermometer"}); + } +} From 651a08d7808a04b43b662c07c7cea3927effb1b7 Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Fri, 30 Jun 2023 14:07:33 +0100 Subject: [PATCH 25/28] Add more tests --- tests/expression_test.cpp | 195 ++++++++++++++++++++++++++++++++++++++ tests/test_utils.cpp | 4 +- 2 files changed, 197 insertions(+), 2 deletions(-) diff --git a/tests/expression_test.cpp b/tests/expression_test.cpp index cb6247aa2..c15d1ac8d 100644 --- a/tests/expression_test.cpp +++ b/tests/expression_test.cpp @@ -577,3 +577,198 @@ TEST(TestExpression, HybridObjectChain) .highlight = "thermometer"}); } } + +TEST(TestExpression, MatchWithKeyPath) +{ + expression_builder builder(1); + builder.start_condition(".*", 0, true); + builder.add_target("server.request.query", {"key"}); + auto expr = builder.build(); + + ddwaf_object root; + ddwaf_object submap; + ddwaf_object tmp; + ddwaf_object_map(&submap); + ddwaf_object_map_add(&submap, "key", ddwaf_object_string(&tmp, "value")); + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", &submap); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + expression::cache_type cache; + EXPECT_TRUE(expr->eval(cache, store, {}, {}, deadline)); + auto matches = expr->get_matches(cache); + EXPECT_MATCHES(matches, {.op = "match_regex", + .op_value = ".*", + .address = "server.request.query", + .path = {"key"}, + .value = "value", + .highlight = "value"}); +} + +TEST(TestExpression, MatchWithTransformer) +{ + expression_builder builder(1); + builder.start_condition("value", 0, true); + builder.add_target("server.request.query", {}, {PWT_LOWERCASE}); + auto expr = builder.build(); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "VALUE")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + expression::cache_type cache; + EXPECT_TRUE(expr->eval(cache, store, {}, {}, deadline)); + auto matches = expr->get_matches(cache); + EXPECT_MATCHES(matches, {.op = "match_regex", + .op_value = "value", + .address = "server.request.query", + .path = {}, + .value = "value", + .highlight = "value"}); +} + +TEST(TestExpression, MatchWithMultipleTransformers) +{ + expression_builder builder(1); + builder.start_condition("^ value $", 0, true); + builder.add_target("server.request.query", {}, {PWT_COMPRESS_WHITE, PWT_LOWERCASE}); + auto expr = builder.build(); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, " VALUE ")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + expression::cache_type cache; + EXPECT_TRUE(expr->eval(cache, store, {}, {}, deadline)); + auto matches = expr->get_matches(cache); + EXPECT_MATCHES(matches, {.op = "match_regex", + .op_value = "^ value $", + .address = "server.request.query", + .path = {}, + .value = " value ", + .highlight = " value "}); +} + +TEST(TestExpression, MatchOnKeys) +{ + expression_builder builder(1); + builder.start_condition("value", 0, true); + builder.add_target("server.request.query", {}, {}, expression::data_source::keys); + auto expr = builder.build(); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object value; + ddwaf_object_map(&value); + ddwaf_object_map_add(&value, "value", ddwaf_object_string(&tmp, "1729")); + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", &value); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + expression::cache_type cache; + EXPECT_TRUE(expr->eval(cache, store, {}, {}, deadline)); + auto matches = expr->get_matches(cache); + EXPECT_MATCHES(matches, {.op = "match_regex", + .op_value = "value", + .address = "server.request.query", + .path = {"value"}, + .value = "value", + .highlight = "value"}); +} + +TEST(TestExpression, MatchOnKeysWithTransformer) +{ + expression_builder builder(1); + builder.start_condition("value", 0, true); + builder.add_target("server.request.query", {}, {PWT_LOWERCASE}, expression::data_source::keys); + auto expr = builder.build(); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object value; + ddwaf_object_map(&value); + ddwaf_object_map_add(&value, "VALUE", ddwaf_object_string(&tmp, "1729")); + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", &value); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + expression::cache_type cache; + EXPECT_TRUE(expr->eval(cache, store, {}, {}, deadline)); + auto matches = expr->get_matches(cache); + EXPECT_MATCHES(matches, {.op = "match_regex", + .op_value = "value", + .address = "server.request.query", + .path = {"VALUE"}, + .value = "value", + .highlight = "value"}); +} + +TEST(TestExpression, ExcludeInput) +{ + expression_builder builder(1); + builder.start_condition(".*", 0, true); + builder.add_target("server.request.query"); + auto expr = builder.build(); + + ddwaf_object root; + ddwaf_object tmp; + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", ddwaf_object_string(&tmp, "value")); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + expression::cache_type cache; + EXPECT_FALSE(expr->eval(cache, store, {&root.array[0]}, {}, deadline)); +} + +TEST(TestExpression, ExcludeKeyPath) +{ + expression_builder builder(1); + builder.start_condition(".*", 0, true); + builder.add_target("server.request.query"); + auto expr = builder.build(); + + ddwaf_object root; + ddwaf_object map; + ddwaf_object tmp; + ddwaf_object_map(&map); + ddwaf_object_map_add(&map, "key", ddwaf_object_string(&tmp, "value")); + + ddwaf_object_map(&root); + ddwaf_object_map_add(&root, "server.request.query", &map); + + ddwaf::object_store store; + store.insert(root); + + ddwaf::timer deadline{2s}; + + expression::cache_type cache; + EXPECT_FALSE(expr->eval(cache, store, {&map.array[0]}, {}, deadline)); +} diff --git a/tests/test_utils.cpp b/tests/test_utils.cpp index e144a49c3..953247cdc 100644 --- a/tests/test_utils.cpp +++ b/tests/test_utils.cpp @@ -42,7 +42,7 @@ std::ostream &operator<<(std::ostream &os, const event::match &m) { os << indent(4) << "{\n" << indent(8) << "operator: " << m.op << ",\n" - << indent(8) << "operator_value:" << m.op_value << ",\n" + << indent(8) << "operator_value: " << m.op_value << ",\n" << indent(8) << "address: " << m.address << ",\n" << indent(8) << "path: ["; @@ -99,7 +99,7 @@ std::ostream &operator<<(std::ostream &os, const event &e) os << indent(8) << "{\n"; os << indent(12) << "operator: " << m.op << ",\n" - << indent(12) << "operator_value:" << m.op_value << ",\n" + << indent(12) << "operator_value: " << m.op_value << ",\n" << indent(12) << "address: " << m.address << ",\n" << indent(12) << "path: ["; From 137f20ca6138fe1a886d0994a5236151e789be47 Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Fri, 30 Jun 2023 15:16:08 +0100 Subject: [PATCH 26/28] Minor change --- src/parser/parser_v1.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/parser/parser_v1.cpp b/src/parser/parser_v1.cpp index 56f6b0c72..ecd170b19 100644 --- a/src/parser/parser_v1.cpp +++ b/src/parser/parser_v1.cpp @@ -81,9 +81,7 @@ expression::ptr parse_expression(parameter::vector &conditions_array, } builder.set_processor(std::move(processor)); - std::vector targets; auto inputs = at(params, "inputs"); - targets.reserve(inputs.size()); for (const auto &input_param : inputs) { auto input = static_cast(input_param); if (input.empty()) { From 604e3417084d9e266fe42e75f881a12869eea38e Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Wed, 5 Jul 2023 11:46:34 +0100 Subject: [PATCH 27/28] Format fix --- tests/rule_test.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/rule_test.cpp b/tests/rule_test.cpp index aa7451c75..1a786fe25 100644 --- a/tests/rule_test.cpp +++ b/tests/rule_test.cpp @@ -253,13 +253,13 @@ TEST(TestRule, NoMatchWithoutCache) TEST(TestRule, FullCachedMatchSecondRun) { - expression_builder builder(2); + expression_builder builder(2); builder.start_condition(std::vector{"192.168.0.1"}); builder.add_target("http.client_ip"); builder.start_condition(std::vector{"admin"}); builder.add_target("usr.id"); - + std::unordered_map tags{{"type", "type"}, {"category", "category"}}; ddwaf::rule rule("id", "name", std::move(tags), builder.build()); From a4071a39b84a48caefa1cdb425afcad3ddcc8de0 Mon Sep 17 00:00:00 2001 From: Anil Mahtani <929854+Anilm3@users.noreply.github.com> Date: Thu, 27 Jul 2023 15:12:41 +0100 Subject: [PATCH 28/28] Update expression to use new transformers --- src/expression.cpp | 60 +++++++++++++-------------------------- src/expression.hpp | 30 ++++++++++---------- tests/expression_test.cpp | 9 +++--- 3 files changed, 40 insertions(+), 59 deletions(-) diff --git a/src/expression.cpp b/src/expression.cpp index cb4eff621..0f93455ba 100644 --- a/src/expression.cpp +++ b/src/expression.cpp @@ -5,61 +5,41 @@ // Copyright 2021 Datadog, Inc. #include -#include -#include -#include #include +#include "exception.hpp" +#include "expression.hpp" +#include "log.hpp" +#include "transformer/manager.hpp" + namespace ddwaf { std::optional expression::evaluator::eval_object(const ddwaf_object *object, const rule_processor::base::ptr &processor, - const std::vector &transformers) const + const std::vector &transformers) const { - const bool has_transform = !transformers.empty(); - bool transform_required = false; - - if (has_transform) { - // This codepath is shared with the mutable path. The structure can't be const :/ - transform_required = - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) - PWTransformer::doesNeedTransform(transformers, const_cast(object)); - } - const size_t length = find_string_cutoff(object->stringValue, object->nbEntries, limits.max_string_length); - // If we don't have transform to perform, or if they're irrelevant, no need to waste time - // copying and allocating data - if (!has_transform || !transform_required) { - return processor->match({object->stringValue, length}); - } - - ddwaf_object copy; - ddwaf_object_stringl(©, (const char *)object->stringValue, length); + if (!transformers.empty()) { + ddwaf_object src; + ddwaf_object dst; + ddwaf_object_stringl_nc(&src, object->stringValue, length); + ddwaf_object_invalid(&dst); - const std::unique_ptr scope( - ©, ddwaf_object_free); - - // Transform it and pick the pointer to process - bool transformFailed = false; - for (const PW_TRANSFORM_ID &transform : transformers) { - transformFailed = !PWTransformer::transform(transform, ©); - if (transformFailed || (copy.type == DDWAF_OBJ_STRING && copy.nbEntries == 0)) { - break; + auto transformed = transformer::manager::transform(src, dst, transformers); + scope_exit on_exit([&dst] { ddwaf_object_free(&dst); }); + if (transformed) { + return processor->match_object(&dst); } } - if (transformFailed) { - return processor->match({object->stringValue, length}); - } - - return processor->match_object(©); + return processor->match({object->stringValue, length}); } template std::optional expression::evaluator::eval_target(const condition &cond, T &it, - const rule_processor::base::ptr &processor, const std::vector &transformers) + const rule_processor::base::ptr &processor, const std::vector &transformers) { std::optional last_result = std::nullopt; @@ -303,7 +283,7 @@ std::tuple explode_local_address(std } // namespace // void expression_builder::add_target(std::string name, std::vector key_path, - std::vector transformers, expression::data_source source) + std::vector transformers, expression::data_source source) { auto [res, index, entity] = explode_local_address(name); if (res) { @@ -315,7 +295,7 @@ void expression_builder::add_target(std::string name, std::vector k } void expression_builder::add_global_target(std::string name, std::vector key_path, - std::vector transformers, expression::data_source source) + std::vector transformers, expression::data_source source) { expression::condition::target_type target; target.scope = expression::eval_scope::global; @@ -331,7 +311,7 @@ void expression_builder::add_global_target(std::string name, std::vector key_path, - std::vector transformers, expression::data_source source) + std::vector transformers, expression::data_source source) { if (cond_idx >= (conditions_.size() - 1)) { throw std::invalid_argument( diff --git a/src/expression.hpp b/src/expression.hpp index caf83b327..a63a1f3ff 100644 --- a/src/expression.hpp +++ b/src/expression.hpp @@ -6,8 +6,6 @@ #pragma once -#include "log.hpp" -#include "utils.hpp" #include #include #include @@ -16,13 +14,15 @@ #include #include -#include -#include -#include -#include -#include -#include -#include +#include "clock.hpp" +#include "context_allocator.hpp" +#include "event.hpp" +#include "iterator.hpp" +#include "log.hpp" +#include "object_store.hpp" +#include "rule_processor/base.hpp" +#include "transformer/manager.hpp" +#include "utils.hpp" namespace ddwaf { @@ -57,7 +57,7 @@ class expression { std::vector key_path{}; // Transformers - std::vector transformers{}; + std::vector transformers{}; data_source source{data_source::values}; }; @@ -126,11 +126,11 @@ class expression { template std::optional eval_target(const condition &cond, T &it, const rule_processor::base::ptr &processor, - const std::vector &transformers); + const std::vector &transformers); std::optional eval_object(const ddwaf_object *object, const rule_processor::base::ptr &processor, - const std::vector &transformers) const; + const std::vector &transformers) const; [[nodiscard]] const rule_processor::base::ptr &get_processor(const condition &cond) const; @@ -215,7 +215,7 @@ class expression_builder { } void add_target(std::string name, std::vector key_path = {}, - std::vector transformers = {}, + std::vector transformers = {}, expression::data_source source = expression::data_source::values); expression::ptr build() @@ -225,11 +225,11 @@ class expression_builder { protected: void add_global_target(std::string name, std::vector key_path = {}, - std::vector transformers = {}, + std::vector transformers = {}, expression::data_source source = expression::data_source::values); void add_local_target(std::string name, std::size_t cond_idx, expression::eval_entity entity, - std::vector key_path = {}, std::vector transformers = {}, + std::vector key_path = {}, std::vector transformers = {}, expression::data_source source = expression::data_source::values); ddwaf::object_limits limits_; diff --git a/tests/expression_test.cpp b/tests/expression_test.cpp index c15d1ac8d..efb58ad59 100644 --- a/tests/expression_test.cpp +++ b/tests/expression_test.cpp @@ -4,7 +4,6 @@ // This product includes software developed at Datadog (https://www.datadoghq.com/). // Copyright 2021 Datadog, Inc. -#include "PWTransformer.h" #include "expression.hpp" #include "test.h" @@ -613,7 +612,7 @@ TEST(TestExpression, MatchWithTransformer) { expression_builder builder(1); builder.start_condition("value", 0, true); - builder.add_target("server.request.query", {}, {PWT_LOWERCASE}); + builder.add_target("server.request.query", {}, {transformer_id::lowercase}); auto expr = builder.build(); ddwaf_object root; @@ -641,7 +640,8 @@ TEST(TestExpression, MatchWithMultipleTransformers) { expression_builder builder(1); builder.start_condition("^ value $", 0, true); - builder.add_target("server.request.query", {}, {PWT_COMPRESS_WHITE, PWT_LOWERCASE}); + builder.add_target("server.request.query", {}, + {transformer_id::compress_whitespace, transformer_id::lowercase}); auto expr = builder.build(); ddwaf_object root; @@ -700,7 +700,8 @@ TEST(TestExpression, MatchOnKeysWithTransformer) { expression_builder builder(1); builder.start_condition("value", 0, true); - builder.add_target("server.request.query", {}, {PWT_LOWERCASE}, expression::data_source::keys); + builder.add_target( + "server.request.query", {}, {transformer_id::lowercase}, expression::data_source::keys); auto expr = builder.build(); ddwaf_object root;