]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Check TLS session resumption for Outgoing TLS connections
authorRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 11 Jun 2021 10:24:46 +0000 (12:24 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 26 Aug 2021 14:30:28 +0000 (16:30 +0200)
regression-tests.dnsdist/test_OutgoingTLS.py

index cb8c19e80360b52f3369eaf581ddfe8202c325e9..6da75473e2f21f876c02692fb72a13392d96b8d7 100644 (file)
@@ -1,5 +1,6 @@
 #!/usr/bin/env python
 import dns
+import requests
 import ssl
 import threading
 import time
@@ -8,11 +9,30 @@ from dnsdisttests import DNSDistTest
 
 class OutgoingTLSTests(object):
 
-    def checkOnlyTLSResponderHit(self):
+    _webTimeout = 2.0
+    _webServerPort = 8083
+    _webServerBasicAuthPassword = 'secret'
+    _webServerAPIKey = 'apisecret'
+    _verboseMode = True
+
+    def checkOnlyTLSResponderHit(self, numberOfTLSQueries=1):
         self.assertNotIn('UDP Responder', self._responsesCounter)
         self.assertNotIn('TCP Responder', self._responsesCounter)
-        self.assertEqual(self._responsesCounter['TLS Responder'], 1)
-        
+        self.assertEqual(self._responsesCounter['TLS Responder'], numberOfTLSQueries)
+
+    def getServerStat(self, key):
+        headers = {'x-api-key': self._webServerAPIKey}
+        url = 'http://127.0.0.1:' + str(self._webServerPort) + '/api/v1/servers/localhost'
+        r = requests.get(url, headers=headers, timeout=self._webTimeout)
+        self.assertTrue(r)
+        self.assertEqual(r.status_code, 200)
+        self.assertTrue(r.json())
+        content = r.json()
+        self.assertTrue(len(content['servers']), 1)
+        server = content['servers'][0]
+        self.assertIn(key, server)
+        return server[key]
+
     def testUDP(self):
         """
         Outgoing TLS: UDP query is sent via TLS
@@ -27,10 +47,23 @@ class OutgoingTLSTests(object):
                                     '127.0.0.1')
         expectedResponse.answer.append(rrset)
 
-        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, expectedResponse)
-        self.assertEqual(query, receivedQuery)
-        self.assertEqual(receivedResponse, expectedResponse)
-        self.checkOnlyTLSResponderHit()
+        numberOfUDPQueries = 10
+        for _ in range(numberOfUDPQueries):
+            (receivedQuery, receivedResponse) = self.sendUDPQuery(query, expectedResponse)
+            self.assertEqual(query, receivedQuery)
+            self.assertEqual(receivedResponse, expectedResponse)
+
+        # there was one TCP query
+        numberOfQueries = numberOfUDPQueries + 1
+        self.checkOnlyTLSResponderHit(numberOfUDPQueries)
+        # our TLS responder does only one query per connection, so we need one for the TCP
+        # query and one for the UDP one (the TCP test is done first)
+        self.assertEqual(self.getServerStat('tcpNewConnections'), numberOfQueries)
+        # we tried to reuse the connection (and then it failed but hey)
+        self.assertEqual(self.getServerStat('tcpReusedConnections'), numberOfQueries - 1)
+        # we resumed the TLS session, though, but since we only learn about that
+        # when the connection is closed, we are off by one
+        self.assertEqual(self.getServerStat('tlsResumptions'), numberOfUDPQueries - 1)
 
     def testTCP(self):
         """
@@ -50,9 +83,17 @@ class OutgoingTLSTests(object):
         self.assertEqual(query, receivedQuery)
         self.assertEqual(receivedResponse, expectedResponse)
         self.checkOnlyTLSResponderHit()
+        self.assertEqual(self.getServerStat('tcpNewConnections'), 1)
+        self.assertEqual(self.getServerStat('tcpReusedConnections'), 0)
+        self.assertEqual(self.getServerStat('tlsResumptions'), 0)
 
 class BrokenOutgoingTLSTests(object):
 
+    _webTimeout = 2.0
+    _webServerPort = 8083
+    _webServerBasicAuthPassword = 'secret'
+    _webServerAPIKey = 'apisecret'
+
     def checkNoResponderHit(self):
         self.assertNotIn('UDP Responder', self._responsesCounter)
         self.assertNotIn('TCP Responder', self._responsesCounter)
@@ -89,9 +130,12 @@ class BrokenOutgoingTLSTests(object):
 
 class TestOutgoingTLSOpenSSL(DNSDistTest, OutgoingTLSTests):
     _tlsBackendPort = 10443
-    _config_params = ['_tlsBackendPort']
+    _config_params = ['_tlsBackendPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
     _config_template = """
+    setMaxTCPClientThreads(1)
     newServer{address="127.0.0.1:%s", tls='openssl', validateCertificates=true, caStore='ca.pem', subjectName='powerdns.com'}
+    webserver("127.0.0.1:%s")
+    setWebserverConfig({password="%s", apiKey="%s"})
     """
 
     @classmethod
@@ -106,15 +150,19 @@ class TestOutgoingTLSOpenSSL(DNSDistTest, OutgoingTLSTests):
 
 class TestOutgoingTLSGnuTLS(DNSDistTest, OutgoingTLSTests):
     _tlsBackendPort = 10444
-    _config_params = ['_tlsBackendPort']
+    _config_params = ['_tlsBackendPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
     _config_template = """
+    setMaxTCPClientThreads(1)
     newServer{address="127.0.0.1:%s", tls='gnutls', validateCertificates=true, caStore='ca.pem', subjectName='powerdns.com'}
+    webserver("127.0.0.1:%s")
+    setWebserverConfig({password="%s", apiKey="%s"})
     """
 
     @classmethod
     def startResponders(cls):
         tlsContext = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
         tlsContext.load_cert_chain('server.chain', 'server.key')
+        tlsContext.keylog_filename = "/tmp/keys"
 
         print("Launching TLS responder..")
         cls._TLSResponder = threading.Thread(name='TLS Responder', target=cls.TCPResponder, args=[cls._tlsBackendPort, cls._toResponderQueue, cls._fromResponderQueue, False, False, None, tlsContext])
@@ -123,9 +171,12 @@ class TestOutgoingTLSGnuTLS(DNSDistTest, OutgoingTLSTests):
 
 class TestOutgoingTLSOpenSSLWrongCertName(DNSDistTest, BrokenOutgoingTLSTests):
     _tlsBackendPort = 10445
-    _config_params = ['_tlsBackendPort']
+    _config_params = ['_tlsBackendPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
     _config_template = """
+    setMaxTCPClientThreads(1)
     newServer{address="127.0.0.1:%s", tls='openssl', validateCertificates=true, caStore='ca.pem', subjectName='not-powerdns.com'}
+    webserver("127.0.0.1:%s")
+    setWebserverConfig({password="%s", apiKey="%s"})
     """
 
     @classmethod
@@ -140,9 +191,12 @@ class TestOutgoingTLSOpenSSLWrongCertName(DNSDistTest, BrokenOutgoingTLSTests):
 
 class TestOutgoingTLSGnuTLSWrongCertName(DNSDistTest, BrokenOutgoingTLSTests):
     _tlsBackendPort = 10446
-    _config_params = ['_tlsBackendPort']
+    _config_params = ['_tlsBackendPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
     _config_template = """
+    setMaxTCPClientThreads(1)
     newServer{address="127.0.0.1:%s", tls='gnutls', validateCertificates=true, caStore='ca.pem', subjectName='not-powerdns.com'}
+    webserver("127.0.0.1:%s")
+    setWebserverConfig({password="%s", apiKey="%s"})
     """
 
     @classmethod
@@ -157,9 +211,12 @@ class TestOutgoingTLSGnuTLSWrongCertName(DNSDistTest, BrokenOutgoingTLSTests):
 
 class TestOutgoingTLSOpenSSLWrongCertNameButNoCheck(DNSDistTest, OutgoingTLSTests):
     _tlsBackendPort = 10447
-    _config_params = ['_tlsBackendPort']
+    _config_params = ['_tlsBackendPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
     _config_template = """
+    setMaxTCPClientThreads(1)
     newServer{address="127.0.0.1:%s", tls='openssl', validateCertificates=false, caStore='ca.pem', subjectName='not-powerdns.com'}
+    webserver("127.0.0.1:%s")
+    setWebserverConfig({password="%s", apiKey="%s"})
     """
 
     @classmethod
@@ -174,9 +231,12 @@ class TestOutgoingTLSOpenSSLWrongCertNameButNoCheck(DNSDistTest, OutgoingTLSTest
 
 class TestOutgoingTLSGnuTLSWrongCertNameButNoCheck(DNSDistTest, OutgoingTLSTests):
     _tlsBackendPort = 10448
-    _config_params = ['_tlsBackendPort']
+    _config_params = ['_tlsBackendPort', '_webServerPort', '_webServerBasicAuthPassword', '_webServerAPIKey']
     _config_template = """
+    setMaxTCPClientThreads(1)
     newServer{address="127.0.0.1:%s", tls='gnutls', validateCertificates=false, caStore='ca.pem', subjectName='not-powerdns.com'}
+    webserver("127.0.0.1:%s")
+    setWebserverConfig({password="%s", apiKey="%s"})
     """
 
     @classmethod