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