예제 #1
0
    def testIncomingProxyDest(self):
        """
        Unexpected Proxy Protocol: should be dropped
        """
        name = 'with-proxy-payload.unexpected-protocol-incoming.tests.powerdns.com.'
        query = dns.message.make_query(name, 'A', 'IN')

        # Make sure that the proxy payload does NOT turn into a legal qname
        destAddr = "ff:db8::ffff"
        destPort = 65535
        srcAddr = "ff:db8::ffff"
        srcPort = 65535

        udpPayload = ProxyProtocol.getPayload(False, False, True, srcAddr, destAddr, srcPort, destPort, [ [ 2, b'foo'], [ 3, b'proxy'] ])
        (_, receivedResponse) = self.sendUDPQuery(udpPayload + query.to_wire(), response=None, useQueue=False, rawQuery=True)
        self.assertEqual(receivedResponse, None)

        tcpPayload = ProxyProtocol.getPayload(False, True, True, srcAddr, destAddr, srcPort, destPort, [ [ 2, b'foo'], [ 3, b'proxy'] ])
        wire = query.to_wire()

        receivedResponse = None
        try:
          conn = self.openTCPConnection(2.0)
          conn.send(tcpPayload)
          conn.send(struct.pack("!H", len(wire)))
          conn.send(wire)
          receivedResponse = self.recvTCPResponseOverConnection(conn)
        except socket.timeout:
          print('timeout')
        self.assertEqual(receivedResponse, None)
예제 #2
0
    def testNOTIFY(self):
        """
        Check that NOTIFY is properly accepted/rejected based on the PROXY header inner address
        """

        query = dns.message.make_query('example.org', 'SOA')
        query.set_opcode(dns.opcode.NOTIFY)

        queryPayload = query.to_wire()

        for task in ('192.0.2.1', dns.rcode.NOERROR), ('192.0.2.2',
                                                       dns.rcode.REFUSED):
            ip, expectedrcode = task

            ppPayload = ProxyProtocol.getPayload(False, False, False, ip,
                                                 "10.1.2.3", 12345, 53, [])
            payload = ppPayload + queryPayload

            self._sock.settimeout(2.0)

            try:
                self._sock.send(payload)
                data = self._sock.recv(4096)
            except socket.timeout:
                data = None
            finally:
                self._sock.settimeout(None)

            res = None
            if data:
                res = dns.message.from_wire(data)

            self.assertRcodeEqual(res, expectedrcode)
예제 #3
0
    def testProxyUDPWithValueOverride(self):
        """
        Incoming Proxy Protocol: override existing value (UDP)
        """
        name = 'override.proxy-protocol-incoming.tests.powerdns.com.'
        query = dns.message.make_query(name, 'A', 'IN')
        response = dns.message.make_response(query)

        destAddr = "2001:db8::9"
        destPort = 9999
        srcAddr = "2001:db8::8"
        srcPort = 8888
        response = dns.message.make_response(query)

        udpPayload = ProxyProtocol.getPayload(False, False, True, srcAddr, destAddr, srcPort, destPort, [ [2, b'foo'], [3, b'proxy'], [ 50, b'initial-value']])
        toProxyQueue.put(response, True, 2.0)
        (_, receivedResponse) = self.sendUDPQuery(udpPayload + query.to_wire(), response=None, useQueue=False, rawQuery=True)

        (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
        self.assertTrue(receivedProxyPayload)
        self.assertTrue(receivedDNSData)
        self.assertTrue(receivedResponse)

        receivedQuery = dns.message.from_wire(receivedDNSData)
        receivedQuery.id = query.id
        receivedResponse.id = response.id
        self.assertEqual(receivedQuery, query)
        self.assertEqual(receivedResponse, response)
        self.checkMessageProxyProtocol(receivedProxyPayload, srcAddr, destAddr, False, [ [50, b'overridden'] ], True, srcPort, destPort)
예제 #4
0
    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
예제 #5
0
    def testTooLargeProxyProtocol(self):
        # the total payload (proxy protocol + DNS) is larger than proxy-protocol-maximum-size
        # so it should be dropped
        qname = 'too-large.proxy-protocol.recursor-tests.powerdns.com.'
        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A',
                                       '192.0.2.1')

        query = dns.message.make_query(qname, 'A', want_dnssec=True)
        queryPayload = query.to_wire()
        ppPayload = ProxyProtocol.getPayload(
            False, True, False, '127.0.0.42', '255.255.255.255', 0, 65535,
            [[0, b'foo'], [1, b'A' * 512], [255, b'bar']])
        payload = ppPayload + queryPayload

        # UDP
        self._sock.settimeout(2.0)

        try:
            self._sock.send(payload)
            data = self._sock.recv(4096)
        except socket.timeout:
            data = None
        finally:
            self._sock.settimeout(None)

        res = None
        if data:
            res = dns.message.from_wire(data)
        self.assertEqual(res, None)

        # TCP
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(2.0)
        sock.connect(("127.0.0.1", self._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()

        res = None
        if data:
            res = dns.message.from_wire(data)
        self.assertEqual(res, None)
예제 #6
0
    def testIncomingProxyDest(self):
        """
        Incoming Proxy Protocol: values from Lua
        """
        name = 'get-forwarded-dest.proxy-protocol-incoming.tests.powerdns.com.'
        query = dns.message.make_query(name, 'A', 'IN')
        # dnsdist set RA = RD for spoofed responses
        query.flags &= ~dns.flags.RD

        destAddr = "2001:db8::9"
        destPort = 9999
        srcAddr = "2001:db8::8"
        srcPort = 8888
        response = dns.message.make_response(query)
        rrset = dns.rrset.from_text(
            name, 60, dns.rdataclass.IN, dns.rdatatype.CNAME,
            "address-was-{}-port-was-{}.proxy-protocol-incoming.tests.powerdns.com."
            .format(destAddr, destPort, self._dnsDistPort))
        response.answer.append(rrset)

        udpPayload = ProxyProtocol.getPayload(False, False, True, srcAddr,
                                              destAddr, srcPort, destPort,
                                              [[2, b'foo'], [3, b'proxy']])
        (_, receivedResponse) = self.sendUDPQuery(udpPayload + query.to_wire(),
                                                  response=None,
                                                  useQueue=False,
                                                  rawQuery=True)
        self.assertEqual(receivedResponse, response)

        tcpPayload = ProxyProtocol.getPayload(False, True, True, srcAddr,
                                              destAddr, srcPort, destPort,
                                              [[2, b'foo'], [3, b'proxy']])
        wire = query.to_wire()

        receivedResponse = None
        try:
            conn = self.openTCPConnection(2.0)
            conn.send(tcpPayload)
            conn.send(struct.pack("!H", len(wire)))
            conn.send(wire)
            receivedResponse = self.recvTCPResponseOverConnection(conn)
        except socket.timeout:
            print('timeout')
        self.assertEqual(receivedResponse, response)
예제 #7
0
    def testLocalProxyProtocol(self):
        qname = 'local.proxy-protocol.recursor-tests.powerdns.com.'
        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A',
                                       '192.0.2.255')

        query = dns.message.make_query(qname, 'A', want_dnssec=True)
        queryPayload = query.to_wire()
        ppPayload = ProxyProtocol.getPayload(True, False, False, None, None,
                                             None, None, [])
        payload = ppPayload + queryPayload

        # UDP
        self._sock.settimeout(2.0)

        try:
            self._sock.send(payload)
            data = self._sock.recv(4096)
        except socket.timeout:
            data = None
        finally:
            self._sock.settimeout(None)

        res = None
        if data:
            res = dns.message.from_wire(data)
        self.assertRcodeEqual(res, dns.rcode.NOERROR)
        self.assertRRsetInAnswer(res, expected)

        # TCP
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(2.0)
        sock.connect(("127.0.0.1", self._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()

        res = None
        if data:
            res = dns.message.from_wire(data)
        self.assertRcodeEqual(res, dns.rcode.NOERROR)
        self.assertRRsetInAnswer(res, expected)
예제 #8
0
    def testInvalidMagicProxyProtocol(self):
        qname = 'invalid-magic.proxy-protocol.recursor-tests.powerdns.com.'

        query = dns.message.make_query(qname, 'A', want_dnssec=True)
        queryPayload = query.to_wire()
        ppPayload = ProxyProtocol.getPayload(True, False, False, None, None,
                                             None, None, [])
        ppPayload = b'\x00' + ppPayload[1:]
        payload = ppPayload + queryPayload

        # UDP
        self._sock.settimeout(2.0)

        try:
            self._sock.send(payload)
            data = self._sock.recv(4096)
        except socket.timeout:
            data = None
        finally:
            self._sock.settimeout(None)

        res = None
        if data:
            res = dns.message.from_wire(data)
        self.assertEqual(res, None)

        # TCP
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(2.0)
        sock.connect(("127.0.0.1", self._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()

        res = None
        if data:
            res = dns.message.from_wire(data)
        self.assertEqual(res, None)
예제 #9
0
    def testProxyTCPWithValuesFromLua(self):
        """
        Incoming Proxy Protocol: values from Lua (TCP)
        """
        name = 'values-lua.proxy-protocol-incoming.tests.powerdns.com.'
        query = dns.message.make_query(name, 'A', 'IN')
        response = dns.message.make_response(query)

        destAddr = "2001:db8::9"
        destPort = 9999
        srcAddr = "2001:db8::8"
        srcPort = 8888
        response = dns.message.make_response(query)

        tcpPayload = ProxyProtocol.getPayload(False, True, True, srcAddr,
                                              destAddr, srcPort, destPort,
                                              [[2, b'foo'], [3, b'proxy']])

        toProxyQueue.put(response, True, 2.0)

        wire = query.to_wire()

        receivedResponse = None
        try:
            conn = self.openTCPConnection(2.0)
            conn.send(tcpPayload)
            conn.send(struct.pack("!H", len(wire)))
            conn.send(wire)
            receivedResponse = self.recvTCPResponseOverConnection(conn)
        except socket.timeout:
            print('timeout')
        self.assertEqual(receivedResponse, response)

        (receivedProxyPayload, receivedDNSData) = fromProxyQueue.get(True, 2.0)
        self.assertTrue(receivedProxyPayload)
        self.assertTrue(receivedDNSData)
        self.assertTrue(receivedResponse)

        receivedQuery = dns.message.from_wire(receivedDNSData)
        receivedQuery.id = query.id
        receivedResponse.id = response.id
        self.assertEqual(receivedQuery, query)
        self.assertEqual(receivedResponse, response)
        self.checkMessageProxyProtocol(
            receivedProxyPayload, srcAddr, destAddr, True,
            [[0, b'foo'], [1, b'dnsdist'], [2, b'foo'], [3, b'proxy'],
             [42, b'bar'], [255, b'proxy-protocol']], True, srcPort, destPort)
예제 #10
0
    def testIPv6ProxyProtocolSeveralQueriesOverTCP(self):
        qname = 'several-queries-tcp.proxy-protocol.recursor-tests.powerdns.com.'
        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A',
                                       '192.0.2.1')

        query = dns.message.make_query(qname, 'A', want_dnssec=True)
        queryPayload = query.to_wire()
        ppPayload = ProxyProtocol.getPayload(False, True, True, '::42',
                                             '2001:db8::ff', 0, 65535,
                                             [[0, b'foo'], [255, b'bar']])
        payload = ppPayload + queryPayload

        # TCP
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(2.0)
        sock.connect(("127.0.0.1", self._recursorPort))

        sock.send(ppPayload)

        count = 0
        for idx in range(5):
            try:
                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
                break
            except socket.error as e:
                print("Network error: %s" % (str(e)))
                data = None
                break

            res = None
            if data:
                res = dns.message.from_wire(data)
            self.assertRcodeEqual(res, dns.rcode.NOERROR)
            self.assertRRsetInAnswer(res, expected)
            count = count + 1

        self.assertEqual(count, 5)
        sock.close()
예제 #11
0
    def testTCPOneByteAtATimeProxyProtocol(self):
        qname = 'tcp-one-byte-at-a-time.proxy-protocol.recursor-tests.powerdns.com.'
        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A',
                                       '192.0.2.1')

        query = dns.message.make_query(qname, 'A', want_dnssec=True)
        queryPayload = query.to_wire()
        ppPayload = ProxyProtocol.getPayload(False, True, False, '127.0.0.42',
                                             '255.255.255.255', 0, 65535,
                                             [[0, b'foo'], [255, b'bar']])

        # TCP
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(2.0)
        sock.connect(("127.0.0.1", self._recursorPort))

        try:
            for i in range(len(ppPayload)):
                sock.send(ppPayload[i:i + 1])
                time.sleep(0.01)
            value = struct.pack("!H", len(queryPayload))
            for i in range(len(value)):
                sock.send(value[i:i + 1])
                time.sleep(0.01)
            for i in range(len(queryPayload)):
                sock.send(queryPayload[i:i + 1])
                time.sleep(0.01)

            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()

        res = None
        if data:
            res = dns.message.from_wire(data)
        self.assertRcodeEqual(res, dns.rcode.NOERROR)
        self.assertRRsetInAnswer(res, expected)
예제 #12
0
    def testAXFR(self):
        """
        Check that AXFR is properly accepted/rejected based on the PROXY header inner address
        """

        query = dns.message.make_query('example.org', 'AXFR')

        queryPayload = query.to_wire()

        for task in ('192.0.2.1', dns.rcode.NOTAUTH), (
                '127.0.0.1', dns.rcode.NOTAUTH), ('192.0.2.53',
                                                  dns.rcode.NOERROR):
            ip, expectedrcode = task

            ppPayload = ProxyProtocol.getPayload(False, True, False, ip,
                                                 "10.1.2.3", 12345, 53, [])

            # TCP
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(2.0)
            sock.connect(("127.0.0.1", self._authPort))

            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()

            res = None
            if data:
                res = dns.message.from_wire(data)

            self.assertRcodeEqual(res, expectedrcode)
예제 #13
0
    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
예제 #14
0
    def testWhoAmI(self):
        """
        See if LUA who picks up the inner address from the PROXY protocol
        """

        for testWithECS in True, False:
            # first test with an unproxied query - should get ignored

            options = []
            expectedText = '192.0.2.1/192.0.2.1'

            if testWithECS:
                ecso = clientsubnetoption.ClientSubnetOption('192.0.2.5', 32)
                options.append(ecso)
                expectedText = '192.0.2.1/192.0.2.5'

            query = dns.message.make_query('myip.example.org',
                                           'TXT',
                                           'IN',
                                           use_edns=testWithECS,
                                           options=options,
                                           payload=512)

            res = self.sendUDPQuery(query)

            self.assertEqual(res, None)  # query was ignored correctly

            # now send a proxied query
            queryPayload = query.to_wire()
            ppPayload = ProxyProtocol.getPayload(False, False, False,
                                                 "192.0.2.1", "10.1.2.3",
                                                 12345, 53, [])
            payload = ppPayload + queryPayload

            # UDP
            self._sock.settimeout(2.0)

            try:
                self._sock.send(payload)
                data = self._sock.recv(4096)
            except socket.timeout:
                data = None
            finally:
                self._sock.settimeout(None)

            res = None
            if data:
                res = dns.message.from_wire(data)

            expected = [
                dns.rrset.from_text('myip.example.org.', 0, dns.rdataclass.IN,
                                    'TXT', expectedText)
            ]
            self.assertRcodeEqual(res, dns.rcode.NOERROR)
            self.assertEqual(res.answer, expected)

            # TCP
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(2.0)
            sock.connect(("127.0.0.1", self._authPort))

            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()

            res = None
            if data:
                res = dns.message.from_wire(data)

            self.assertRcodeEqual(res, dns.rcode.NOERROR)
            self.assertEqual(res.answer, expected)