Skip to content

Commit

Permalink
WAF Builder: independent configuration manager to generate WAF instan…
Browse files Browse the repository at this point in the history
…ces (#363)
  • Loading branch information
Anilm3 authored Jan 30, 2025
1 parent 73ad8e7 commit 1de83d9
Show file tree
Hide file tree
Showing 137 changed files with 13,235 additions and 7,767 deletions.
2 changes: 1 addition & 1 deletion .clang-tidy
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
# readability-function-cognitive-complexity temporarily disabled until clang-tidy is fixed
# right now emalloc causes it to misbehave
Checks: '*,misc-const-correctness,-bugprone-reserved-identifier,-hicpp-signed-bitwise,-llvmlibc-restrict-system-libc-headers,-altera-unroll-loops,-hicpp-named-parameter,-cert-dcl37-c,-cert-dcl51-cpp,-read,-cppcoreguidelines-init-variables,-cppcoreguidelines-avoid-non-const-global-variables,-altera-id-dependent-backward-branch,-performance-no-int-to-ptr,-altera-struct-pack-align,-google-readability-casting,-modernize-use-trailing-return-type,-llvmlibc-implementation-in-namespace,-llvmlibc-callee-namespace,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-fuchsia-default-arguments-declarations,-fuchsia-overloaded-operator,-cppcoreguidelines-pro-type-union-access,-fuchsia-default-arguments-calls,-cppcoreguidelines-non-private-member-variables-in-classes,-misc-non-private-member-variables-in-classes,-google-readability-todo,-llvm-header-guard,-readability-function-cognitive-complexity,-readability-identifier-length,-cppcoreguidelines-owning-memory,-cert-err58-cpp,-fuchsia-statically-constructed-objects,-google-build-using-namespace,-hicpp-avoid-goto,-cppcoreguidelines-avoid-goto,-hicpp-no-array-decay,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-abseil-string-find-str-contains,-bugprone-unchecked-optional-access,-readability-use-anyofallof,-modernize-loop-convert,-cppcoreguidelines-avoid-c-arrays,-hicpp-avoid-c-arrays,-cppcoreguidelines-no-malloc,-llvmlibc-inline-function-decl'
Checks: '*,misc-const-correctness,-bugprone-reserved-identifier,-hicpp-signed-bitwise,-llvmlibc-restrict-system-libc-headers,-altera-unroll-loops,-hicpp-named-parameter,-cert-dcl37-c,-cert-dcl51-cpp,-read,-cppcoreguidelines-init-variables,-cppcoreguidelines-avoid-non-const-global-variables,-altera-id-dependent-backward-branch,-performance-no-int-to-ptr,-altera-struct-pack-align,-google-readability-casting,-modernize-use-trailing-return-type,-llvmlibc-implementation-in-namespace,-llvmlibc-callee-namespace,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-fuchsia-default-arguments-declarations,-fuchsia-overloaded-operator,-cppcoreguidelines-pro-type-union-access,-fuchsia-default-arguments-calls,-cppcoreguidelines-non-private-member-variables-in-classes,-misc-non-private-member-variables-in-classes,-google-readability-todo,-llvm-header-guard,-readability-function-cognitive-complexity,-readability-identifier-length,-cppcoreguidelines-owning-memory,-cert-err58-cpp,-fuchsia-statically-constructed-objects,-google-build-using-namespace,-hicpp-avoid-goto,-cppcoreguidelines-avoid-goto,-hicpp-no-array-decay,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-avoid-magic-numbers,-readability-magic-numbers,-abseil-string-find-str-contains,-bugprone-unchecked-optional-access,-readability-use-anyofallof,-modernize-loop-convert,-cppcoreguidelines-avoid-c-arrays,-hicpp-avoid-c-arrays,-cppcoreguidelines-no-malloc,-llvmlibc-inline-function-decl,-boost-use-ranges,-modernize-use-ranges'
WarningsAsErrors: '*'
HeaderFilterRegex: ''
CheckOptions:
Expand Down
31 changes: 16 additions & 15 deletions cmake/objects.cmake
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
set(LIBDDWAF_SOURCE
${libddwaf_SOURCE_DIR}/src/ruleset_builder.cpp
${libddwaf_SOURCE_DIR}/src/clock.cpp
${libddwaf_SOURCE_DIR}/src/parameter.cpp
${libddwaf_SOURCE_DIR}/src/interface.cpp
Expand All @@ -17,13 +16,15 @@ set(LIBDDWAF_SOURCE
${libddwaf_SOURCE_DIR}/src/obfuscator.cpp
${libddwaf_SOURCE_DIR}/src/uri_utils.cpp
${libddwaf_SOURCE_DIR}/src/utils.cpp
${libddwaf_SOURCE_DIR}/src/waf.cpp
${libddwaf_SOURCE_DIR}/src/platform.cpp
${libddwaf_SOURCE_DIR}/src/sha256.cpp
${libddwaf_SOURCE_DIR}/src/uuid.cpp
${libddwaf_SOURCE_DIR}/src/action_mapper.cpp
${libddwaf_SOURCE_DIR}/src/builder/action_mapper_builder.cpp
${libddwaf_SOURCE_DIR}/src/builder/matcher_builder.cpp
${libddwaf_SOURCE_DIR}/src/builder/module_builder.cpp
${libddwaf_SOURCE_DIR}/src/builder/processor_builder.cpp
${libddwaf_SOURCE_DIR}/src/builder/ruleset_builder.cpp
${libddwaf_SOURCE_DIR}/src/tokenizer/sql_base.cpp
${libddwaf_SOURCE_DIR}/src/tokenizer/pgsql.cpp
${libddwaf_SOURCE_DIR}/src/tokenizer/mysql.cpp
Expand All @@ -33,19 +34,19 @@ set(LIBDDWAF_SOURCE
${libddwaf_SOURCE_DIR}/src/exclusion/input_filter.cpp
${libddwaf_SOURCE_DIR}/src/exclusion/object_filter.cpp
${libddwaf_SOURCE_DIR}/src/exclusion/rule_filter.cpp
${libddwaf_SOURCE_DIR}/src/parser/actions_parser.cpp
${libddwaf_SOURCE_DIR}/src/parser/common.cpp
${libddwaf_SOURCE_DIR}/src/parser/parser.cpp
${libddwaf_SOURCE_DIR}/src/parser/parser_v1.cpp
${libddwaf_SOURCE_DIR}/src/parser/data_parser.cpp
${libddwaf_SOURCE_DIR}/src/parser/processor_parser.cpp
${libddwaf_SOURCE_DIR}/src/parser/expression_parser.cpp
${libddwaf_SOURCE_DIR}/src/parser/matcher_parser.cpp
${libddwaf_SOURCE_DIR}/src/parser/transformer_parser.cpp
${libddwaf_SOURCE_DIR}/src/parser/rule_parser.cpp
${libddwaf_SOURCE_DIR}/src/parser/rule_override_parser.cpp
${libddwaf_SOURCE_DIR}/src/parser/scanner_parser.cpp
${libddwaf_SOURCE_DIR}/src/parser/exclusion_parser.cpp
${libddwaf_SOURCE_DIR}/src/configuration/common/expression_parser.cpp
${libddwaf_SOURCE_DIR}/src/configuration/common/matcher_parser.cpp
${libddwaf_SOURCE_DIR}/src/configuration/common/transformer_parser.cpp
${libddwaf_SOURCE_DIR}/src/configuration/common/reference_parser.cpp
${libddwaf_SOURCE_DIR}/src/configuration/actions_parser.cpp
${libddwaf_SOURCE_DIR}/src/configuration/data_parser.cpp
${libddwaf_SOURCE_DIR}/src/configuration/exclusion_parser.cpp
${libddwaf_SOURCE_DIR}/src/configuration/processor_parser.cpp
${libddwaf_SOURCE_DIR}/src/configuration/rule_override_parser.cpp
${libddwaf_SOURCE_DIR}/src/configuration/rule_parser.cpp
${libddwaf_SOURCE_DIR}/src/configuration/legacy_rule_parser.cpp
${libddwaf_SOURCE_DIR}/src/configuration/scanner_parser.cpp
${libddwaf_SOURCE_DIR}/src/configuration/configuration_manager.cpp
${libddwaf_SOURCE_DIR}/src/processor/extract_schema.cpp
${libddwaf_SOURCE_DIR}/src/processor/fingerprint.cpp
${libddwaf_SOURCE_DIR}/src/condition/exists.cpp
Expand Down
92 changes: 71 additions & 21 deletions include/ddwaf.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,19 @@
namespace ddwaf{
class waf;
class context_wrapper;
class waf_builder;
} // namespace ddwaf
using ddwaf_handle = ddwaf::waf *;
using ddwaf_context = ddwaf::context_wrapper *;
using ddwaf_builder = ddwaf::waf_builder *;

extern "C"
{
#endif

#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <stdint.h>

#define DDWAF_MAX_STRING_LENGTH 4096
#define DDWAF_MAX_CONTAINER_DEPTH 20
Expand Down Expand Up @@ -61,11 +63,11 @@ typedef enum
**/
typedef enum
{
DDWAF_ERR_INTERNAL = -3,
DDWAF_ERR_INVALID_OBJECT = -2,
DDWAF_ERR_INTERNAL = -3,
DDWAF_ERR_INVALID_OBJECT = -2,
DDWAF_ERR_INVALID_ARGUMENT = -1,
DDWAF_OK = 0,
DDWAF_MATCH = 1,
DDWAF_OK = 0,
DDWAF_MATCH = 1,
} DDWAF_RET_CODE;

/**
Expand All @@ -86,6 +88,7 @@ typedef enum
#ifndef __cplusplus
typedef struct _ddwaf_handle* ddwaf_handle;
typedef struct _ddwaf_context* ddwaf_context;
typedef struct _ddwaf_builder* ddwaf_builder;
#endif

typedef struct _ddwaf_object ddwaf_object;
Expand Down Expand Up @@ -207,22 +210,6 @@ typedef void (*ddwaf_log_cb)(
ddwaf_handle ddwaf_init(const ddwaf_object *ruleset,
const ddwaf_config* config, ddwaf_object *diagnostics);

/**
* ddwaf_update
*
* Update a ddwaf instance
*
* @param ruleset ddwaf::object map containing rules, exclusions, rules_override and rules_data. (nonnull)
* @param diagnostics Optional ruleset parsing diagnostics. (nullable)
*
* @return Handle to the new WAF instance or NULL if there was an error processing the ruleset.
*
* @note If handle or ruleset are NULL, the diagnostics object will not be initialised.
* @note This function is not thread-safe
**/
ddwaf_handle ddwaf_update(ddwaf_handle handle, const ddwaf_object *ruleset,
ddwaf_object *diagnostics);

/**
* ddwaf_destroy
*
Expand Down Expand Up @@ -364,6 +351,69 @@ void ddwaf_context_destroy(ddwaf_context context);
**/
void ddwaf_result_free(ddwaf_result *result);

/**
* ddwaf_builder_init
*
* Initialize an instace of the waf builder.
*
* @param config Optional configuration of the WAF. (nullable)
*
* @return Handle to the builer instance or NULL on error.
*
* @note If config is NULL, default values will be used, including the default
* free function (ddwaf_object_free).
**/
ddwaf_builder ddwaf_builder_init(const ddwaf_config *config);

/**
* ddwaf_builder_add_or_update_config
*
* Adds or updates a configuration based on the given path, which must be a unique
* identifier for the provided configuration.
*
* @param builder Builder to perform the operation on. (nonnull)
* @param path A string containing the path of the configuration, this must uniquely identify the configuration. (nonnull)
* @param path_len The length of the string contained within path.
* @param config ddwaf::object map containing rules, exclusions, rules_override and rules_data. (nonnull)
* @param diagnostics Optional ruleset parsing diagnostics. (nullable)
*
* @return Whether the operation succeeded (true) or failed (false).
**/
bool ddwaf_builder_add_or_update_config(ddwaf_builder builder, const char *path, uint32_t path_len, ddwaf_object *config, ddwaf_object *diagnostics);

/**
* ddwaf_builder_remove_config
*
* Removes a configuration based on the provided path.
*
* @param builder Builder to perform the operation on. (nonnull)
* @param path A string containing the path of the configuration to be removed. (nonnull)
* @param path_len The length of the string contained within path.
*
* @return Whether the operation succeeded (true) or failed (false).
**/
bool ddwaf_builder_remove_config(ddwaf_builder builder, const char *path, uint32_t path_len);

/**
* ddwaf_builder_build_instance
*
* Builds a ddwaf instance based on the current set of configurations.
*
* @param builder Builder to perform the operation on. (nonnull)
*
* @return Handle to the new WAF instance or NULL if there was an error.
**/
ddwaf_handle ddwaf_builder_build_instance(ddwaf_builder builder);

/**
* ddwaf_builder_destroy
*
* Destroy an instance of the builder.
*
* @param builder Builder to perform the operation on. (nonnull)
*/
void ddwaf_builder_destroy(ddwaf_builder builder);

/**
* ddwaf_object_invalid
*
Expand Down
6 changes: 5 additions & 1 deletion libddwaf.def
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
LIBRARY ddwaf
EXPORTS
ddwaf_init
ddwaf_update
ddwaf_destroy
ddwaf_builder_init
ddwaf_builder_add_or_update_config
ddwaf_builder_remove_config
ddwaf_builder_build_instance
ddwaf_builder_destroy
ddwaf_known_addresses
ddwaf_context_init
ddwaf_run
Expand Down
58 changes: 0 additions & 58 deletions src/action_mapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,7 @@
// This product includes software developed at Datadog (https://www.datadoghq.com/).
// Copyright 2021 Datadog, Inc.

#include <functional>
#include <map>
#include <memory>
#include <stdexcept>
#include <string>
#include <string_view>
#include <unordered_map>
#include <utility>

#include "action_mapper.hpp"

Expand All @@ -37,55 +30,4 @@ action_type action_type_from_string(std::string_view type)
return action_type::unknown;
}

void action_mapper_builder::alias_default_action_to(std::string_view default_id, std::string alias)
{
auto it = default_actions_.find(default_id);
if (it == default_actions_.end()) {
throw std::runtime_error(
"attempting to add alias to non-existent default action " + std::string(default_id));
}
action_by_id_.emplace(std::move(alias), it->second);
}

void action_mapper_builder::set_action(
std::string id, std::string type, std::unordered_map<std::string, std::string> parameters)
{
if (action_by_id_.find(id) != action_by_id_.end()) {
throw std::runtime_error("duplicate action '" + id + '\'');
}

action_by_id_.emplace(std::move(id),
action_spec{action_type_from_string(type), std::move(type), std::move(parameters)});
}

[[nodiscard]] const action_spec &action_mapper_builder::get_default_action(std::string_view id)
{
auto it = default_actions_.find(id);
if (it == default_actions_.end()) {
throw std::out_of_range("unknown action " + std::string(id));
}
return it->second;
}

std::shared_ptr<action_mapper> action_mapper_builder::build_shared()
{
return std::make_shared<action_mapper>(build());
}

action_mapper action_mapper_builder::build()
{
for (const auto &[action_id, action_spec] : default_actions_) {
action_by_id_.try_emplace(action_id, action_spec);
}

return std::move(action_by_id_);
}

const std::map<std::string, action_spec, std::less<>> action_mapper_builder::default_actions_ = {
{"block", {action_type::block_request, "block_request",
{{"status_code", "403"}, {"type", "auto"}, {"grpc_status_code", "10"}}}},
{"stack_trace", {action_type::generate_stack, "generate_stack", {}}},
{"extract_schema", {action_type::generate_schema, "generate_schema", {}}},
{"monitor", {action_type::monitor, "monitor", {}}}};

} // namespace ddwaf
32 changes: 2 additions & 30 deletions src/action_mapper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@
#include <string_view>
#include <unordered_map>

#include "utils.hpp"

namespace ddwaf {

enum class action_type : uint8_t {
Expand All @@ -34,38 +32,12 @@ inline bool is_blocking_action(action_type type)
return type == action_type::block_request || type == action_type::redirect_request;
}

struct action_spec {
struct action_parameters {
action_type type;
std::string type_str;
std::unordered_map<std::string, std::string> parameters;
};

using action_mapper = std::map<std::string, action_spec, std::less<>>;

class action_mapper_builder {
public:
action_mapper_builder() = default;
~action_mapper_builder() = default;
action_mapper_builder(const action_mapper_builder &) = delete;
action_mapper_builder(action_mapper_builder &&) = delete;
action_mapper_builder &operator=(const action_mapper_builder &) = delete;
action_mapper_builder &operator=(action_mapper_builder &&) = delete;

void alias_default_action_to(std::string_view default_id, std::string alias);

void set_action(
std::string id, std::string type, std::unordered_map<std::string, std::string> parameters);

[[nodiscard]] static const action_spec &get_default_action(std::string_view id);

std::shared_ptr<action_mapper> build_shared();

// Used for testing
action_mapper build();

protected:
std::map<std::string, action_spec, std::less<>> action_by_id_;
static const std::map<std::string, action_spec, std::less<>> default_actions_;
};
using action_mapper = std::map<std::string, action_parameters, std::less<>>;

} // namespace ddwaf
Loading

0 comments on commit 1de83d9

Please sign in to comment.