diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 0000000000..4444b77666 --- /dev/null +++ b/.bazelrc @@ -0,0 +1,5 @@ +# Default options +build --cxxopt='-std=c++17' +build --host_cxxopt='-std=c++17' +build --cxxopt='-O2' +build --experimental_scale_timeouts=10.0 \ No newline at end of file diff --git a/.bazelversion b/.bazelversion new file mode 100644 index 0000000000..905c243928 --- /dev/null +++ b/.bazelversion @@ -0,0 +1 @@ +8.3.1 \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..9336e81109 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,17 @@ +{ + "name": "libtraceable-dev", + "image": "ghcr.io/traceableai/native-build-images/ubuntu-20.04:0.1.98", + "mounts": [ + "source=${env:HOME}/.ssh,target=/home/builder/.ssh,type=bind,consistency=cached" + ], + "customizations": { + "vscode": { + "extensions": [ + "bazelbuild.vscode-bazel", + "ms-vscode.cpptools", + "ms-vscode.cpptools-extension-pack" + ] + } + }, + "remoteUser": "builder" +} diff --git a/.gitignore b/.gitignore index 4e314e466e..b6359c6514 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,7 @@ examples/multithread/multithread examples/reading_logs_via_rule_message/simple_request examples/reading_logs_with_offset/read examples/using_bodies_in_chunks/simple_request + +# bazel +MODULE.bazel.lock +bazel-* \ No newline at end of file diff --git a/BUILD.bazel b/BUILD.bazel new file mode 100644 index 0000000000..5c752f98bd --- /dev/null +++ b/BUILD.bazel @@ -0,0 +1,27 @@ +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") + +cc_library( + name = "modsecurity", + srcs = glob( + [ + "src/**/*.h", + "src/**/*.hh", + "src/**/*.cc", + ], + ), + hdrs = glob([ + "headers/**/*.h", + ]), + includes = ["headers", "others"], + strip_include_prefix = "headers", + linkopts = select({ + "@platforms//os:linux": ["-lpthread"], + "@platforms//os:macos": ["-lpthread"], + "//conditions:default": [], + }), + visibility = ["//visibility:public"], + deps = [ + "//others:mbedtls", + "//others:libinjection", + ], +) \ No newline at end of file diff --git a/MODULE.bazel b/MODULE.bazel new file mode 100644 index 0000000000..fa5b2cdde2 --- /dev/null +++ b/MODULE.bazel @@ -0,0 +1,7 @@ +module ( + name = "modsecurity", + compatibility_level = 1, +) + +bazel_dep(name = "rules_cc", version = "0.2.14") +bazel_dep(name = "platforms", version = "1.0.0") \ No newline at end of file diff --git a/examples/bazel/BUILD.bazel b/examples/bazel/BUILD.bazel new file mode 100644 index 0000000000..b4b0afbd56 --- /dev/null +++ b/examples/bazel/BUILD.bazel @@ -0,0 +1,16 @@ +cc_binary ( + name = "main", + srcs = ["main.cc"], + deps = ["//:modsecurity", "@rules_cc//cc/runfiles"], + data = ["basic_rules.conf"], + linkopts = [ + "-l:libpcre2-8.a", + "-ldl", + "-lstdc++fs", + "-lstdc++", + # "Ws2_32.lib", + # "Iphlpapi.lib", + # "pcre2-8-static.lib", + # "PocoFoundationmd.lib" + ] +) \ No newline at end of file diff --git a/examples/bazel/basic_rules.conf b/examples/bazel/basic_rules.conf new file mode 100644 index 0000000000..0d17471d82 --- /dev/null +++ b/examples/bazel/basic_rules.conf @@ -0,0 +1,10 @@ +SecRule REQUEST_HEADERS:User-Agent ".*" "id:100,phase:1,t:sha1,t:hexEncode,setvar:tx.ua_hash=%{MATCHED_VAR}" + +SecAction "id:2,phase:2,initcol:ip=%{REMOTE_ADDR}_%{tx.ua_hash}" + +SecRule REQUEST_HEADERS:User-Agent "@rx .*" "id:3,phase:2,setvar:ip.auth_attempt=+1" +SecRule REQUEST_HEADERS:Jacob "@rx .*" "id:300,phase:2,setvar:ip.auth_attempt=+1,msg:'Matched value: %{MATCHED_VAR}'" +SecRule ARGS:foo "@rx herewego" "id:4,phase:2,setvar:ip.foo=bar,expirevar:ip.foo=2" +#SecRule ARGS:foo "@rx herewego" "id:4,phase:2,setvar:ip.foo=bar" +SecRule IP "@rx bar" "id:5,phase:2,pass" +SecRule IP:auth_attempt "@rx bar" "id:6,phase:2,pass" \ No newline at end of file diff --git a/examples/bazel/main.cc b/examples/bazel/main.cc new file mode 100644 index 0000000000..59e4ef0717 --- /dev/null +++ b/examples/bazel/main.cc @@ -0,0 +1,106 @@ +#include + +#include +#include +#include +#include +#include "rules_cc/cc/runfiles/runfiles.h" + + +void ModsecurityTest(const char* argv0); + +static const std::string GetTestConfPath(const char* argv0) { + std::string error; + std::unique_ptr runfiles( + rules_cc::cc::runfiles::Runfiles::Create(argv0, BAZEL_CURRENT_REPOSITORY, + &error)); + + if (!runfiles) { + std::cerr << "Failed to create Runfiles: " << error << "\n"; + return ""; + } + std::string repo_part = BAZEL_CURRENT_REPOSITORY; + if (repo_part.empty()) { + repo_part = "_main"; + } + + std::string logical_path = + repo_part + "/examples/bazel/basic_rules.conf"; + std::string physical_path = runfiles->Rlocation(logical_path); + + if (physical_path.empty()) { + return ""; + } + + return physical_path; +} + + +int main(int argc, char* argv[]) +{ + + std::cout << "Hello world!" << std::endl; + std::cout << "Test project for modsec windows is here!\n"; + try + { + ModsecurityTest(argv[0]); + } + catch (const std::exception &e) + { + std::cerr << "An error occurred: " << e.what() << std::endl; + } + return 0; +} + +void ModsecurityTest(const char* argv0) +{ + std::cout << "Starting ModSecurity test..." << std::endl; + std::cout << "About to create ModSecurity instance..." << std::endl; + std::cout.flush(); + auto modsec = std::make_unique(); + std::cout << "ModSecurity instance created." << std::endl; + std::cout << "ModSecurity whoAmI: " << modsec->whoAmI() << std::endl; + + std::cout << "About to create RulesSet..." << std::endl; + std::cout.flush(); + auto rules = std::make_unique(); + std::cout << "RulesSet created." << std::endl; + + std::string confPath = GetTestConfPath(argv0); + std::cout << "Config path: " << confPath << std::endl; + std::cout.flush(); + + if (rules->loadFromUri(confPath.c_str()) < 0) + { + std::cout<< "Failed to load rules from: " << confPath << std::endl; + std::cerr << "Problems loading the rules..." << std::endl; + std::cerr << rules->m_parserError.str() << std::endl; + return; + } + + std::cout<< "Rules loaded successfully from: " << confPath << std::endl; + auto modsecTransaction = std::make_unique(modsec.get(), rules.get(), nullptr); + modsecTransaction->processConnection("127.0.0.1", 12345, "127.0.0.1", 80); + modsecTransaction->processURI( + "https://www.modsecurity.org/test?foo=herewego", + "GET", "1.1"); + + modsecTransaction->addRequestHeader("User-Agent", + "Basic ModSecurity example"); + modsecTransaction->addRequestHeader("Jacob", + "matched-header"); + modsecTransaction->processRequestHeaders(); + modsecTransaction->processRequestBody(); + + modsecTransaction->addResponseHeader("HTTP/1.1", + "200 OK"); + modsecTransaction->processResponseHeaders(200, "HTTP 1.2"); + modsecTransaction->processResponseBody(); + + modsecTransaction->processLogging(); + + for (const auto &x : modsecTransaction->m_rulesMessages) + { + std::cout << std::to_string(x.m_rule.m_ruleId) << " " << x.m_message << std::endl; + } +} \ No newline at end of file diff --git a/others/BUILD.bazel b/others/BUILD.bazel new file mode 100644 index 0000000000..3b2a19b2c3 --- /dev/null +++ b/others/BUILD.bazel @@ -0,0 +1,32 @@ +load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test") + +cc_library( + name = "mbedtls", + srcs = glob( + [ + "mbedtls/library/**/*.h", + "mbedtls/library/**/*.c", + ], + ), + hdrs = glob([ + "mbedtls/include/**/*.h", + ]), + includes = ["mbedtls/include"], + strip_include_prefix = "mbedtls/include", + visibility = ["//visibility:public"], +) + +cc_library( + name = "libinjection", + srcs = glob( + [ + "libinjection/src/**/*.h", + "libinjection/src/**/*.c", + ], + ), + hdrs = glob([ + "libinjection/src/**/*.h", + ]), + visibility = ["//visibility:public"], + defines = ["LIBINJECTION_VERSION=2"], +) \ No newline at end of file