]> git.ipfire.org Git - thirdparty/pdns.git/blobdiff - regression-tests.recursor-dnssec/recursortests.py
Merge pull request #13106 from omoerbeek/rec-aggr-cache-replace
[thirdparty/pdns.git] / regression-tests.recursor-dnssec / recursortests.py
index 4b9a745e9847d1b36e01f38b454dd5f129fda595..cf883fb4ee1dfbfcbdd9b8e85fa3910853305d4e 100644 (file)
@@ -39,7 +39,6 @@ class RecursorTest(AssertEqualDNSMessageMixin, unittest.TestCase):
 
     _confdir = 'recursor'
 
-    _recursorStartupDelay = 2.0
     _recursorPort = 5300
 
     _recursor = None
@@ -51,13 +50,14 @@ daemon=no
 trace=yes
 dont-query=
 local-address=127.0.0.1
-packetcache-ttl=0
-packetcache-servfail-ttl=0
+packetcache-ttl=15
+packetcache-servfail-ttl=15
 max-cache-ttl=15
-threads=1
+threads=2
 loglevel=9
 disable-syslog=yes
 log-common-errors=yes
+statistics-interval=0
 """
     _config_template = """
 """
@@ -160,8 +160,26 @@ cname-custom-a-target.example.      3600 IN A 192.0.2.102
 secure.example.          3600 IN SOA  {soa}
 secure.example.          3600 IN NS   ns.secure.example.
 ns.secure.example.       3600 IN A    {prefix}.9
+secure.example.          3600 IN MX   10 mx1.secure.example.
+secure.example.          3600 IN MX   20 mx2.secure.example.
+sub.secure.example.      3600 IN MX   10 mx1.secure.example.
+sub.secure.example.      3600 IN MX   20 mx2.secure.example.
+
+naptr.secure.example.    60   IN NAPTR   10 10 "a" "X" "A" s1.secure.example.
+naptr.secure.example.    60   IN NAPTR   10 10 "s" "Y" "B" service1.secure.example.
+naptr.secure.example.    60   IN NAPTR   10 10 "s" "Z" "C" service2.secure.example.
+service1.secure.example. 60   IN SRV     20 100 8080 a.secure.example.
+service2.secure.example. 60   IN SRV     20 100 8080 b.secure.example.
+
 
 secure.example.          3600 IN A    192.0.2.17
+mx1.secure.example.      3600 IN A    192.0.2.18
+mx2.secure.example.      3600 IN AAAA    1::2
+s1.secure.example.       3600 IN A    192.0.2.19
+a.secure.example.        3600 IN A    192.0.2.20
+a.secure.example.        3600 IN A    192.0.2.22
+b.secure.example.        3600 IN A    192.0.2.21
+b.secure.example.        3600 IN AAAA  1::3
 
 host1.secure.example.    3600 IN A    192.0.2.2
 cname.secure.example.    3600 IN CNAME host1.secure.example.
@@ -282,7 +300,9 @@ node1.undelegated.insecure.example.  3600 IN A    192.0.2.22
 delay1.example.                       3600 IN SOA  {soa}
 delay1.example.                       3600 IN NS n1.delay1.example.
 ns1.delay1.example.                   3600 IN A    {prefix}.16
+8.delay1.example.                     3600 IN A    192.0.2.100
 *.delay1.example.                     0    LUA TXT ";" "local socket=require('socket')" "socket.sleep(tonumber(qname:getRawLabels()[1])/10)" "return 'a'"
+*.delay1.example.                     0    LUA AAAA ";" "local socket=require('socket')" "socket.sleep(tonumber(qname:getRawLabels()[1])/10)" "return '1::2'"
         """,
         
         'delay2.example': """
@@ -625,14 +645,14 @@ distributor-threads={threads}""".format(confdir=confdir,
             with open(logFile, 'r') as fdLog:
                 print(fdLog.read())
             print(f"*** End startRecursor log for {logFile} ***")
-            raise AssertionError('%s failed (%d)' % (recursorcmd, _recursor.returncode))
+            raise AssertionError('%s failed (%d)' % (recursorcmd, cls._recursor.returncode))
 
     @classmethod
-    def wipeRecursorCache(cls, confdir):
+    def wipeRecursorCache(cls, confdir, name='.$'):
         rec_controlCmd = [os.environ['RECCONTROL'],
                           '--config-dir=%s' % confdir,
                           'wipe-cache',
-                          '.$']
+                          name]
         try:
             subprocess.check_output(rec_controlCmd, stderr=subprocess.STDOUT)
         except subprocess.CalledProcessError as e:
@@ -862,6 +882,30 @@ distributor-threads={threads}""".format(confdir=confdir,
         if not found:
             raise AssertionError("RRset not found in answer\n\n%s" % ret)
 
+    def assertRRsetInAdditional(self, msg, rrset):
+        """Asserts the rrset (without comparing TTL) exists in the
+        additional section of msg
+
+        @param msg: the dns.message.Message to check
+        @param rrset: a dns.rrset.RRset object"""
+
+        ret = ''
+        if not isinstance(msg, dns.message.Message):
+            raise TypeError("msg is not a dns.message.Message")
+
+        if not isinstance(rrset, dns.rrset.RRset):
+            raise TypeError("rrset is not a dns.rrset.RRset")
+
+        found = False
+        for ans in msg.additional:
+            ret += "%s\n" % ans.to_text()
+            if ans.match(rrset.name, rrset.rdclass, rrset.rdtype, 0, None):
+                self.assertEqual(ans, rrset, "'%s' != '%s'" % (ans.to_text(), rrset.to_text()))
+                found = True
+
+        if not found:
+            raise AssertionError("RRset not found in additional section\n\n%s" % ret)
+
     def assertMatchingRRSIGInAnswer(self, msg, coveredRRset, keys=None):
         """Looks for coveredRRset in the answer section and if there is an RRSIG RRset
         that covers that RRset. If keys is not None, this function will also try to
@@ -903,6 +947,47 @@ distributor-threads={threads}""".format(confdir=confdir,
             except dns.dnssec.ValidationFailure as e:
                 raise AssertionError("Signature validation failed for %s:\n%s" % (msg.question[0].to_text(), e))
 
+    def assertMatchingRRSIGInAdditional(self, msg, coveredRRset, keys=None):
+        """Looks for coveredRRset in the additional section and if there is an RRSIG RRset
+        that covers that RRset. If keys is not None, this function will also try to
+        validate the RRset against the RRSIG
+
+        @param msg: The dns.message.Message to check
+        @param coveredRRset: The RRSet to check for
+        @param keys: a dictionary keyed by dns.name.Name with node or rdataset values to use for validation"""
+
+        if not isinstance(msg, dns.message.Message):
+            raise TypeError("msg is not a dns.message.Message")
+
+        if not isinstance(coveredRRset, dns.rrset.RRset):
+            raise TypeError("coveredRRset is not a dns.rrset.RRset")
+
+        msgRRsigRRSet = None
+        msgRRSet = None
+
+        ret = ''
+        for ans in msg.additional:
+            ret += ans.to_text() + "\n"
+
+            if ans.match(coveredRRset.name, coveredRRset.rdclass, coveredRRset.rdtype, 0, None):
+                msgRRSet = ans
+            if ans.match(coveredRRset.name, dns.rdataclass.IN, dns.rdatatype.RRSIG, coveredRRset.rdtype, None):
+                msgRRsigRRSet = ans
+            if msgRRSet and msgRRsigRRSet:
+                break
+
+        if not msgRRSet:
+            raise AssertionError("RRset for '%s' not found in additional" % msg.question[0].to_text())
+
+        if not msgRRsigRRSet:
+            raise AssertionError("No RRSIGs found in additional for %s:\nFull answer:\n%s" % (msg.question[0].to_text(), ret))
+
+        if keys:
+            try:
+                dns.dnssec.validate(msgRRSet, msgRRsigRRSet.to_rdataset(), keys)
+            except dns.dnssec.ValidationFailure as e:
+                raise AssertionError("Signature validation failed for %s:\n%s" % (msg.question[0].to_text(), e))
+
     def assertNoRRSIGsInAnswer(self, msg):
         """Checks if there are _no_ RRSIGs in the answer section of msg"""
 
@@ -920,6 +1005,9 @@ distributor-threads={threads}""".format(confdir=confdir,
     def assertAnswerEmpty(self, msg):
         self.assertTrue(len(msg.answer) == 0, "Data found in the the answer section for %s:\n%s" % (msg.question[0].to_text(), '\n'.join([i.to_text() for i in msg.answer])))
 
+    def assertAdditionalEmpty(self, msg):
+        self.assertTrue(len(msg.additional) == 0, "Data found in the the additional section for %s:\n%s" % (msg.question[0].to_text(), '\n'.join([i.to_text() for i in msg.additional])))
+
     def assertRcodeEqual(self, msg, rcode):
         if not isinstance(msg, dns.message.Message):
             raise TypeError("msg is not a dns.message.Message but a %s" % type(msg))