openappsec/components/include/rate_limit_config.h
2024-01-31 17:34:53 +00:00

166 lines
5.0 KiB
C++
Executable File

#ifndef __RATE_LIMIT_CONFIG_H__
#define __RATE_LIMIT_CONFIG_H__
#include <string>
#include <vector>
#include <algorithm>
#include <cereal/archives/json.hpp>
#include "debug.h"
#include "generic_rulebase/rulebase_config.h"
#include "generic_rulebase/triggers_config.h"
#include "generic_rulebase/match_query.h"
#include "generic_rulebase/evaluators/trigger_eval.h"
USE_DEBUG_FLAG(D_RATE_LIMIT);
enum class RateLimitAction
{
INACTIVE,
ACCORDING_TO_PRACTICE,
DETECT,
PREVENT,
UNKNOWN
};
class RateLimitTrigger
{
public:
void
load(cereal::JSONInputArchive &ar);
const std::string & getTriggerId() const { return id; }
private:
std::string id;
};
class RateLimitRule
{
public:
void load(cereal::JSONInputArchive &ar);
void prepare(const std::string &asset_id, int zone_id);
operator bool() const
{
if (uri.empty()) {
dbgTrace(D_RATE_LIMIT) << "Recived empty URI in rate-limit rule";
return false;
}
if (uri.at(0) != '/') {
dbgWarning(D_RATE_LIMIT)
<< "Recived invalid rate-limit URI in rate-limit rule: "
<< uri
<< " rate-limit URI must start with /";
return false;
}
if (limit <= 0) {
dbgWarning(D_RATE_LIMIT)
<< "Recived invalid rate-limit limit in rate-limit rule: "
<< limit
<< " rate-limit rule limit must be positive";
return false;
}
return true;
}
friend std::ostream &
operator<<(std::ostream &os, const RateLimitRule &rule)
{
os << "Uri: " << rule.uri << ", Rate scope: " << rule.scope << ", Limit: " << rule.limit;
return os;
}
int getRateLimit() const { return limit; }
const std::string & getRateLimitZone() const { return limit_req_zone_template_value; }
const std::string & getRateLimitReq() const { return limit_req_template_value; }
const std::string & getRateLimitUri() const { return uri; }
const std::string & getRateLimitScope() const { return scope; }
const RateLimitAction & getRateLimitAction() const { return action; }
const MatchQuery & getRateLimitMatch() const { return match; }
const LogTriggerConf & getRateLimitTrigger() const { return trigger; }
const std::vector<RateLimitTrigger> & getRateLimitTriggers() const { return rate_limit_triggers; }
bool isRootLocation() const;
bool isMatchAny() const;
bool operator==(const RateLimitRule &rhs) { return uri == rhs.uri; }
bool operator<(const RateLimitRule &rhs) { return uri < rhs.uri; }
bool isExactMatch() const { return exact_match || (!uri.empty() && uri.back() != '/'); }
void setExactMatch() { exact_match = true; }
void appendSlash() { uri += '/'; }
private:
std::string uri;
std::string scope;
std::string limit_req_template_value;
std::string limit_req_zone_template_value;
std::string cache_size = "5m";
RateLimitAction action = RateLimitAction::ACCORDING_TO_PRACTICE;
MatchQuery match = MatchQuery(default_match);
std::vector<RateLimitTrigger> rate_limit_triggers;
LogTriggerConf trigger;
int limit;
bool exact_match = false;
static const std::string default_match;
};
class RateLimitConfig
{
public:
void load(cereal::JSONInputArchive &ar);
void addSiblingRateLimitRules();
void prepare();
const std::vector<RateLimitRule> & getRateLimitRules() const { return rate_limit_rules; }
const RateLimitAction & getRateLimitMode() const { return mode; }
RateLimitRule generateSiblingRateLimitRule(const RateLimitRule &rule);
const LogTriggerConf
getRateLimitTrigger(const std::string &nginx_uri) const
{
const RateLimitRule rule = findLongestMatchingRule(nginx_uri);
std::set<std::string> rate_limit_triggers_set;
for (const RateLimitTrigger &rate_limit_trigger : rule.getRateLimitTriggers()) {
dbgTrace(D_RATE_LIMIT)
<< "Adding trigger ID: "
<< rate_limit_trigger.getTriggerId()
<< " of rule URI: "
<< rule.getRateLimitUri()
<< " to the context set";
rate_limit_triggers_set.insert(rate_limit_trigger.getTriggerId());
}
ScopedContext ctx;
ctx.registerValue<std::set<GenericConfigId>>(TriggerMatcher::ctx_key, rate_limit_triggers_set);
return getConfigurationWithDefault(LogTriggerConf(), "rulebase", "log");
}
static void setIsActive(bool _is_active) { is_active |= _is_active; }
static void resetIsActive() { is_active = false; }
static bool isActive() { return is_active; }
static const std::map<RateLimitAction, std::string> rate_limit_action_to_string;
static const std::map<std::string, RateLimitAction> rate_limit_string_to_action;
private:
const RateLimitRule
findLongestMatchingRule(const std::string &nginx_uri) const;
static bool is_active;
RateLimitAction mode;
std::vector<RateLimitRule> rate_limit_rules;
};
#endif // __RATE_LIMIT_CONFIG_H__