DNSAction::Action g_dynBlockAction = DNSAction::Action::Drop;
#ifndef DISABLE_DYNBLOCKS
-void DynBlockRulesGroup::apply(const struct timespec& now)
+void DynBlockRulesGroup::apply(const timespec& now)
{
counts_t counts;
StatNode statNodeRoot;
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 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, std::shared_ptr<DynBlock::TagSettings> tagSettings)
{
unsigned int count = 0;
bool expired = false;
}
dblock.blocks = count;
+ if (action == DNSAction::Action::SetTag) {
+ dblock.tagSettings = std::move(tagSettings);
+ }
if (got == nullptr || expired || wasWarning) {
const auto actualAction = getActualAction(dblock);
return true;
}
-bool addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const struct timespec& now, const DNSName& name, const std::string& reason, unsigned int duration, DNSAction::Action action, 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, std::shared_ptr<DynBlock::TagSettings> tagSettings)
{
struct timespec until = now;
until.tv_sec += duration;
}
dblock.blocks = count;
+ if (action == DNSAction::Action::SetTag) {
+ dblock.tagSettings = std::move(tagSettings);
+ }
if (!beQuiet && (got == nullptr || expired)) {
warnlog("Inserting dynamic block for %s for %d seconds: %s", name, duration, reason);
blocks = g_dynblockNMG.getCopy();
}
- updated = dnsdist::DynamicBlocks::addOrRefreshBlock(*blocks, now, requestor, rule.d_blockReason, rule.d_blockDuration, rule.d_action, warning, d_beQuiet);
+ updated = dnsdist::DynamicBlocks::addOrRefreshBlock(*blocks, now, requestor, rule.d_blockReason, rule.d_blockDuration, rule.d_action, warning, d_beQuiet, rule.d_tagSettings);
if (updated && d_newBlockHook) {
try {
d_newBlockHook(dnsdist_ffi_dynamic_block_type_nmt, requestor.toString().c_str(), rule.d_blockReason.c_str(), static_cast<uint8_t>(rule.d_action), rule.d_blockDuration, warning);
return;
}
- updated = dnsdist::DynamicBlocks::addOrRefreshBlockSMT(blocks, now, name, rule.d_blockReason, rule.d_blockDuration, rule.d_action, d_beQuiet);
+ updated = dnsdist::DynamicBlocks::addOrRefreshBlockSMT(blocks, now, name, rule.d_blockReason, rule.d_blockDuration, rule.d_action, d_beQuiet, rule.d_tagSettings);
if (updated && d_newBlockHook) {
try {
d_newBlockHook(dnsdist_ffi_dynamic_block_type_smt, name.toString().c_str(), rule.d_blockReason.c_str(), static_cast<uint8_t>(rule.d_action), rule.d_blockDuration, false);
class DynBlockRulesGroup
{
-private:
- struct Counts
- {
- std::map<uint8_t, uint64_t> d_rcodeCounts;
- std::map<uint16_t, uint64_t> d_qtypeCounts;
- uint64_t queries{0};
- uint64_t responses{0};
- uint64_t respBytes{0};
- uint64_t cacheMisses{0};
- };
-
+public:
struct DynBlockRule
{
DynBlockRule() = default;
std::string toString() const;
std::string d_blockReason;
+ std::shared_ptr<DynBlock::TagSettings> d_tagSettings;
struct timespec d_cutOff;
struct timespec d_minTime;
unsigned int d_blockDuration{0};
double d_minimumGlobalCacheHitRatio{0.0};
};
+private:
+ struct Counts
+ {
+ std::map<uint8_t, uint64_t> d_rcodeCounts;
+ std::map<uint16_t, uint64_t> d_qtypeCounts;
+ uint64_t queries{0};
+ uint64_t responses{0};
+ uint64_t respBytes{0};
+ uint64_t cacheMisses{0};
+ };
using counts_t = std::unordered_map<AddressAndPortRange, Counts, AddressAndPortRange::hash>;
public:
{
}
- void setQueryRate(unsigned int rate, unsigned int warningRate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, DNSAction::Action action)
+ void setQueryRate(DynBlockRule&& rule)
{
- d_queryRateRule = DynBlockRule(reason, blockDuration, rate, warningRate, seconds, action);
+ d_queryRateRule = std::move(rule);
}
/* rate is in bytes per second */
- void setResponseByteRate(unsigned int rate, unsigned int warningRate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, DNSAction::Action action)
+ void setResponseByteRate(DynBlockRule&& rule)
{
- d_respRateRule = DynBlockRule(reason, blockDuration, rate, warningRate, seconds, action);
+ d_respRateRule = std::move(rule);
}
- void setRCodeRate(uint8_t rcode, unsigned int rate, unsigned int warningRate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, DNSAction::Action action)
+ void setRCodeRate(uint8_t rcode, DynBlockRule&& rule)
{
- auto& entry = d_rcodeRules[rcode];
- entry = DynBlockRule(reason, blockDuration, rate, warningRate, seconds, action);
+ d_rcodeRules[rcode] = std::move(rule);
}
- void setRCodeRatio(uint8_t rcode, double ratio, double warningRatio, unsigned int seconds, const std::string& reason, unsigned int blockDuration, DNSAction::Action action, size_t minimumNumberOfResponses)
+ void setRCodeRatio(uint8_t rcode, DynBlockRatioRule&& rule)
{
- auto& entry = d_rcodeRatioRules[rcode];
- entry = DynBlockRatioRule(reason, blockDuration, ratio, warningRatio, seconds, action, minimumNumberOfResponses);
+ d_rcodeRatioRules[rcode] = std::move(rule);
}
- void setQTypeRate(uint16_t qtype, unsigned int rate, unsigned int warningRate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, DNSAction::Action action)
+ void setQTypeRate(uint16_t qtype, DynBlockRule&& rule)
{
- auto& entry = d_qtypeRules[qtype];
- entry = DynBlockRule(reason, blockDuration, rate, warningRate, seconds, action);
+ d_qtypeRules[qtype] = std::move(rule);
}
- void setCacheMissRatio(double ratio, double warningRatio, unsigned int seconds, const std::string& reason, unsigned int blockDuration, DNSAction::Action action, size_t minimumNumberOfResponses, double minimumGlobalCacheHitRatio)
+ void setCacheMissRatio(DynBlockCacheMissRatioRule&& rule)
{
- d_respCacheMissRatioRule = DynBlockCacheMissRatioRule(reason, blockDuration, ratio, warningRatio, seconds, action, minimumNumberOfResponses, minimumGlobalCacheHitRatio);
+ d_respCacheMissRatioRule = std::move(rule);
}
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)
+ void setSuffixMatchRule(DynBlockRule&& rule, smtVisitor_t visitor)
{
- d_suffixMatchRule = DynBlockRule(reason, blockDuration, 0, 0, seconds, action);
+ d_suffixMatchRule = std::move(rule);
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)
+ void setSuffixMatchRuleFFI(DynBlockRule&& rule, dnsdist_ffi_stat_node_visitor_t visitor)
{
- d_suffixMatchRule = DynBlockRule(reason, blockDuration, 0, 0, seconds, action);
+ d_suffixMatchRule = std::move(rule);
d_smtVisitorFFI = std::move(visitor);
}
void apply()
{
- struct timespec now;
+ timespec now{};
gettime(&now);
apply(now);
}
- void apply(const struct timespec& now);
+ void apply(const timespec& now);
void excludeRange(const Netmask& range)
{
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);
+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, std::shared_ptr<DynBlock::TagSettings> tagSettings);
+bool addOrRefreshBlockSMT(SuffixMatchTree<DynBlock>& blocks, const struct timespec& now, const DNSName& name, const std::string& reason, unsigned int duration, DNSAction::Action action, bool beQuiet, std::shared_ptr<DynBlock::TagSettings> tagSettings);
}
#endif /* DISABLE_DYNBLOCKS */
AddressAndPortRange target(clientIPCA, clientIPMask, clientIPPortMask);
- struct timespec now
- {
- };
+ timespec now{};
gettime(&now);
auto slow = g_dynblockNMG.getCopy();
- if (dnsdist::DynamicBlocks::addOrRefreshBlock(slow, now, target, message, duration, static_cast<DNSAction::Action>(action), false, false)) {
+#warning FIXME: need to handle tags
+ if (dnsdist::DynamicBlocks::addOrRefreshBlock(slow, now, target, message, duration, static_cast<DNSAction::Action>(action), false, false, nullptr)) {
g_dynblockNMG.setState(slow);
return true;
}
return false;
}
- struct timespec now
- {
- };
+ timespec now{};
gettime(&now);
auto slow = g_dynblockSMT.getCopy();
- if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(slow, now, domain, message, duration, static_cast<DNSAction::Action>(action), false)) {
+#warning FIXME: need to handle tags
+ if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(slow, now, domain, message, duration, static_cast<DNSAction::Action>(action), false, nullptr)) {
g_dynblockSMT.setState(slow);
return true;
}
return nmmatch && dnmatch && msecmatch;
}
+#ifndef DISABLE_DYNBLOCKS
+using DynamicActionOptionalParameters = boost::optional<LuaAssociativeTable<std::string>>;
+
+static void parseDynamicActionOptionalParameters(const std::string& directive, DynBlockRulesGroup::DynBlockRule& rule, const boost::optional<DNSAction::Action>& action, const DynamicActionOptionalParameters& optionalParameters)
+{
+ if (action && *action == DNSAction::Action::SetTag) {
+ if (!optionalParameters) {
+ throw std::runtime_error("SetTag action passed to " + directive + " without additional parameters");
+ }
+ const auto& paramNameIt = optionalParameters->find("tagName");
+ if (paramNameIt == optionalParameters->end()) {
+ throw std::runtime_error("SetTag action passed to " + directive + " without a tag name");
+ }
+ rule.d_tagSettings = std::make_shared<DynBlock::TagSettings>();
+ rule.d_tagSettings->d_name = paramNameIt->second;
+ const auto& paramValueIt = optionalParameters->find("tagValue");
+ if (paramValueIt != optionalParameters->end()) {
+ rule.d_tagSettings->d_value = paramValueIt->second;
+ }
+ }
+}
+#endif /* DISABLE_DYNBLOCKS */
+
// NOLINTNEXTLINE(readability-function-cognitive-complexity): this function declares Lua bindings, even with a good refactoring it will likely blow up the threshold
void setupLuaInspection(LuaContext& luaCtx)
{
/* DynBlockRulesGroup */
luaCtx.writeFunction("dynBlockRulesGroup", []() { return std::make_shared<DynBlockRulesGroup>(); });
- luaCtx.registerFunction<void (std::shared_ptr<DynBlockRulesGroup>::*)(unsigned int, unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, boost::optional<unsigned int>)>("setQueryRate", [](std::shared_ptr<DynBlockRulesGroup>& group, unsigned int rate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, boost::optional<unsigned int> warningRate) {
+ luaCtx.registerFunction<void (std::shared_ptr<DynBlockRulesGroup>::*)(unsigned int, unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, boost::optional<unsigned int>, DynamicActionOptionalParameters)>("setQueryRate", [](std::shared_ptr<DynBlockRulesGroup>& group, unsigned int rate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, boost::optional<unsigned int> warningRate, DynamicActionOptionalParameters optionalParameters) {
if (group) {
- group->setQueryRate(rate, warningRate ? *warningRate : 0, seconds, reason, blockDuration, action ? *action : DNSAction::Action::None);
+ DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, rate, warningRate ? *warningRate : 0, seconds, action ? *action : DNSAction::Action::None);
+ parseDynamicActionOptionalParameters("setQueryRate", rule, action, optionalParameters);
+ group->setQueryRate(std::move(rule));
}
});
- luaCtx.registerFunction<void (std::shared_ptr<DynBlockRulesGroup>::*)(unsigned int, unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, boost::optional<unsigned int>)>("setResponseByteRate", [](std::shared_ptr<DynBlockRulesGroup>& group, unsigned int rate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, boost::optional<unsigned int> warningRate) {
+ luaCtx.registerFunction<void (std::shared_ptr<DynBlockRulesGroup>::*)(unsigned int, unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, boost::optional<unsigned int>, DynamicActionOptionalParameters)>("setResponseByteRate", [](std::shared_ptr<DynBlockRulesGroup>& group, unsigned int rate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, boost::optional<unsigned int> warningRate, DynamicActionOptionalParameters optionalParameters) {
if (group) {
- group->setResponseByteRate(rate, warningRate ? *warningRate : 0, seconds, reason, blockDuration, action ? *action : DNSAction::Action::None);
+ DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, rate, warningRate ? *warningRate : 0, seconds, action ? *action : DNSAction::Action::None);
+ parseDynamicActionOptionalParameters("setResponseByteRate", rule, action, optionalParameters);
+ group->setResponseByteRate(std::move(rule));
}
});
- luaCtx.registerFunction<void (std::shared_ptr<DynBlockRulesGroup>::*)(unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, DynBlockRulesGroup::smtVisitor_t)>("setSuffixMatchRule", [](std::shared_ptr<DynBlockRulesGroup>& group, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, DynBlockRulesGroup::smtVisitor_t visitor) {
+ luaCtx.registerFunction<void (std::shared_ptr<DynBlockRulesGroup>::*)(unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, DynBlockRulesGroup::smtVisitor_t, DynamicActionOptionalParameters)>("setSuffixMatchRule", [](std::shared_ptr<DynBlockRulesGroup>& group, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, DynBlockRulesGroup::smtVisitor_t visitor, DynamicActionOptionalParameters optionalParameters) {
if (group) {
- group->setSuffixMatchRule(seconds, reason, blockDuration, action ? *action : DNSAction::Action::None, std::move(visitor));
+ DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 0, 0, seconds, action ? *action : DNSAction::Action::None);
+ parseDynamicActionOptionalParameters("setSuffixMatchRule", rule, action, optionalParameters);
+ group->setSuffixMatchRule(std::move(rule), std::move(visitor));
}
});
- luaCtx.registerFunction<void (std::shared_ptr<DynBlockRulesGroup>::*)(unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, dnsdist_ffi_stat_node_visitor_t)>("setSuffixMatchRuleFFI", [](std::shared_ptr<DynBlockRulesGroup>& group, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, dnsdist_ffi_stat_node_visitor_t visitor) {
+ luaCtx.registerFunction<void (std::shared_ptr<DynBlockRulesGroup>::*)(unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, dnsdist_ffi_stat_node_visitor_t, DynamicActionOptionalParameters)>("setSuffixMatchRuleFFI", [](std::shared_ptr<DynBlockRulesGroup>& group, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, dnsdist_ffi_stat_node_visitor_t visitor, DynamicActionOptionalParameters optionalParameters) {
if (group) {
- group->setSuffixMatchRuleFFI(seconds, reason, blockDuration, action ? *action : DNSAction::Action::None, std::move(visitor));
+ DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 0, 0, seconds, action ? *action : DNSAction::Action::None);
+ parseDynamicActionOptionalParameters("setSuffixMatchRuleFFI", rule, action, optionalParameters);
+ group->setSuffixMatchRuleFFI(std::move(rule), std::move(visitor));
}
});
luaCtx.registerFunction<void (std::shared_ptr<DynBlockRulesGroup>::*)(const dnsdist_ffi_dynamic_block_inserted_hook&)>("setNewBlockInsertedHook", [](std::shared_ptr<DynBlockRulesGroup>& group, const dnsdist_ffi_dynamic_block_inserted_hook& hook) {
group->setNewBlockHook(hook);
}
});
- luaCtx.registerFunction<void (std::shared_ptr<DynBlockRulesGroup>::*)(uint8_t, unsigned int, unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, boost::optional<unsigned int>)>("setRCodeRate", [](std::shared_ptr<DynBlockRulesGroup>& group, uint8_t rcode, unsigned int rate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, boost::optional<unsigned int> warningRate) {
+ luaCtx.registerFunction<void (std::shared_ptr<DynBlockRulesGroup>::*)(uint8_t, unsigned int, unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, boost::optional<unsigned int>, DynamicActionOptionalParameters)>("setRCodeRate", [](std::shared_ptr<DynBlockRulesGroup>& group, uint8_t rcode, unsigned int rate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, boost::optional<unsigned int> warningRate, DynamicActionOptionalParameters optionalParameters) {
if (group) {
- group->setRCodeRate(rcode, rate, warningRate ? *warningRate : 0, seconds, reason, blockDuration, action ? *action : DNSAction::Action::None);
+ DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, rate, warningRate ? *warningRate : 0, seconds, action ? *action : DNSAction::Action::None);
+ parseDynamicActionOptionalParameters("setRCodeRate", rule, action, optionalParameters);
+ group->setRCodeRate(rcode, std::move(rule));
}
});
- luaCtx.registerFunction<void (std::shared_ptr<DynBlockRulesGroup>::*)(uint8_t, double, unsigned int, const std::string&, unsigned int, size_t, boost::optional<DNSAction::Action>, boost::optional<double>)>("setRCodeRatio", [](std::shared_ptr<DynBlockRulesGroup>& group, uint8_t rcode, double ratio, unsigned int seconds, const std::string& reason, unsigned int blockDuration, size_t minimumNumberOfResponses, boost::optional<DNSAction::Action> action, boost::optional<double> warningRatio) {
+ luaCtx.registerFunction<void (std::shared_ptr<DynBlockRulesGroup>::*)(uint8_t, double, unsigned int, const std::string&, unsigned int, size_t, boost::optional<DNSAction::Action>, boost::optional<double>, DynamicActionOptionalParameters)>("setRCodeRatio", [](std::shared_ptr<DynBlockRulesGroup>& group, uint8_t rcode, double ratio, unsigned int seconds, const std::string& reason, unsigned int blockDuration, size_t minimumNumberOfResponses, boost::optional<DNSAction::Action> action, boost::optional<double> warningRatio, DynamicActionOptionalParameters optionalParameters) {
if (group) {
- group->setRCodeRatio(rcode, ratio, warningRatio ? *warningRatio : 0.0, seconds, reason, blockDuration, action ? *action : DNSAction::Action::None, minimumNumberOfResponses);
+ DynBlockRulesGroup::DynBlockRatioRule rule(reason, blockDuration, ratio, warningRatio ? *warningRatio : 0.0, seconds, action ? *action : DNSAction::Action::None, minimumNumberOfResponses);
+ parseDynamicActionOptionalParameters("setRCodeRatio", rule, action, optionalParameters);
+ group->setRCodeRatio(rcode, std::move(rule));
}
});
- luaCtx.registerFunction<void (std::shared_ptr<DynBlockRulesGroup>::*)(uint16_t, unsigned int, unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, boost::optional<unsigned int>)>("setQTypeRate", [](std::shared_ptr<DynBlockRulesGroup>& group, uint16_t qtype, unsigned int rate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, boost::optional<unsigned int> warningRate) {
+ luaCtx.registerFunction<void (std::shared_ptr<DynBlockRulesGroup>::*)(uint16_t, unsigned int, unsigned int, const std::string&, unsigned int, boost::optional<DNSAction::Action>, boost::optional<unsigned int>, DynamicActionOptionalParameters)>("setQTypeRate", [](std::shared_ptr<DynBlockRulesGroup>& group, uint16_t qtype, unsigned int rate, unsigned int seconds, const std::string& reason, unsigned int blockDuration, boost::optional<DNSAction::Action> action, boost::optional<unsigned int> warningRate, DynamicActionOptionalParameters optionalParameters) {
if (group) {
- group->setQTypeRate(qtype, rate, warningRate ? *warningRate : 0, seconds, reason, blockDuration, action ? *action : DNSAction::Action::None);
+ DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, rate, warningRate ? *warningRate : 0.0, seconds, action ? *action : DNSAction::Action::None);
+ parseDynamicActionOptionalParameters("setQTypeRate", rule, action, optionalParameters);
+ group->setQTypeRate(qtype, std::move(rule));
}
});
- luaCtx.registerFunction<void (std::shared_ptr<DynBlockRulesGroup>::*)(double, unsigned int, const std::string&, unsigned int, size_t, double, boost::optional<DNSAction::Action>, boost::optional<double>)>("setCacheMissRatio", [](std::shared_ptr<DynBlockRulesGroup>& group, double ratio, unsigned int seconds, const std::string& reason, unsigned int blockDuration, size_t minimumNumberOfResponses, double minimumGlobalCacheHitRatio, boost::optional<DNSAction::Action> action, boost::optional<double> warningRatio) {
+ luaCtx.registerFunction<void (std::shared_ptr<DynBlockRulesGroup>::*)(double, unsigned int, const std::string&, unsigned int, size_t, double, boost::optional<DNSAction::Action>, boost::optional<double>, DynamicActionOptionalParameters)>("setCacheMissRatio", [](std::shared_ptr<DynBlockRulesGroup>& group, double ratio, unsigned int seconds, const std::string& reason, unsigned int blockDuration, size_t minimumNumberOfResponses, double minimumGlobalCacheHitRatio, boost::optional<DNSAction::Action> action, boost::optional<double> warningRatio, DynamicActionOptionalParameters optionalParameters) {
if (group) {
- group->setCacheMissRatio(ratio, warningRatio ? *warningRatio : 0.0, seconds, reason, blockDuration, action ? *action : DNSAction::Action::None, minimumNumberOfResponses, minimumGlobalCacheHitRatio);
+ DynBlockRulesGroup::DynBlockCacheMissRatioRule rule(reason, blockDuration, ratio, warningRatio ? *warningRatio : 0.0, seconds, action ? *action : DNSAction::Action::None, minimumNumberOfResponses, minimumGlobalCacheHitRatio);
+ parseDynamicActionOptionalParameters("setCacheMissRatio", rule, action, optionalParameters);
+ group->setCacheMissRatio(std::move(rule));
}
});
luaCtx.registerFunction<void (std::shared_ptr<DynBlockRulesGroup>::*)(uint8_t, uint8_t, uint8_t)>("setMasks", [](std::shared_ptr<DynBlockRulesGroup>& group, uint8_t v4addr, uint8_t v6addr, uint8_t port) {
void setupLuaVars(LuaContext& luaCtx)
{
- luaCtx.writeVariable("DNSAction", LuaAssociativeTable<int>{{"Drop", (int)DNSAction::Action::Drop}, {"Nxdomain", (int)DNSAction::Action::Nxdomain}, {"Refused", (int)DNSAction::Action::Refused}, {"Spoof", (int)DNSAction::Action::Spoof}, {"SpoofPacket", (int)DNSAction::Action::SpoofPacket}, {"SpoofRaw", (int)DNSAction::Action::SpoofRaw}, {"Allow", (int)DNSAction::Action::Allow}, {"HeaderModify", (int)DNSAction::Action::HeaderModify}, {"Pool", (int)DNSAction::Action::Pool}, {"None", (int)DNSAction::Action::None}, {"NoOp", (int)DNSAction::Action::NoOp}, {"Delay", (int)DNSAction::Action::Delay}, {"Truncate", (int)DNSAction::Action::Truncate}, {"ServFail", (int)DNSAction::Action::ServFail}, {"NoRecurse", (int)DNSAction::Action::NoRecurse}});
+ luaCtx.writeVariable("DNSAction", LuaAssociativeTable<int>{{"Drop", (int)DNSAction::Action::Drop}, {"Nxdomain", (int)DNSAction::Action::Nxdomain}, {"Refused", (int)DNSAction::Action::Refused}, {"Spoof", (int)DNSAction::Action::Spoof}, {"SpoofPacket", (int)DNSAction::Action::SpoofPacket}, {"SpoofRaw", (int)DNSAction::Action::SpoofRaw}, {"Allow", (int)DNSAction::Action::Allow}, {"HeaderModify", (int)DNSAction::Action::HeaderModify}, {"Pool", (int)DNSAction::Action::Pool}, {"None", (int)DNSAction::Action::None}, {"NoOp", (int)DNSAction::Action::NoOp}, {"Delay", (int)DNSAction::Action::Delay}, {"Truncate", (int)DNSAction::Action::Truncate}, {"ServFail", (int)DNSAction::Action::ServFail}, {"NoRecurse", (int)DNSAction::Action::NoRecurse}, {"SetTag", (int)DNSAction::Action::SetTag}});
luaCtx.writeVariable("DNSResponseAction", LuaAssociativeTable<int>{{"Allow", (int)DNSResponseAction::Action::Allow}, {"Delay", (int)DNSResponseAction::Action::Delay}, {"Drop", (int)DNSResponseAction::Action::Drop}, {"HeaderModify", (int)DNSResponseAction::Action::HeaderModify}, {"ServFail", (int)DNSResponseAction::Action::ServFail}, {"Truncate", (int)DNSResponseAction::Action::Truncate}, {"None", (int)DNSResponseAction::Action::None}});
for (const auto& capair : names) {
DNSName domain(capair.second);
domain.makeUsLowerCase();
-
- if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(slow, now, domain, msg, actualSeconds, action ? *action : DNSAction::Action::None, false)) {
+#warning FIXME: need to handle tags
+ if (dnsdist::DynamicBlocks::addOrRefreshBlockSMT(slow, now, domain, msg, actualSeconds, action ? *action : DNSAction::Action::None, false, nullptr)) {
needUpdate = true;
}
}
timespec now{};
gettime(&now);
auto slow = g_dynblockNMG.getCopy();
- if (dnsdist::DynamicBlocks::addOrRefreshBlock(slow, now, target, msg, actualSeconds, action ? *action : DNSAction::Action::None, false, false)) {
+#warning FIXME: need to handle tags
+ if (dnsdist::DynamicBlocks::addOrRefreshBlock(slow, now, target, msg, actualSeconds, action ? *action : DNSAction::Action::None, false, false, nullptr)) {
g_dynblockNMG.setState(slow);
}
});
string reason;
DNSName domain;
timespec until{};
- std::unique_ptr<TagSettings> tagSettings{nullptr};
+ std::shared_ptr<TagSettings> tagSettings{nullptr};
mutable std::atomic<uint32_t> blocks{0};
DNSAction::Action action{DNSAction::Action::None};
bool warning{false};
.. versionchanged:: 1.8.0
``DNSAction.SpoofPacket`` has been added.
+.. versionchanged:: 2.0.0
+ ``DNSAction.SetTag`` has been added.
+
These constants represent an Action that can be returned from :func:`LuaAction` functions.
* ``DNSAction.Allow``: let the query pass, skipping other rules
* ``DNSAction.HeaderModify``: indicate that the query has been turned into a response
* ``DNSAction.None``: continue to the next rule
* ``DNSAction.NoOp``: continue to the next rule (used for Dynamic Block actions where None has a different meaning)
+ * ``DNSAction.NoRecurse``: set rd=0 on the query
* ``DNSAction.Nxdomain``: return a response with a NXDomain rcode
* ``DNSAction.Pool``: use the specified pool to forward this query
* ``DNSAction.Refused``: return a response with a Refused rcode
* ``DNSAction.ServFail``: return a response with a ServFail rcode
+ * ``DNSAction.SetTag``: set a tag, see :function:`SetTagAction` (only used for Dynamic Block actions, see meth:`DNSQuestion:setTag` to set a tag from Lua)
* ``DNSAction.Spoof``: spoof the response using the supplied IPv4 (A), IPv6 (AAAA) or string (CNAME) value. TTL will be 60 seconds.
* ``DNSAction.SpoofPacket``: spoof the response using the supplied raw packet
* ``DNSAction.SpoofRaw``: spoof the response using the supplied raw value as record data (see also :meth:`DNSQuestion:spoof` and :func:`dnsdist_ffi_dnsquestion_spoof_raw` to spoof multiple values)
* ``DNSAction.Truncate``: truncate the response
- * ``DNSAction.NoRecurse``: set rd=0 on the query
.. _DNSQType:
DynBlockRulesGroup dbrg;
dbrg.setQuiet(true);
- /* block above 50 qps for numberOfSeconds seconds, no warning */
- dbrg.setQueryRate(50, 0, numberOfSeconds, reason, blockDuration, action);
+ {
+ /* block above 50 qps for numberOfSeconds seconds, no warning */
+ DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 50, 0, numberOfSeconds, action);
+ dbrg.setQueryRate(std::move(rule));
+ }
{
/* insert 45 qps from a given client in the last 10s
dbrg.setQuiet(true);
dbrg.setMasks(32, 64, 0);
- /* block above 50 qps for numberOfSeconds seconds, no warning */
- dbrg.setQueryRate(50, 0, numberOfSeconds, reason, blockDuration, action);
+ {
+ /* block above 50 qps for numberOfSeconds seconds, no warning */
+ DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 50, 0, numberOfSeconds, action);
+ dbrg.setQueryRate(std::move(rule));
+ }
{
/* insert 45 qps from a given client in the last 10s
/* split v4 by ports using a /2 (0 - 16383, 16384 - 32767, 32768 - 49151, 49152 - 65535) */
dbrg.setMasks(32, 128, 2);
- /* block above 50 qps for numberOfSeconds seconds, no warning */
- dbrg.setQueryRate(50, 0, numberOfSeconds, reason, blockDuration, action);
+ {
+ /* block above 50 qps for numberOfSeconds seconds, no warning */
+ DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 50, 0, numberOfSeconds, action);
+ dbrg.setQueryRate(std::move(rule));
+ }
{
/* insert 45 qps from a given client in the last 10s
DynBlockRulesGroup dbrg;
dbrg.setQuiet(true);
- /* block above 50 qps for numberOfSeconds seconds, no warning */
- dbrg.setQueryRate(50, 0, numberOfSeconds, reason, blockDuration, action);
- dbrg.setRCodeRate(RCode::ServFail, 50, 40, 5, "Exceeded ServFail rate", 60, DNSAction::Action::Drop);
+ {
+ /* block above 50 qps for numberOfSeconds seconds, no warning */
+ DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 50, 0, numberOfSeconds, action);
+ dbrg.setQueryRate(std::move(rule));
+ }
+ {
+ DynBlockRulesGroup::DynBlockRule rule("Exceeded ServFail rate", 60, 50, 40, 5, DNSAction::Action::Drop);
+ dbrg.setRCodeRate(RCode::ServFail, std::move(rule));
+ }
{
/* insert 45 qps (including responses) from a given client for the last 100s
DynBlockRulesGroup dbrg;
dbrg.setQuiet(true);
- /* block above 50 qps for numberOfSeconds seconds, no warning */
- dbrg.setQTypeRate(QType::AAAA, 50, 0, numberOfSeconds, reason, blockDuration, action);
+ {
+ /* block above 50 qps for numberOfSeconds seconds, no warning */
+ DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 50, 0, numberOfSeconds, action);
+ dbrg.setQTypeRate(QType::AAAA, std::move(rule));
+ }
{
/* insert 45 qps from a given client in the last 10s
DynBlockRulesGroup dbrg;
dbrg.setQuiet(true);
- /* block above 50 ServFail/s for numberOfSeconds seconds, no warning */
- dbrg.setRCodeRate(rcode, 50, 0, numberOfSeconds, reason, blockDuration, action);
+ {
+ /* block above 50 ServFail/s for numberOfSeconds seconds, no warning */
+ DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 50, 0, numberOfSeconds, action);
+ dbrg.setRCodeRate(rcode, std::move(rule));
+ }
{
/* insert 45 ServFail/s from a given client in the last 10s
DynBlockRulesGroup dbrg;
dbrg.setQuiet(true);
- /* block above 0.2 ServFail/Total ratio over numberOfSeconds seconds, no warning, minimum number of queries should be at least 51 */
- dbrg.setRCodeRatio(rcode, 0.2, 0, numberOfSeconds, reason, blockDuration, action, 51);
+ {
+ /* block above 0.2 ServFail/Total ratio over numberOfSeconds seconds, no warning, minimum number of queries should be at least 51 */
+ DynBlockRulesGroup::DynBlockRatioRule rule(reason, blockDuration, 0.2, 0.0, numberOfSeconds, action, 51);
+ dbrg.setRCodeRatio(rcode, std::move(rule));
+ }
{
/* insert 20 ServFail and 80 NoErrors from a given client in the last 10s
DynBlockRulesGroup dbrg;
dbrg.setQuiet(true);
- /* block above 10kB/s for numberOfSeconds seconds, no warning */
- dbrg.setResponseByteRate(10000, 0, numberOfSeconds, reason, blockDuration, action);
+ {
+ /* block above 10kB/s for numberOfSeconds seconds, no warning */
+ DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 10000, 0, numberOfSeconds, action);
+ dbrg.setResponseByteRate(std::move(rule));
+ }
{
/* insert 99 answers of 100 bytes per second from a given client in the last 10s
/* block above 0.5 Cache-Miss/Total ratio over numberOfSeconds seconds, no warning, minimum number of queries should be at least 51, global cache hit at least 80% */
dnsdist::metrics::g_stats.cacheHits.store(80);
dnsdist::metrics::g_stats.cacheMisses.store(20);
- dbrg.setCacheMissRatio(0.5, 0, numberOfSeconds, reason, blockDuration, action, 51, 0.8);
+ {
+ DynBlockRulesGroup::DynBlockCacheMissRatioRule rule(reason, blockDuration, 0.5, 0.0, numberOfSeconds, action, 51, 0.8);
+ dbrg.setCacheMissRatio(std::move(rule));
+ }
{
/* insert 50 cache misses and 50 cache hits from a given client in the last 10s
DynBlockRulesGroup dbrg;
dbrg.setQuiet(true);
- /* warn above 20 qps for numberOfSeconds seconds, block above 50 qps */
- dbrg.setQueryRate(50, 20, numberOfSeconds, reason, blockDuration, action);
+ {
+ /* warn above 20 qps for numberOfSeconds seconds, block above 50 qps */
+ DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 50, 20, numberOfSeconds, action);
+ dbrg.setQueryRate(std::move(rule));
+ }
{
/* insert 20 qps from a given client in the last 10s
/* but exclude 192.0.2.42 only */
dbrg.excludeRange(Netmask("192.0.2.42/32"));
- /* block above 50 qps for numberOfSeconds seconds, no warning */
- dbrg.setQueryRate(50, 0, numberOfSeconds, reason, blockDuration, action);
+ {
+ /* block above 50 qps for numberOfSeconds seconds, no warning */
+ DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 50, 0, numberOfSeconds, action);
+ dbrg.setQueryRate(std::move(rule));
+ }
{
/* insert just above 50 qps from the two clients in the last 10s
g_rings.clear();
g_dynblockNMG.setState(emptyNMG);
- /* block above 0 qps for numberOfSeconds seconds, no warning */
- dbrg.setQueryRate(0, 0, numberOfSeconds, reason, blockDuration, action);
+ {
+ /* block above 0 qps for numberOfSeconds seconds, no warning */
+ DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 0, 0, numberOfSeconds, action);
+ dbrg.setQueryRate(std::move(rule));
+ }
/* insert one fake query from 255 clients:
*/
g_dynblockNMG.setState(emptyNMG);
g_dynblockSMT.setState(emptySMT);
- dbrg.setSuffixMatchRule(numberOfSeconds, reason, blockDuration, action, [](const StatNode& node, const StatNode::Stat& self, const StatNode::Stat& children) {
- if (self.queries > 0) {
- return std::tuple<bool, boost::optional<std::string>, boost::optional<int>>(true, boost::none, boost::none);
- }
- return std::tuple<bool, boost::optional<std::string>, boost::optional<int>>(false, boost::none, boost::none);
- });
+ {
+ DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 0, 0, numberOfSeconds, action);
+ dbrg.setSuffixMatchRule(std::move(rule), [](const StatNode& node, const StatNode::Stat& self, const StatNode::Stat& children) {
+ if (self.queries > 0) {
+ return std::tuple<bool, boost::optional<std::string>, boost::optional<int>>(true, boost::none, boost::none);
+ }
+ return std::tuple<bool, boost::optional<std::string>, boost::optional<int>>(false, boost::none, boost::none);
+ });
+ }
/* insert one fake response for 255 DNS names */
const ComboAddress requestor("192.0.2.1");
g_dynblockNMG.setState(emptyNMG);
g_dynblockSMT.setState(emptySMT);
- dbrg.setSuffixMatchRule(numberOfSeconds, reason, blockDuration, action, [](const StatNode& node, const StatNode::Stat& self, const StatNode::Stat& children) {
- if (self.queries > 0) {
- return std::tuple<bool, boost::optional<std::string>, boost::optional<int>>(true, "blocked for a different reason", static_cast<int>(DNSAction::Action::Truncate));
- }
- return std::tuple<bool, boost::optional<std::string>, boost::optional<int>>(false, boost::none, boost::none);
- });
+ {
+ DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 0, 0, numberOfSeconds, action);
+ dbrg.setSuffixMatchRule(std::move(rule), [](const StatNode& node, const StatNode::Stat& self, const StatNode::Stat& children) {
+ if (self.queries > 0) {
+ return std::tuple<bool, boost::optional<std::string>, boost::optional<int>>(true, "blocked for a different reason", static_cast<int>(DNSAction::Action::Truncate));
+ }
+ return std::tuple<bool, boost::optional<std::string>, boost::optional<int>>(false, boost::none, boost::none);
+ });
+ }
/* insert one fake response for 255 DNS names */
const ComboAddress requestor("192.0.2.1");
g_dynblockNMG.setState(emptyNMG);
g_dynblockSMT.setState(emptySMT);
- dbrg.setSuffixMatchRule(numberOfSeconds, reason, blockDuration, action, [](const StatNode& node, const StatNode::Stat& self, const StatNode::Stat& children) {
- if (self.queries > 0) {
- return std::tuple<bool, boost::optional<std::string>, boost::optional<int>>(true, boost::none, boost::none);
- }
- return std::tuple<bool, boost::optional<std::string>, boost::optional<int>>(false, boost::none, boost::none);
- });
+ {
+ DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 0, 0, numberOfSeconds, action);
+ dbrg.setSuffixMatchRule(std::move(rule), [](const StatNode& node, const StatNode::Stat& self, const StatNode::Stat& children) {
+ if (self.queries > 0) {
+ return std::tuple<bool, boost::optional<std::string>, boost::optional<int>>(true, boost::none, boost::none);
+ }
+ return std::tuple<bool, boost::optional<std::string>, boost::optional<int>>(false, boost::none, boost::none);
+ });
+ }
bool done = false;
const ComboAddress requestor("192.0.2.1");
g_rings.clear();
g_dynblockNMG.setState(emptyNMG);
g_dynblockSMT.setState(emptySMT);
- dbrg.setQueryRate(0, 0, numberOfSeconds, reason, blockDuration, action);
+ {
+ DynBlockRulesGroup::DynBlockRule rule(reason, blockDuration, 0, 0, numberOfSeconds, action);
+ dbrg.setQueryRate(std::move(rule));
+ }
bool done = false;
for (size_t idxB = 0; !done && idxB < 256; idxB++) {