Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] WAF Builder #363

Draft
wants to merge 32 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
2cb9137
Configuration parser / manager
Anilm3 Dec 6, 2024
5367308
Restructure the code, remove intermediate container types, split data…
Anilm3 Dec 9, 2024
3ea643b
Format
Anilm3 Dec 9, 2024
bcc7b94
Lint
Anilm3 Dec 9, 2024
347ae12
Minor change
Anilm3 Dec 10, 2024
57ed5f7
Merge branch 'master' into anilm3/waf_builder
Anilm3 Dec 10, 2024
7adcde8
Split actions
Anilm3 Dec 11, 2024
754008c
Connect new configuration manager and relevant builders
Anilm3 Dec 11, 2024
2dcb3f8
Delete parser stuff
Anilm3 Dec 12, 2024
b1d8dcf
Changes... wip
Anilm3 Dec 16, 2024
a5b8535
Fix bugs and update tests
Anilm3 Dec 17, 2024
b5976ff
Changes to the interface, tests and other fixes
Anilm3 Dec 18, 2024
6eab052
Update more tests and add more fixes
Anilm3 Dec 18, 2024
2729947
Fix more tests
Anilm3 Dec 18, 2024
f948219
Fix more tests
Anilm3 Dec 18, 2024
44ecc2e
Add support for legacy ruleset schema
Anilm3 Dec 18, 2024
9cedae0
Add parser tests
Anilm3 Jan 6, 2025
2e2a891
Add more parser tests
Anilm3 Jan 7, 2025
5044c50
More tests
Anilm3 Jan 7, 2025
ddc8f91
Fix typos
Anilm3 Jan 7, 2025
f473ed1
Remaining parser tests
Anilm3 Jan 7, 2025
a1839b7
Fixes and missing changes
Anilm3 Jan 7, 2025
9308259
Fixes and missing changes
Anilm3 Jan 7, 2025
185e42f
More fixes
Anilm3 Jan 7, 2025
014f86d
Split builder and fix lint
Anilm3 Jan 7, 2025
0b335a3
Rename manager to avoid static linking problems
Anilm3 Jan 7, 2025
dc793bf
Install mono on package-nuget job
Anilm3 Jan 7, 2025
e70b634
Add test
Anilm3 Jan 8, 2025
7bd9e1f
Simplify waf builder
Anilm3 Jan 8, 2025
d33404b
Changes
Anilm3 Jan 8, 2025
49398c6
Split action mapper builder, update tests and prevent overrides from …
Anilm3 Jan 9, 2025
c088e11
Lint fixes
Anilm3 Jan 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ jobs:

- name: Package Nuget
run: |
sudo apt-get update && sudo apt-get install -y libarchive-tools
sudo apt-get update && sudo apt-get install -y libarchive-tools mono-complete
function extract_file {
local -r arch=$1 filepat=$2 dest=$3
local -r file_in_arch=$(bsdtar -tf "$arch" | grep "$filepat" | head -1)
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_MATCH = 1,
DDWAF_OK = 0,
DDWAF_ERR_INVALID_ARGUMENT = -1,
DDWAF_OK = 0,
DDWAF_MATCH = 1,
DDWAF_ERR_INVALID_OBJECT = -2,
DDWAF_ERR_INTERNAL = -3,
} 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 of 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, this must uniquely identify the configuration. (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
Loading