Ejemplo n.º 1
0
    def testSendECS(self):
        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN,
                                       'TXT', '127.0.0.1/32')
        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
        query = dns.message.make_query(nameECS,
                                       'TXT',
                                       'IN',
                                       use_edns=True,
                                       options=[ecso],
                                       payload=512)
        self.sendECSQuery(query, expected)

        # check that a query in a different range is a miss
        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.2', 32)
        query = dns.message.make_query(nameECS,
                                       'TXT',
                                       'IN',
                                       use_edns=True,
                                       options=[ecso],
                                       payload=512)
        self.sendECSQuery(query, expected)
Ejemplo n.º 2
0
    def testRequireNoECS(self):
        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN,
                                       'TXT', '192.168.0.1/32')

        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
        query = dns.message.make_query(nameECS,
                                       'TXT',
                                       'IN',
                                       use_edns=True,
                                       options=[ecso],
                                       payload=512)
        self.sendECSQuery(query, expected, ttlECS)
Ejemplo n.º 3
0
    def testSendECS(self):
        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN,
                                       'TXT', emptyECSText)

        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
        query = dns.message.make_query(nameECS,
                                       'TXT',
                                       'IN',
                                       use_edns=True,
                                       options=[ecso],
                                       payload=512)
        self.sendECSQuery(query, expected)
Ejemplo n.º 4
0
    def testSendECS(self):
        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN,
                                       'TXT', '127.0.0.0/24')
        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
        query = dns.message.make_query(nameECS,
                                       'TXT',
                                       'IN',
                                       use_edns=True,
                                       options=[ecso],
                                       payload=512)
        self.sendECSQuery(query, expected)

        # check that a query in a different ECS range is a hit, because we don't use the incoming ECS
        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.2', 32)
        query = dns.message.make_query(nameECS,
                                       'TXT',
                                       'IN',
                                       use_edns=True,
                                       options=[ecso],
                                       payload=512)
        self.checkECSQueryHit(query, expected)
Ejemplo n.º 5
0
    def testWithEDNSNoECSResponseWithECS(self):
        """
        ECS: Existing EDNS without ECS (BE returning only the ECS option)

        Send a query with EDNS but no ECS value.
        Check that the query received by the responder
        has a valid ECS value and that the response
        received from dnsdist contains an EDNS pseudo-RR.
        This time the response returned by the backend contains
        an ECS option with scope set.
        """
        name = 'withednsnoecs.bereturnsecs.ecs.tests.powerdns.com.'
        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096)
        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
        response = dns.message.make_response(expectedQuery)
        ecsoResponse = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24, scope=24)
        response.use_edns(edns=True, payload=4096, options=[ecsoResponse])
        expectedResponse = dns.message.make_response(query)
        rrset = dns.rrset.from_text(name,
                                    3600,
                                    dns.rdataclass.IN,
                                    dns.rdatatype.A,
                                    '127.0.0.1')
        response.answer.append(rrset)
        expectedResponse.answer.append(rrset)

        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
        self.assertTrue(receivedQuery)
        self.assertTrue(receivedResponse)
        receivedQuery.id = expectedQuery.id
        self.checkQueryEDNSWithECS(expectedQuery, receivedQuery)
        self.checkResponseEDNSWithoutECS(expectedResponse, receivedResponse)

        (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
        self.assertTrue(receivedQuery)
        self.assertTrue(receivedResponse)
        receivedQuery.id = expectedQuery.id
        self.checkQueryEDNSWithECS(expectedQuery, receivedQuery)
        self.checkResponseEDNSWithoutECS(expectedResponse, receivedResponse)
Ejemplo n.º 6
0
    def testRequireNoECS(self):
        # we will get ::1 because ecs-scope-zero-addr is set to ::1
        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN,
                                       'TXT', '::1/128')

        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
        query = dns.message.make_query(nameECS,
                                       'TXT',
                                       'IN',
                                       use_edns=True,
                                       options=[ecso],
                                       payload=512)
        self.sendECSQuery(query, expected, ttlECS)
Ejemplo n.º 7
0
    def testWithoutEDNSResponseWithECS(self):
        """
        ECS: No existing EDNS (BE returning ECS)

        Send a query without EDNS, check that the query
        received by the responder has the correct ECS value
        and that the response received from dnsdist does not
        have an EDNS pseudo-RR.
        This time the response returned by the backend contains
        an ECS option with scope set.
        """
        name = 'withoutedns.bereturnsecs.ecs.tests.powerdns.com.'
        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
        query = dns.message.make_query(name, 'A', 'IN')
        expectedQuery = dns.message.make_query(name,
                                               'A',
                                               'IN',
                                               use_edns=True,
                                               options=[ecso],
                                               payload=512)
        response = dns.message.make_response(expectedQuery)
        ecsoResponse = clientsubnetoption.ClientSubnetOption('127.0.0.1',
                                                             24,
                                                             scope=24)
        response.use_edns(edns=True, payload=4096, options=[ecsoResponse])
        expectedResponse = dns.message.make_response(query)
        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN,
                                    dns.rdatatype.A, '127.0.0.1')
        response.answer.append(rrset)
        expectedResponse.answer.append(rrset)

        for method in ("sendUDPQuery", "sendTCPQuery"):
            sender = getattr(self, method)
            (receivedQuery, receivedResponse) = sender(query, response)
            self.assertTrue(receivedQuery)
            self.assertTrue(receivedResponse)
            receivedQuery.id = expectedQuery.id
            self.checkQueryEDNSWithECS(expectedQuery, receivedQuery)
            self.checkResponseNoEDNS(expectedResponse, receivedResponse)
Ejemplo n.º 8
0
    def testRequireNoECS(self):
        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN,
                                       'TXT', '127.0.0.0/24')

        # the request for no ECS is ignored because use-incoming-edns-subnet is not set
        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
        query = dns.message.make_query(nameECS,
                                       'TXT',
                                       'IN',
                                       use_edns=True,
                                       options=[ecso],
                                       payload=512)
        self.sendECSQuery(query, expected)
Ejemplo n.º 9
0
    def testLatlonloc(self):
        """
        Basic latlonloc() test
        """
        name = 'latlonloc.geo.example.org.'
        expected = dns.rrset.from_text(name, 0,dns.rdataclass.IN, 'TXT',
                                       '"47 54 46.8 N 122 18 15.12 W 0.00m 1.00m 10000.00m 10.00m"')
        ecso = clientsubnetoption.ClientSubnetOption('1.2.3.0', 24)
        query = dns.message.make_query(name, 'TXT', 'IN', use_edns=True, payload=4096, options=[ecso])

        res = self.sendUDPQuery(query)
        self.assertRcodeEqual(res, dns.rcode.NOERROR)
        self.assertRRsetInAnswer(res, expected)
Ejemplo n.º 10
0
    def testWithEDNSSameSizeInitialECS(self):
        """
        ECS Override: Existing EDNS with ECS (same)

        Send a query with EDNS and a crafted ECS value.
        Check that the query received by the responder
        has an overwritten ECS value (not the initial one)
        and that the response received from dnsdist contains
        an EDNS pseudo-RR.
        The initial ECS value is exactly the same size as
        the one it will replaced with.
        """
        name = 'withednsecs.overridden.ecs.tests.powerdns.com.'
        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 24)
        rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
        expectedQuery = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[rewrittenEcso])
        response = dns.message.make_response(query)
        response.use_edns(edns=True, payload=4096, options=[rewrittenEcso])
        rrset = dns.rrset.from_text(name,
                                    3600,
                                    dns.rdataclass.IN,
                                    dns.rdatatype.A,
                                    '127.0.0.1')
        response.answer.append(rrset)

        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
        self.assertTrue(receivedQuery)
        self.assertTrue(receivedResponse)
        receivedQuery.id = expectedQuery.id
        self.checkQueryEDNSWithECS(expectedQuery, receivedQuery)
        self.checkResponseEDNSWithECS(response, receivedResponse)

        (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
        self.assertTrue(receivedQuery)
        self.assertTrue(receivedResponse)
        receivedQuery.id = expectedQuery.id
        self.checkQueryEDNSWithECS(expectedQuery, receivedQuery)
        self.checkResponseEDNSWithECS(response, receivedResponse)
Ejemplo n.º 11
0
    def testTeeWithECS(self):
        """
        TeeAction: ECS
        """
        name = 'ecs.tee.tests.powerdns.com.'
        query = dns.message.make_query(name, 'A', 'IN')
        response = dns.message.make_response(query)

        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN,
                                    dns.rdatatype.A, '192.0.2.1')
        response.answer.append(rrset)

        numberOfQueries = 10
        for _ in range(numberOfQueries):
            # push the response to the Tee server
            self._toTeeQueue.put(response, True, 2.0)

            (receivedQuery,
             receivedResponse) = self.sendUDPQuery(query, response)
            self.assertTrue(receivedQuery)
            self.assertTrue(receivedResponse)
            receivedQuery.id = query.id
            self.assertEquals(query, receivedQuery)
            self.assertEquals(response, receivedResponse)

            # retrieve the query from the Tee server
            teedQuery = self._fromTeeQueue.get(True, 2.0)
            ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
            expectedQuery = dns.message.make_query(name,
                                                   'A',
                                                   'IN',
                                                   use_edns=True,
                                                   options=[ecso],
                                                   payload=512)
            expectedQuery.id = query.id
            self.checkQueryEDNSWithECS(expectedQuery, teedQuery)

        # check the TeeAction stats
        stats = self.sendConsoleCommand("getAction(0):printStats()")
        self.assertEquals(
            stats, """noerrors\t%d
nxdomains\t0
other-rcode\t0
queries\t%d
recv-errors\t0
refuseds\t0
responses\t%d
send-errors\t0
servfails\t0
tcp-drops\t0
""" % (numberOfQueries, numberOfQueries, numberOfQueries))
Ejemplo n.º 12
0
    def testWithECSOverrideSetViaLua(self):
        """
        ECS Override: set via Lua
        """
        name = 'overriddenvialua.ecsrules.tests.powerdns.com.'
        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 24)
        rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
        query = dns.message.make_query(name,
                                       'A',
                                       'IN',
                                       use_edns=True,
                                       payload=4096,
                                       options=[ecso])
        expectedQuery = dns.message.make_query(name,
                                               'A',
                                               'IN',
                                               use_edns=True,
                                               payload=4096,
                                               options=[rewrittenEcso])
        response = dns.message.make_response(query)
        response.use_edns(edns=True, payload=4096, options=[rewrittenEcso])
        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN,
                                    dns.rdatatype.A, '127.0.0.1')
        response.answer.append(rrset)

        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
        self.assertTrue(receivedQuery)
        self.assertTrue(receivedResponse)
        receivedQuery.id = expectedQuery.id
        self.checkQueryEDNSWithECS(expectedQuery, receivedQuery)
        self.checkResponseEDNSWithECS(response, receivedResponse)

        (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
        self.assertTrue(receivedQuery)
        self.assertTrue(receivedResponse)
        receivedQuery.id = expectedQuery.id
        self.checkQueryEDNSWithECS(expectedQuery, receivedQuery)
        self.checkResponseEDNSWithECS(response, receivedResponse)
Ejemplo n.º 13
0
    def testRequireNoECS(self):
        # we should get ::1/128 because neither ecs-scope-zero-addr nor query-local-address are set,
        # but query-local-address6 is set to ::1
        expected = dns.rrset.from_text(nameECS, ttlECS, dns.rdataclass.IN,
                                       'TXT', "::1/128")

        ecso = clientsubnetoption.ClientSubnetOption('0.0.0.0', 0)
        query = dns.message.make_query(nameECS,
                                       'TXT',
                                       'IN',
                                       use_edns=True,
                                       options=[ecso],
                                       payload=512)
        self.sendECSQuery(query, expected, ttlECS)
Ejemplo n.º 14
0
 def testSubnet(self):
     name = 'gettag-subnet.lua.'
     subnet = '192.0.2.255'
     subnetMask = 32
     ecso = clientsubnetoption.ClientSubnetOption(subnet, subnetMask)
     expected = [
         dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', '192.0.2.1'),
         dns.rrset.from_text_list(name, 0, dns.rdataclass.IN, 'TXT', [name, 'gettag-qtype-1', 'edns-subnet-' + subnet + '/' + str(subnetMask),
                                                                      'ednsoption-8-count-1', 'ednsoption-8-total-len-8']),
         ]
     query = dns.message.make_query(name, 'A', want_dnssec=True, options=[ecso])
     query.flags |= dns.flags.CD
     res = self.sendUDPQuery(query)
     self.assertResponseMatches(query, expected, res)
Ejemplo n.º 15
0
    def testSendECSInvalidScope(self):
        # test that the recursor does not cache with a more specific scope than the source it sent
        expected = dns.rrset.from_text(nameECSInvalidScope, ttlECS,
                                       dns.rdataclass.IN, 'TXT',
                                       '192.0.2.0/24')

        ecso = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
        query = dns.message.make_query(nameECSInvalidScope,
                                       'TXT',
                                       'IN',
                                       use_edns=True,
                                       options=[ecso],
                                       payload=512)

        self.sendECSQuery(query, expected)
Ejemplo n.º 16
0
    def testWithEDNSNoECS(self):
        """
        ECS: Existing EDNS without ECS

        Send a query with EDNS but no ECS value.
        Check that the query received by the responder
        has a valid ECS value and that the response
        received from dnsdist contains an EDNS pseudo-RR.
        """
        name = 'withednsnoecs.ecs.tests.powerdns.com.'
        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
        query = dns.message.make_query(name,
                                       'A',
                                       'IN',
                                       use_edns=True,
                                       payload=4096)
        expectedQuery = dns.message.make_query(name,
                                               'A',
                                               'IN',
                                               use_edns=True,
                                               payload=4096,
                                               options=[ecso])
        response = dns.message.make_response(expectedQuery)
        expectedResponse = dns.message.make_response(query)
        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN,
                                    dns.rdatatype.A, '127.0.0.1')
        response.answer.append(rrset)
        expectedResponse.answer.append(rrset)

        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
        self.assertTrue(receivedQuery)
        self.assertTrue(receivedResponse)
        receivedQuery.id = expectedQuery.id
        self.assertEquals(expectedQuery, receivedQuery)
        self.assertEquals(expectedResponse, receivedResponse)
        self.assertEquals(receivedResponse.edns, 0)
        self.assertEquals(len(receivedResponse.options), 0)

        (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
        self.assertTrue(receivedQuery)
        self.assertTrue(receivedResponse)
        receivedQuery.id = expectedQuery.id
        self.assertEquals(expectedQuery, receivedQuery)
        self.assertEquals(expectedResponse, receivedResponse)
        self.assertEquals(receivedResponse.edns, 0)
        self.assertEquals(len(receivedResponse.options), 0)
Ejemplo n.º 17
0
    def testClosest(self):
        """
        Basic pickclosest() test
        """
        queries = [
            ('1.1.1.0', 24,  '1.1.1.2'),
            ('1.2.3.0', 24,  '1.2.3.4'),
            ('17.1.0.0', 16, '1.1.1.2')
        ]
        name = 'closest.geo.example.org.'
        for (subnet, mask, ip) in queries:
            ecso = clientsubnetoption.ClientSubnetOption(subnet, mask)
            query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])
            expected = dns.rrset.from_text(name, 0, dns.rdataclass.IN, 'A', ip)

            res = self.sendUDPQuery(query)
            self.assertRcodeEqual(res, dns.rcode.NOERROR)
            self.assertRRsetInAnswer(res, expected)
Ejemplo n.º 18
0
    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)
Ejemplo n.º 19
0
def query_nameserver(nameserver, name):
    """
    Do a DNS query against a specified  nameserver
    """
    LOG.debug("Querying {0} for {1}".format(nameserver, name))
    qname = dns.name.from_text(name)
    cso = clientsubnetoption.ClientSubnetOption(get_external_ip())
    message = dns.message.make_query(qname, 'A')
    message.use_edns(options=[cso])
    try:
        r = dns.query.udp(message, nameserver, timeout=DNS_TIMEOUT, port=53)
    except dns.exception.Timeout:
        return 'TIMEOUT'

    ns_rrset = r.find_rrset(r.answer, qname, dns.rdataclass.IN,
                            dns.rdatatype.A)
    for rr in ns_rrset:
        DNS_REQUESTS.inc()
        return rr
Ejemplo n.º 20
0
    def testWithoutEDNS(self):
        """
        ECS Override: No existing EDNS

        Send a query without EDNS, check that the query
        received by the responder has the correct ECS value
        and that the response received from dnsdist does not
        have an EDNS pseudo-RR.
        """
        name = 'withoutedns.overriden.ecs.tests.powerdns.com.'
        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
        query = dns.message.make_query(name, 'A', 'IN')
        expectedQuery = dns.message.make_query(name,
                                               'A',
                                               'IN',
                                               use_edns=True,
                                               options=[ecso],
                                               payload=512)
        response = dns.message.make_response(expectedQuery)
        expectedResponse = dns.message.make_response(query)
        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN,
                                    dns.rdatatype.A, '127.0.0.1')
        response.answer.append(rrset)
        expectedResponse.answer.append(rrset)

        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
        self.assertTrue(receivedQuery)
        self.assertTrue(receivedResponse)
        receivedQuery.id = expectedQuery.id
        self.assertEquals(expectedQuery, receivedQuery)
        self.assertEquals(expectedResponse, receivedResponse)
        self.assertEquals(receivedResponse.edns, -1)
        self.assertEquals(len(receivedResponse.options), 0)

        (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
        self.assertTrue(receivedQuery)
        self.assertTrue(receivedResponse)
        receivedQuery.id = expectedQuery.id
        self.assertEquals(expectedQuery, receivedQuery)
        self.assertEquals(expectedResponse, receivedResponse)
        self.assertEquals(receivedResponse.edns, -1)
        self.assertEquals(len(receivedResponse.options), 0)
Ejemplo n.º 21
0
    def testAWithECS(self):
        """
        Basics: A query with an ECS value
        """
        name = 'awithecs.tests.powerdns.com.'
        ecso = clientsubnetoption.ClientSubnetOption('1.2.3.4')
        query = dns.message.make_query(name, 'A', 'IN', use_edns=True, options=[ecso])
        response = dns.message.make_response(query)
        rrset = dns.rrset.from_text(name,
                                    60,
                                    dns.rdataclass.IN,
                                    dns.rdatatype.A,
                                    '127.0.0.1')

        response.answer.append(rrset)

        for method in ("sendUDPQuery", "sendTCPQuery"):
            sender = getattr(self, method)
            (receivedQuery, receivedResponse) = sender(query, response)
            receivedQuery.id = query.id
            self.assertEquals(query, receivedQuery)
            self.assertEquals(response, receivedResponse)
Ejemplo n.º 22
0
    def testWithEDNSECS(self):
        """
        ECS: Existing EDNS with ECS

        Send a query with EDNS and a crafted ECS value.
        Check that the query received by the responder
        has the initial ECS value (not overwritten)
        and that the response received from dnsdist contains
        an EDNS pseudo-RR.
        """
        name = 'withednsecs.ecs.tests.powerdns.com.'
        ecso = clientsubnetoption.ClientSubnetOption('1.2.3.4', 24)
        query = dns.message.make_query(name,
                                       'A',
                                       'IN',
                                       use_edns=True,
                                       payload=4096,
                                       options=[ecso])
        response = dns.message.make_response(query)
        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN,
                                    dns.rdatatype.A, '127.0.0.1')
        response.answer.append(rrset)

        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
        self.assertTrue(receivedQuery)
        self.assertTrue(receivedResponse)
        receivedQuery.id = query.id
        receivedResponse.id = response.id
        self.assertEquals(query, receivedQuery)
        self.assertEquals(response, receivedResponse)

        (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
        self.assertTrue(receivedQuery)
        self.assertTrue(receivedResponse)
        receivedQuery.id = query.id
        receivedResponse.id = response.id
        self.assertEquals(query, receivedQuery)
        self.assertEquals(response, receivedResponse)
Ejemplo n.º 23
0
def responseCallback(request):
    if len(request.question) != 1:
        print("Skipping query with question count %d" % (len(request.question)))
        return None
    healthCheck = str(request.question[0].name).endswith('a.root-servers.net.')
    if healthCheck:
        response = dns.message.make_response(request)
        return response.to_wire()
    # now we create a broken response
    response = dns.message.make_response(request)
    ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 32)
    response.use_edns(edns=True, payload=4096, options=[ecso])
    rrset = dns.rrset.from_text(request.question[0].name,
                                3600,
                                dns.rdataclass.IN,
                                dns.rdatatype.A,
                                '127.0.0.1')
    response.answer.append(rrset)
    raw = response.to_wire()
    # first label length of this rrset is at 12 (dnsheader) + length(qname) + 2 (leading label length + trailing 0) + 2 (qtype) + 2 (qclass)
    offset = 12 + len(str(request.question[0].name)) + 2 + 2 + 2
    altered = raw[:offset] + b'\xff' + raw[offset+1:]
    return altered
Ejemplo n.º 24
0
    def testCookie(self):
        """
        EDNS Options: Cookie (adding ECS)
        """
        name = 'cookie.ednsoptions-ecs.tests.powerdns.com.'
        eco = cookiesoption.CookiesOption('deadbeef', 'deadbeef')
        query = dns.message.make_query(name,
                                       'A',
                                       'IN',
                                       use_edns=True,
                                       payload=4096,
                                       options=[eco])
        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
        expectedQuery = dns.message.make_query(name,
                                               'A',
                                               'IN',
                                               use_edns=True,
                                               options=[eco, ecso],
                                               payload=512)
        response = dns.message.make_response(query)
        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN,
                                    dns.rdatatype.A, '127.0.0.1')
        response.answer.append(rrset)

        (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response)
        self.assertTrue(receivedQuery)
        self.assertTrue(receivedResponse)
        receivedQuery.id = expectedQuery.id
        self.checkQueryEDNSWithECS(expectedQuery, receivedQuery, 1)
        self.checkResponseEDNSWithoutECS(response, receivedResponse)

        (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response)
        self.assertTrue(receivedQuery)
        self.assertTrue(receivedResponse)
        receivedQuery.id = expectedQuery.id
        self.checkQueryEDNSWithECS(expectedQuery, receivedQuery, 1)
        self.checkResponseEDNSWithoutECS(response, receivedResponse)
Ejemplo n.º 25
0
    def testDOHExistingEDNS(self):
        """
        DOH with ECS: Existing EDNS
        """
        name = 'existing-edns.doh-ecs.tests.powerdns.com.'
        query = dns.message.make_query(name,
                                       'A',
                                       'IN',
                                       use_edns=True,
                                       payload=8192)
        query.id = 0
        rewrittenEcso = clientsubnetoption.ClientSubnetOption('127.0.0.0', 24)
        expectedQuery = dns.message.make_query(name,
                                               'A',
                                               'IN',
                                               use_edns=True,
                                               payload=8192,
                                               options=[rewrittenEcso])
        response = dns.message.make_response(query)
        rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN,
                                    dns.rdatatype.A, '127.0.0.1')
        response.answer.append(rrset)

        (receivedQuery,
         receivedResponse) = self.sendDOHQuery(self._dohServerPort,
                                               self._serverName,
                                               self._dohBaseURL,
                                               query,
                                               response=response,
                                               caFile=self._caCert)
        self.assertTrue(receivedQuery)
        self.assertTrue(receivedResponse)
        receivedQuery.id = expectedQuery.id
        self.assertEquals(expectedQuery, receivedQuery)
        self.assertEquals(response, receivedResponse)
        self.checkQueryEDNSWithECS(expectedQuery, receivedQuery)
        self.checkResponseEDNSWithoutECS(response, receivedResponse)
Ejemplo n.º 26
0
    def testClosestMagic(self):
        """
        Basic closestMagic() test
        """
        name = 'www-balanced.example.org.'
        cname = '1-1-1-3.17-1-2-4.1-2-3-5.magic.example.org.'
        queries = [
            ('1.1.1.0', 24,  '1.1.1.3'),
            ('1.2.3.0', 24,  '1.2.3.5'),
            ('17.1.0.0', 16, '17.1.2.4')
        ]
                
        for (subnet, mask, ip) in queries:
            ecso = clientsubnetoption.ClientSubnetOption(subnet, mask)
            query = dns.message.make_query(name, 'A', 'IN', use_edns=True, payload=4096, options=[ecso])

            response = dns.message.make_response(query)

            response.answer.append(dns.rrset.from_text(name, 0, dns.rdataclass.IN, dns.rdatatype.CNAME, cname))
            response.answer.append(dns.rrset.from_text(cname, 0, dns.rdataclass.IN, 'A', ip))

            res = self.sendUDPQuery(query)
            self.assertRcodeEqual(res, dns.rcode.NOERROR)
            self.assertEqual(res.answer, response.answer)
Ejemplo n.º 27
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)
Ejemplo n.º 28
0
def main(arguments):

    # default: start from 1.0.0.0
    IP_binary = struct.unpack('!L', socket.inet_aton(arguments.start))[0]
    step = 24  # /24 is the minium step

    mask = step
    suggested_mask = step  # the mask suggested by DNS response

    pool = {}  # the mapping results

    count = 1
    timeout = 0
    failed = 0
    isFailed = False

    # # first, restore the current states from last time
    # if os.path.isfile(CACHE_FILE):
    #     with open(CACHE_FILE, 'rb') as f:
    #         pool = pickle.load(f)

    if os.path.isfile(NOW_FILE):
        with open(NOW_FILE, 'rb') as f:
            IP_binary = pickle.load(f)
    # load geo ip data
    READER = geoip2.database.Reader('./geoip/GeoLite2-City.mmdb')
    print("准备就绪")
    # main loop over all IPs
    # while IP_binary < 255*(1<<24): #255.0.0.0
    while IP_binary < 2 * (1 << 24):  # 1.0.0.0
        IP_pack = struct.pack('!L', IP_binary)
        IP = socket.inet_ntoa(IP_pack)

        # skip private IP
        if not good_IP(IP, READER):
            IP_binary = advance(IP_binary, mask)
            continue
        # skip google IP as their locations are all reported as MTV
        googlemask = isGoogleIP(IP_binary)
        if googlemask > 0:
            IP_binary = advance(IP_binary, googlemask)
            continue
        # creat the query message
        cso = clientsubnetoption.ClientSubnetOption(IP, bits=mask)
        print(IP, cso)
        print("CSO打印完啦")
        # default: 'google'
        message = dns.message.make_query(CDN[arguments.name], 'A')
        message.use_edns(options=[cso])
        print(message)
        print("Message打印完啦")
        try:
            # rotating the DNS server we use
            r = dns.query.udp(message,
                              DNS_servers[count % len(DNS_servers)],
                              timeout=arguments.timeout)
            print(r)
            print("打印完啦")
        except dns.exception.Timeout:
            timeout += 1
            print('timeout:', DNS_servers[count % len(DNS_servers)], IP)
            IP_binary = advance(IP_binary, mask)
            continue

        # only use A record here because it seems enough
        servers = {}
        for ans in r.answer:
            if ans.to_rdataset().rdtype == dns.rdatatype.A:
                # use /24 prefix to represent
                # all the servers in the same location
                server = networkMask(ans[0].to_text(), 24)
                servers[server] = 1
        print(servers)
        # if ENDS0 is used, get the suggested mask.
        for options in r.options:
            if isinstance(options, clientsubnetoption.ClientSubnetOption):
                suggested_mask = int(options.scope)

        if len(servers) > 0:
            for server in servers:
                clients = pool.get(server, [])
                clients.append((IP, suggested_mask))
                pool[server] = clients
                isFailed = False
        else:
            failed += 1
            print(r.answer)
            print ('failed:', DNS_servers[count%len(DNS_servers)],\
                            IP, suggested_mask)
            isFailed = True

        if suggested_mask == 0:
            # suggested == 0 *might* imply EDNS0 is not supported
            mask = step
        elif suggested_mask == 32:
            # suggested == 0 *might* imply
            # the EDNS0 record for this prefix is not set
            mask = 17  # rule of thumb: take a big step forward
        else:
            mask = suggested_mask

        IP_binary = advance(IP_binary, mask)
        count += 1
        print(pool)
        break

        # save and report every 500 prefixes
        if count % 500 == 0:
            print(IP, mask, suggested_mask)
            print("Servers %d, errors %d/%d" % (len(pool), timeout, failed))
            # start another thread to save so that it will not be interrupted
            # by signals such as ctrl+c
            a = Thread(target=save_states, args=(pool, IP_binary))
            a.start()
            a.join()
        if isFailed:
            # might need to slow down because we sent too many requests
            # rule of thumb: 90 seconds should be enough
            time.sleep(arguments.cooldown)
        else:
            time.sleep(arguments.delay)
    def testWithEDNSNoOptions(self):
        """
        EDNS on Self-Generated: EDNS with options in the query
        """
        name = 'edns-options.rcode.edns-self.tests.powerdns.com.'
        ecso = clientsubnetoption.ClientSubnetOption('127.0.0.1', 24)
        query = dns.message.make_query(name,
                                       'A',
                                       'IN',
                                       use_edns=True,
                                       options=[ecso],
                                       payload=512,
                                       want_dnssec=True)
        expectedResponse = dns.message.make_response(query)
        expectedResponse.set_rcode(dns.rcode.REFUSED)

        (_, receivedResponse) = self.sendUDPQuery(query,
                                                  response=None,
                                                  useQueue=False)
        self.checkMessageEDNSWithoutOptions(expectedResponse, receivedResponse)
        self.assertTrue(receivedResponse.ednsflags & dns.flags.DO)
        self.assertEquals(receivedResponse.payload, 1042)

        (_, receivedResponse) = self.sendTCPQuery(query,
                                                  response=None,
                                                  useQueue=False)
        self.checkMessageEDNSWithoutOptions(expectedResponse, receivedResponse)
        self.assertTrue(receivedResponse.ednsflags & dns.flags.DO)
        self.assertEquals(receivedResponse.payload, 1042)

        name = 'edns-options.tc.edns-self.tests.powerdns.com.'
        query = dns.message.make_query(name,
                                       'A',
                                       'IN',
                                       use_edns=True,
                                       options=[ecso],
                                       payload=512,
                                       want_dnssec=True)
        expectedResponse = dns.message.make_response(query)
        expectedResponse.flags |= dns.flags.TC

        (_, receivedResponse) = self.sendUDPQuery(query,
                                                  response=None,
                                                  useQueue=False)
        self.checkMessageEDNSWithoutOptions(expectedResponse, receivedResponse)
        self.assertTrue(receivedResponse.ednsflags & dns.flags.DO)
        self.assertEquals(receivedResponse.payload, 1042)

        (_, receivedResponse) = self.sendTCPQuery(query,
                                                  response=None,
                                                  useQueue=False)
        self.checkMessageEDNSWithoutOptions(expectedResponse, receivedResponse)
        self.assertTrue(receivedResponse.ednsflags & dns.flags.DO)
        self.assertEquals(receivedResponse.payload, 1042)

        name = 'edns-options.lua.edns-self.tests.powerdns.com.'
        query = dns.message.make_query(name,
                                       'A',
                                       'IN',
                                       use_edns=True,
                                       options=[ecso],
                                       payload=512,
                                       want_dnssec=True)
        expectedResponse = dns.message.make_response(query)
        expectedResponse.set_rcode(dns.rcode.NXDOMAIN)

        (_, receivedResponse) = self.sendUDPQuery(query,
                                                  response=None,
                                                  useQueue=False)
        self.checkMessageEDNSWithoutOptions(expectedResponse, receivedResponse)
        self.assertTrue(receivedResponse.ednsflags & dns.flags.DO)
        self.assertEquals(receivedResponse.payload, 1042)

        (_, receivedResponse) = self.sendTCPQuery(query,
                                                  response=None,
                                                  useQueue=False)
        self.checkMessageEDNSWithoutOptions(expectedResponse, receivedResponse)
        self.assertTrue(receivedResponse.ednsflags & dns.flags.DO)
        self.assertEquals(receivedResponse.payload, 1042)

        name = 'edns-options.spoof.edns-self.tests.powerdns.com.'
        query = dns.message.make_query(name,
                                       'A',
                                       'IN',
                                       use_edns=True,
                                       options=[ecso],
                                       payload=512,
                                       want_dnssec=True)
        # dnsdist set RA = RD for spoofed responses
        query.flags &= ~dns.flags.RD
        expectedResponse = dns.message.make_response(query)
        expectedResponse.answer.append(
            dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A,
                                '192.0.2.1', '192.0.2.2'))

        (_, receivedResponse) = self.sendUDPQuery(query,
                                                  response=None,
                                                  useQueue=False)
        self.checkMessageEDNSWithoutOptions(expectedResponse, receivedResponse)
        self.assertTrue(receivedResponse.ednsflags & dns.flags.DO)
        self.assertEquals(receivedResponse.payload, 1042)

        (_, receivedResponse) = self.sendTCPQuery(query,
                                                  response=None,
                                                  useQueue=False)
        self.checkMessageEDNSWithoutOptions(expectedResponse, receivedResponse)
        self.assertTrue(receivedResponse.ednsflags & dns.flags.DO)
        self.assertEquals(receivedResponse.payload, 1042)
Ejemplo n.º 30
0
    def testPacketCache(self):
        # first query, no cookie
        qname = 'a.example.'
        query = dns.message.make_query(qname, 'A', want_dnssec=True)
        expected = dns.rrset.from_text(qname, 0, dns.rdataclass.IN, 'A',
                                       '192.0.2.42')

        for method in ("sendUDPQuery", "sendTCPQuery"):
            sender = getattr(self, method)
            res = sender(query)
            self.assertRcodeEqual(res, dns.rcode.NOERROR)
            self.assertRRsetInAnswer(res, expected)

        self.checkPacketCacheMetrics(0, 1)

        # we should get a hit over UDP this time
        res = self.sendUDPQuery(query)
        self.assertRcodeEqual(res, dns.rcode.NOERROR)
        self.assertRRsetInAnswer(res, expected)
        self.checkPacketCacheMetrics(1, 1)

        eco1 = cookiesoption.CookiesOption(b'deadbeef', b'deadbeef')
        eco2 = cookiesoption.CookiesOption(b'deadc0de', b'deadc0de')
        ecso1 = clientsubnetoption.ClientSubnetOption('192.0.2.1', 32)
        ecso2 = clientsubnetoption.ClientSubnetOption('192.0.2.2', 32)

        # we add a cookie, should not match anymore
        query = dns.message.make_query(qname,
                                       'A',
                                       want_dnssec=True,
                                       options=[eco1])
        res = self.sendUDPQuery(query)
        self.assertRcodeEqual(res, dns.rcode.NOERROR)
        self.assertRRsetInAnswer(res, expected)
        self.checkPacketCacheMetrics(1, 2)

        # same cookie, should match
        query = dns.message.make_query(qname,
                                       'A',
                                       want_dnssec=True,
                                       options=[eco1])
        res = self.sendUDPQuery(query)
        self.assertRcodeEqual(res, dns.rcode.NOERROR)
        self.assertRRsetInAnswer(res, expected)
        self.checkPacketCacheMetrics(2, 2)

        # different cookie, should still match
        query = dns.message.make_query(qname,
                                       'A',
                                       want_dnssec=True,
                                       options=[eco2])
        res = self.sendUDPQuery(query)
        self.assertRcodeEqual(res, dns.rcode.NOERROR)
        self.assertRRsetInAnswer(res, expected)
        self.checkPacketCacheMetrics(3, 2)

        # first cookie but with an ECS option, should not match
        query = dns.message.make_query(qname,
                                       'A',
                                       want_dnssec=True,
                                       options=[eco1, ecso1])
        res = self.sendUDPQuery(query)
        self.assertRcodeEqual(res, dns.rcode.NOERROR)
        self.assertRRsetInAnswer(res, expected)
        self.checkPacketCacheMetrics(3, 3)

        # different cookie but same ECS option, should match
        query = dns.message.make_query(qname,
                                       'A',
                                       want_dnssec=True,
                                       options=[eco2, ecso1])
        res = self.sendUDPQuery(query)
        self.assertRcodeEqual(res, dns.rcode.NOERROR)
        self.assertRRsetInAnswer(res, expected)
        self.checkPacketCacheMetrics(4, 3)

        # first cookie but different ECS option, should still match (we ignore EDNS Client Subnet
        # in the recursor's packet cache, but ECS-specific responses are not cached
        query = dns.message.make_query(qname,
                                       'A',
                                       want_dnssec=True,
                                       options=[eco1, ecso2])
        res = self.sendUDPQuery(query)
        self.assertRcodeEqual(res, dns.rcode.NOERROR)
        self.assertRRsetInAnswer(res, expected)
        self.checkPacketCacheMetrics(5, 3)