def fetch_dns(self): try: name_server = self.settings.get("dns", "server") keyring = dns.tsigkeyring.from_text( {self.settings.get("dns", "tsig_name"): self.settings.get("dns", "tsig_key")} ) for domain in self.settings.get("dns", "domains").split(","): try: responses = query.xfr( name_server, dns_name.from_text(domain), keyring=keyring, keyname=self.settings.get("dns", "tsig_name"), keyalgorithm=dns.tsig.HMAC_SHA512 ) with open(pjoin(self.configs, "dns." + domain), "w") as config: for response in responses: for line in response.answer: config.write(line.to_text() + u"\n") except: pass except: logging.error("can't fetch from DNS: %s" % self.settings.get('dns', 'server'))
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 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 pull_zone(self, nameserver): """Sends the domain transfer request""" try: q = query.xfr(nameserver, self.domain, relativize=False, timeout=2, lifetime=5) except dns.exception.Timeout: raise EOFError zone = {} for m in q: for rrset in m.answer: for rd in rrset: # result_string = str(rrset.name).ljust(30) + str(dns.rdatatype.to_text(rrset.rdtype)).ljust(10) + rd.to_text(origin=None, relativize=True) # zone += result_string + '\ parse_type = dns.rdatatype.to_text(rrset.rdtype) if parse_type == 'A': sub_domain = str(rrset.name) if re.match(r'^.*\.$', sub_domain): sub_domain = sub_domain[:-1] zone[sub_domain] = rd.to_text(origin=None, relativize=True) if not zone: raise EOFError return zone
def discover(self): new_serial = self.remote_soa_serial() if self.serial and self.serial == new_serial: log.debug("No change of SOA serial") return for item in six.itervalues(self._patterns): item.accumulator = set() for message in xfr(self.ip, self.domain, port=self.port, use_udp=False, rdtype=self.rdtype): for answer in message.answer: if answer.rdtype in [A, AAAA, CNAME] and answer.name: for pattern, item in six.iteritems(self._patterns): if pattern.match(answer.name.labels[0]): item.accumulator.add(str(answer.name)) for item in six.itervalues(self._patterns): log.debug("{}: {}".format(new_serial, item.accumulator)) item.accumulator.difference_update(item.items) gone = item.items.difference(item.accumulator) for callback in item.callbacks: callback(item.accumulator, gone) item.items.update(item.accumulator) self.serial = new_serial
def discover(self): new_serial = self.remote_soa_serial() if self.serial and self.serial == new_serial: log.debug("No change of SOA serial") return for item in six.itervalues(self._patterns): item.accumulator = set() for message in xfr(self.ip, self.domain, port=self.port, use_udp=False, rdtype=self.rdtype, keyname=self.keyname, keyring=self.keyring): for answer in message.answer: if answer.rdtype in [A, AAAA, CNAME] and answer.name: for pattern, item in six.iteritems(self._patterns): if pattern.match(answer.name.labels[0]): item.accumulator.add(str(answer.name)) for item in six.itervalues(self._patterns): log.debug("{}: {}".format(new_serial, item.accumulator)) item.accumulator.difference_update(item.items) gone = item.items.difference(item.accumulator) for callback in item.callbacks: callback(item.accumulator, gone) item.items.update(item.accumulator) self.serial = new_serial
def pull_zone(self, nameserver): """Sends the domain transfer request""" q = query.xfr(nameserver, self.domain, relativize=False, timeout=2) zone = "" ## janky, but this library returns for m in q: ## an empty generator on timeout zone += str(m) if not zone: raise EOFError return zone
def pull_zone(self, nameserver): """Sends the domain transfer request""" q = query.xfr(nameserver, self.domain, relativize=False, timeout=2) zone = "" for m in q: zone += str(m) if not zone: raise EOFError return zone
def remote_soa_serial(self): for message in xfr(self.ip, self.domain, port=self.port, use_udp=False, rdtype=SOA, keyname=self.keyname, keyring=self.keyring): for answer in message.answer: if answer.rdtype == SOA: return answer[0].serial return None
def __do_dns_transfer(self, ip: str) -> List[str]: """Do the DNS Zone Transfer, returning the subdomains @type ip: str @param ip: The IP from the name server @returns List[str]: The list with the subdomains """ try: zones = zone.from_xfr(query.xfr(ip.rstrip('.'), self.host)) except query.TransferError: return [] else: return [str(subdomain) for subdomain in zones]
def AXFR(domain, nameserver): try: axfr = dz.from_xfr(dq.xfr(nameserver, domain)) if axfr: print('[*] Successful Zone Transfer from {}'.format(nameserver)) for record in axfr: Subdomains.append('{}.{}'.format(record.to_text(), domain)) except Exception as error: print(error) pass
def get_axfr_records(self, server, domains): """Return a `list` of `dict`s containing the zones and their records, obtained from the DNS server Returns: :obj:`list` of `dict` """ zones = [] for zoneName in domains: try: zone = { 'zone_id': get_resource_id('axfrz', zoneName), 'name': zoneName, 'source': 'AXFR', 'comment': None, 'tags': {}, 'records': [] } z = dns_zone.from_xfr(query.xfr(server, zoneName)) rdata_fields = ('name', 'ttl', 'rdata') for rr in [ dict(zip(rdata_fields, x)) for x in z.iterate_rdatas() ]: record_name = rr['name'].derelativize(z.origin).to_text() zone['records'].append({ 'id': get_resource_id( 'axfrr', record_name, ['{}={}'.format(k, str(v)) for k, v in rr.items()]), 'zone_id': zone['zone_id'], 'name': record_name, 'value': sorted([rr['rdata'].to_text()]), 'type': type_to_text(rr['rdata'].rdtype) }) if len(zone['records']) > 0: zones.append(zone) except Exception as ex: self.log.exception( 'Failed fetching DNS zone information for {}: {}'.format( zoneName, ex)) raise return zones
def perform_zone_transfer(domain, server): serv_addr = resolver.resolve(server, "A")[0].address try: records = zone.from_xfr(query.xfr(serv_addr, domain)) deliverable = [] for record in sorted(records.nodes.keys()): deliverable.append(records[record].to_text(record)) except xfr.TransferError: return False return deliverable
def zoneTransfer(db, domain): print(colored("\n[*]-Attempting to zone transfer from the identified nameservers...", "yellow")) for row in db.query(Record).filter(Record.domain == domain, Record.type == "NS"): try: zone = from_xfr(xfr(row.value, domain)) subdomains = set([str(key) for key in zone.nodes.keys()]) print(" \__ {0}: {1}".format(colored("Subdomains retrieved", "cyan"), colored(len(subdomains), "yellow"))) return subdomains except Exception: continue print(" \__", colored("Failed to zone transfer.", "red")) return None
def AXFR(domain, nameserver): # Try zone transfer for given domain and namerserver try: # Perform the zone transfer axfr = dz.from_xfr(dq.xfr(nameserver, domain)) # If zone transfer was successful if axfr: print('[*] 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 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 remote_soa_serial(self): try: # returns an iterator, that's evaluated lazily messages = xfr(self.ip, self.domain, port=self.port, use_udp=False, rdtype=SOA, keyname=self.keyname, keyring=self.keyring, keyalgorithm=KEYALGORITHM) for message in messages: for answer in message.answer: if answer.rdtype == SOA: return answer[0].serial except (OSError, EOFError): LOG.exception('Handled an exception on retrieving the new SOA ' 'serial gracefully.') return None
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 get_target_subdomains_from_auth_ns(target, auth_ns): """ Checks domains nameserver for zone transfers, if allowed returns a list of enumerated subdomain DNS records""" if valid_ip(target): # handle IPs try: gethostbyaddr(str(target)) except herror: print(RED + "Could not get hostname from " + str(target) + ", check target is live/up." + END) exit(-1) try: z = from_xfr(xfr(str(auth_ns), target)) # zone transfer dig request using auth ns subdomains = [] names = z.nodes.keys() # node key values for n in names: at = match("@", str(n)) # removes dns self (@) symbol if not at: subdomain = str(n) + "." + target subdomains.append(subdomain) # print(subdomain) print(RED + target, "is VULNERABLE to DNS Zone Transfers!!!" + END) return subdomains except TransferError: # most domains print(GREEN + target, "is SECURE against DNS Zone Transfers :-)" + END) exit(1) except FormError: # google.co.uk print(GREEN + target, "is SECURE against DNS Zone Transfers :-)" + END) exit(1) except TimeoutError: # rhul.ac.uk print(GREEN + target, "is VERY SECURE against DNS Zone Transfers :-)" + END) exit(1) except OSError: # the next router print(RED + "[No route to host] Lookup Failure!" + END) print( "Domain name reverse fqdn lookup error - Check your on the domains internal network, or setup dnscrypt " "for the domain as all european ISPs high-jack all dns traffic to censor the internet!" ) exit(1)
def discover(self): new_serial = self.remote_soa_serial() if not new_serial: LOG.warning("Could not fetch SOA serial") return if self.serial and self.serial == new_serial: LOG.debug("No change of SOA serial") return for item in self._patterns.values(): item.accumulator = set() for message in xfr(self.ip, self.domain, port=self.port, use_udp=False, rdtype=self.rdtype, keyname=self.keyname, keyring=self.keyring, keyalgorithm=KEYALGORITHM): for answer in message.answer: if answer.rdtype in [A, AAAA, CNAME] and answer.name: for pattern, item in self._patterns.items(): if pattern.match(answer.name.labels[0]): item.accumulator.add(str(answer.name)) for item in self._patterns.values(): LOG.debug(f"{new_serial}: {item.accumulator}") item.accumulator.difference_update(item.items) gone = item.items.difference(item.accumulator) for callback in item.callbacks: callback(item.accumulator, gone) item.items.update(item.accumulator) self.serial = new_serial
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 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 remote_soa_serial(self): for message in xfr(self.ip, self.domain, port=self.port, use_udp=False, rdtype=SOA): for answer in message.answer: if answer.rdtype==SOA: return answer[0].serial return None
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 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 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")