def dns_query(input="", query_type="", server="", timeout=2.0): """A unified IPv4 & IPv6 DNS lookup interface; this is essentially just a wrapper around dnspython's API. When you query a PTR record, you can use an IPv4 or IPv6 address (which will automatically be converted into an in-addr.arpa name. This wrapper only supports a subset of DNS records: 'A', 'AAAA', 'CNAME', 'MX', 'NS', 'PTR', and 'TXT' Kwargs: - input (str): A string containing the DNS record to lookup - query_type (str): A string containing the DNS record type (SOA not supported) - server (str): A string containing the fqdn or IP address of the dns server - timeout (float): DNS lookup timeout duration (default: 2.0 seconds) Returns: A set() of :class:`~ccp_util.DNSResponse` instances >>> from ciscoconfparse.ccp_util import dns_query >>> dns_query('www.pennington.net', 'A', '4.2.2.2') set([<DNSResponse 'A' result_str='65.19.187.2'>]) >>> answer = dns_query('www.pennington.net', 'A', '4.2.2.2') >>> str(answer.pop()) '65.19.187.2' >>> """ valid_records = set( ['A', 'AAAA', 'AXFR', 'CNAME', 'MX', 'NS', 'PTR', 'TXT']) query_type = query_type.upper() assert query_type in valid_records assert server != "" assert float(timeout) > 0 assert input != "" intput = input.strip() retval = set([]) resolver = Resolver() resolver.server = [socket.gethostbyname(server)] resolver.timeout = float(timeout) resolver.lifetime = float(timeout) start = time.time() if (query_type == "A") or (query_type == "AAAA"): try: answer = resolver.query(input, query_type) duration = time.time() - start for result in answer: response = DNSResponse(query_type=query_type, duration=duration, input=input, result_str=str(result.address)) retval.add(response) except DNSException as e: duration = time.time() - start response = DNSResponse(input=input, duration=duration, query_type=query_type) response.has_error = True response.error_str = e retval.add(response) elif query_type == "AXFR": """This is a hack: return text of zone transfer, instead of axfr objs""" _zone = zone.from_xfr(query.xfr(server, input, lifetime=timeout)) return [_zone[node].to_text(node) for node in _zone.nodes.keys()] elif query_type == "CNAME": try: answer = resolver.query(input, query_type) duration = time.time() - start for result in answer: response = DNSResponse(query_type=query_type, duration=duration, input=input, result_str=str(result.target)) retval.add(response) except DNSException as e: duration = time.time() - start response = DNSResponse(input=input, duration=duration, query_type=query_type) response.has_error = True response.error_str = e retval.add(response) elif query_type == "MX": try: answer = resolver.query(input, query_type) duration = time.time() - start for result in answer: response = DNSResponse(query_type=query_type, input=input, result_str=str(result.target)) response.preference = int(result.preference) retval.add(response) except DNSException as e: duration = time.time() - start response = DNSResponse(input=input, duration=duration, query_type=query_type) response.has_error = True response.error_str = e retval.add(response) elif query_type == "NS": try: answer = resolver.query(input, query_type) duration = time.time() - start for result in answer: response = DNSResponse(query_type=query_type, duration=duration, input=input, result_str=str(result.target)) retval.add(response) except DNSException as e: duration = time.time() - start response = DNSResponse(input=input, duration=duration, query_type=query_type) response.has_error = True response.error_str = e retval.add(response) elif query_type == "PTR": if is_valid_ipv4_addr(input) or is_valid_ipv6_addr(input): inaddr = reversename.from_address(input) elif 'in-addr.arpa' in input.lower(): inaddr = input else: raise ValueError('Cannot query PTR record for "{0}"'.format(input)) try: answer = resolver.query(inaddr, query_type) duration = time.time() - start for result in answer: response = DNSResponse(query_type=query_type, duration=duration, input=inaddr, result_str=str(result.target)) retval.add(response) except DNSException as e: duration = time.time() - start response = DNSResponse(input=input, duration=duration, query_type=query_type) response.has_error = True response.error_str = e retval.add(response) elif query_type == "TXT": try: answer = resolver.query(input, query_type) duration = time.time() - start for result in answer: response = DNSResponse(query_type=query_type, duration=duration, input=inaddr, result_str=str(result.strings)) retval.add(response) except DNSException as e: duration = time.time() - start response = DNSResponse(input=input, duration=duration, query_type=query_type) response.has_error = True response.error_str = e retval.add(response) return retval
def dns_query(input="", query_type="", server="", timeout=2.0): """A unified IPv4 & IPv6 DNS lookup interface; this is essentially just a wrapper around dnspython's API. When you query a PTR record, you can use an IPv4 or IPv6 address (which will automatically be converted into an in-addr.arpa name. This wrapper only supports a subset of DNS records: 'A', 'AAAA', 'CNAME', 'MX', 'NS', 'PTR', and 'TXT' Kwargs: - input (str): A string containing the DNS record to lookup - query_type (str): A string containing the DNS record type (SOA not supported) - server (str): A string containing the fqdn or IP address of the dns server - timeout (float): DNS lookup timeout duration (default: 2.0 seconds) Returns: A set() of :class:`~ccp_util.DNSResponse` instances >>> from ciscoconfparse.ccp_util import dns_query >>> dns_query('www.pennington.net', "A", "4.2.2.2") set([<DNSResponse "A" result_str="65.19.187.2">]) >>> answer = dns_query('www.pennington.net', 'A', '4.2.2.2') >>> str(answer.pop()) '65.19.187.2' >>> """ valid_records = set(['A', 'AAAA', 'AXFR', 'CNAME', 'MX', 'NS', 'PTR', 'TXT']) query_type = query_type.upper() assert query_type in valid_records assert server!="" assert float(timeout)>0 assert input != "" intput = input.strip() retval = set([]) resolver = Resolver() resolver.server = [socket.gethostbyname(server)] resolver.timeout = float(timeout) resolver.lifetime = float(timeout) start = time.time() if (query_type=="A") or (query_type=="AAAA"): try: answer = resolver.query(input, query_type) duration = time.time() - start for result in answer: response = DNSResponse(query_type=query_type, duration=duration, input=input, result_str = str(result.address)) retval.add(response) except DNSException as e: duration = time.time() - start response = DNSResponse(input=input, duration=duration, query_type=query_type) response.has_error = True response.error_str = e retval.add(response) elif query_type=="AXFR": """This is a hack: return text of zone transfer, instead of axfr objs""" _zone = zone.from_xfr(query.xfr(server, input, lifetime=timeout)) return [_zone[node].to_text(node) for node in _zone.nodes.keys()] elif query_type=="CNAME": try: answer = resolver.query(input, query_type) duration = time.time() - start for result in answer: response = DNSResponse(query_type=query_type, duration=duration, input=input, result_str = str(result.target)) retval.add(response) except DNSException as e: duration = time.time() - start response = DNSResponse(input=input, duration=duration, query_type=query_type) response.has_error = True response.error_str = e retval.add(response) elif query_type=="MX": try: answer = resolver.query(input, query_type) duration = time.time() - start for result in answer: response = DNSResponse(query_type=query_type, input=input, result_str = str(result.target)) response.preference = int(result.preference) retval.add(response) except DNSException as e: duration = time.time() - start response = DNSResponse(input=input, duration=duration, query_type=query_type) response.has_error = True response.error_str = e retval.add(response) elif query_type=="NS": try: answer = resolver.query(input, query_type) duration = time.time() - start for result in answer: response = DNSResponse(query_type=query_type, duration=duration, input=input, result_str = str(result.target)) retval.add(response) except DNSException as e: duration = time.time() - start response = DNSResponse(input=input, duration=duration, query_type=query_type) response.has_error = True response.error_str = e retval.add(response) elif query_type=="PTR": if is_valid_ipv4_addr(input) or is_valid_ipv6_addr(input): inaddr = reversename.from_address(input) elif 'in-addr.arpa' in input.lower(): inaddr = input else: raise ValueError('Cannot query PTR record for "{0}"'.format(input)) try: answer = resolver.query(inaddr, query_type) duration = time.time() - start for result in answer: response = DNSResponse(query_type=query_type, duration=duration, input=inaddr, result_str = str(result.target)) retval.add(response) except DNSException as e: duration = time.time() - start response = DNSResponse(input=input, duration=duration, query_type=query_type) response.has_error = True response.error_str = e retval.add(response) elif query_type=="TXT": try: answer = resolver.query(input, query_type) duration = time.time() - start for result in answer: response = DNSResponse(query_type=query_type, duration=duration, input=inaddr, result_str = str(result.strings)) retval.add(response) except DNSException as e: duration = time.time() - start response = DNSResponse(input=input, duration=duration, query_type=query_type) response.has_error = True response.error_str = e retval.add(response) return retval