]> git.ipfire.org Git - thirdparty/pdns.git/blobdiff - regression-tests.recursor-dnssec/test_AggressiveNSECCache.py
Merge pull request #13509 from rgacogne/ddist-teeaction-proxyprotocol
[thirdparty/pdns.git] / regression-tests.recursor-dnssec / test_AggressiveNSECCache.py
index a4640176c69df64241f9d6321345128d79dfed6c..1e149af6acdd404f64e4f805c7046e4dd67a5831 100644 (file)
@@ -4,6 +4,7 @@ import os
 import requests
 import subprocess
 import time
+import extendederrors
 
 class AggressiveNSECCacheBase(RecursorTest):
     __test__ = False
@@ -11,20 +12,25 @@ class AggressiveNSECCacheBase(RecursorTest):
     _wsTimeout = 10
     _wsPassword = 'secretpassword'
     _apiKey = 'secretapikey'
+    #_recursorStartupDelay = 4.0
     _config_template = """
     dnssec=validate
     aggressive-nsec-cache-size=10000
+    nsec3-max-iterations=150
     webserver=yes
     webserver-port=%d
     webserver-address=127.0.0.1
     webserver-password=%s
     api-key=%s
+    devonly-regression-test-mode
+    extended-resolution-errors=yes
     """ % (_wsPort, _wsPassword, _apiKey)
 
     @classmethod
     def wipe(cls):
         confdir = os.path.join('configs', cls._confdir)
-        cls.wipeRecursorCache(confdir)
+        # Only wipe examples, as wiping the root triggers root NS refreshes
+        cls.wipeRecursorCache(confdir, "example$")
 
     def getMetric(self, name):
         headers = {'x-api-key': self._apiKey}
@@ -41,10 +47,31 @@ class AggressiveNSECCacheBase(RecursorTest):
 
         self.assertTrue(False)
 
-    def testNoData(self):
+    def testNoEDE(self):
+        # This isn't an aggresive cache check, but the strcuture is very similar to the others,
+        # so letys place it here.
+        # It test the issue that an intermediate EDE does not get reported with the final answer
+        # https://github.com/PowerDNS/pdns/pull/12694
+        self.wipe()
+
+        res = self.sendQuery('host1.sub.secure.example.', 'TXT')
+        self.assertRcodeEqual(res, dns.rcode.NOERROR)
+        self.assertAnswerEmpty(res)
+        self.assertAuthorityHasSOA(res)
+        self.assertMessageIsAuthenticated(res)
+        self.assertEqual(res.edns, 0)
+        self.assertEqual(len(res.options), 0)
+
+        res = self.sendQuery('host1.sub.secure.example.', 'A')
+        self.assertRcodeEqual(res, dns.rcode.NOERROR)
+        self.assertMessageIsAuthenticated(res)
+        self.assertEqual(res.edns, 0)
+        self.assertEqual(len(res.options), 0)
 
+    def testNoData(self):
         self.wipe()
-        # first we query a non-existent type, to get the NSEC in our cache
+
+        # first we query a nonexistent type, to get the NSEC in our cache
         entries = self.getMetric('aggressive-nsec-cache-entries')
         res = self.sendQuery('host1.secure.example.', 'TXT')
         self.assertRcodeEqual(res, dns.rcode.NOERROR)
@@ -64,6 +91,10 @@ class AggressiveNSECCacheBase(RecursorTest):
         self.assertMessageIsAuthenticated(res)
         self.assertEqual(nbQueries, self.getMetric('all-outqueries'))
         self.assertEqual(self.getMetric('aggressive-nsec-cache-entries'), entries)
+        self.assertEqual(res.edns, 0)
+        self.assertEqual(len(res.options), 1)
+        self.assertEqual(res.options[0].otype, 15)
+        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized from aggressive NSEC cache (RFC8198)'))
 
 class AggressiveNSECCacheNSEC(AggressiveNSECCacheBase):
     _confdir = 'AggressiveNSECCacheNSEC'
@@ -72,9 +103,9 @@ class AggressiveNSECCacheNSEC(AggressiveNSECCacheBase):
     # we can't use the same tests for NSEC and NSEC3 because the hashed NSEC3s
     # do not deny the same names than the non-hashed NSECs do
     def testNXD(self):
-
         self.wipe()
-        # first we query a non-existent name, to get the needed NSECs (name + widcard) in our cache
+
+        # first we query a nonexistent name, to get the needed NSECs (name + widcard) in our cache
         entries = self.getMetric('aggressive-nsec-cache-entries')
         hits = self.getMetric('aggressive-nsec-cache-nsec-hits')
         res = self.sendQuery('host2.secure.example.', 'TXT')
@@ -98,11 +129,15 @@ class AggressiveNSECCacheNSEC(AggressiveNSECCacheBase):
         self.assertEqual(nbQueries, self.getMetric('all-outqueries'))
         self.assertEqual(self.getMetric('aggressive-nsec-cache-entries'), entries)
         self.assertGreater(self.getMetric('aggressive-nsec-cache-nsec-hits'), hits)
+        self.assertEqual(res.edns, 0)
+        self.assertEqual(len(res.options), 1)
+        self.assertEqual(res.options[0].otype, 15)
+        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized from aggressive NSEC cache (RFC8198)'))
 
     def testWildcard(self):
-
         self.wipe()
-        # first we query a non-existent name, but for which a wildcard matches,
+
+        # first we query a nonexistent name, but for which a wildcard matches,
         # to get the NSEC in our cache
         res = self.sendQuery('test1.wildcard.secure.example.', 'A')
         expected = dns.rrset.from_text('test1.wildcard.secure.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
@@ -121,6 +156,10 @@ class AggressiveNSECCacheNSEC(AggressiveNSECCacheBase):
         self.assertMessageIsAuthenticated(res)
         self.assertEqual(nbQueries, self.getMetric('all-outqueries'))
         self.assertGreater(self.getMetric('aggressive-nsec-cache-nsec-wc-hits'), hits)
+        self.assertEqual(res.edns, 0)
+        self.assertEqual(len(res.options), 1)
+        self.assertEqual(res.options[0].otype, 15)
+        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized from aggressive NSEC cache (RFC8198)'))
 
         # now we ask for a type that does not exist at the wildcard
         hits = self.getMetric('aggressive-nsec-cache-nsec-hits')
@@ -132,6 +171,10 @@ class AggressiveNSECCacheNSEC(AggressiveNSECCacheBase):
         self.assertMessageIsAuthenticated(res)
         self.assertEqual(nbQueries, self.getMetric('all-outqueries'))
         self.assertGreater(self.getMetric('aggressive-nsec-cache-nsec-hits'), hits)
+        self.assertEqual(res.edns, 0)
+        self.assertEqual(len(res.options), 1)
+        self.assertEqual(res.options[0].otype, 15)
+        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized from aggressive NSEC cache (RFC8198)'))
 
         # we can also ask a different type, for a different name that is covered
         # by the NSEC and matches the wildcard (but the type does not exist)
@@ -144,6 +187,10 @@ class AggressiveNSECCacheNSEC(AggressiveNSECCacheBase):
         self.assertMessageIsAuthenticated(res)
         self.assertEqual(nbQueries, self.getMetric('all-outqueries'))
         self.assertGreater(self.getMetric('aggressive-nsec-cache-nsec-hits'), hits)
+        self.assertEqual(res.edns, 0)
+        self.assertEqual(len(res.options), 1)
+        self.assertEqual(res.options[0].otype, 15)
+        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized from aggressive NSEC cache (RFC8198)'))
 
     def test_Bogus(self):
         self.wipe()
@@ -181,6 +228,11 @@ class AggressiveNSECCacheNSEC(AggressiveNSECCacheBase):
 
         # Check that we stil have one aggressive cache entry
         self.assertEqual(1, self.getMetric('aggressive-nsec-cache-entries'))
+        print(res.options)
+        self.assertEqual(res.edns, 0)
+        self.assertEqual(len(res.options), 1)
+        self.assertEqual(res.options[0].otype, 15)
+        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(9, b''))
 
 class AggressiveNSECCacheNSEC3(AggressiveNSECCacheBase):
     _confdir = 'AggressiveNSECCacheNSEC3'
@@ -231,8 +283,9 @@ class AggressiveNSECCacheNSEC3(AggressiveNSECCacheBase):
             raise AssertionError('%s failed (%d): %s' % (pdnsutilCmd, e.returncode, e.output))
 
     def testNXD(self):
+        self.wipe()
 
-        # first we query a non-existent name, to get the needed NSEC3s in our cache
+        # first we query a nonexistent name, to get the needed NSEC3s in our cache
         res = self.sendQuery('host2.secure.example.', 'TXT')
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
         self.assertAnswerEmpty(res)
@@ -248,8 +301,13 @@ class AggressiveNSECCacheNSEC3(AggressiveNSECCacheBase):
         self.assertAuthorityHasSOA(res)
         self.assertMessageIsAuthenticated(res)
         self.assertEqual(nbQueries, self.getMetric('all-outqueries'))
+        self.assertEqual(res.edns, 0)
+        self.assertEqual(len(res.options), 1)
+        self.assertEqual(res.options[0].otype, 15)
+        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized from aggressive NSEC cache (RFC8198)'))
 
     def testWildcard(self):
+        self.wipe()
 
         # first let's get the SOA and wildcard NSEC in our cache by asking a name that matches the wildcard
         # but a type that does not exist
@@ -259,7 +317,7 @@ class AggressiveNSECCacheNSEC3(AggressiveNSECCacheBase):
         self.assertAuthorityHasSOA(res)
         self.assertMessageIsAuthenticated(res)
 
-        # we query a non-existent name, but for which a wildcard matches,
+        # we query a nonexistent name, but for which a wildcard matches,
         # to get the NSEC3 in our cache
         res = self.sendQuery('test5.wildcard.secure.example.', 'A')
         expected = dns.rrset.from_text('test5.wildcard.secure.example.', 0, dns.rdataclass.IN, 'A', '{prefix}.10'.format(prefix=self._PREFIX))
@@ -276,6 +334,10 @@ class AggressiveNSECCacheNSEC3(AggressiveNSECCacheBase):
         self.assertMatchingRRSIGInAnswer(res, expected)
         self.assertMessageIsAuthenticated(res)
         self.assertEqual(nbQueries, self.getMetric('all-outqueries'))
+        self.assertEqual(res.edns, 0)
+        self.assertEqual(len(res.options), 1)
+        self.assertEqual(res.options[0].otype, 15)
+        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized from aggressive NSEC cache (RFC8198)'))
 
         # now we ask for a type that does not exist at the wildcard
         nbQueries = self.getMetric('all-outqueries')
@@ -285,6 +347,10 @@ class AggressiveNSECCacheNSEC3(AggressiveNSECCacheBase):
         self.assertAuthorityHasSOA(res)
         self.assertMessageIsAuthenticated(res)
         self.assertEqual(nbQueries, self.getMetric('all-outqueries'))
+        self.assertEqual(res.edns, 0)
+        self.assertEqual(len(res.options), 1)
+        self.assertEqual(res.options[0].otype, 15)
+        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized from aggressive NSEC cache (RFC8198)'))
 
         # we can also ask a different type, for a different name that is covered
         # by the NSEC3s and matches the wildcard (but the type does not exist)
@@ -295,8 +361,14 @@ class AggressiveNSECCacheNSEC3(AggressiveNSECCacheBase):
         self.assertAuthorityHasSOA(res)
         self.assertMessageIsAuthenticated(res)
         self.assertEqual(nbQueries, self.getMetric('all-outqueries'))
+        self.assertEqual(res.edns, 0)
+        self.assertEqual(len(res.options), 1)
+        self.assertEqual(res.options[0].otype, 15)
+        self.assertEqual(res.options[0], extendederrors.ExtendedErrorOption(29, b'Result synthesized from aggressive NSEC cache (RFC8198)'))
 
     def test_OptOut(self):
+        self.wipe()
+
         # query a name in an opt-out zone
         res = self.sendQuery('ns2.optout.example.', 'A')
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
@@ -310,3 +382,5 @@ class AggressiveNSECCacheNSEC3(AggressiveNSECCacheBase):
         self.assertAnswerEmpty(res)
         self.assertAuthorityHasSOA(res)
         self.assertGreater(self.getMetric('all-outqueries'), nbQueries)
+        self.assertEqual(res.edns, 0)
+        self.assertEqual(len(res.options), 0)