]> git.ipfire.org Git - thirdparty/pdns.git/blobdiff - regression-tests.recursor-dnssec/test_RecDnstap.py
Merge pull request #13423 from phonedph1/patch-3
[thirdparty/pdns.git] / regression-tests.recursor-dnssec / test_RecDnstap.py
index 8993f432f582765f3b0e9789e0c01aa3d8f3181a..5856a1bb00cc35d35bc448274c8b0a186a5c2701 100644 (file)
@@ -1,3 +1,4 @@
+import errno
 import os
 import socket
 import struct
@@ -5,7 +6,7 @@ import sys
 import threading
 import dns
 import dnstap_pb2
-from nose import SkipTest
+from unittest import SkipTest
 from recursortests import RecursorTest
 
 FSTRM_CONTROL_ACCEPT = 0x01
@@ -26,7 +27,7 @@ except NameError:
     pass
 
 
-def checkDnstapBase(testinstance, dnstap, protocol, initiator):
+def checkDnstapBase(testinstance, dnstap, protocol, initiator, responder, response_port=53):
     testinstance.assertTrue(dnstap)
     testinstance.assertTrue(dnstap.HasField('identity'))
     #testinstance.assertEqual(dnstap.identity, b'a.server')
@@ -40,19 +41,20 @@ def checkDnstapBase(testinstance, dnstap, protocol, initiator):
     testinstance.assertTrue(dnstap.message.HasField('socket_family'))
     testinstance.assertEqual(dnstap.message.socket_family, dnstap_pb2.INET)
     #
-    # We cannot check the query address and port since we only log outgoing queries via dnstap
+    # The query address and port are from the the recursor, we don't know the port
     #
-    #testinstance.assertTrue(dnstap.message.HasField('query_address'))
-    #testinstance.assertEqual(socket.inet_ntop(socket.AF_INET, dnstap.message.query_address), initiator)
+    testinstance.assertTrue(dnstap.message.HasField('query_address'))
+    testinstance.assertEqual(socket.inet_ntop(socket.AF_INET, dnstap.message.query_address), initiator)
+    testinstance.assertTrue(dnstap.message.HasField('query_port'))
     testinstance.assertTrue(dnstap.message.HasField('response_address'))
-    testinstance.assertEqual(socket.inet_ntop(socket.AF_INET, dnstap.message.response_address), initiator)
+    testinstance.assertEqual(socket.inet_ntop(socket.AF_INET, dnstap.message.response_address), responder)
     testinstance.assertTrue(dnstap.message.HasField('response_port'))
-    testinstance.assertEqual(dnstap.message.response_port, 53)
+    testinstance.assertEqual(dnstap.message.response_port, response_port)
 
 
-def checkDnstapQuery(testinstance, dnstap, protocol, initiator='127.0.0.1'):
+def checkDnstapQuery(testinstance, dnstap, protocol, initiator, responder):
     testinstance.assertEqual(dnstap.message.type, dnstap_pb2.Message.RESOLVER_QUERY)
-    checkDnstapBase(testinstance, dnstap, protocol, initiator)
+    checkDnstapBase(testinstance, dnstap, protocol, initiator, responder)
 
     testinstance.assertTrue(dnstap.message.HasField('query_time_sec'))
     testinstance.assertTrue(dnstap.message.HasField('query_time_nsec'))
@@ -65,6 +67,28 @@ def checkDnstapQuery(testinstance, dnstap, protocol, initiator='127.0.0.1'):
     #wire_message = dns.message.from_wire(dnstap.message.query_message)
     #testinstance.assertEqual(wire_message, query)
 
+def checkDnstapNOD(testinstance, dnstap, protocol, initiator, responder, response_port, query_zone):
+    testinstance.assertEqual(dnstap.message.type, dnstap_pb2.Message.CLIENT_QUERY)
+    checkDnstapBase(testinstance, dnstap, protocol, initiator, responder, response_port)
+
+    testinstance.assertTrue(dnstap.message.HasField('query_time_sec'))
+    testinstance.assertTrue(dnstap.message.HasField('query_time_nsec'))
+
+    testinstance.assertTrue(dnstap.message.HasField('query_zone'))
+    testinstance.assertEqual(dns.name.from_wire(dnstap.message.query_zone, 0)[0].to_text(), query_zone)
+
+def checkDnstapUDR(testinstance, dnstap, protocol, initiator, responder, response_port, query_zone):
+    testinstance.assertEqual(dnstap.message.type, dnstap_pb2.Message.RESOLVER_RESPONSE)
+    checkDnstapBase(testinstance, dnstap, protocol, initiator, responder, response_port)
+
+    testinstance.assertTrue(dnstap.message.HasField('query_time_sec'))
+    testinstance.assertTrue(dnstap.message.HasField('query_time_nsec'))
+
+    testinstance.assertTrue(dnstap.message.HasField('query_zone'))
+    testinstance.assertEqual(dns.name.from_wire(dnstap.message.query_zone, 0)[0].to_text(), query_zone)
+
+    testinstance.assertTrue(dnstap.message.HasField('response_message'))
+    wire_message = dns.message.from_wire(dnstap.message.response_message)
 
 def checkDnstapExtra(testinstance, dnstap, expected):
     testinstance.assertTrue(dnstap.HasField('extra'))
@@ -75,9 +99,9 @@ def checkDnstapNoExtra(testinstance, dnstap):
     testinstance.assertFalse(dnstap.HasField('extra'))
 
 
-def checkDnstapResponse(testinstance, dnstap, protocol, response, initiator='127.0.0.1'):
+def checkDnstapResponse(testinstance, dnstap, protocol, response, initiator, responder):
     testinstance.assertEqual(dnstap.message.type, dnstap_pb2.Message.RESOLVER_RESPONSE)
-    checkDnstapBase(testinstance, dnstap, protocol, initiator)
+    checkDnstapBase(testinstance, dnstap, protocol, initiator, responder)
 
     testinstance.assertTrue(dnstap.message.HasField('query_time_sec'))
     testinstance.assertTrue(dnstap.message.HasField('query_time_nsec'))
@@ -163,13 +187,13 @@ class TestRecursorDNSTap(RecursorTest):
                 fstrm_handle_bidir_connection(conn, lambda data: \
                 param.queue.put(data, True, timeout=2.0))
             except socket.error as e:
-                if e.errno == 9:
+                if e.errno in (errno.EBADF, errno.EPIPE):
                     break
                 sys.stderr.write("Unexpected socket error %s\n" % str(e))
                 sys.exit(1)
             except exception as e:
                 sys.stderr.write("Unexpected socket error %s\n" % str(e))
-                sys.exit(1)                
+                sys.exit(1)
         conn.close()
 
     @classmethod
@@ -193,7 +217,7 @@ class TestRecursorDNSTap(RecursorTest):
                 listener.setDaemon(True)
                 listener.start()
             except socket.error as e:
-                if e.errno != 9:
+                if e.errno != errno.EBADF:
                     sys.stderr.write("Socket error on accept: %s\n" % str(e))
                 else:
                     break
@@ -281,20 +305,15 @@ dnstapFrameStreamServer({"%s"})
         query.flags |= dns.flags.RD
         res = self.sendUDPQuery(query)
         self.assertNotEqual(res, None)
-        
+
         # check the dnstap message corresponding to the UDP query
         dnstap = self.getFirstDnstap()
 
-        checkDnstapQuery(self, dnstap, dnstap_pb2.UDP, '127.0.0.8')
+        checkDnstapQuery(self, dnstap, dnstap_pb2.UDP, '127.0.0.1', '127.0.0.8')
         # We don't expect a response
         checkDnstapNoExtra(self, dnstap)
 
 class DNSTapLogNoQueriesTest(TestRecursorDNSTap):
-    """
-    This test makes sure that we correctly export outgoing queries over DNSTap.
-    It must be improved and setup env so we can check for incoming responses, but makes sure for now
-    that the recursor at least connects to the DNSTap server.
-    """
 
     _confdir = 'DNSTapLogNoQueries'
     _config_template = """
@@ -312,3 +331,141 @@ dnstapFrameStreamServer({"%s"}, {logQueries=false})
 
         # We don't expect anything
         self.assertTrue(DNSTapServerParameters.queue.empty())
+
+class DNSTapLogNODTest(TestRecursorDNSTap):
+    """
+    This test makes sure that we correctly export outgoing queries over DNSTap.
+    It must be improved and setup env so we can check for incoming responses, but makes sure for now
+    that the recursor at least connects to the DNSTap server.
+    """
+
+    _confdir = 'DNSTapLogNODQueries'
+    _config_template = """
+new-domain-tracking=yes
+new-domain-history-dir=configs/%s/nod
+unique-response-tracking=yes
+unique-response-history-dir=configs/%s/udr
+auth-zones=example=configs/%s/example.zone""" % (_confdir, _confdir, _confdir)
+    _lua_config_file = """
+dnstapNODFrameStreamServer({"%s"})
+    """ % (DNSTapServerParameters.path)
+
+    @classmethod
+    def generateRecursorConfig(cls, confdir):
+        for directory in ["nod", "udr"]:
+            path = os.path.join('configs', cls._confdir, directory)
+            cls.createConfigDir(path)
+        super(DNSTapLogNODTest, cls).generateRecursorConfig(confdir)
+
+    def getFirstDnstap(self):
+        try:
+            data = DNSTapServerParameters.queue.get(True, timeout=2.0)
+        except:
+            data = False
+        self.assertTrue(data)
+        dnstap = dnstap_pb2.Dnstap()
+        dnstap.ParseFromString(data)
+        return dnstap
+
+    def testA(self):
+        name = 'www.example.org.'
+        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        query.flags |= dns.flags.RD
+        res = self.sendUDPQuery(query)
+        self.assertNotEqual(res, None)
+
+        # check the dnstap message corresponding to the UDP query
+        dnstap = self.getFirstDnstap()
+
+        checkDnstapNOD(self, dnstap, dnstap_pb2.UDP, '127.0.0.1', '127.0.0.1', 5300, name)
+        # We don't expect a response
+        checkDnstapNoExtra(self, dnstap)
+
+class DNSTapLogUDRTest(TestRecursorDNSTap):
+
+    _confdir = 'DNSTapLogUDRResponses'
+    _config_template = """
+new-domain-tracking=yes
+new-domain-history-dir=configs/%s/nod
+unique-response-tracking=yes
+unique-response-history-dir=configs/%s/udr
+auth-zones=example=configs/%s/example.zone""" % (_confdir, _confdir, _confdir)
+    _lua_config_file = """
+dnstapNODFrameStreamServer({"%s"}, {logNODs=false, logUDRs=true})
+    """ % (DNSTapServerParameters.path)
+
+    @classmethod
+    def generateRecursorConfig(cls, confdir):
+        for directory in ["nod", "udr"]:
+            path = os.path.join('configs', cls._confdir, directory)
+            cls.createConfigDir(path)
+        super(DNSTapLogUDRTest, cls).generateRecursorConfig(confdir)
+
+    def getFirstDnstap(self):
+        try:
+            data = DNSTapServerParameters.queue.get(True, timeout=2.0)
+        except:
+            data = False
+        self.assertTrue(data)
+        dnstap = dnstap_pb2.Dnstap()
+        dnstap.ParseFromString(data)
+        return dnstap
+
+    def testA(self):
+        name = 'types.example.'
+        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        query.flags |= dns.flags.RD
+        res = self.sendUDPQuery(query)
+        self.assertNotEqual(res, None)
+
+        # check the dnstap message corresponding to the UDP query
+        dnstap = self.getFirstDnstap()
+
+        checkDnstapUDR(self, dnstap, dnstap_pb2.UDP, '127.0.0.1', '127.0.0.1', 5300, name)
+        # We don't expect a rpasesponse
+        checkDnstapNoExtra(self, dnstap)
+
+class DNSTapLogNODUDRTest(TestRecursorDNSTap):
+
+    _confdir = 'DNSTapLogNODUDRs'
+    _config_template = """
+new-domain-tracking=yes
+new-domain-history-dir=configs/%s/nod
+unique-response-tracking=yes
+unique-response-history-dir=configs/%s/udr
+auth-zones=example=configs/%s/example.zone""" % (_confdir, _confdir, _confdir)
+    _lua_config_file = """
+dnstapNODFrameStreamServer({"%s"}, {logNODs=true, logUDRs=true})
+    """ % (DNSTapServerParameters.path)
+
+    @classmethod
+    def generateRecursorConfig(cls, confdir):
+        for directory in ["nod", "udr"]:
+            path = os.path.join('configs', cls._confdir, directory)
+            cls.createConfigDir(path)
+        super(DNSTapLogNODUDRTest, cls).generateRecursorConfig(confdir)
+
+    def getFirstDnstap(self):
+        try:
+            data = DNSTapServerParameters.queue.get(True, timeout=2.0)
+        except:
+            data = False
+        self.assertTrue(data)
+        dnstap = dnstap_pb2.Dnstap()
+        dnstap.ParseFromString(data)
+        return dnstap
+
+    def testA(self):
+        name = 'types.example.'
+        query = dns.message.make_query(name, 'A', want_dnssec=True)
+        query.flags |= dns.flags.RD
+        res = self.sendUDPQuery(query)
+        self.assertNotEqual(res, None)
+
+        dnstap = self.getFirstDnstap()
+        checkDnstapUDR(self, dnstap, dnstap_pb2.UDP, '127.0.0.1', '127.0.0.1', 5300, name)
+
+        dnstap = self.getFirstDnstap()
+        checkDnstapNOD(self, dnstap, dnstap_pb2.UDP, '127.0.0.1', '127.0.0.1', 5300, name)
+
+        checkDnstapNoExtra(self, dnstap)