#! /usr/bin/env python3 # vim:set noet sw=8 ts=8 sts=8: import sys, socket import dns.query import dns.name import dns.rdatatype import dns.zone def resolve(hostname): try: addrs = socket.getaddrinfo( hostname, 53, proto=socket.IPPROTO_UDP) return list(dict.fromkeys([addr[4][0] for addr in addrs])) except Exception as e: raise (Exception(f"resolving {hostname}: {e}")) def axfr(zonename, hostname): addrs = resolve(hostname) last_exc = None for addr in addrs: try: name = dns.name.from_unicode(zonename) zone = dns.zone.Zone(origin=name) dns.query.inbound_xfr(addr, zone) return zone except Exception as e: last_exc = e raise (last_exc) def print_catalog(zone): def origin(node): try: return [ ''.join(s.decode('utf-8') for s in rdata.strings) for rdata in zone.find_node(f"origin.ext.{node}") .find_rdataset(dns.rdataclass.IN, dns.rdatatype.TXT) ] except KeyError: return [] nodes = [node for (name, node) in zone.nodes.items() if len(name) == 2 and name[1] == b"zones"] ptrs = [str(ptr.target).rstrip('.') for node in nodes for rdataset in node.rdatasets if rdataset.rdtype == dns.rdatatype.PTR for ptr in rdataset] print("\n".join(ptrs)) def main(): if len(sys.argv) != 3: print(f"Usage: {sys.argv[0]} ", file=sys.stderr) return 1 zone_name = sys.argv[1] server = sys.argv[2] try: zone = axfr(zone_name, server) print_catalog(zone) except Exception as e: print(f"Failed to load catalog: {e}", file=sys.stderr) return 1 return 0 if __name__ == "__main__": sys.exit(main())