From: Remi Gacogne Date: Fri, 8 Mar 2024 15:14:17 +0000 (+0100) Subject: dnsdist: Add a new query rules chain triggered after a cache miss X-Git-Tag: rec-5.1.0-alpha1~69^2~1 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cd1675bd166abfe52589cef61724cb61b3431b89;p=thirdparty%2Fpdns.git dnsdist: Add a new query rules chain triggered after a cache miss This new chain of rules allows postponing the decision of what to do with the query to after a cache-lookup has been done. This is particularly useful when dealing with abuse: we might want to allow cache hits to be processed normally since they are cheap while dropping/ refusing/routing to a different pool queries that result in a cache miss. --- diff --git a/pdns/dnsdistdist/dnsdist-lua-actions.cc b/pdns/dnsdistdist/dnsdist-lua-actions.cc index 0112fd17c3..51348375f0 100644 --- a/pdns/dnsdistdist/dnsdist-lua-actions.cc +++ b/pdns/dnsdistdist/dnsdist-lua-actions.cc @@ -2481,13 +2481,26 @@ void setupLuaActions(LuaContext& luaCtx) return std::make_shared(ruleaction); }); - luaCtx.writeFunction("addAction", [](const luadnsrule_t& var, boost::variant, std::shared_ptr> era, boost::optional params) { - if (era.type() != typeid(std::shared_ptr)) { - throw std::runtime_error("addAction() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?"); - } + for (const auto& chain : dnsdist::rules::getRuleChains()) { + auto fullName = std::string("add") + chain.prefix + std::string("Action"); + luaCtx.writeFunction(fullName, [&fullName, &chain](const luadnsrule_t& var, boost::variant, std::shared_ptr> era, boost::optional params) { + if (era.type() != typeid(std::shared_ptr)) { + throw std::runtime_error(fullName + "() can only be called with query-related actions, not response-related ones. Are you looking for addResponseAction()?"); + } - addAction(&dnsdist::rules::g_ruleactions, var, boost::get>(era), params); - }); + addAction(&chain.holder, var, boost::get>(era), params); + }); + fullName = std::string("get") + chain.prefix + std::string("Action"); + luaCtx.writeFunction(fullName, [&chain](unsigned int num) { + setLuaNoSideEffect(); + boost::optional> ret; + auto ruleactions = chain.holder.getCopy(); + if (num < ruleactions.size()) { + ret = ruleactions[num].d_action; + } + return ret; + }); + } for (const auto& chain : dnsdist::rules::getResponseRuleChains()) { const auto fullName = std::string("add") + chain.prefix + std::string("ResponseAction"); @@ -2515,16 +2528,6 @@ void setupLuaActions(LuaContext& luaCtx) } }); - luaCtx.writeFunction("getAction", [](unsigned int num) { - setLuaNoSideEffect(); - boost::optional> ret; - auto ruleactions = dnsdist::rules::g_ruleactions.getCopy(); - if (num < ruleactions.size()) { - ret = ruleactions[num].d_action; - } - return ret; - }); - luaCtx.registerFunction("getStats", &DNSAction::getStats); luaCtx.registerFunction("reload", &DNSAction::reload); luaCtx.registerFunction("reload", &DNSResponseAction::reload); diff --git a/pdns/dnsdistdist/dnsdist-lua-rules.cc b/pdns/dnsdistdist/dnsdist-lua-rules.cc index 6209a54ac4..a4d7adbcfd 100644 --- a/pdns/dnsdistdist/dnsdist-lua-rules.cc +++ b/pdns/dnsdistdist/dnsdist-lua-rules.cc @@ -362,57 +362,66 @@ void setupLuaRules(LuaContext& luaCtx) auto rules = chain.holder.getLocal(); return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars); }); + + luaCtx.writeFunction("clear" + chain.prefix + "ResponseRules", [&chain]() { + setLuaSideEffect(); + chain.holder.modify([](std::remove_reference_t::value_type& ruleactions) { + ruleactions.clear(); + }); + }); } - luaCtx.writeFunction("rmRule", [](const boost::variant& identifier) { - rmRule(&dnsdist::rules::g_ruleactions, identifier); - }); + for (const auto& chain : dnsdist::rules::getRuleChains()) { + luaCtx.writeFunction("show" + chain.prefix + "Rules", [&chain](boost::optional vars) { + showRules(&chain.holder, vars); + }); + luaCtx.writeFunction("rm" + chain.prefix + "Rule", [&chain](const boost::variant& identifier) { + rmRule(&chain.holder, identifier); + }); + luaCtx.writeFunction("mv" + chain.prefix + "RuleToTop", [&chain]() { + moveRuleToTop(&chain.holder); + }); + luaCtx.writeFunction("mv" + chain.prefix + "Rule", [&chain](unsigned int from, unsigned int dest) { + mvRule(&chain.holder, from, dest); + }); + luaCtx.writeFunction("get" + chain.prefix + "Rule", [&chain](const boost::variant& selector) -> boost::optional { + auto rules = chain.holder.getLocal(); + return getRuleFromSelector(*rules, selector); + }); - luaCtx.writeFunction("mvRuleToTop", []() { - moveRuleToTop(&dnsdist::rules::g_ruleactions); - }); + luaCtx.writeFunction("getTop" + chain.prefix + "Rules", [&chain](boost::optional top) { + setLuaNoSideEffect(); + auto rules = chain.holder.getLocal(); + return toLuaArray(getTopRules(*rules, (top ? *top : 10))); + }); - luaCtx.writeFunction("mvRule", [](unsigned int from, unsigned int dest) { - mvRule(&dnsdist::rules::g_ruleactions, from, dest); - }); + luaCtx.writeFunction("top" + chain.prefix + "Rules", [&chain](boost::optional top, boost::optional vars) { + setLuaNoSideEffect(); + auto rules = chain.holder.getLocal(); + return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars); + }); - luaCtx.writeFunction("clearRules", []() { - setLuaSideEffect(); - dnsdist::rules::g_ruleactions.modify([](decltype(dnsdist::rules::g_ruleactions)::value_type& ruleactions) { - ruleactions.clear(); + luaCtx.writeFunction("clear" + chain.prefix + "Rules", [&chain]() { + setLuaSideEffect(); + chain.holder.modify([](std::remove_reference_t::value_type& ruleactions) { + ruleactions.clear(); + }); }); - }); - luaCtx.writeFunction("setRules", [](const LuaArray>& newruleactions) { - setLuaSideEffect(); - dnsdist::rules::g_ruleactions.modify([newruleactions](decltype(dnsdist::rules::g_ruleactions)::value_type& gruleactions) { - gruleactions.clear(); - for (const auto& pair : newruleactions) { - const auto& newruleaction = pair.second; - if (newruleaction->d_action) { - auto rule = newruleaction->d_rule; - gruleactions.push_back({std::move(rule), newruleaction->d_action, newruleaction->d_name, newruleaction->d_id, newruleaction->d_creationOrder}); + luaCtx.writeFunction("set" + chain.prefix + "Rules", [&chain](const LuaArray>& newruleactions) { + setLuaSideEffect(); + chain.holder.modify([newruleactions](std::remove_reference_t::value_type& gruleactions) { + gruleactions.clear(); + for (const auto& pair : newruleactions) { + const auto& newruleaction = pair.second; + if (newruleaction->d_action) { + auto rule = newruleaction->d_rule; + gruleactions.push_back({std::move(rule), newruleaction->d_action, newruleaction->d_name, newruleaction->d_id, newruleaction->d_creationOrder}); + } } - } + }); }); - }); - - luaCtx.writeFunction("getRule", [](const boost::variant& selector) -> boost::optional { - auto rules = dnsdist::rules::g_ruleactions.getLocal(); - return getRuleFromSelector(*rules, selector); - }); - - luaCtx.writeFunction("getTopRules", [](boost::optional top) { - setLuaNoSideEffect(); - auto rules = dnsdist::rules::g_ruleactions.getLocal(); - return toLuaArray(getTopRules(*rules, (top ? *top : 10))); - }); - - luaCtx.writeFunction("topRules", [](boost::optional top, boost::optional vars) { - setLuaNoSideEffect(); - auto rules = dnsdist::rules::g_ruleactions.getLocal(); - return rulesToString(getTopRules(*rules, (top ? *top : 10)), vars); - }); + } luaCtx.writeFunction("MaxQPSIPRule", [](unsigned int qps, boost::optional ipv4trunc, boost::optional ipv6trunc, boost::optional burst, boost::optional expiration, boost::optional cleanupDelay, boost::optional scanFraction, boost::optional shards) { return std::shared_ptr(new MaxQPSIPRule(qps, (burst ? *burst : qps), (ipv4trunc ? *ipv4trunc : 32), (ipv6trunc ? *ipv6trunc : 64), (expiration ? *expiration : 300), (cleanupDelay ? *cleanupDelay : 60), (scanFraction ? *scanFraction : 10), (shards ? *shards : 10))); @@ -627,10 +636,6 @@ void setupLuaRules(LuaContext& luaCtx) return std::shared_ptr(new EDNSOptionRule(optcode)); }); - luaCtx.writeFunction("showRules", [](boost::optional vars) { - showRules(&dnsdist::rules::g_ruleactions, vars); - }); - luaCtx.writeFunction("RDRule", []() { return std::shared_ptr(new RDRule()); }); diff --git a/pdns/dnsdistdist/dnsdist-rule-chains.cc b/pdns/dnsdistdist/dnsdist-rule-chains.cc index 62cf8435c5..1c79fd0a24 100644 --- a/pdns/dnsdistdist/dnsdist-rule-chains.cc +++ b/pdns/dnsdistdist/dnsdist-rule-chains.cc @@ -24,7 +24,8 @@ namespace dnsdist::rules { -GlobalStateHolder> g_ruleactions; +GlobalStateHolder> s_ruleActions; +GlobalStateHolder> s_cacheMissRuleActions; GlobalStateHolder> s_respruleactions; GlobalStateHolder> s_cachehitrespruleactions; GlobalStateHolder> s_selfansweredrespruleactions; @@ -48,4 +49,19 @@ GlobalStateHolder>& getResponseRuleChainHolder(R { return s_responseRuleChains.at(static_cast(chain)).holder; } + +static const std::vector s_ruleChains{ + {"", "rules", s_ruleActions}, + {"CacheMiss", "cache-miss-rules", s_cacheMissRuleActions}, +}; + +const std::vector& getRuleChains() +{ + return s_ruleChains; +} + +GlobalStateHolder>& getRuleChainHolder(RuleChain chain) +{ + return s_ruleChains.at(static_cast(chain)).holder; +} } diff --git a/pdns/dnsdistdist/dnsdist-rule-chains.hh b/pdns/dnsdistdist/dnsdist-rule-chains.hh index 0b0ede3d14..5d2220cdd5 100644 --- a/pdns/dnsdistdist/dnsdist-rule-chains.hh +++ b/pdns/dnsdistdist/dnsdist-rule-chains.hh @@ -34,15 +34,6 @@ class DNSResponseAction; namespace dnsdist::rules { -enum class ResponseRuleChain : uint8_t -{ - ResponseRules = 0, - CacheHitResponseRules = 1, - CacheInsertedResponseRules = 2, - SelfAnsweredResponseRules = 3, - XFRResponseRules = 4, -}; - struct RuleAction { std::shared_ptr d_rule; @@ -52,6 +43,22 @@ struct RuleAction uint64_t d_creationOrder; }; +struct RuleChainDescription +{ + std::string prefix; + std::string metricName; + GlobalStateHolder>& holder; +}; + +enum class RuleChain : uint8_t +{ + Rules = 0, + CacheMissRules = 1, +}; + +const std::vector& getRuleChains(); +GlobalStateHolder>& getRuleChainHolder(RuleChain chain); + struct ResponseRuleAction { std::shared_ptr d_rule; @@ -61,6 +68,15 @@ struct ResponseRuleAction uint64_t d_creationOrder; }; +enum class ResponseRuleChain : uint8_t +{ + ResponseRules = 0, + CacheHitResponseRules = 1, + CacheInsertedResponseRules = 2, + SelfAnsweredResponseRules = 3, + XFRResponseRules = 4, +}; + struct ResponseRuleChainDescription { std::string prefix; @@ -68,8 +84,6 @@ struct ResponseRuleChainDescription GlobalStateHolder>& holder; }; -extern GlobalStateHolder> g_ruleactions; - const std::vector& getResponseRuleChains(); GlobalStateHolder>& getResponseRuleChainHolder(ResponseRuleChain chain); diff --git a/pdns/dnsdistdist/dnsdist-web.cc b/pdns/dnsdistdist/dnsdist-web.cc index 696915017f..7e0fd1fb44 100644 --- a/pdns/dnsdistdist/dnsdist-web.cc +++ b/pdns/dnsdistdist/dnsdist-web.cc @@ -892,7 +892,9 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp) output << "# HELP dnsdist_rule_hits " << "Number of hits of that rule" << "\n"; output << "# TYPE dnsdist_rule_hits " << "counter" << "\n"; - addRulesToPrometheusOutput(output, dnsdist::rules::g_ruleactions); + for (const auto& chain : dnsdist::rules::getRuleChains()) { + addRulesToPrometheusOutput(output, chain.holder); + } for (const auto& chain : dnsdist::rules::getResponseRuleChains()) { addRulesToPrometheusOutput(output, chain.holder); } @@ -1265,27 +1267,6 @@ static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp) } } - Json::array rules; - /* unfortunately DNSActions have getStats(), - and DNSResponseActions do not. */ - { - auto localRules = dnsdist::rules::g_ruleactions.getLocal(); - num = 0; - rules.reserve(localRules->size()); - for (const auto& lrule : *localRules) { - Json::object rule{ - {"id", num++}, - {"creationOrder", (double)lrule.d_creationOrder}, - {"uuid", boost::uuids::to_string(lrule.d_id)}, - {"name", lrule.d_name}, - {"matches", (double)lrule.d_rule->d_matches}, - {"rule", lrule.d_rule->toString()}, - {"action", lrule.d_action->toString()}, - {"action-stats", lrule.d_action->getStats()}}; - rules.emplace_back(std::move(rule)); - } - } - string acl; { auto aclEntries = g_ACL.getLocal()->toStringVector(); @@ -1320,12 +1301,33 @@ static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp) {"servers", std::move(servers)}, {"frontends", std::move(frontends)}, {"pools", std::move(pools)}, - {"rules", std::move(rules)}, {"acl", std::move(acl)}, {"local", std::move(localaddressesStr)}, {"dohFrontends", std::move(dohs)}, {"statistics", std::move(stats)}}; + /* unfortunately DNSActions have getStats(), + and DNSResponseActions do not. */ + for (const auto& chain : dnsdist::rules::getRuleChains()) { + Json::array rules; + auto localRules = chain.holder.getLocal(); + num = 0; + rules.reserve(localRules->size()); + for (const auto& lrule : *localRules) { + Json::object rule{ + {"id", num++}, + {"creationOrder", (double)lrule.d_creationOrder}, + {"uuid", boost::uuids::to_string(lrule.d_id)}, + {"name", lrule.d_name}, + {"matches", (double)lrule.d_rule->d_matches}, + {"rule", lrule.d_rule->toString()}, + {"action", lrule.d_action->toString()}, + {"action-stats", lrule.d_action->getStats()}}; + rules.emplace_back(std::move(rule)); + } + responseObject[chain.metricName] = std::move(rules); + } + for (const auto& chain : dnsdist::rules::getResponseRuleChains()) { auto responseRules = someResponseRulesToJson(&chain.holder); responseObject[chain.metricName] = std::move(responseRules); diff --git a/pdns/dnsdistdist/dnsdist.cc b/pdns/dnsdistdist/dnsdist.cc index 70fb23cc4b..4de6f6eae5 100644 --- a/pdns/dnsdistdist/dnsdist.cc +++ b/pdns/dnsdistdist/dnsdist.cc @@ -1050,7 +1050,28 @@ bool processRulesResult(const DNSAction::Action& action, DNSQuestion& dnsQuestio return false; } -static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dnsQuestion, const struct timespec& now) +static bool applyRulesChainToQuery(const std::vector& rules, DNSQuestion& dnsQuestion) +{ + DNSAction::Action action = DNSAction::Action::None; + string ruleresult; + bool drop = false; + + for (const auto& rule : rules) { + if (!rule.d_rule->matches(&dnsQuestion)) { + continue; + } + + rule.d_rule->d_matches++; + action = (*rule.d_action)(&dnsQuestion, &ruleresult); + if (processRulesResult(action, dnsQuestion, ruleresult, drop)) { + break; + } + } + + return !drop; +} + +static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dnsQuestion, const timespec& now) { if (g_rings.shouldRecordQueries()) { g_rings.insertQuery(now, dnsQuestion.ids.origRemote, dnsQuestion.ids.qname, dnsQuestion.ids.qtype, dnsQuestion.getData().size(), *dnsQuestion.getHeader(), dnsQuestion.getProtocol()); @@ -1211,20 +1232,7 @@ static bool applyRulesToQuery(LocalHolders& holders, DNSQuestion& dnsQuestion, c } #endif /* DISABLE_DYNBLOCKS */ - DNSAction::Action action = DNSAction::Action::None; - string ruleresult; - bool drop = false; - for (const auto& rule : *holders.ruleactions) { - if (rule.d_rule->matches(&dnsQuestion)) { - rule.d_rule->d_matches++; - action = (*rule.d_action)(&dnsQuestion, &ruleresult); - if (processRulesResult(action, dnsQuestion, ruleresult, drop)) { - break; - } - } - } - - return !drop; + return applyRulesChainToQuery(*holders.ruleactions, dnsQuestion); } ssize_t udpClientSendRequestToBackend(const std::shared_ptr& backend, const int socketDesc, const PacketBuffer& request, bool healthCheck) @@ -1416,39 +1424,49 @@ static bool prepareOutgoingResponse(LocalHolders& holders, const ClientState& cl return true; } +static ProcessQueryResult handleQueryTurnedIntoSelfAnsweredResponse(DNSQuestion& dnsQuestion, LocalHolders& holders) +{ + fixUpQueryTurnedResponse(dnsQuestion, dnsQuestion.ids.origFlags); + + if (!prepareOutgoingResponse(holders, *dnsQuestion.ids.cs, dnsQuestion, false)) { + return ProcessQueryResult::Drop; + } + + const auto rcode = dnsQuestion.getHeader()->rcode; + if (rcode == RCode::NXDomain) { + ++dnsdist::metrics::g_stats.ruleNXDomain; + } + else if (rcode == RCode::Refused) { + ++dnsdist::metrics::g_stats.ruleRefused; + } + else if (rcode == RCode::ServFail) { + ++dnsdist::metrics::g_stats.ruleServFail; + } + + ++dnsdist::metrics::g_stats.selfAnswered; + ++dnsQuestion.ids.cs->responses; + return ProcessQueryResult::SendAnswer; +} + +static void selectBackendForOutgoingQuery(DNSQuestion& dnsQuestion, const std::shared_ptr& serverPool, LocalHolders& holders, std::shared_ptr& selectedBackend) +{ + std::shared_ptr poolPolicy = serverPool->policy; + const auto& policy = poolPolicy != nullptr ? *poolPolicy : *(holders.policy); + const auto servers = serverPool->getServers(); + selectedBackend = policy.getSelectedBackend(*servers, dnsQuestion); +} + ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, LocalHolders& holders, std::shared_ptr& selectedBackend) { const uint16_t queryId = ntohs(dnsQuestion.getHeader()->id); try { if (dnsQuestion.getHeader()->qr) { // something turned it into a response - fixUpQueryTurnedResponse(dnsQuestion, dnsQuestion.ids.origFlags); - - if (!prepareOutgoingResponse(holders, *dnsQuestion.ids.cs, dnsQuestion, false)) { - return ProcessQueryResult::Drop; - } - - const auto rcode = dnsQuestion.getHeader()->rcode; - if (rcode == RCode::NXDomain) { - ++dnsdist::metrics::g_stats.ruleNXDomain; - } - else if (rcode == RCode::Refused) { - ++dnsdist::metrics::g_stats.ruleRefused; - } - else if (rcode == RCode::ServFail) { - ++dnsdist::metrics::g_stats.ruleServFail; - } - - ++dnsdist::metrics::g_stats.selfAnswered; - ++dnsQuestion.ids.cs->responses; - return ProcessQueryResult::SendAnswer; + return handleQueryTurnedIntoSelfAnsweredResponse(dnsQuestion, holders); } std::shared_ptr serverPool = getPool(*holders.pools, dnsQuestion.ids.poolName); - std::shared_ptr poolPolicy = serverPool->policy; dnsQuestion.ids.packetCache = serverPool->packetCache; - const auto& policy = poolPolicy != nullptr ? *poolPolicy : *(holders.policy); - const auto servers = serverPool->getServers(); - selectedBackend = policy.getSelectedBackend(*servers, dnsQuestion); + selectBackendForOutgoingQuery(dnsQuestion, serverPool, holders, selectedBackend); uint32_t allowExpired = selectedBackend ? 0 : g_staleCacheEntriesTTL; @@ -1527,6 +1545,21 @@ ProcessQueryResult processQueryAfterRules(DNSQuestion& dnsQuestion, LocalHolders vinfolog("Packet cache miss for query for %s|%s from %s (%s, %d bytes)", dnsQuestion.ids.qname.toLogString(), QType(dnsQuestion.ids.qtype).toString(), dnsQuestion.ids.origRemote.toStringWithPort(), dnsQuestion.ids.protocol.toString(), dnsQuestion.getData().size()); ++dnsdist::metrics::g_stats.cacheMisses; + + const auto existingPool = dnsQuestion.ids.poolName; + if (!applyRulesChainToQuery(*holders.cacheMissRuleActions, dnsQuestion)) { + return ProcessQueryResult::Drop; + } + if (dnsQuestion.getHeader()->qr) { // something turned it into a response + return handleQueryTurnedIntoSelfAnsweredResponse(dnsQuestion, holders); + } + /* let's be nice and allow the selection of a different pool, + but no second cache-lookup for you */ + if (dnsQuestion.ids.poolName != existingPool) { + serverPool = getPool(*holders.pools, dnsQuestion.ids.poolName); + dnsQuestion.ids.packetCache = serverPool->packetCache; + selectBackendForOutgoingQuery(dnsQuestion, serverPool, holders, selectedBackend); + } } if (!selectedBackend) { @@ -2743,7 +2776,9 @@ static void cleanupLuaObjects() { /* when our coverage mode is enabled, we need to make sure that the Lua objects are destroyed before the Lua contexts. */ - dnsdist::rules::g_ruleactions.setState({}); + for (const auto& chain : dnsdist::rules::getRuleChains()) { + chain.holder.setState({}); + } for (const auto& chain : dnsdist::rules::getResponseRuleChains()) { chain.holder.setState({}); } diff --git a/pdns/dnsdistdist/dnsdist.hh b/pdns/dnsdistdist/dnsdist.hh index 3aca751af5..561e8f68c1 100644 --- a/pdns/dnsdistdist/dnsdist.hh +++ b/pdns/dnsdistdist/dnsdist.hh @@ -1225,13 +1225,14 @@ enum class ProcessQueryResult : uint8_t struct LocalHolders { LocalHolders() : - acl(g_ACL.getLocal()), policy(g_policy.getLocal()), ruleactions(dnsdist::rules::g_ruleactions.getLocal()), cacheHitRespRuleactions(dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheHitResponseRules).getLocal()), cacheInsertedRespRuleActions(dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules).getLocal()), selfAnsweredRespRuleactions(dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::SelfAnsweredResponseRules).getLocal()), servers(g_dstates.getLocal()), dynNMGBlock(g_dynblockNMG.getLocal()), dynSMTBlock(g_dynblockSMT.getLocal()), pools(g_pools.getLocal()) + acl(g_ACL.getLocal()), policy(g_policy.getLocal()), ruleactions(dnsdist::rules::getRuleChainHolder(dnsdist::rules::RuleChain::Rules).getLocal()), cacheMissRuleActions(dnsdist::rules::getRuleChainHolder(dnsdist::rules::RuleChain::CacheMissRules).getLocal()), cacheHitRespRuleactions(dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheHitResponseRules).getLocal()), cacheInsertedRespRuleActions(dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::CacheInsertedResponseRules).getLocal()), selfAnsweredRespRuleactions(dnsdist::rules::getResponseRuleChainHolder(dnsdist::rules::ResponseRuleChain::SelfAnsweredResponseRules).getLocal()), servers(g_dstates.getLocal()), dynNMGBlock(g_dynblockNMG.getLocal()), dynSMTBlock(g_dynblockSMT.getLocal()), pools(g_pools.getLocal()) { } LocalStateHolder acl; LocalStateHolder policy; LocalStateHolder> ruleactions; + LocalStateHolder> cacheMissRuleActions; LocalStateHolder> cacheHitRespRuleactions; LocalStateHolder> cacheInsertedRespRuleActions; LocalStateHolder> selfAnsweredRespRuleactions; diff --git a/pdns/dnsdistdist/docs/reference/rules-management.rst b/pdns/dnsdistdist/docs/reference/rules-management.rst index ba9e0f4069..3c70c04bff 100644 --- a/pdns/dnsdistdist/docs/reference/rules-management.rst +++ b/pdns/dnsdistdist/docs/reference/rules-management.rst @@ -36,79 +36,84 @@ For Rules related to the incoming query: :param int n: The rule number -.. function:: getCacheHitResponseRule(selector) -> DNSDistResponseRuleAction +.. function:: getRule(selector) -> DNSDistRuleAction .. versionadded:: 1.9.0 - Return the cache-hit response rule corresponding to the selector, if any. + Return the rule corresponding to the selector, if any. The selector can be the position of the rule in the list, as an integer, its name as a string or its UUID as a string as well. :param int or str selector: The position in the list, name or UUID of the rule to return. -.. function:: getCacheInsertedResponseRule(selector) -> DNSDistResponseRuleAction +.. function:: mvRule(from, to) - .. versionadded:: 1.9.0 + Move rule ``from`` to a position where it is in front of ``to``. + ``to`` can be one larger than the largest rule, in which case the rule will be moved to the last position. - Return the cache-inserted response rule corresponding to the selector, if any. - The selector can be the position of the rule in the list, as an integer, - its name as a string or its UUID as a string as well. + :param int from: Rule number to move + :param int to: Location to more the Rule to - :param int or str selector: The position in the list, name or UUID of the rule to return. +.. function:: mvRuleToTop() -.. function:: getResponseRule(selector) -> DNSDistResponseRuleAction + .. versionadded:: 1.6.0 - .. versionadded:: 1.9.0 + This function moves the last rule to the first position. Before 1.6.0 this was handled by :func:`topRule`. - Return the response rule corresponding to the selector, if any. - The selector can be the position of the rule in the list, as an integer, - its name as a string or its UUID as a string as well. +.. function:: setRules(rules) - :param int or str selector: The position in the list, name or UUID of the rule to return. + Replace the current rules with the supplied list of pairs of DNS Rules and DNS Actions (see :func:`newRuleAction`) -.. function:: getRule(selector) -> DNSDistRuleAction + :param [RuleAction] rules: A list of RuleActions - .. versionadded:: 1.9.0 +.. function:: showRules([options]) - Return the rule corresponding to the selector, if any. - The selector can be the position of the rule in the list, as an integer, - its name as a string or its UUID as a string as well. + Show all defined rules for queries, optionally displaying their UUIDs. - :param int or str selector: The position in the list, name or UUID of the rule to return. + :param table options: A table with key: value pairs with display options. -.. function:: getSelfAnsweredResponseRule(selector) -> DNSDistResponseRuleAction + Options: - .. versionadded:: 1.9.0 + * ``showUUIDs=false``: bool - Whether to display the UUIDs, defaults to false. + * ``truncateRuleWidth=-1``: int - Truncate rules output to ``truncateRuleWidth`` size. Defaults to ``-1`` to display the full rule. - Return the self-answered response rule corresponding to the selector, if any. - The selector can be the position of the rule in the list, as an integer, - its name as a string or its UUID as a string as well. +.. function:: topRule() - :param int or str selector: The position in the list, name or UUID of the rule to return. + .. versionchanged:: 1.6.0 + Replaced by :func:`mvRuleToTop` -.. function:: mvRule(from, to) + Before 1.6.0 this function used to move the last rule to the first position, which is now handled by :func:`mvRuleToTop`. - Move rule ``from`` to a position where it is in front of ``to``. - ``to`` can be one larger than the largest rule, in which case the rule will be moved to the last position. +.. function:: rmRule(id) - :param int from: Rule number to move - :param int to: Location to more the Rule to + .. versionchanged:: 1.6.0 + ``id`` can now be a string representing the name of the rule. -.. function:: mvRuleToTop() + Remove rule ``id``. - .. versionadded:: 1.6.0 + :param int id: The position of the rule to remove if ``id`` is numerical, its UUID or name otherwise - This function moves the last rule to the first position. Before 1.6.0 this was handled by :func:`topRule`. +Cache misses +------------ -.. function:: newRuleAction(rule, action[, options]) +For Rules related to the incoming query after a cache miss: - .. versionchanged:: 1.6.0 - Added ``name`` to the ``options``. +.. warning:: + While all selectors and actions are available, some actions will no longer be honored at + this point. For example changing the backend pool will not trigger a second cache-lookup. + Switching from a backend pool that has EDNS Client Subnet enabled to one that doesn't + will result in the EDNS Client Subnet corresponding to the initial server pool to be + added to the query. - Return a pair of DNS Rule and DNS Action, to be used with :func:`setRules`. +.. function:: addCacheMissAction(DNSrule, action [, options]) - :param Rule rule: A Rule (see :doc:`selectors`) - :param Action action: The Action (see :doc:`actions`) to apply to the matched traffic + .. versionadded:: 1.10 + + Add a Rule and Action to the existing cache miss rules. + If a string (or list of) is passed as the first parameter instead of a :class:`DNSRule`, it behaves as if the string or list of strings was passed to :func:`NetmaskGroupRule` or :func:`SuffixMatchNodeRule`. + + :param DNSrule rule: A :class:`DNSRule`, e.g. an :func:`AllRule`, or a compounded bunch of rules using e.g. :func:`AndRule`. + :param action: The action to take :param table options: A table with key: value pairs with options. Options: @@ -116,15 +121,59 @@ For Rules related to the incoming query: * ``uuid``: string - UUID to assign to the new rule. By default a random UUID is generated for each rule. * ``name``: string - Name to assign to the new rule. -.. function:: setRules(rules) +.. function:: clearCacheMissRules() - Replace the current rules with the supplied list of pairs of DNS Rules and DNS Actions (see :func:`newRuleAction`) + .. versionadded:: 1.10 + + Remove all current cache miss rules. + +.. function:: getCacheMissAction(n) -> DNSDistRuleAction + + .. versionadded:: 1.10 + + Returns the :class:`DNSDistRuleAction` associated with cache miss rule ``n``. + + :param int n: The rule number + +.. function:: getCacheMissRule(selector) -> DNSDistRuleAction + + .. versionadded:: 1.10 + + Return the cache miss rule corresponding to the selector, if any. + The selector can be the position of the rule in the list, as an integer, + its name as a string or its UUID as a string as well. + + :param int or str selector: The position in the list, name or UUID of the rule to return. + +.. function:: mvCacheMissRule(from, to) + + .. versionadded:: 1.10 + + Move cache miss rule ``from`` to a position where it is in front of ``to``. + ``to`` can be one larger than the largest rule, in which case the rule will be moved to the last position. + + :param int from: Rule number to move + :param int to: Location to more the Rule to + +.. function:: mvCacheMissRuleToTop() + + .. versionadded:: 1.10 + + This function moves the last cache miss rule to the first position. + +.. function:: setCacheMissRules(rules) + + .. versionadded:: 1.10 + + Replace the current cache miss rules with the supplied list of pairs of DNS Rules and DNS Actions (see :func:`newRuleAction`) :param [RuleAction] rules: A list of RuleActions -.. function:: showRules([options]) +.. function:: showCacheMissRules([options]) - Show all defined rules for queries, optionally displaying their UUIDs. + .. versionadded:: 1.10 + + Show all defined cache miss rules for queries, optionally displaying their UUIDs. :param table options: A table with key: value pairs with display options. @@ -133,21 +182,13 @@ For Rules related to the incoming query: * ``showUUIDs=false``: bool - Whether to display the UUIDs, defaults to false. * ``truncateRuleWidth=-1``: int - Truncate rules output to ``truncateRuleWidth`` size. Defaults to ``-1`` to display the full rule. -.. function:: topRule() - - .. versionchanged:: 1.6.0 - Replaced by :func:`mvRuleToTop` - - Before 1.6.0 this function used to move the last rule to the first position, which is now handled by :func:`mvRuleToTop`. - -.. function:: rmRule(id) +.. function:: rmCacheMissRule(id) - .. versionchanged:: 1.6.0 - ``id`` can now be a string representing the name of the rule. + .. versionadded:: 1.10 Remove rule ``id``. - :param int id: The position of the rule to remove if ``id`` is numerical, its UUID or name otherwise + :param int id: The position of the cache miss rule to remove if ``id`` is numerical, its UUID or name otherwise Responses --------- @@ -174,6 +215,22 @@ For Rules related to responses: * ``uuid``: string - UUID to assign to the new rule. By default a random UUID is generated for each rule. * ``name``: string - Name to assign to the new rule. +.. function:: clearResponseRules() + + .. versionadded:: 1.10 + + Remove all current response rules. + +.. function:: getResponseRule(selector) -> DNSDistResponseRuleAction + + .. versionadded:: 1.9.0 + + Return the response rule corresponding to the selector, if any. + The selector can be the position of the rule in the list, as an integer, + its name as a string or its UUID as a string as well. + + :param int or str selector: The position in the list, name or UUID of the rule to return. + .. function:: mvResponseRule(from, to) Move response rule ``from`` to a position where it is in front of ``to``. @@ -240,6 +297,22 @@ Functions for manipulating Cache Hit Response Rules: * ``uuid``: string - UUID to assign to the new rule. By default a random UUID is generated for each rule. * ``name``: string - Name to assign to the new rule. +.. function:: clearCacheHitResponseRules() + + .. versionadded:: 1.10 + + Remove all current cache-hit response rules. + +.. function:: getCacheHitResponseRule(selector) -> DNSDistResponseRuleAction + + .. versionadded:: 1.9.0 + + Return the cache-hit response rule corresponding to the selector, if any. + The selector can be the position of the rule in the list, as an integer, + its name as a string or its UUID as a string as well. + + :param int or str selector: The position in the list, name or UUID of the rule to return. + .. function:: mvCacheHitResponseRule(from, to) Move cache hit response rule ``from`` to a position where it is in front of ``to``. @@ -303,6 +376,22 @@ Functions for manipulating Cache Inserted Response Rules: * ``uuid``: string - UUID to assign to the new rule. By default a random UUID is generated for each rule. * ``name``: string - Name to assign to the new rule. +.. function:: clearCacheInsertedResponseRules() + + .. versionadded:: 1.10 + + Remove all current cache-inserted response rules. + +.. function:: getCacheInsertedResponseRule(selector) -> DNSDistResponseRuleAction + + .. versionadded:: 1.9.0 + + Return the cache-inserted response rule corresponding to the selector, if any. + The selector can be the position of the rule in the list, as an integer, + its name as a string or its UUID as a string as well. + + :param int or str selector: The position in the list, name or UUID of the rule to return. + .. function:: mvCacheInsertedResponseRule(from, to) .. versionadded:: 1.8.0 @@ -363,6 +452,22 @@ Functions for manipulating Self-Answered Response Rules: * ``uuid``: string - UUID to assign to the new rule. By default a random UUID is generated for each rule. * ``name``: string - Name to assign to the new rule. +.. function:: clearSelfAnsweredResponseRules() + + .. versionadded:: 1.10 + + Remove all current self-answered response rules. + +.. function:: getSelfAnsweredResponseRule(selector) -> DNSDistResponseRuleAction + + .. versionadded:: 1.9.0 + + Return the self-answered response rule corresponding to the selector, if any. + The selector can be the position of the rule in the list, as an integer, + its name as a string or its UUID as a string as well. + + :param int or str selector: The position in the list, name or UUID of the rule to return. + .. function:: mvSelfAnsweredResponseRule(from, to) Move self answered response rule ``from`` to a position where it is in front of ``to``. @@ -495,3 +600,19 @@ Convenience Functions ``makeRule("0.0.0.0/0")`` will for example match all IPv4 traffic, ``makeRule({"be","nl","lu"})`` will match all Benelux DNS traffic. :param string rule: A string, or list of strings, to convert to a rule. + +.. function:: newRuleAction(rule, action[, options]) + + .. versionchanged:: 1.6.0 + Added ``name`` to the ``options``. + + Return a pair of DNS Rule and DNS Action, to be used with :func:`setRules`. + + :param Rule rule: A Rule (see :doc:`selectors`) + :param Action action: The Action (see :doc:`actions`) to apply to the matched traffic + :param table options: A table with key: value pairs with options. + + Options: + + * ``uuid``: string - UUID to assign to the new rule. By default a random UUID is generated for each rule. + * ``name``: string - Name to assign to the new rule. diff --git a/pdns/dnsdistdist/test-dnsdisttcp_cc.cc b/pdns/dnsdistdist/test-dnsdisttcp_cc.cc index 3566d61c50..db9238d770 100644 --- a/pdns/dnsdistdist/test-dnsdisttcp_cc.cc +++ b/pdns/dnsdistdist/test-dnsdisttcp_cc.cc @@ -35,7 +35,6 @@ #include "dnsdist-tcp-upstream.hh" GlobalStateHolder g_ACL; -GlobalStateHolder > g_ruleactions; GlobalStateHolder g_dstates; QueryCount g_qcount;