-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Module-based rule evaluation precedence (#353)
- Loading branch information
Showing
117 changed files
with
5,248 additions
and
1,563 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,3 +37,4 @@ perf/test_files/breakdown.numbers | |
.vscode | ||
*.swp | ||
*.swo | ||
*.swn |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// 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 <algorithm> | ||
#include <array> | ||
#include <cstddef> | ||
#include <memory> | ||
#include <string_view> | ||
#include <utility> | ||
#include <vector> | ||
|
||
#include "builder/module_builder.hpp" | ||
#include "module.hpp" | ||
#include "module_category.hpp" | ||
#include "rule.hpp" | ||
|
||
namespace ddwaf { | ||
|
||
rule_module rule_module_builder::build() | ||
{ | ||
const auto &sort_fn = [this](const auto *left, const auto *right) { | ||
const auto lverdict = left->get_verdict(); | ||
const auto rverdict = right->get_verdict(); | ||
const auto lsource = left->get_source(); | ||
const auto rsource = right->get_source(); | ||
return lverdict > rverdict || | ||
(lverdict == rverdict && | ||
(source_precedence_fn_(lsource, rsource) || | ||
(lsource == rsource && grouping_key_fn_(left) < grouping_key_fn_(right)))); | ||
}; | ||
|
||
// Sort first | ||
std::sort(rules_.begin(), rules_.end(), sort_fn); | ||
|
||
// Generate collections by grouping based on the grouping key | ||
std::string_view prev_key; | ||
for (std::size_t i = 0; i < rules_.size(); ++i) { | ||
const auto *rule = rules_[i]; | ||
auto cur_key = grouping_key_fn_(rule); | ||
if (cur_key != prev_key) { | ||
if (!collections_.empty()) { | ||
collections_.back().end = i; | ||
} | ||
using rule_collection = rule_module::rule_collection; | ||
collections_.emplace_back(rule_collection{cur_key, rule->get_verdict(), i, i + 1}); | ||
prev_key = cur_key; | ||
} | ||
} | ||
|
||
if (!collections_.empty()) { | ||
collections_.back().end = rules_.size(); | ||
} | ||
|
||
return rule_module{std::move(rules_), std::move(collections_), policy_}; | ||
} | ||
|
||
std::array<rule_module, rule_module_count> rule_module_set_builder::build( | ||
const std::vector<std::shared_ptr<core_rule>> &rules) | ||
{ | ||
std::array<rule_module, rule_module_count> all_modules; | ||
|
||
for (const auto &rule : rules) { | ||
auto &builder = builders_[static_cast<std::size_t>(rule->get_module())]; | ||
builder.insert(rule.get()); | ||
} | ||
|
||
for (std::size_t i = 0; i < builders_.size(); ++i) { all_modules[i] = builders_[i].build(); } | ||
|
||
return all_modules; | ||
} | ||
|
||
} // namespace ddwaf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
// 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 "module.hpp" | ||
#include "module_category.hpp" | ||
#include "rule.hpp" | ||
|
||
namespace ddwaf { | ||
|
||
// Helpers | ||
inline bool user_rule_precedence( | ||
const core_rule::source_type left, const core_rule::source_type right) | ||
{ | ||
return left > right; | ||
} | ||
|
||
inline bool base_rule_precedence( | ||
const core_rule::source_type left, const core_rule::source_type right) | ||
{ | ||
return left < right; | ||
} | ||
|
||
[[gnu::const]] inline std::string_view type_grouping_key(const core_rule *rule) | ||
{ | ||
return rule->get_type(); | ||
} | ||
[[gnu::const]] constexpr std::string_view null_grouping_key(const core_rule * /*rule*/) | ||
{ | ||
return {}; | ||
} | ||
|
||
// The module builder can be used to build a single module | ||
class rule_module_builder { | ||
public: | ||
using source_type = core_rule::source_type; | ||
using source_precedence_fn_type = bool (*)(source_type left, source_type right); | ||
using grouping_key_fn_type = std::string_view (*)(const core_rule *rule); | ||
using expiration_policy = rule_module::expiration_policy; | ||
|
||
rule_module_builder(source_precedence_fn_type source_precedence, | ||
grouping_key_fn_type grouping_key, expiration_policy policy = expiration_policy::expiring) | ||
: source_precedence_fn_(source_precedence), grouping_key_fn_(grouping_key), policy_(policy) | ||
{} | ||
~rule_module_builder() = default; | ||
rule_module_builder(rule_module_builder &&) = delete; | ||
rule_module_builder(const rule_module_builder &) = delete; | ||
rule_module_builder &operator=(rule_module_builder &&) = delete; | ||
rule_module_builder &operator=(const rule_module_builder &) = delete; | ||
|
||
void insert(core_rule *rule) { rules_.emplace_back(rule); } | ||
|
||
rule_module build(); | ||
|
||
protected: | ||
source_precedence_fn_type source_precedence_fn_; | ||
grouping_key_fn_type grouping_key_fn_; | ||
std::vector<core_rule *> rules_; | ||
std::vector<rule_module::rule_collection> collections_; | ||
expiration_policy policy_; | ||
}; | ||
|
||
class rule_module_set_builder { | ||
public: | ||
rule_module_set_builder() = default; | ||
~rule_module_set_builder() = default; | ||
rule_module_set_builder(rule_module_set_builder &&) = delete; | ||
rule_module_set_builder(const rule_module_set_builder &) = delete; | ||
rule_module_set_builder &operator=(rule_module_set_builder &&) = delete; | ||
rule_module_set_builder &operator=(const rule_module_set_builder &) = delete; | ||
|
||
std::array<rule_module, rule_module_count> build( | ||
const std::vector<std::shared_ptr<core_rule>> &rules); | ||
|
||
protected: | ||
/* Rules Ordering | ||
* --------------------------- | ||
* network_acl: (ignore timeout) | ||
* - Collection: [order by: verdict (block then monitor), source (base then user)] | ||
* | ||
* authentication_acl: (ignore timeout) | ||
* - Collection: [order by: verdict, source (base then user)] | ||
* | ||
* custom_acl: | ||
* - Collection: [order by: verdict, source (user then base)] | ||
* | ||
* configuration: | ||
* - Collection: [order by: verdict, source (user then base)] | ||
* | ||
* business_logic: | ||
* - Collection: [order by: verdict, source (user then base)] | ||
* | ||
* rasp: | ||
* - Collection: [order by: verdict, source (base then user)] | ||
* | ||
* waf: | ||
* - Collection: [verdict=block, source=user, type=<type 1>] | ||
* - Collection: [verdict=block, source=user, type=...] | ||
* - Collection: [verdict=block, source=base, type=<type 1>] | ||
* - Collection: [verdict=block, source=base, type=...] | ||
* - Collection: [verdict=monitor, source=user, type=<type 1>] | ||
* - Collection: [verdict=monitor, source=user, type=...] | ||
* - Collection: [verdict=monitor, source=base, type=<type 1>] | ||
* - Collection: [verdict=monitor, source=base, type=...] | ||
* | ||
* Note: Non expiring modules should always be placed before expiring modules. | ||
*/ | ||
|
||
std::array<rule_module_builder, rule_module_count> builders_{{ | ||
// Network-ACL | ||
{base_rule_precedence, null_grouping_key, rule_module::expiration_policy::non_expiring}, | ||
// Authentication-ACL | ||
{base_rule_precedence, null_grouping_key, rule_module::expiration_policy::non_expiring}, | ||
// Custom-ACL | ||
{user_rule_precedence, null_grouping_key, rule_module::expiration_policy::expiring}, | ||
// Configuration | ||
{user_rule_precedence, null_grouping_key, rule_module::expiration_policy::expiring}, | ||
// Business logic | ||
{user_rule_precedence, null_grouping_key, rule_module::expiration_policy::expiring}, | ||
// RASP | ||
{base_rule_precedence, null_grouping_key, rule_module::expiration_policy::expiring}, | ||
// WAF | ||
{user_rule_precedence, type_grouping_key, rule_module::expiration_policy::expiring}, | ||
}}; | ||
}; | ||
|
||
} // namespace ddwaf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.