Beispiel #1
0
    def handle_response(self, packet, sender):
        """Handle DNS response from upstream server."""
        if packet['qdcount'] == 0:
            logging.warn('Bad response from upstream server: %s',
                         pprint.pformat(packet))
            return

        # Find original query
        query_id_o = packet['id']
        query_o = self.find_query(sender[0], sender[1], query_id_o)
        if query_o and packet['qdcount'] > 0:
            qname = packet['questions'][0][0]
            qtype = packet['questions'][0][1]
            send_reply = True
            query_again = False
            hit_found = False
            packet_o = query_o[0]
            # Replace with the original query id
            packet['id'] = packet_o['id']

            if qtype == DNS.Type.HIP and query_o[3] in (DNS.Type.A,
                                                        DNS.Type.AAAA):
                # Restore qtype
                packet['questions'][0][1] = query_o[3]
                self.hip_lookup(packet)
                if packet['ancount'] > 0:
                    hit_found = True

                if (not self.prefix or
                    (hit_found
                     and not (self.getaaaa(qname) or self.geta(qname)))):
                    query_again = True
                    send_reply = False
                elif self.prefix:
                    hit_found = True
                    packet['questions'][0][0] = (self.prefix +
                                                 packet['questions'][0][0])
                    for answer in packet['answers']:
                        answer[0] = self.prefix + answer[0]

            elif qtype in (DNS.Type.A, DNS.Type.AAAA):
                hit = self.getaaaa_hit(qname)
                ip6 = self.getaaaa(qname)
                ip4 = self.geta(qname)
                for answer in packet['answers']:
                    if answer[1] in (DNS.Type.A, DNS.Type.AAAA):
                        self.cache_name(qname, answer[4], answer[3])

                if hit is not None:
                    for answer in packet['answers']:
                        if (answer[1] == DNS.Type.A
                                or (answer[1] == DNS.Type.AAAA
                                    and not hosts.valid_hit(answer[4]))):
                            add_hit_ip_map(hit[0], answer[4])

                    # Reply with HIT/LSI once it's been mapped
                    # to an IP
                    if ip6 is None and ip4 is None:
                        if (packet_o['ancount'] == 0 and not self.prefix):
                            # No LSI available. Return IPv4
                            tmp = packet['answers']
                            packet = packet_o
                            packet['answers'] = tmp
                            packet['ancount'] = len(packet['answers'])
                        else:
                            packet = packet_o
                            if self.prefix:
                                packet['questions'][0][0] = (
                                    self.prefix + packet['questions'][0][0])
                                for answer in packet['answers']:
                                    answer[0] = (self.prefix + answer[0])

                    else:
                        send_reply = False

                elif query_o[3] == 0:
                    # Prefix is in use
                    # IP was queried for cache only
                    send_reply = False

            elif qtype == DNS.Type.PTR and isinstance(query_o[3], str):
                packet['questions'][0][0] = query_o[3]
                for answer in packet['answers']:
                    answer[0] = query_o[3]

            if query_again:
                if hit_found:
                    qtypes = [DNS.Type.AAAA, DNS.Type.A]
                    pckt = copy.deepcopy(packet)
                else:
                    qtypes = [query_o[3]]
                    pckt = copy.copy(packet)

                pckt['qr'] = 0
                pckt['answers'] = []
                pckt['ancount'] = 0
                pckt['nslist'] = []
                pckt['nscount'] = 0
                pckt['additional'] = []
                pckt['arcount'] = 0
                for qtype in qtypes:
                    if self.prefix:
                        query = (packet, query_o[1], query_o[2], 0)
                    else:
                        query = (packet, query_o[1], query_o[2], qtype)

                    self.query_id = (self.query_id % 65535) + 1
                    pckt['id'] = self.query_id
                    pckt['questions'][0][1] = qtype
                    outbuf = DNS.Serialize(pckt).get_packet()
                    self.clisock.sendto(outbuf,
                                        (self.server_ip, self.server_port))
                    self.add_query(self.server_ip, self.server_port,
                                   self.query_id, query)

                packet['questions'][0][1] = query_o[3]

            if send_reply:
                outbuf = DNS.Serialize(packet).get_packet()
                self.servsock.sendto(outbuf, (query_o[1], query_o[2]))
Beispiel #2
0
    def handle_query(self, packet, sender):
        """Handle DNS query from downstream client."""
        qtype = packet['questions'][0][1]

        sent_answer = False

        if qtype in (DNS.Type.A, DNS.Type.AAAA, DNS.Type.PTR):
            if self.hip_cache_lookup(packet):
                try:
                    outbuf = DNS.Serialize(packet).get_packet()
                    self.servsock.sendto(outbuf, sender)
                    sent_answer = True
                except socket.error:
                    logging.exception('Exception:')

        elif (self.prefix
              and packet['questions'][0][0].startswith(self.prefix)):
            # Query with HIP prefix for unsupported RR type.
            # Send empty response.
            packet['qr'] = 1
            try:
                outbuf = DNS.Serialize(packet).get_packet()
                self.servsock.sendto(outbuf, sender)
                sent_answer = True
            except socket.error:
                logging.exception('Exception:')

        if self.connected and not sent_answer:
            logging.info('Query type %d for %s from %s', qtype,
                         packet['questions'][0][0],
                         (self.server_ip, self.server_port))

            query = (packet, sender[0], sender[1], qtype)
            # FIXME: Should randomize for security
            self.query_id = (self.query_id % 65535) + 1
            pckt = copy.copy(packet)
            pckt['id'] = self.query_id
            if ((qtype == DNS.Type.AAAA or
                 (qtype == DNS.Type.A and not self.disable_lsi))
                    and not is_reverse_hit_query(packet['questions'][0][0])):

                if not self.prefix:
                    pckt['questions'][0][1] = DNS.Type.HIP

                if (self.prefix
                        and pckt['questions'][0][0].startswith(self.prefix)):
                    pckt['questions'][0][0] = pckt['questions'][0][0][
                        len(self.prefix):]
                    pckt['questions'][0][1] = DNS.Type.HIP

            if qtype == DNS.Type.PTR and not self.disable_lsi:
                qname = packet['questions'][0][0]
                addr_str = hosts.ptr_to_addr(qname)
                if (addr_str is not None and hosts.valid_lsi(addr_str)):
                    query = (packet, sender[0], sender[1], qname)
                    hit_str = lsi_to_hit(addr_str)
                    if hit_str is not None:
                        pckt['questions'][0][0] = hosts.addr_to_ptr(hit_str)

            outbuf = DNS.Serialize(pckt).get_packet()
            self.clisock.sendto(outbuf, (self.server_ip, self.server_port))

            self.add_query(self.server_ip, self.server_port, self.query_id,
                           query)