From: Remi Gacogne Date: Thu, 1 Feb 2024 13:44:45 +0000 (+0100) Subject: dnsdist: Add regression tests for eBPF blocks (static / dynamic) X-Git-Tag: dnsdist-1.9.0~12^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9bf515e1e07f2dc7a3b37e14af16f833e59148b0;p=thirdparty%2Fpdns.git dnsdist: Add regression tests for eBPF blocks (static / dynamic) --- diff --git a/regression-tests.dnsdist/dnsdistDynBlockTests.py b/regression-tests.dnsdist/dnsdistDynBlockTests.py index 67f986b585..27b4f3cfa9 100644 --- a/regression-tests.dnsdist/dnsdistDynBlockTests.py +++ b/regression-tests.dnsdist/dnsdistDynBlockTests.py @@ -23,7 +23,7 @@ class DynBlocksTest(DNSDistTest): _dynBlockDuration = _maintenanceWaitTime + 2 _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort'] - def doTestDynBlockViaAPI(self, ipRange, reason, minSeconds, maxSeconds, minBlocks, maxBlocks): + def doTestDynBlockViaAPI(self, ipRange, reason, minSeconds, maxSeconds, minBlocks, maxBlocks, ebpf=False): headers = {'x-api-key': self._webServerAPIKey} url = 'http://127.0.0.1:' + str(self._webServerPort) + '/jsonstat?command=dynblocklist' r = requests.get(url, headers=headers, timeout=self._webTimeout) @@ -35,7 +35,7 @@ class DynBlocksTest(DNSDistTest): self.assertIn(ipRange, content) values = content[ipRange] - for key in ['reason', 'seconds', 'blocks', 'action']: + for key in ['reason', 'seconds', 'blocks', 'action', 'ebpf']: self.assertIn(key, values) self.assertEqual(values['reason'], reason) @@ -43,8 +43,9 @@ class DynBlocksTest(DNSDistTest): self.assertLessEqual(values['seconds'], maxSeconds) self.assertGreaterEqual(values['blocks'], minBlocks) self.assertLessEqual(values['blocks'], maxBlocks) + self.assertEqual(values['ebpf'], True if ebpf else False) - def doTestQRate(self, name, testViaAPI=True): + def doTestQRate(self, name, testViaAPI=True, ebpf=False): query = dns.message.make_query(name, 'A', 'IN') response = dns.message.make_response(query) rrset = dns.rrset.from_text(name, @@ -81,7 +82,7 @@ class DynBlocksTest(DNSDistTest): self.assertEqual(receivedResponse, None) if testViaAPI: - self.doTestDynBlockViaAPI('127.0.0.1/32', 'Exceeded query rate', 1, self._dynBlockDuration, (sent-allowed)+1, (sent-allowed)+1) + self.doTestDynBlockViaAPI('127.0.0.1/32', 'Exceeded query rate', 1, self._dynBlockDuration, (sent-allowed)+1, (sent-allowed)+1, ebpf) # wait until we are not blocked anymore time.sleep(self._dynBlockDuration + self._dynBlockPeriod) diff --git a/regression-tests.dnsdist/dnsdisttests.py b/regression-tests.dnsdist/dnsdisttests.py index d8e0cd9fff..ef2dc35364 100644 --- a/regression-tests.dnsdist/dnsdisttests.py +++ b/regression-tests.dnsdist/dnsdisttests.py @@ -88,6 +88,7 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase): _answerUnexpected = True _checkConfigExpectedOutput = None _verboseMode = False + _sudoMode = False _skipListeningOnCL = False _alternateListeningAddr = None _alternateListeningPort = None @@ -150,6 +151,10 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase): if cls._verboseMode: dnsdistcmd.append('-v') + if cls._sudoMode: + if 'LD_LIBRARY_PATH' in os.environ: + dnsdistcmd.insert(0, 'LD_LIBRARY_PATH=' + os.environ['LD_LIBRARY_PATH']) + dnsdistcmd.insert(0, 'sudo') for acl in cls._acl: dnsdistcmd.extend(['--acl', acl]) @@ -693,7 +698,11 @@ class DNSDistTest(AssertEqualDNSMessageMixin, unittest.TestCase): if useQueue: cls._toResponderQueue.put(response, True, timeout) - sock = cls.openTCPConnection(timeout) + try: + sock = cls.openTCPConnection(timeout) + except socket.timeout as e: + print("Timeout while opening TCP connection: %s" % (str(e))) + return (None, None) try: cls.sendTCPQueryOverConnection(sock, query, rawQuery) diff --git a/regression-tests.dnsdist/test_DynBlocksEBPF.py b/regression-tests.dnsdist/test_DynBlocksEBPF.py new file mode 100644 index 0000000000..8260649968 --- /dev/null +++ b/regression-tests.dnsdist/test_DynBlocksEBPF.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +import dns +import os +import unittest +from dnsdisttests import DNSDistTest +from dnsdistDynBlockTests import DynBlocksTest + +class EBPFTest(object): + pass + +@unittest.skipUnless('ENABLE_SUDO_TESTS' in os.environ, "sudo is not available") +class TestDynBlockEBPFQPS(DynBlocksTest): + + _config_template = """ + bpf = newBPFFilter({ipv4MaxItems=10, ipv6MaxItems=10, qnamesMaxItems=10}) + setDefaultBPFFilter(bpf) + local dbr = dynBlockRulesGroup() + dbr:setQueryRate(%d, %d, "Exceeded query rate", %d) + function maintenance() + dbr:apply() + end + + -- not going to wait 60s! + setDynBlocksPurgeInterval(1) + + -- exercise the manual blocking methods + bpf:block(newCA("2001:DB8::42")) + bpf:blockQName(newDNSName("powerdns.com."), 255) + bpf:getStats() + bpf:unblock(newCA("2001:DB8::42")) + bpf:unblockQName(newDNSName("powerdns.com."), 255) + + newServer{address="127.0.0.1:%s"} + webserver("127.0.0.1:%s") + setWebserverConfig({password="%s", apiKey="%s"}) + """ + _config_params = ['_dynBlockQPS', '_dynBlockPeriod', '_dynBlockDuration', '_testServerPort', '_webServerPort', '_webServerBasicAuthPasswordHashed', '_webServerAPIKeyHashed'] + _sudoMode = True + + def testDynBlocksQRate(self): + """ + Dyn Blocks: QRate + """ + name = 'qrate.dynblocks.tests.powerdns.com.' + self.doTestQRate(name, ebpf=True)