From: Remi Gacogne Date: Mon, 19 Apr 2021 09:13:47 +0000 (+0200) Subject: rec: Add regression tests for Proxy Protocol / ECS interaction X-Git-Tag: rec-4.4.4~2^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f76fbd294837ed22342085f31b557e203516528f;p=thirdparty%2Fpdns.git rec: Add regression tests for Proxy Protocol / ECS interaction (cherry picked from commit 9166ee1b3fc9d5df9b93570d883cf154aa98e425) --- diff --git a/regression-tests.recursor-dnssec/recursortests.py b/regression-tests.recursor-dnssec/recursortests.py index 5051e2f5da..084697f404 100644 --- a/regression-tests.recursor-dnssec/recursortests.py +++ b/regression-tests.recursor-dnssec/recursortests.py @@ -13,6 +13,8 @@ import unittest import dns import dns.message +from proxyprotocol import ProxyProtocol + from eqdnsmessage import AssertEqualDNSMessageMixin @@ -974,3 +976,59 @@ distributor-threads={threads}""".format(confdir=confdir, msg.flags += dns.flags.from_text('RD') msg.use_edns(edns=0, ednsflags=dns.flags.edns_from_text(ednsflags)) return msg + + @classmethod + def sendUDPQueryWithProxyProtocol(cls, query, v6, source, destination, sourcePort, destinationPort, values=[], timeout=2.0): + queryPayload = query.to_wire() + ppPayload = ProxyProtocol.getPayload(False, False, v6, source, destination, sourcePort, destinationPort, values) + payload = ppPayload + queryPayload + + if timeout: + cls._sock.settimeout(timeout) + + try: + cls._sock.send(payload) + data = cls._sock.recv(4096) + except socket.timeout: + data = None + finally: + if timeout: + cls._sock.settimeout(None) + + message = None + if data: + message = dns.message.from_wire(data) + return message + + @classmethod + def sendTCPQueryWithProxyProtocol(cls, query, v6, source, destination, sourcePort, destinationPort, values=[], timeout=2.0): + queryPayload = query.to_wire() + ppPayload = ProxyProtocol.getPayload(False, False, v6, source, destination, sourcePort, destinationPort, values) + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + if timeout: + sock.settimeout(timeout) + + sock.connect(("127.0.0.1", cls._recursorPort)) + + try: + sock.send(ppPayload) + sock.send(struct.pack("!H", len(queryPayload))) + sock.send(queryPayload) + data = sock.recv(2) + if data: + (datalen,) = struct.unpack("!H", data) + data = sock.recv(datalen) + except socket.timeout as e: + print("Timeout: %s" % (str(e))) + data = None + except socket.error as e: + print("Network error: %s" % (str(e))) + data = None + finally: + sock.close() + + message = None + if data: + message = dns.message.from_wire(data) + return message diff --git a/regression-tests.recursor-dnssec/test_ECS.py b/regression-tests.recursor-dnssec/test_ECS.py index d1b80505fa..efed1a9321 100644 --- a/regression-tests.recursor-dnssec/test_ECS.py +++ b/regression-tests.recursor-dnssec/test_ECS.py @@ -499,6 +499,98 @@ forward-zones=ecs-echo.example=%s.21 query = dns.message.make_query(nameECS, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512) self.sendECSQuery(query, expected) +class testECSWithProxyProtocoldRecursorTest(ECSTest): + _confdir = 'ECSWithProxyProtocol' + _config_template = """ + ecs-add-for=2001:db8::1/128 + edns-subnet-allow-list=ecs-echo.example. + forward-zones=ecs-echo.example=%s.21 + proxy-protocol-from=127.0.0.1/32 + allow-from=2001:db8::1/128 +""" % (os.environ['PREFIX']) + + def testProxyProtocolPlusECS(self): + qname = nameECS + expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'TXT', '2001:db8::/56') + + query = dns.message.make_query(qname, 'TXT', use_edns=True) + for method in ("sendUDPQueryWithProxyProtocol", "sendTCPQueryWithProxyProtocol"): + sender = getattr(self, method) + res = sender(query, True, '2001:db8::1', '2001:db8::2', 0, 65535) + self.assertRcodeEqual(res, dns.rcode.NOERROR) + self.assertRRsetInAnswer(res, expected) + +class testTooLargeToAddZeroScope(RecursorTest): + + _confdir = 'TooLargeToAddZeroScope' + _config_template_default = """ +use-incoming-edns-subnet=yes +dnssec=validate +daemon=no +trace=yes +packetcache-ttl=0 +packetcache-servfail-ttl=0 +max-cache-ttl=15 +threads=1 +loglevel=9 +disable-syslog=yes +log-common-errors=yes +""" + _config_template = """ + """ + _lua_dns_script_file = """ + function preresolve(dq) + if dq.qname == newDN('toolarge.ecs.') then + dq:addRecord(pdns.TXT, '%s', pdns.place.ANSWER) + return true + end + return false + end + """ % ('A'*447) + + _roothints = None + + @classmethod + def setUpClass(cls): + + # we don't need all the auth stuff + cls.setUpSockets() + cls.startResponders() + + confdir = os.path.join('configs', cls._confdir) + cls.createConfigDir(confdir) + + cls.generateRecursorConfig(confdir) + cls.startRecursor(confdir, cls._recursorPort) + + @classmethod + def tearDownClass(cls): + cls.tearDownRecursor() + + @classmethod + def generateRecursorConfig(cls, confdir): + super(testTooLargeToAddZeroScope, cls).generateRecursorConfig(confdir) + + def testTooLarge(self): + qname = 'toolarge.ecs.' + ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 24) + query = dns.message.make_query(qname, 'TXT', 'IN', use_edns=True, options=[ecso], payload=512) + + # should not have an ECS Option since the packet is too large already + res = self.sendUDPQuery(query, timeout=5.0) + self.assertRcodeEqual(res, dns.rcode.NOERROR) + self.assertEqual(len(res.answer), 1) + self.assertEqual(res.edns, 0) + self.assertEqual(len(res.options), 0) + + res = self.sendTCPQuery(query, timeout=5.0) + self.assertRcodeEqual(res, dns.rcode.NOERROR) + self.assertEqual(len(res.answer), 1) + self.assertEqual(res.edns, 0) + self.assertEqual(len(res.options), 1) + self.assertEqual(res.options[0].otype, 8) + self.assertEqual(res.options[0].scope, 0) + class UDPECSResponder(DatagramProtocol): @staticmethod def ipToStr(option): diff --git a/regression-tests.recursor-dnssec/test_ProxyProtocol.py b/regression-tests.recursor-dnssec/test_ProxyProtocol.py index fcc489b2bd..8200dcacdc 100644 --- a/regression-tests.recursor-dnssec/test_ProxyProtocol.py +++ b/regression-tests.recursor-dnssec/test_ProxyProtocol.py @@ -11,7 +11,6 @@ except NameError: pass from recursortests import RecursorTest -from proxyprotocol import ProxyProtocol class ProxyProtocolRecursorTest(RecursorTest): @@ -32,62 +31,6 @@ class ProxyProtocolRecursorTest(RecursorTest): def tearDownClass(cls): cls.tearDownRecursor() - @classmethod - def sendUDPQueryWithProxyProtocol(cls, query, v6, source, destination, sourcePort, destinationPort, values=[], timeout=2.0): - queryPayload = query.to_wire() - ppPayload = ProxyProtocol.getPayload(False, False, v6, source, destination, sourcePort, destinationPort, values) - payload = ppPayload + queryPayload - - if timeout: - cls._sock.settimeout(timeout) - - try: - cls._sock.send(payload) - data = cls._sock.recv(4096) - except socket.timeout: - data = None - finally: - if timeout: - cls._sock.settimeout(None) - - message = None - if data: - message = dns.message.from_wire(data) - return message - - @classmethod - def sendTCPQueryWithProxyProtocol(cls, query, v6, source, destination, sourcePort, destinationPort, values=[], timeout=2.0): - queryPayload = query.to_wire() - ppPayload = ProxyProtocol.getPayload(False, False, v6, source, destination, sourcePort, destinationPort, values) - - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - if timeout: - sock.settimeout(timeout) - - sock.connect(("127.0.0.1", cls._recursorPort)) - - try: - sock.send(ppPayload) - sock.send(struct.pack("!H", len(queryPayload))) - sock.send(queryPayload) - data = sock.recv(2) - if data: - (datalen,) = struct.unpack("!H", data) - data = sock.recv(datalen) - except socket.timeout as e: - print("Timeout: %s" % (str(e))) - data = None - except socket.error as e: - print("Network error: %s" % (str(e))) - data = None - finally: - sock.close() - - message = None - if data: - message = dns.message.from_wire(data) - return message - class ProxyProtocolAllowedRecursorTest(ProxyProtocolRecursorTest): _confdir = 'ProxyProtocol' _lua_dns_script_file = """