def zone_transfer(logger, url): ''' This function is responsible to try to get the `zone transfer` file. If he success, he shows the `zone transfer` file and he will finish. How this function works? he get all the DNS Records and try to get the `zone transfer` file by all the records. If he failed, he will continue to try to get the `zone transfer file` by the next DNS record. If all the records will fail, we cant to get a `zone transfer` file. The function will returns false value. ''' try: logger.info("[DNS] Trying zone transfer first..") answers = resolver.query(url, 'NS') for ns in (ns.to_text().rstrip('.') for ns in answers): try: z = zone.from_xfr( query.xfr(ns, url) ) zone_record = "\n".join(z[z_node].to_text(z_node) for z_node in z.nodes.keys()) logger.info("[DNS] Zone file:!\n%s" % zone_record) return True except socket.error: pass except (FormError, dns.resolver.NoAnswer, dns.exception.Timeout, EOFError): pass except Exception as e: logger.error('[DNS][Error] %s' % e.message) return False
def dump(self): try: z = zone.from_xfr(query.xfr(self.server, self.domain, timeout=10)) except: print "Exception in bind9.BIND9.dump() on zone xfr" for name, node in z.nodes.items(): if str(name) == '@': continue rdatasets = node.rdatasets for rdataset in rdatasets: if rdataset.rdclass == IN and rdataset.rdtype in [A, CNAME]: record = str(rdataset).split(' ') self.records[str(name)] = { 'ttl': record[0], 'type': record[2], 'resolveto': record[3], } return self.records
def AXFR(domain, nameserver): # Try zone transfer for given domain and namerserver try: # Perform the zone transfer # print("NS: " + nameserver + " - Domain: " + domain) axfr = dz.from_xfr(dq.xfr(nameserver, domain), check_origin=False) # print(axfr) # If zone transfer was successful if axfr: print("\n[*] Successful Zone Transfer from {}".format(nameserver)) # Add found subdomains to global 'Subdomain' list for record in axfr: Subdomains.append("{}.{}".format(record.to_text(), domain)) # If zone transfer fails except Exception as error: print(error) pass
def zoneTransfer(nameservers, domain): print( colored( "\n[*]-Attempting to zone transfer from the identified nameservers...", "yellow")) for nameserver in nameservers: try: zone = from_xfr(xfr(nameserver, domain)) hosts = [ "{0}.{1}".format(key, domain) for key in sorted(list(set(zone.nodes.keys()))) ] print(" \__", colored("Unique subdomains retrieved:", "cyan"), colored(len(hosts), "yellow")) try: with open(join("results", domain, "zone_transfer.txt"), "w") as zone_file: for host in hosts: zone_file.write("{0}\n".format(host)) except OSError: pass except IOError: pass return hosts except Exception: continue print(" \__", colored("Failed to zone transfer.", "red")) return []
def is_xfr_enabled(domain: str, nameserver: str) -> bool: """ Check if zone transfer is enabled. :param domain: Name of the zone to transfer. :param nameserver: IPv4 or 6 to test. """ axfr_query = dns.query.xfr(nameserver, domain, timeout=5, relativize=False, lifetime=10) result = True try: zone = from_xfr(axfr_query, relativize=False) if not str(zone.origin).rstrip('.'): show_close('Zone transfer not enabled on server', details=dict(domain=domain, nameserver=nameserver)) result = False result = True show_open('Zone transfer enabled on server', details=dict(domain=domain, nameserver=nameserver)) except (NoSOA, NoNS, BadZone, dns.query.BadResponse): show_close('Zone transfer not enabled on server', details=dict(domain=domain, nameserver=nameserver)) result = False except (socket.error, dns.exception.Timeout, dns.exception.FormError) as exc: show_unknown('Could not connect', details=dict(domain=domain, nameserver=nameserver, error=str(exc).replace(':', ','))) result = False return result
def main(): parser = argparse.ArgumentParser(description='Process some integers.') parser.add_argument('-d', action="store", type=str, dest="view") parser.add_argument('-s', action="store", type=str, dest="server") parser.add_argument('-l', action="store", type=int, dest="zone_limit") parser.add_argument('-o', action="store", type=str, dest="origin") parser.add_argument('-p', action="store", type=str, dest="zone_path") parser.add_argument('-w', action="store", type=str, dest="override_path") parser.add_argument('-x', action="store_true", dest="delete_unknown_zone") parser.add_argument('-e', action="store", dest="named_restart_command") args = parser.parse_args() config_obj = Config() o_config = config_obj.get_config() stop_update_file_path = o_config.get('Global', 'StopUpdate') statefile_path = o_config.get('Global', 'StateFile') try: is_config_valid, config_message = config_obj.config_valid(o_config) except AttributeError: is_config_valid = False config_message = "No Configuration File Found" if os.path.exists(stop_update_file_path): print "Stop Update file Exists" sys.exit(2) if is_config_valid is False: print config_message sys.exit(2) if not args.view: msg = "DNS View command line argument required" Common.write_stop_update(stop_update_file_path, msg) print msg sys.exit(2) if not args.server: msg = "server command line argument required" Common.write_stop_update(stop_update_file_path, msg) print msg sys.exit(2) if not args.zone_path: msg = "zone_path command line argument required" Common.write_stop_update(stop_update_file_path, msg) print msg sys.exit(2) named_restart_command = "service named restart" if args.named_restart_command: named_restart_command = args.named_restart_command override_path = None if args.override_path: override_path = args.override_path named_reload = False named_failures = None reload_zones = [] api = API(o_config, args.view, origin=args.origin) all_records = [] all_zones = api.build_all_zones() # Track all of the zone names to compare via os.listdir all_zone_names = [] if args.zone_limit: all_zones = all_zones[:args.zone_limit] for zone in all_zones: is_reverse = Common.is_reverse_zone_name(zone) if is_reverse: zone = Common.reverse_name(zone) d_cmd = CMD(zone, args.server) output, errors = d_cmd.run() build = Build(output) all_records += build.run() local_zone = ZoneObject(zone, path=args.zone_path) local_serial = local_zone.get_serial() all_zone_names.append(local_zone.zone_name) try: axfr_zone = dnszone.from_xfr(query.xfr(args.server, zone)) except dns.exception.FormError: axfr_zone = None except dns.name.EmptyLabel: axfr_zone = None except Exception, e: axfr_zone = None if axfr_zone is None or local_zone is None: continue if axfr_zone is not None: axfr_zone_object = ZoneObject(zone, zone_obj=axfr_zone) axfr_serial = axfr_zone_object.get_serial() if axfr_serial != local_serial: named_reload = True write_path = os.path.join(args.zone_path, zone) try: axfr_zone.to_file(write_path) except Exception, e: print "Exception: {0}".format(exception) reload_zones.append({'zone': zone, 'path': write_path})
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
def update_records(self): ''' Run route53 updates based on AXFR request ''' # performing axfr try: print("Making AXFR request to " + self.options.dns_server + "...") except TypeError: raise SystemExit("No DNS server set. try again with -s to set the " "server to make the AXFR request against.") try: z = dnszone.from_xfr(query.xfr( self.options.dns_server, self.options.domain)) except AttributeError: raise SystemExit("No domin set. try again with -d to set the " "domain to reuest AXFR request for.") if self.options.hostedzone is not None: print("AXFR Request recieved a reply from the server." "Preping to send to R53 Hoested Zone: " + str(self.options.hostedzone)) else: raise SystemExit("No Hosted Zone set. try again with -z to set " "the zone to submit the records to.") dns_changes = [] adict = {} print("Processing " + str( self.options.recordtype) + " records for " + str( self.options.domain) + "...") if len(z.nodes) == 0: raise SystemExit("No records found to " "process... is AXFR enabled the DNS server you " "are pulling from?") print("Total records downloaded: " + str(len(z.nodes))) if self.options.recordtype == "A": rdtypevar = A rdclassvar = IN elif self.options.recordtype == "AAAA": rdtypevar = AAAA rdclassvar = IN elif self.options.recordtype == "CNAME": rdtypevar = CNAME rdclassvar = IN elif self.options.recordtype == "MX": rdtypevar = MX rdclassvar = IN elif self.options.recordtype == "NS": rdtypevar = NS rdclassvar = IN elif self.options.recordtype == "PTR": rdtypevar = PTR rdclassvar = IN elif self.options.recordtype == "SPF": rdtypevar = SPF rdclassvar = IN elif self.options.recordtype == "TXT": rdtypevar = TXT rdclassvar = IN elif self.options.recordtype == "SRV": rdtypevar = SRV rdclassvar = IN else: raise SystemExit("Unknown or unsupported record type " "in Route 53: " + str(self.options.recordtype)) for name, node in z.nodes.items(): rdataset = None rdataset = node.get_rdataset( rdclass=rdclassvar, rdtype=rdtypevar) if not rdataset: continue for rds in rdataset: if str(name) == "@": continue else: recordname = str(name) + "." + self.options.domain + "." if recordname in adict: ipaddr = str(rds) adict[recordname]['records'].append(ipaddr) else: ipaddr = str(rds) adict[recordname] = {'records': [ipaddr]} adict[recordname].update({'ttl': str(rdataset.ttl)}) for key, thedict in adict.iteritems(): ResourceRecordList = [] for record in thedict['records']: ResourceRecordList.append({'Value': record}) dns_changes.append({'Action': 'UPSERT', 'ResourceRecordSet': { 'Name': key, 'Type': self.options.recordtype, 'TTL': int(thedict['ttl']), 'ResourceRecords': ResourceRecordList } }) if len(dns_changes) == 0: raise SystemExit("No " + self.options.recordtype + " records " "processed... Are there records of this type on " "the DNS server you are pulling from?") print("Total records processed: " + str(len(dns_changes))) # connecting to route53 via boto print("Connecting to Route53 via boto3...") client = boto3.client('route53') if len(dns_changes) > 98: print("Breaking up records into batches of 100 " "to send to Route53...") chunks = [dns_changes[x:x+98] for x in xrange(0, len( dns_changes), 98)] chunkcount = 0 for chunk in chunks: chunkcount = chunkcount + 1 client.change_resource_record_sets( HostedZoneId=str(self.options.hostedzone), ChangeBatch={'Changes': chunk}) print("Batch " + str(chunkcount) + " submitted to Route 53") else: client.change_resource_record_sets( HostedZoneId=str(self.options.hostedzone), ChangeBatch={'Changes': dns_changes}) print("Batch 1 submitted to Route 53")