]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Add SkipCacheResponseAction 9960/head
authorRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 12 Jan 2021 14:59:26 +0000 (15:59 +0100)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 12 Jan 2021 14:59:26 +0000 (15:59 +0100)
pdns/dnsdist-console.cc
pdns/dnsdist-lua-actions.cc
pdns/dnsdistdist/docs/rules-actions.rst
regression-tests.dnsdist/test_Caching.py

index c2ac58bed05b3e5c0df3523847fce170324ff464..232c46b0996fa6e33121bf8490cd5faa47dbc194 100644 (file)
@@ -606,6 +606,7 @@ const std::vector<ConsoleKeyword> g_consoleKeywords{
   { "shutdown", true, "", "shut down `dnsdist`" },
   { "SetProxyProtocolValuesAction", true, "values", "Set the Proxy-Protocol values for this queries to 'values'" },
   { "SkipCacheAction", true, "", "Don’t lookup the cache for this query, don’t store the answer" },
+  { "SkipCacheResponseAction", true, "", "Don’t store this response into the cache" },
   { "SNIRule", true, "name", "Create a rule which matches on the incoming TLS SNI value, if any (DoT or DoH)" },
   { "snmpAgent", true, "enableTraps [, masterSocket]", "enable `SNMP` support. `enableTraps` is a boolean indicating whether traps should be sent and `masterSocket` an optional string specifying how to connect to the master agent"},
   { "SNMPTrapAction", true, "[reason]", "send an SNMP trap, adding the optional `reason` string as the query description"},
index 45fa66633713a3477766cd5ce6ec2618be284f08..4ae206fc72dab4ad74f198686c0ad0295814f164 100644 (file)
@@ -856,6 +856,20 @@ public:
   }
 };
 
+class SkipCacheResponseAction : public DNSResponseAction
+{
+public:
+  DNSResponseAction::Action operator()(DNSResponse* dr, std::string* ruleresult) const override
+  {
+    dr->skipCache = true;
+    return Action::None;
+  }
+  std::string toString() const override
+  {
+    return "skip cache";
+  }
+};
+
 class TempFailureCacheTTLAction : public DNSAction
 {
 public:
@@ -1704,6 +1718,10 @@ void setupLuaActions(LuaContext& luaCtx)
       return std::shared_ptr<DNSAction>(new SkipCacheAction);
     });
 
+  luaCtx.writeFunction("SkipCacheResponseAction", []() {
+      return std::shared_ptr<DNSResponseAction>(new SkipCacheResponseAction);
+    });
+
   luaCtx.writeFunction("TempFailureCacheTTLAction", [](int maxTTL) {
       return std::shared_ptr<DNSAction>(new TempFailureCacheTTLAction(maxTTL));
     });
index 6e6679cf5f60bdeb8584fd4fa948cadff40b6585..930979e057471efa2639c982076742877ac242b8 100644 (file)
@@ -1359,6 +1359,12 @@ The following actions exist.
 
   Don't lookup the cache for this query, don't store the answer.
 
+.. function:: SkipCacheResponseAction()
+
+  .. versionadded:: 1.6.0
+
+  Don't store this answer into the cache.
+
 .. function:: SNMPTrapAction([message])
 
   Send an SNMP trap, adding the optional ``message`` string as the query description.
index d3f91753c2b5dc89ba7dd7cbd3a421b9e3c877b0..be9927d4c1cc29c53c074c418e63240e5caf96ef 100644 (file)
@@ -12,6 +12,7 @@ class TestCaching(DNSDistTest):
     pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
     getPool(""):setCache(pc)
     addAction(makeRule("nocache.cache.tests.powerdns.com."), SkipCacheAction())
+    addResponseAction(makeRule("nocache-response.cache.tests.powerdns.com."), SkipCacheResponseAction())
     function skipViaLua(dq)
         dq.skipCache = true
         return DNSAction.None, ""
@@ -200,6 +201,38 @@ class TestCaching(DNSDistTest):
             value = self._responsesCounter[key]
             self.assertEquals(value, numberOfQueries)
 
+    def testSkipCacheResponse(self):
+        """
+        Cache: SkipCacheResponseAction
+
+        dnsdist is configured to not cache entries for answer matching nocache-response.cache.tests.powerdns.com.
+         we are sending several requests and checking that the backend get them all.
+        """
+        name = 'nocache-response.cache.tests.powerdns.com.'
+        numberOfQueries = 10
+        query = dns.message.make_query(name, 'AAAA', 'IN')
+        response = dns.message.make_response(query)
+        rrset = dns.rrset.from_text(name,
+                                    3600,
+                                    dns.rdataclass.IN,
+                                    dns.rdatatype.AAAA,
+                                    '::1')
+        response.answer.append(rrset)
+
+        for _ in range(numberOfQueries):
+            for method in ("sendUDPQuery", "sendTCPQuery"):
+                sender = getattr(self, method)
+                (receivedQuery, receivedResponse) = sender(query, response)
+                self.assertTrue(receivedQuery)
+                self.assertTrue(receivedResponse)
+                receivedQuery.id = query.id
+                self.assertEquals(query, receivedQuery)
+                self.assertEquals(receivedResponse, response)
+
+        for key in self._responsesCounter:
+            value = self._responsesCounter[key]
+            self.assertEquals(value, numberOfQueries)
+
     def testCacheExpiration(self):
         """
         Cache: Cache expiration