]> git.ipfire.org Git - thirdparty/pdns.git/blobdiff - regression-tests.recursor-dnssec/recursortests.py
rec: dnspython's API changed wrt NSID, apply (version dependent) fix in regression...
[thirdparty/pdns.git] / regression-tests.recursor-dnssec / recursortests.py
index 86d8f441b29674f7b050aed46d123814dab9c4ea..c19426965e0b892733af3bd26912b31667576584 100644 (file)
@@ -39,7 +39,6 @@ class RecursorTest(AssertEqualDNSMessageMixin, unittest.TestCase):
 
     _confdir = 'recursor'
 
-    _recursorStartupDelay = 2.0
     _recursorPort = 5300
 
     _recursor = None
@@ -51,14 +50,36 @@ 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_yaml_default = """
+recursor:
+  daemon: false
+  threads: 2
+  include_dir: %s
+recordcache:
+  max_ttl: 15
+incoming:
+  listen:
+  - 127.0.0.1
+packetcache:
+  ttl: 15
+  servfail_ttl: 15
+outgoing:
+  dont_query: []
+logging:
+  trace: true
+  disable_syslog: true
+  common_errors: true
+  loglevel: 9
+  statistics_interval: 0
 """
     _config_template = """
 """
@@ -161,8 +182,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.
@@ -283,7 +322,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': """
@@ -601,6 +642,44 @@ distributor-threads={threads}""".format(confdir=confdir,
                     roothints.write(cls._roothints)
                 conf.write("hint-file=%s\n" % roothintspath)
 
+    @classmethod
+    def generateRecursorYamlConfig(cls, confdir):
+        params = tuple([getattr(cls, param) for param in cls._config_params])
+        if len(params):
+            print(params)
+
+        recursorconf = os.path.join(confdir, 'recursor.yml')
+
+        with open(recursorconf, 'w') as conf:
+            conf.write("# Autogenerated by recursortests.py\n")
+            conf.write(cls._config_template_yaml_default % confdir)
+        recursorconf = os.path.join(confdir, 'recursor01.yml')
+        with open(recursorconf, 'w') as conf:
+            conf.write(cls._config_template % params)
+            conf.write("\n")
+        recursorconf = os.path.join(confdir, 'recursor02.yml')
+        with open(recursorconf, 'w') as conf:
+            conf.write("recursor:\n")
+            conf.write("  socket_dir: %s\n" % confdir)
+            if cls._lua_config_file or cls._root_DS:
+                luaconfpath = os.path.join(confdir, 'conffile.lua')
+                with open(luaconfpath, 'w') as luaconf:
+                    if cls._root_DS:
+                        luaconf.write("addTA('.', '%s')\n" % cls._root_DS)
+                    if cls._lua_config_file:
+                        luaconf.write(cls._lua_config_file)
+                conf.write("  lua_config_file: %s\n" % luaconfpath)
+            if cls._lua_dns_script_file:
+                luascriptpath = os.path.join(confdir, 'dnsscript.lua')
+                with open(luascriptpath, 'w') as luascript:
+                    luascript.write(cls._lua_dns_script_file)
+                conf.write("  lua_dns_script: %s\n" % luascriptpath)
+            if cls._roothints:
+                roothintspath = os.path.join(confdir, 'root.hints')
+                with open(roothintspath, 'w') as roothints:
+                    roothints.write(cls._roothints)
+                conf.write("  hint_file: %s\n" % roothintspath)
+
     @classmethod
     def startResponders(cls):
         pass
@@ -629,11 +708,11 @@ distributor-threads={threads}""".format(confdir=confdir,
             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:
@@ -863,6 +942,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
@@ -904,6 +1007,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"""
 
@@ -921,6 +1065,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))