]> git.ipfire.org Git - thirdparty/pdns.git/blobdiff - regression-tests.recursor-dnssec/test_Lua.py
auth: switch circleci mssql image
[thirdparty/pdns.git] / regression-tests.recursor-dnssec / test_Lua.py
index f615cf62932676285e9b7330bdceec1c43904a5c..f000bcf7a9f243c9205b771b2fd70a316a068481 100644 (file)
@@ -2,6 +2,11 @@ import clientsubnetoption
 import cookiesoption
 import dns
 import os
+import threading
+import time
+
+from twisted.internet.protocol import DatagramProtocol
+from twisted.internet import reactor
 
 from recursortests import RecursorTest
 
@@ -117,19 +122,6 @@ class GettagRecursorTest(RecursorTest):
     def tearDownClass(cls):
         cls.tearDownRecursor()
 
-    def assertResponseMatches(self, query, expectedRRs, response):
-        expectedResponse = dns.message.make_response(query)
-
-        if query.flags & dns.flags.RD:
-            expectedResponse.flags |= dns.flags.RA
-        if query.flags & dns.flags.CD:
-            expectedResponse.flags |= dns.flags.CD
-
-        expectedResponse.answer = expectedRRs
-        print(expectedResponse)
-        print(response)
-        self.assertEquals(response, expectedResponse)
-
     def testA(self):
         name = 'gettag.lua.'
         expected = [
@@ -163,6 +155,17 @@ class GettagRecursorTest(RecursorTest):
         res = self.sendUDPQuery(query)
         self.assertResponseMatches(query, expected, res)
 
+    def testAAAA(self):
+        name = 'gettag-tcpaaaa.lua.'
+        expected = [
+            dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'AAAA', '2001:db8::1'),
+            dns.rrset.from_text_list(name, 0, dns.rdataclass.IN, 'TXT', [ name, 'gettag-qtype-28', 'gettag-tcp'])
+            ]
+        query = dns.message.make_query(name, 'AAAA', want_dnssec=True)
+        query.flags |= dns.flags.CD
+        res = self.sendTCPQuery(query)
+        self.assertResponseMatches(query, expected, res)
+
     def testSubnet(self):
         name = 'gettag-subnet.lua.'
         subnet = '192.0.2.255'
@@ -198,10 +201,297 @@ class GettagRecursorTest(RecursorTest):
         res = self.sendUDPQuery(query)
         self.assertResponseMatches(query, expected, res)
 
-# TODO:
-# - postresolve
-# - preoutquery
-# - ipfilter
-# - prerpz
-# - nxdomain
-# - nodata
+class GettagRecursorDistributesQueriesTest(GettagRecursorTest):
+    _confdir = 'LuaGettagDistributes'
+    _config_template = """
+    log-common-errors=yes
+    gettag-needs-edns-options=yes
+    pdns-distributes-queries=yes
+    threads=2
+    """
+
+hooksReactorRunning = False
+
+class UDPHooksResponder(DatagramProtocol):
+
+    def datagramReceived(self, datagram, address):
+        request = dns.message.from_wire(datagram)
+
+        response = dns.message.make_response(request)
+        response.flags |= dns.flags.AA
+
+        if request.question[0].name == dns.name.from_text('nxdomain.luahooks.example.'):
+            soa = dns.rrset.from_text('luahooks.example.', 86400, dns.rdataclass.IN, 'SOA', 'ns.luahooks.example. hostmaster.luahooks.example. 1 3600 3600 3600 1')
+            response.authority.append(soa)
+            response.set_rcode(dns.rcode.NXDOMAIN)
+
+        elif request.question[0].name == dns.name.from_text('nodata.luahooks.example.'):
+            soa = dns.rrset.from_text('luahooks.example.', 86400, dns.rdataclass.IN, 'SOA', 'ns.luahooks.example. hostmaster.luahooks.example. 1 3600 3600 3600 1')
+            response.authority.append(soa)
+
+        elif request.question[0].name == dns.name.from_text('postresolve.luahooks.example.'):
+            answer = dns.rrset.from_text('postresolve.luahooks.example.', 3600, dns.rdataclass.IN, 'A', '192.0.2.1')
+            response.answer.append(answer)
+
+        self.transport.write(response.to_wire(), address)
+
+class LuaHooksRecursorTest(RecursorTest):
+    _confdir = 'LuaHooks'
+    _config_template = """
+forward-zones=luahooks.example=%s.23
+log-common-errors=yes
+quiet=no
+    """ % (os.environ['PREFIX'])
+    _lua_dns_script_file = """
+
+    allowedips = newNMG()
+    allowedips:addMask("%s.0/24")
+
+    function ipfilter(remoteip, localip, dh)
+      -- allow only 127.0.0.1 and AD=0
+      if allowedips:match(remoteip) and not dh:getAD() then
+        return false
+      end
+
+      return true
+    end
+
+    function nodata(dq)
+      if dq.qtype == pdns.AAAA and dq.qname == newDN("nodata.luahooks.example.") then
+        dq:addAnswer(pdns.AAAA, "2001:DB8::1")
+        return true
+      end
+
+      return false
+    end
+
+    function nxdomain(dq)
+      if dq.qtype == pdns.A and dq.qname == newDN("nxdomain.luahooks.example.") then
+        dq.rcode=0
+        dq:addAnswer(pdns.A, "192.0.2.1")
+        return true
+      end
+
+      return false
+    end
+
+    function postresolve(dq)
+      if dq.qtype == pdns.A and dq.qname == newDN("postresolve.luahooks.example.") then
+        local records = dq:getRecords()
+        for k,v in pairs(records) do
+          if v.type == pdns.A and v:getContent() == "192.0.2.1" then
+            v:changeContent("192.0.2.42")
+            v.ttl=1
+          end
+       end
+        dq:setRecords(records)
+        return true
+      end
+
+      return false
+    end
+
+    function preoutquery(dq)
+      if dq.remoteaddr:equal(newCA("%s.23")) and dq.qname == newDN("preout.luahooks.example.") and dq.qtype == pdns.A then
+        dq.rcode = -3 -- "kill"
+        return true
+      end
+
+      return false
+    end
+
+    """ % (os.environ['PREFIX'], os.environ['PREFIX'])
+
+    @classmethod
+    def startResponders(cls):
+        global hooksReactorRunning
+        print("Launching responders..")
+
+        address = cls._PREFIX + '.23'
+        port = 53
+
+        if not hooksReactorRunning:
+            reactor.listenUDP(port, UDPHooksResponder(), interface=address)
+            hooksReactorRunning = True
+
+        if not reactor.running:
+            cls._UDPResponder = threading.Thread(name='UDP Hooks Responder', target=reactor.run, args=(False,))
+            cls._UDPResponder.setDaemon(True)
+            cls._UDPResponder.start()
+
+    @classmethod
+    def setUpClass(cls):
+        cls.setUpSockets()
+
+        cls.startResponders()
+
+        confdir = os.path.join('configs', cls._confdir)
+        cls.createConfigDir(confdir)
+
+        cls.generateRecursorConfig(confdir)
+        cls.startRecursor(confdir, cls._recursorPort)
+
+        print("Launching tests..")
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.tearDownRecursor()
+
+    def testNoData(self):
+        expected = dns.rrset.from_text('nodata.luahooks.example.', 3600, dns.rdataclass.IN, 'AAAA', '2001:DB8::1')
+        query = dns.message.make_query('nodata.luahooks.example.', 'AAAA', 'IN')
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            res = sender(query)
+            self.assertRcodeEqual(res, dns.rcode.NOERROR)
+            self.assertRRsetInAnswer(res, expected)
+
+    def testVanillaNXD(self):
+        #expected = dns.rrset.from_text('nxdomain.luahooks.example.', 3600, dns.rdataclass.IN, 'A', '192.0.2.1')
+        query = dns.message.make_query('nxdomain.luahooks.example.', 'AAAA', 'IN')
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            res = sender(query)
+            self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
+
+    def testHookedNXD(self):
+        expected = dns.rrset.from_text('nxdomain.luahooks.example.', 3600, dns.rdataclass.IN, 'A', '192.0.2.1')
+        query = dns.message.make_query('nxdomain.luahooks.example.', 'A', 'IN')
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            res = sender(query)
+            self.assertRcodeEqual(res, dns.rcode.NOERROR)
+            self.assertRRsetInAnswer(res, expected)
+
+    def testPostResolve(self):
+        expected = dns.rrset.from_text('postresolve.luahooks.example.', 1, dns.rdataclass.IN, 'A', '192.0.2.42')
+        query = dns.message.make_query('postresolve.luahooks.example.', 'A', 'IN')
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            res = sender(query)
+            self.assertRcodeEqual(res, dns.rcode.NOERROR)
+            self.assertRRsetInAnswer(res, expected)
+            self.assertEqual(res.answer[0].ttl, 1)
+
+    def testIPFilterHeader(self):
+        query = dns.message.make_query('ipfiler.luahooks.example.', 'A', 'IN')
+        query.flags |= dns.flags.AD
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            res = sender(query)
+            self.assertEqual(res, None)
+
+    def testPreOutInterceptedQuery(self):
+        query = dns.message.make_query('preout.luahooks.example.', 'A', 'IN')
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            res = sender(query)
+            self.assertRcodeEqual(res, dns.rcode.SERVFAIL)
+
+    def testPreOutNotInterceptedQuery(self):
+        query = dns.message.make_query('preout.luahooks.example.', 'AAAA', 'IN')
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            res = sender(query)
+            self.assertRcodeEqual(res, dns.rcode.NOERROR)
+
+class LuaHooksRecursorDistributesTest(LuaHooksRecursorTest):
+    _confdir = 'LuaHooksDistributes'
+    _config_template = """
+forward-zones=luahooks.example=%s.23
+log-common-errors=yes
+pdns-distributes-queries=yes
+threads=2
+quiet=no
+    """ % (os.environ['PREFIX'])
+
+class DNS64Test(RecursorTest):
+    """Tests the dq.followupAction("getFakeAAAARecords")"""
+
+    _confdir = 'dns64'
+    _config_template = """
+    """
+    _lua_dns_script_file = """
+    prefix = "2001:DB8:64::"
+
+    function nodata (dq)
+      if dq.qtype ~= pdns.AAAA then
+        return false
+      end  --  only AAAA records
+
+      -- don't fake AAAA records if DNSSEC validation failed
+      if dq.validationState == pdns.validationstates.Bogus then
+         return false
+      end
+
+      dq.followupFunction = "getFakeAAAARecords"
+      dq.followupPrefix = prefix
+      dq.followupName = dq.qname
+      return true
+    end
+    """
+
+    def testAtoAAAA(self):
+        expected = [
+            dns.rrset.from_text('ns.secure.example.', 15, dns.rdataclass.IN, 'AAAA', '2001:db8:64::7f00:9')
+        ]
+        query = dns.message.make_query('ns.secure.example', 'AAAA')
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            res = sender(query)
+
+            self.assertRcodeEqual(res, dns.rcode.NOERROR)
+            self.assertEqual(len(res.answer), 1)
+            self.assertEqual(len(res.authority), 0)
+            self.assertResponseMatches(query, expected, res)
+
+    def testAtoCNAMEtoAAAA(self):
+        expected = [
+            dns.rrset.from_text('cname-to-insecure.secure.example.', 3600, dns.rdataclass.IN, 'CNAME', 'node1.insecure.example.'),
+            dns.rrset.from_text('node1.insecure.example.', 3600, dns.rdataclass.IN, 'AAAA', '2001:db8:64::c000:206')
+        ]
+        query = dns.message.make_query('cname-to-insecure.secure.example.', 'AAAA')
+
+        for method in ("sendUDPQuery", "sendTCPQuery"):
+            sender = getattr(self, method)
+            res = sender(query)
+
+            self.assertRcodeEqual(res, dns.rcode.NOERROR)
+            self.assertEqual(len(res.answer), 2)
+            self.assertEqual(len(res.authority), 0)
+            self.assertResponseMatches(query, expected, res)
+
+
+class PDNSRandomTest(RecursorTest):
+    """Tests if pdnsrandom works"""
+
+    _confdir = 'pdnsrandom'
+    _config_template = """
+    """
+    _lua_dns_script_file = """
+    function preresolve (dq)
+      dq.rcode = pdns.NOERROR
+      dq:addAnswer(pdns.TXT, pdnsrandom())
+      return true
+    end
+    """
+
+    def testRandom(self):
+        query = dns.message.make_query('whatever.example.', 'TXT')
+
+        ans = set()
+
+        ret = self.sendUDPQuery(query)
+        ans.add(ret.answer[0])
+        ret = self.sendUDPQuery(query)
+        ans.add(ret.answer[0])
+
+        self.assertEqual(len(ans), 2)