summaryrefslogtreecommitdiffstats
path: root/dnsdist-dynblocks.hh
diff options
context:
space:
mode:
Diffstat (limited to 'dnsdist-dynblocks.hh')
-rw-r--r--dnsdist-dynblocks.hh221
1 files changed, 81 insertions, 140 deletions
diff --git a/dnsdist-dynblocks.hh b/dnsdist-dynblocks.hh
index c9b1e4a..1a8b3a6 100644
--- a/dnsdist-dynblocks.hh
+++ b/dnsdist-dynblocks.hh
@@ -28,40 +28,51 @@
#include "dnsdist-rings.hh"
#include "statnode.hh"
-extern "C" {
+extern "C"
+{
#include "dnsdist-lua-inspection-ffi.h"
}
// dnsdist_ffi_stat_node_t is a lightuserdata
-template<>
-struct LuaContext::Pusher<dnsdist_ffi_stat_node_t*> {
- static const int minSize = 1;
- static const int maxSize = 1;
-
- static PushedObject push(lua_State* state, dnsdist_ffi_stat_node_t* ptr) noexcept {
- lua_pushlightuserdata(state, ptr);
- return PushedObject{state, 1};
- }
+template <>
+struct LuaContext::Pusher<dnsdist_ffi_stat_node_t*>
+{
+ static const int minSize = 1;
+ static const int maxSize = 1;
+
+ static PushedObject push(lua_State* state, dnsdist_ffi_stat_node_t* ptr) noexcept
+ {
+ lua_pushlightuserdata(state, ptr);
+ return PushedObject{state, 1};
+ }
};
-typedef std::function<bool(dnsdist_ffi_stat_node_t*)> dnsdist_ffi_stat_node_visitor_t;
+using dnsdist_ffi_stat_node_visitor_t = std::function<bool(dnsdist_ffi_stat_node_t*)>;
+
+struct SMTBlockParameters
+{
+ std::optional<std::string> d_reason;
+ std::optional<DNSAction::Action> d_action;
+};
struct dnsdist_ffi_stat_node_t
{
- dnsdist_ffi_stat_node_t(const StatNode& node_, const StatNode::Stat& self_, const StatNode::Stat& children_, std::optional<std::string>& reason_): node(node_), self(self_), children(children_), reason(reason_)
+ dnsdist_ffi_stat_node_t(const StatNode& node_, const StatNode::Stat& self_, const StatNode::Stat& children_, SMTBlockParameters& blockParameters) :
+ node(node_), self(self_), children(children_), d_blockParameters(blockParameters)
{
}
const StatNode& node;
const StatNode::Stat& self;
const StatNode::Stat& children;
- std::optional<std::string>& reason;
+ SMTBlockParameters& d_blockParameters;
};
+using dnsdist_ffi_dynamic_block_inserted_hook = std::function<void(uint8_t type, const char* key, const char* reason, uint8_t action, uint64_t duration, bool warning)>;
+
class DynBlockRulesGroup
{
private:
-
struct Counts
{
std::map<uint8_t, uint64_t> d_rcodeCounts;
@@ -69,83 +80,27 @@ private:
uint64_t queries{0};
uint64_t responses{0};
uint64_t respBytes{0};
+ uint64_t cacheMisses{0};
};
struct DynBlockRule
{
- DynBlockRule(): d_enabled(false)
+ DynBlockRule() = default;
+ DynBlockRule(const std::string& blockReason, unsigned int blockDuration, unsigned int rate, unsigned int warningRate, unsigned int seconds, DNSAction::Action action) :
+ d_blockReason(blockReason), d_blockDuration(blockDuration), d_rate(rate), d_warningRate(warningRate), d_seconds(seconds), d_action(action), d_enabled(true)
{
}
- DynBlockRule(const std::string& blockReason, unsigned int blockDuration, unsigned int rate, unsigned int warningRate, unsigned int seconds, DNSAction::Action action): d_blockReason(blockReason), d_blockDuration(blockDuration), d_rate(rate), d_warningRate(warningRate), d_seconds(seconds), d_action(action), d_enabled(true)
- {
- }
-
- bool matches(const struct timespec& when)
- {
- if (!d_enabled) {
- return false;
- }
-
- if (d_seconds && when < d_cutOff) {
- return false;
- }
-
- if (when < d_minTime) {
- d_minTime = when;
- }
-
- return true;
- }
-
- bool rateExceeded(unsigned int count, const struct timespec& now) const
- {
- if (!d_enabled) {
- return false;
- }
-
- double delta = d_seconds ? d_seconds : DiffTime(now, d_minTime);
- double limit = delta * d_rate;
- return (count > limit);
- }
-
- bool warningRateExceeded(unsigned int count, const struct timespec& now) const
- {
- if (!d_enabled) {
- return false;
- }
-
- if (d_warningRate == 0) {
- return false;
- }
-
- double delta = d_seconds ? d_seconds : DiffTime(now, d_minTime);
- double limit = delta * d_warningRate;
- return (count > limit);
- }
+ bool matches(const struct timespec& when);
+ bool rateExceeded(unsigned int count, const struct timespec& now) const;
+ bool warningRateExceeded(unsigned int count, const struct timespec& now) const;
bool isEnabled() const
{
return d_enabled;
}
- std::string toString() const
- {
- if (!isEnabled()) {
- return "";
- }
-
- std::stringstream result;
- if (d_action != DNSAction::Action::None) {
- result << DNSAction::typeToString(d_action) << " ";
- }
- else {
- result << "Apply the global DynBlock action ";
- }
- result << "for " << std::to_string(d_blockDuration) << " seconds when over " << std::to_string(d_rate) << " during the last " << d_seconds << " seconds, reason: '" << d_blockReason << "'";
-
- return result.str();
- }
+ std::string toString() const;
std::string d_blockReason;
struct timespec d_cutOff;
@@ -158,72 +113,40 @@ private:
bool d_enabled{false};
};
- struct DynBlockRatioRule: DynBlockRule
+ struct DynBlockRatioRule : DynBlockRule
{
- DynBlockRatioRule(): DynBlockRule()
- {
- }
-
- DynBlockRatioRule(const std::string& blockReason, unsigned int blockDuration, double ratio, double warningRatio, unsigned int seconds, DNSAction::Action action, size_t minimumNumberOfResponses): DynBlockRule(blockReason, blockDuration, 0, 0, seconds, action), d_minimumNumberOfResponses(minimumNumberOfResponses), d_ratio(ratio), d_warningRatio(warningRatio)
+ DynBlockRatioRule() = default;
+ DynBlockRatioRule(const std::string& blockReason, unsigned int blockDuration, double ratio, double warningRatio, unsigned int seconds, DNSAction::Action action, size_t minimumNumberOfResponses) :
+ DynBlockRule(blockReason, blockDuration, 0, 0, seconds, action), d_minimumNumberOfResponses(minimumNumberOfResponses), d_ratio(ratio), d_warningRatio(warningRatio)
{
}
- bool ratioExceeded(unsigned int total, unsigned int count) const
- {
- if (!d_enabled) {
- return false;
- }
-
- if (total < d_minimumNumberOfResponses) {
- return false;
- }
+ bool ratioExceeded(unsigned int total, unsigned int count) const;
+ bool warningRatioExceeded(unsigned int total, unsigned int count) const;
+ std::string toString() const;
- double allowed = d_ratio * static_cast<double>(total);
- return (count > allowed);
- }
+ size_t d_minimumNumberOfResponses{0};
+ double d_ratio{0.0};
+ double d_warningRatio{0.0};
+ };
- bool warningRatioExceeded(unsigned int total, unsigned int count) const
+ struct DynBlockCacheMissRatioRule : public DynBlockRatioRule
+ {
+ DynBlockCacheMissRatioRule() = default;
+ DynBlockCacheMissRatioRule(const std::string& blockReason, unsigned int blockDuration, double ratio, double warningRatio, unsigned int seconds, DNSAction::Action action, size_t minimumNumberOfResponses, double minimumGlobalCacheHitRatio) :
+ DynBlockRatioRule(blockReason, blockDuration, ratio, warningRatio, seconds, action, minimumNumberOfResponses), d_minimumGlobalCacheHitRatio(minimumGlobalCacheHitRatio)
{
- if (!d_enabled) {
- return false;
- }
-
- if (d_warningRatio == 0.0) {
- return false;
- }
-
- if (total < d_minimumNumberOfResponses) {
- return false;
- }
-
- double allowed = d_warningRatio * static_cast<double>(total);
- return (count > allowed);
}
- std::string toString() const
- {
- if (!isEnabled()) {
- return "";
- }
-
- std::stringstream result;
- if (d_action != DNSAction::Action::None) {
- result << DNSAction::typeToString(d_action) << " ";
- }
- else {
- result << "Apply the global DynBlock action ";
- }
- result << "for " << std::to_string(d_blockDuration) << " seconds when over " << std::to_string(d_ratio) << " ratio during the last " << d_seconds << " seconds, reason: '" << d_blockReason << "'";
-
- return result.str();
- }
+ bool checkGlobalCacheHitRatio() const;
+ bool ratioExceeded(unsigned int total, unsigned int count) const;
+ bool warningRatioExceeded(unsigned int total, unsigned int count) const;
+ std::string toString() const;
- size_t d_minimumNumberOfResponses{0};
- double d_ratio{0.0};
- double d_warningRatio{0.0};
+ double d_minimumGlobalCacheHitRatio{0.0};
};
- typedef std::unordered_map<AddressAndPortRange, Counts, AddressAndPortRange::hash> counts_t;
+ using counts_t = std::unordered_map<AddressAndPortRange, Counts, AddressAndPortRange::hash>;
public:
DynBlockRulesGroup()
@@ -259,18 +182,28 @@ public:
entry = DynBlockRule(reason, blockDuration, rate, warningRate, seconds, action);
}
- typedef std::function<std::tuple<bool, boost::optional<std::string>>(const StatNode&, const StatNode::Stat&, const StatNode::Stat&)> smtVisitor_t;
+ void setCacheMissRatio(double ratio, double warningRatio, unsigned int seconds, const std::string& reason, unsigned int blockDuration, DNSAction::Action action, size_t minimumNumberOfResponses, double minimumGlobalCacheHitRatio)
+ {
+ d_respCacheMissRatioRule = DynBlockCacheMissRatioRule(reason, blockDuration, ratio, warningRatio, seconds, action, minimumNumberOfResponses, minimumGlobalCacheHitRatio);
+ }
+
+ using smtVisitor_t = std::function<std::tuple<bool, boost::optional<std::string>, boost::optional<int>>(const StatNode&, const StatNode::Stat&, const StatNode::Stat&)>;
void setSuffixMatchRule(unsigned int seconds, const std::string& reason, unsigned int blockDuration, DNSAction::Action action, smtVisitor_t visitor)
{
d_suffixMatchRule = DynBlockRule(reason, blockDuration, 0, 0, seconds, action);
- d_smtVisitor = visitor;
+ d_smtVisitor = std::move(visitor);
}
void setSuffixMatchRuleFFI(unsigned int seconds, const std::string& reason, unsigned int blockDuration, DNSAction::Action action, dnsdist_ffi_stat_node_visitor_t visitor)
{
d_suffixMatchRule = DynBlockRule(reason, blockDuration, 0, 0, seconds, action);
- d_smtVisitorFFI = visitor;
+ d_smtVisitorFFI = std::move(visitor);
+ }
+
+ void setNewBlockHook(const dnsdist_ffi_dynamic_block_inserted_hook& callback)
+ {
+ d_newBlockHook = callback;
}
void setMasks(uint8_t v4, uint8_t v6, uint8_t port)
@@ -332,6 +265,7 @@ public:
result << "Query rate rule: " << d_queryRateRule.toString() << std::endl;
result << "Response rate rule: " << d_respRateRule.toString() << std::endl;
result << "SuffixMatch rule: " << d_suffixMatchRule.toString() << std::endl;
+ result << "Response cache-miss ratio rule: " << d_respCacheMissRatioRule.toString() << std::endl;
result << "RCode rules: " << std::endl;
for (const auto& rule : d_rcodeRules) {
result << "- " << RCode::to_s(rule.first) << ": " << rule.second.toString() << std::endl;
@@ -355,18 +289,18 @@ public:
}
private:
-
+ void applySMT(const struct timespec& now, StatNode& statNodeRoot);
bool checkIfQueryTypeMatches(const Rings::Query& query);
bool checkIfResponseCodeMatches(const Rings::Response& response);
- void addOrRefreshBlock(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange> >& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated, bool warning);
+ void addOrRefreshBlock(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange>>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated, bool warning);
void addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const struct timespec& now, const DNSName& name, const DynBlockRule& rule, bool& updated);
- void addBlock(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange> >& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated)
+ void addBlock(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange>>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated)
{
addOrRefreshBlock(blocks, now, requestor, rule, updated, false);
}
- void handleWarning(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange> >& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated)
+ void handleWarning(boost::optional<NetmaskTree<DynBlock, AddressAndPortRange>>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const DynBlockRule& rule, bool& updated)
{
addOrRefreshBlock(blocks, now, requestor, rule, updated, true);
}
@@ -378,7 +312,7 @@ private:
bool hasResponseRules() const
{
- return d_respRateRule.isEnabled() || !d_rcodeRules.empty() || !d_rcodeRatioRules.empty();
+ return d_respRateRule.isEnabled() || !d_rcodeRules.empty() || !d_rcodeRatioRules.empty() || d_respCacheMissRatioRule.isEnabled();
}
bool hasSuffixMatchRules() const
@@ -400,10 +334,12 @@ private:
DynBlockRule d_queryRateRule;
DynBlockRule d_respRateRule;
DynBlockRule d_suffixMatchRule;
+ DynBlockCacheMissRatioRule d_respCacheMissRatioRule;
NetmaskGroup d_excludedSubnets;
SuffixMatchNode d_excludedDomains;
smtVisitor_t d_smtVisitor;
dnsdist_ffi_stat_node_visitor_t d_smtVisitorFFI;
+ dnsdist_ffi_dynamic_block_inserted_hook d_newBlockHook;
uint8_t d_v6Mask{128};
uint8_t d_v4Mask{32};
uint8_t d_portMask{0};
@@ -449,4 +385,9 @@ private:
static size_t s_topN;
};
+namespace dnsdist::DynamicBlocks
+{
+bool addOrRefreshBlock(NetmaskTree<DynBlock, AddressAndPortRange>& blocks, const struct timespec& now, const AddressAndPortRange& requestor, const std::string& reason, unsigned int duration, DNSAction::Action action, bool warning, bool beQuiet);
+bool addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const struct timespec& now, const DNSName& name, const std::string& reason, unsigned int duration, DNSAction::Action action, bool beQuiet);
+}
#endif /* DISABLE_DYNBLOCKS */