From a0a790cd0a0d7f15b624ccffae806a8fc60fdb1e Mon Sep 17 00:00:00 2001 From: Remi Gacogne Date: Tue, 6 Dec 2022 16:23:04 +0100 Subject: [PATCH] dnsdist: Add a new chain of rules triggered after cache insertion The general idea is to be able to store the unedited version into the cache while delivering a different version to the actual client. This is useful when one is sending different answers to different clients, like when dealing with abuse traffic, but still want to be able to cache the initial response from the backend. We already have a chain of rules that are triggered after a cache-hit, but until now we lacked the ability to trigger after getting the response corresponding to a cache-miss. --- pdns/dnsdist-lua-actions.cc | 8 ++ pdns/dnsdist-lua-rules.cc | 16 +++ pdns/dnsdist-tcp.cc | 2 +- pdns/dnsdist-web.cc | 3 + pdns/dnsdist.cc | 29 +++-- pdns/dnsdist.hh | 6 +- pdns/dnsdistdist/dnsdist-tcp-upstream.hh | 6 +- pdns/dnsdistdist/docs/rules-actions.rst | 52 +++++++++ pdns/dnsdistdist/doh.cc | 10 +- pdns/dnsdistdist/test-dnsdisttcp_cc.cc | 73 ++++++------- .../test_CacheInsertedResponses.py | 101 ++++++++++++++++++ 11 files changed, 250 insertions(+), 56 deletions(-) create mode 100644 regression-tests.dnsdist/test_CacheInsertedResponses.py diff --git a/pdns/dnsdist-lua-actions.cc b/pdns/dnsdist-lua-actions.cc index 7aab4c5de0..d0df07c791 100644 --- a/pdns/dnsdist-lua-actions.cc +++ b/pdns/dnsdist-lua-actions.cc @@ -2094,6 +2094,14 @@ void setupLuaActions(LuaContext& luaCtx) addAction(&g_cachehitrespruleactions, var, boost::get >(era), params); }); + luaCtx.writeFunction("addCacheInsertedResponseAction", [](luadnsrule_t var, boost::variant, std::shared_ptr> era, boost::optional params) { + if (era.type() != typeid(std::shared_ptr)) { + throw std::runtime_error("addCacheInsertedResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?"); + } + + addAction(&g_cacheInsertedRespRuleActions, var, boost::get >(era), params); + }); + luaCtx.writeFunction("addSelfAnsweredResponseAction", [](luadnsrule_t var, boost::variant, std::shared_ptr> era, boost::optional params) { if (era.type() != typeid(std::shared_ptr)) { throw std::runtime_error("addSelfAnsweredResponseAction() can only be called with response-related actions, not query-related ones. Are you looking for addAction()?"); diff --git a/pdns/dnsdist-lua-rules.cc b/pdns/dnsdist-lua-rules.cc index 5fd9c9cd74..60ec310dd5 100644 --- a/pdns/dnsdist-lua-rules.cc +++ b/pdns/dnsdist-lua-rules.cc @@ -272,6 +272,22 @@ void setupLuaRules(LuaContext& luaCtx) mvRule(&g_cachehitrespruleactions, from, to); }); + luaCtx.writeFunction("showCacheInsertedResponseRules", [](boost::optional vars) { + showRules(&g_cacheInsertedRespRuleActions, vars); + }); + + luaCtx.writeFunction("rmCacheInsertedResponseRule", [](boost::variant id) { + rmRule(&g_cacheInsertedRespRuleActions, id); + }); + + luaCtx.writeFunction("mvCacheInsertedResponseRuleToTop", []() { + moveRuleToTop(&g_cacheInsertedRespRuleActions); + }); + + luaCtx.writeFunction("mvCacheInsertedResponseRule", [](unsigned int from, unsigned int to) { + mvRule(&g_cacheInsertedRespRuleActions, from, to); + }); + luaCtx.writeFunction("showSelfAnsweredResponseRules", [](boost::optional vars) { showRules(&g_selfansweredrespruleactions, vars); }); diff --git a/pdns/dnsdist-tcp.cc b/pdns/dnsdist-tcp.cc index c9f4120b77..c800c616a9 100644 --- a/pdns/dnsdist-tcp.cc +++ b/pdns/dnsdist-tcp.cc @@ -538,7 +538,7 @@ void IncomingTCPConnectionState::handleResponse(const struct timeval& now, TCPRe memcpy(&response.d_cleartextDH, dr.getHeader(), sizeof(response.d_cleartextDH)); - if (!processResponse(response.d_buffer, state->d_threadData.localRespRuleActions, dr, false, false)) { + if (!processResponse(response.d_buffer, *state->d_threadData.localRespRuleActions, *state->d_threadData.localCacheInsertedRespRuleActions, dr, false, false)) { state->terminateClientConnection(); return; } diff --git a/pdns/dnsdist-web.cc b/pdns/dnsdist-web.cc index 603a8e5bee..39363981f2 100644 --- a/pdns/dnsdist-web.cc +++ b/pdns/dnsdist-web.cc @@ -833,6 +833,7 @@ static void handlePrometheus(const YaHTTP::Request& req, YaHTTP::Response& resp) addRulesToPrometheusOutput(output, g_ruleactions); addRulesToPrometheusOutput(output, g_respruleactions); addRulesToPrometheusOutput(output, g_cachehitrespruleactions); + addRulesToPrometheusOutput(output, g_cacheInsertedRespRuleActions); addRulesToPrometheusOutput(output, g_selfansweredrespruleactions); #ifndef DISABLE_DYNBLOCKS @@ -1195,6 +1196,7 @@ static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp) } auto responseRules = someResponseRulesToJson(&g_respruleactions); auto cacheHitResponseRules = someResponseRulesToJson(&g_cachehitrespruleactions); + auto cacheInsertedResponseRules = someResponseRulesToJson(&g_cacheInsertedRespRuleActions); auto selfAnsweredResponseRules = someResponseRulesToJson(&g_selfansweredrespruleactions); string acl; @@ -1236,6 +1238,7 @@ static void handleStats(const YaHTTP::Request& req, YaHTTP::Response& resp) { "rules", std::move(rules) }, { "response-rules", std::move(responseRules) }, { "cache-hit-response-rules", std::move(cacheHitResponseRules) }, + { "cache-inserted-response-rules", std::move(cacheInsertedResponseRules) }, { "self-answered-response-rules", std::move(selfAnsweredResponseRules) }, { "acl", std::move(acl) }, { "local", std::move(localaddressesStr) }, diff --git a/pdns/dnsdist.cc b/pdns/dnsdist.cc index d0b3fbec93..b34a54b43d 100644 --- a/pdns/dnsdist.cc +++ b/pdns/dnsdist.cc @@ -135,6 +135,7 @@ std::vector g_TCPFastOpenKey; GlobalStateHolder > g_ruleactions; GlobalStateHolder > g_respruleactions; GlobalStateHolder > g_cachehitrespruleactions; +GlobalStateHolder > g_cacheInsertedRespRuleActions; GlobalStateHolder > g_selfansweredrespruleactions; Rings g_rings; @@ -477,15 +478,15 @@ static bool encryptResponse(PacketBuffer& response, size_t maximumSize, bool tcp } #endif /* HAVE_DNSCRYPT */ -static bool applyRulesToResponse(LocalStateHolder >& localRespRuleActions, DNSResponse& dr) +static bool applyRulesToResponse(const std::vector& respRuleActions, DNSResponse& dr) { - DNSResponseAction::Action action=DNSResponseAction::Action::None; + DNSResponseAction::Action action = DNSResponseAction::Action::None; std::string ruleresult; - for(const auto& lr : *localRespRuleActions) { - if(lr.d_rule->matches(&dr)) { + for (const auto& lr : respRuleActions) { + if (lr.d_rule->matches(&dr)) { lr.d_rule->d_matches++; - action=(*lr.d_action)(&dr, &ruleresult); - switch(action) { + action = (*lr.d_action)(&dr, &ruleresult); + switch (action) { case DNSResponseAction::Action::Allow: return true; break; @@ -514,9 +515,9 @@ static bool applyRulesToResponse(LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted, bool receivedOverUDP) +bool processResponse(PacketBuffer& response, const vector& respRuleActions, const vector& insertedRespRuleActions, DNSResponse& dr, bool muted, bool receivedOverUDP) { - if (!applyRulesToResponse(localRespRuleActions, dr)) { + if (!applyRulesToResponse(respRuleActions, dr)) { return false; } @@ -547,6 +548,10 @@ bool processResponse(PacketBuffer& response, LocalStateHolderinsert(cacheKey, zeroScope ? boost::none : dr.subnet, dr.cacheFlags, dr.dnssecOK, *dr.qname, dr.qtype, dr.qclass, response, receivedOverUDP, dr.getHeader()->rcode, dr.tempFailureTTL); + + if (!applyRulesToResponse(insertedRespRuleActions, dr)) { + return false; + } } #ifdef HAVE_DNSCRYPT @@ -637,6 +642,7 @@ void responderThread(std::shared_ptr dss) try { setThreadName("dnsdist/respond"); auto localRespRuleActions = g_respruleactions.getLocal(); + auto localCacheInsertedRespRuleActions = g_cacheInsertedRespRuleActions.getLocal(); const size_t initialBufferSize = getInitialUDPPacketBufferSize(); PacketBuffer response(initialBufferSize); @@ -744,7 +750,7 @@ void responderThread(std::shared_ptr dss) } memcpy(&cleartextDH, dr.getHeader(), sizeof(cleartextDH)); - if (!processResponse(response, localRespRuleActions, dr, ids->cs && ids->cs->muted, true)) { + if (!processResponse(response, *localRespRuleActions, *localCacheInsertedRespRuleActions, dr, ids->cs && ids->cs->muted, true)) { dss->releaseState(queryId); continue; } @@ -1233,7 +1239,7 @@ static bool prepareOutgoingResponse(LocalHolders& holders, ClientState& cs, DNSQ dr.qTag = std::move(dq.qTag); dr.delayMsec = dq.delayMsec; - if (!applyRulesToResponse(cacheHit ? holders.cacheHitRespRuleactions : holders.selfAnsweredRespRuleactions, dr)) { + if (!applyRulesToResponse(cacheHit ? *holders.cacheHitRespRuleactions : *holders.selfAnsweredRespRuleactions, dr)) { return false; } @@ -1413,6 +1419,7 @@ public: auto& ids = response.d_idstate; static thread_local LocalStateHolder> localRespRuleActions = g_respruleactions.getLocal(); + static thread_local LocalStateHolder> localCacheInsertedRespRuleActions = g_cacheInsertedRespRuleActions.getLocal(); DNSResponse dr = makeDNSResponseFromIDState(ids, response.d_buffer); if (response.d_buffer.size() > d_payloadSize) { vinfolog("Got a response of size %d over TCP, while the initial UDP payload size was %d, truncating", response.d_buffer.size(), d_payloadSize); @@ -1423,7 +1430,7 @@ public: dnsheader cleartextDH; memcpy(&cleartextDH, dr.getHeader(), sizeof(cleartextDH)); - if (!processResponse(response.d_buffer, localRespRuleActions, dr, false, true)) { + if (!processResponse(response.d_buffer, *localRespRuleActions, *localCacheInsertedRespRuleActions, dr, false, true)) { return; } diff --git a/pdns/dnsdist.hh b/pdns/dnsdist.hh index 698aee212e..651268bb74 100644 --- a/pdns/dnsdist.hh +++ b/pdns/dnsdist.hh @@ -1146,6 +1146,7 @@ extern GlobalStateHolder > g_ruleactions; extern GlobalStateHolder > g_respruleactions; extern GlobalStateHolder > g_cachehitrespruleactions; extern GlobalStateHolder > g_selfansweredrespruleactions; +extern GlobalStateHolder > g_cacheInsertedRespRuleActions; extern GlobalStateHolder g_ACL; extern ComboAddress g_serverControl; // not changed during runtime @@ -1181,7 +1182,7 @@ extern std::vector > g_dynBPFFilters; struct LocalHolders { - LocalHolders(): acl(g_ACL.getLocal()), policy(g_policy.getLocal()), ruleactions(g_ruleactions.getLocal()), cacheHitRespRuleactions(g_cachehitrespruleactions.getLocal()), selfAnsweredRespRuleactions(g_selfansweredrespruleactions.getLocal()), servers(g_dstates.getLocal()), dynNMGBlock(g_dynblockNMG.getLocal()), dynSMTBlock(g_dynblockSMT.getLocal()), pools(g_pools.getLocal()) + LocalHolders(): acl(g_ACL.getLocal()), policy(g_policy.getLocal()), ruleactions(g_ruleactions.getLocal()), cacheHitRespRuleactions(g_cachehitrespruleactions.getLocal()), cacheInsertedRespRuleActions(g_cacheInsertedRespRuleActions.getLocal()), selfAnsweredRespRuleactions(g_selfansweredrespruleactions.getLocal()), servers(g_dstates.getLocal()), dynNMGBlock(g_dynblockNMG.getLocal()), dynSMTBlock(g_dynblockSMT.getLocal()), pools(g_pools.getLocal()) { } @@ -1189,6 +1190,7 @@ struct LocalHolders LocalStateHolder policy; LocalStateHolder > ruleactions; LocalStateHolder > cacheHitRespRuleactions; + LocalStateHolder > cacheInsertedRespRuleActions; LocalStateHolder > selfAnsweredRespRuleactions; LocalStateHolder servers; LocalStateHolder > dynNMGBlock; @@ -1210,7 +1212,7 @@ bool getLuaNoSideEffect(); // set if there were only explicit declarations of _n void resetLuaSideEffect(); // reset to indeterminate state bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, const uint16_t qtype, const uint16_t qclass, const std::shared_ptr& remote, unsigned int& qnameWireLength); -bool processResponse(PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted, bool receivedOverUDP); +bool processResponse(PacketBuffer& response, const std::vector& respRuleActions, const std::vector& insertedRespRuleActions, DNSResponse& dr, bool muted, bool receivedOverUDP); bool processRulesResult(const DNSAction::Action& action, DNSQuestion& dq, std::string& ruleresult, bool& drop); bool checkQueryHeaders(const struct dnsheader* dh, ClientState& cs); diff --git a/pdns/dnsdistdist/dnsdist-tcp-upstream.hh b/pdns/dnsdistdist/dnsdist-tcp-upstream.hh index 6fa76ab6a1..fea6bdb28a 100644 --- a/pdns/dnsdistdist/dnsdist-tcp-upstream.hh +++ b/pdns/dnsdistdist/dnsdist-tcp-upstream.hh @@ -6,12 +6,14 @@ class TCPClientThreadData { public: - TCPClientThreadData(): localRespRuleActions(g_respruleactions.getLocal()), mplexer(std::unique_ptr(FDMultiplexer::getMultiplexerSilent())) + TCPClientThreadData(): + localRespRuleActions(g_respruleactions.getLocal()), localCacheInsertedRespRuleActions(g_cacheInsertedRespRuleActions.getLocal()), mplexer(std::unique_ptr(FDMultiplexer::getMultiplexerSilent())) { } LocalHolders holders; - LocalStateHolder > localRespRuleActions; + LocalStateHolder> localRespRuleActions; + LocalStateHolder> localCacheInsertedRespRuleActions; std::unique_ptr mplexer{nullptr}; int crossProtocolResponsesPipe{-1}; }; diff --git a/pdns/dnsdistdist/docs/rules-actions.rst b/pdns/dnsdistdist/docs/rules-actions.rst index 5173ee6bc0..4c31d5788c 100644 --- a/pdns/dnsdistdist/docs/rules-actions.rst +++ b/pdns/dnsdistdist/docs/rules-actions.rst @@ -353,6 +353,58 @@ Functions for manipulating Cache Hit Response Rules: Before 1.6.0 this function used to move the last cache hit response rule to the first position, which is now handled by :func:`mvCacheHitResponseRuleToTop`. +Functions for manipulating Cache Inserted Response Rules: + +.. function:: addCacheInsertedResponseAction(DNSRule, action [, options]) + + .. versionadded:: 1.8.0 + + Add a Rule and ResponseAction that is executed after a cache entry has been inserted to the existing rules. + + :param DNSRule: A 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: + + * ``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:: mvCacheInsertedResponseRule(from, to) + + .. versionadded:: 1.8.0 + + Move cache inserted response 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:: mvCacheInsertedResponseRuleToTop() + + .. versionadded:: 1.8.0 + + This function moves the last cache inserted response rule to the first position. + +.. function:: rmCacheInsertedResponseRule(id) + + .. versionadded:: 1.8.0 + + :param int id: The position of the rule to remove if ``id`` is numerical, its UUID or name otherwise + +.. function:: showCacheInsertedResponseRules([options]) + + .. versionadded:: 1.8.0 + + Show all defined cache inserted response rules, optionally displaying their UUIDs. + + :param table options: A table with key: value pairs with display options. + + Options: + + * ``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. + Functions for manipulating Self-Answered Response Rules: .. function:: addSelfAnsweredResponseAction(DNSRule, action [, options]) diff --git a/pdns/dnsdistdist/doh.cc b/pdns/dnsdistdist/doh.cc index cf9c316690..088f618b74 100644 --- a/pdns/dnsdistdist/doh.cc +++ b/pdns/dnsdistdist/doh.cc @@ -458,12 +458,13 @@ public: du->response = std::move(response.d_buffer); du->ids = std::move(response.d_idstate); - thread_local LocalStateHolder> localRespRuleActions = g_respruleactions.getLocal(); + static thread_local LocalStateHolder> localRespRuleActions = g_respruleactions.getLocal(); + static thread_local LocalStateHolder> localCacheInsertedRespRuleActions = g_cacheInsertedRespRuleActions.getLocal(); DNSResponse dr = makeDNSResponseFromIDState(du->ids, du->response); dnsheader cleartextDH; memcpy(&cleartextDH, dr.getHeader(), sizeof(cleartextDH)); - if (!processResponse(du->response, localRespRuleActions, dr, false, false)) { + if (!processResponse(du->response, *localRespRuleActions, *localCacheInsertedRespRuleActions, dr, false, false)) { du.reset(); return; } @@ -1666,12 +1667,13 @@ void handleUDPResponseForDoH(DOHUnitUniquePtr&& du, PacketBuffer&& udpResponse, const dnsheader* dh = reinterpret_cast(du->response.data()); if (!dh->tc) { - thread_local LocalStateHolder> localRespRuleActions = g_respruleactions.getLocal(); + static thread_local LocalStateHolder> localRespRuleActions = g_respruleactions.getLocal(); + static thread_local LocalStateHolder> localcacheInsertedRespRuleActions = g_cacheInsertedRespRuleActions.getLocal(); DNSResponse dr = makeDNSResponseFromIDState(du->ids, du->response); dnsheader cleartextDH; memcpy(&cleartextDH, dr.getHeader(), sizeof(cleartextDH)); - if (!processResponse(du->response, localRespRuleActions, dr, false, true)) { + if (!processResponse(du->response, *localRespRuleActions, *localcacheInsertedRespRuleActions, dr, false, true)) { return; } diff --git a/pdns/dnsdistdist/test-dnsdisttcp_cc.cc b/pdns/dnsdistdist/test-dnsdisttcp_cc.cc index f3c8678a39..056c08ed12 100644 --- a/pdns/dnsdistdist/test-dnsdisttcp_cc.cc +++ b/pdns/dnsdistdist/test-dnsdisttcp_cc.cc @@ -36,6 +36,7 @@ GlobalStateHolder g_ACL; GlobalStateHolder > g_ruleactions; GlobalStateHolder > g_respruleactions; GlobalStateHolder > g_cachehitrespruleactions; +GlobalStateHolder > g_cacheInsertedRespRuleActions; GlobalStateHolder > g_selfansweredrespruleactions; GlobalStateHolder g_dstates; @@ -78,12 +79,12 @@ bool responseContentMatches(const PacketBuffer& response, const DNSName& qname, return true; } -static std::function >& localRespRuleActions, DNSResponse& dr, bool muted)> s_processResponse; +static std::function s_processResponse; -bool processResponse(PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted, bool receivedOverUDP) +bool processResponse(PacketBuffer& response, const std::vector& localRespRuleActions, const std::vector& localCacheInsertedRespRuleActions, DNSResponse& dr, bool muted, bool receivedOverUDP) { if (s_processResponse) { - return s_processResponse(response, localRespRuleActions, dr, muted); + return s_processResponse(response, dr, muted); } return false; @@ -898,7 +899,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -938,7 +939,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { throw std::runtime_error("Unexpected error while processing the response"); }; @@ -977,7 +978,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return false; }; @@ -1020,7 +1021,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -1047,7 +1048,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR) s_processQuery = [](DNSQuestion& dq, ClientState& cs, LocalHolders& holders, std::shared_ptr& selectedBackend) -> ProcessQueryResult { return ProcessQueryResult::SendAnswer; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -1085,7 +1086,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -1153,7 +1154,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -1216,7 +1217,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -1252,7 +1253,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -1298,7 +1299,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -1355,7 +1356,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -1411,7 +1412,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -1470,7 +1471,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -1522,7 +1523,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -1582,7 +1583,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -1623,7 +1624,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -1685,7 +1686,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnection_BackendNoOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -1874,7 +1875,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -2006,7 +2007,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -2186,7 +2187,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -2262,7 +2263,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR) } return ProcessQueryResult::Drop; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -2345,7 +2346,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR) } return ProcessQueryResult::Drop; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -2462,7 +2463,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -2614,7 +2615,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -2821,7 +2822,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -2995,7 +2996,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR) selectedBackend = proxyEnabledBackend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -3259,7 +3260,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -3385,7 +3386,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR) selectedBackend = proxyEnabledBackend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -3470,7 +3471,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR) selectedBackend = proxyEnabledBackend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -3535,7 +3536,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -3726,7 +3727,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR) selectedBackend = backend1; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -3811,7 +3812,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; @@ -4043,7 +4044,7 @@ BOOST_AUTO_TEST_CASE(test_IncomingConnectionOOOR_BackendNotOOOR) selectedBackend = backend; return ProcessQueryResult::PassToBackend; }; - s_processResponse = [](PacketBuffer& response, LocalStateHolder >& localRespRuleActions, DNSResponse& dr, bool muted) -> bool { + s_processResponse = [](PacketBuffer& response, DNSResponse& dr, bool muted) -> bool { return true; }; diff --git a/regression-tests.dnsdist/test_CacheInsertedResponses.py b/regression-tests.dnsdist/test_CacheInsertedResponses.py new file mode 100644 index 0000000000..42b70078b4 --- /dev/null +++ b/regression-tests.dnsdist/test_CacheInsertedResponses.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python +import base64 +import time +import dns +from dnsdisttests import DNSDistTest + +class TestCacheInsertedResponses(DNSDistTest): + + capTTLMax = 3600 + capTTLMin = 60 + _config_template = """ + pc = newPacketCache(100, {maxTTL=86400, minTTL=1}) + getPool(""):setCache(pc) + addCacheInsertedResponseAction(makeRule("cacheinsertedresponses.tests.powerdns.com."), LimitTTLResponseAction(%d, %d)) + newServer{address="127.0.0.1:%s"} + """ + _config_params = ['capTTLMax', 'capTTLMin', '_testServerPort'] + + def testTTLSetAfterInsertion(self): + """ + CacheInsertedResponse: Check that the TTL is capped after inserting into the cache + """ + initialTTL = 86400 + name = 'reduce-ttl-after-insertion.cacheinsertedresponses.tests.powerdns.com.' + query = dns.message.make_query(name, 'AAAA', 'IN') + + response = dns.message.make_response(query) + rrset = dns.rrset.from_text(name, + initialTTL, + dns.rdataclass.IN, + dns.rdatatype.AAAA, + '::1') + response.answer.append(rrset) + + responseOnMiss = dns.message.make_response(query) + rrset = dns.rrset.from_text(name, + self.capTTLMax, + dns.rdataclass.IN, + dns.rdatatype.AAAA, + '::1') + responseOnMiss.answer.append(rrset) + + # first query to fill the cache + (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) + self.assertTrue(receivedQuery) + self.assertTrue(receivedResponse) + receivedQuery.id = query.id + self.assertEqual(query, receivedQuery) + self.assertEqual(receivedResponse, responseOnMiss) + self.assertLessEqual(receivedResponse.answer[0].ttl, self.capTTLMax) + + # now the result should be cached + (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) + self.assertEqual(receivedResponse, response) + self.assertGreater(receivedResponse.answer[0].ttl, self.capTTLMax) + self.assertLessEqual(receivedResponse.answer[0].ttl, initialTTL) + + def testTTLRaisedAfterInsertion(self): + """ + CacheInsertedResponse: Check that the TTL can be raised after inserting into the cache + """ + initialTTL = 0 + name = 'raise-ttl-after-insertion.cacheinsertedresponses.tests.powerdns.com.' + query = dns.message.make_query(name, 'AAAA', 'IN') + + response = dns.message.make_response(query) + rrset = dns.rrset.from_text(name, + initialTTL, + dns.rdataclass.IN, + dns.rdatatype.AAAA, + '::1') + response.answer.append(rrset) + + responseOnMiss = dns.message.make_response(query) + rrset = dns.rrset.from_text(name, + self.capTTLMax, + dns.rdataclass.IN, + dns.rdatatype.AAAA, + '::1') + responseOnMiss.answer.append(rrset) + + # first query to fill the cache + (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) + self.assertTrue(receivedQuery) + self.assertTrue(receivedResponse) + receivedQuery.id = query.id + self.assertEqual(query, receivedQuery) + self.assertEqual(receivedResponse, responseOnMiss) + self.assertGreater(receivedResponse.answer[0].ttl, initialTTL) + self.assertLessEqual(receivedResponse.answer[0].ttl, self.capTTLMin) + + # the result should NOT have been cached + (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) + self.assertTrue(receivedQuery) + self.assertTrue(receivedResponse) + receivedQuery.id = query.id + self.assertEqual(query, receivedQuery) + self.assertEqual(receivedResponse, responseOnMiss) + self.assertGreater(receivedResponse.answer[0].ttl, initialTTL) + self.assertLessEqual(receivedResponse.answer[0].ttl, self.capTTLMin) + -- 2.47.2