diff options
| -rw-r--r-- | README | 1 | ||||
| -rwxr-xr-x | bin/get_catalog | 95 |
2 files changed, 55 insertions, 41 deletions
@@ -20,6 +20,7 @@ requirements: + bmake (or pmake, not tested) + getaddrinfo(1) ++ Python 3 with dnspython + ruby with the 'erb' gem (FreeBSD: devel/rubygem-erb) + nsupdate (from BIND, FreeBSD: dns/bind-tools) + nsdiff (https://dotat.at/prog/nsdiff/, FreeBSD: dns/p5-DNS-nsdiff) diff --git a/bin/get_catalog b/bin/get_catalog index d9e744b..772d5b4 100755 --- a/bin/get_catalog +++ b/bin/get_catalog @@ -1,41 +1,54 @@ -#! /bin/sh -# -# Fetch the catalog zone '$1' from the server '$2' and print a list of zones. - -set -e - -catalog="$1" -server="$2" - -tempfile="$(mktemp -t catalog)" -trap 'rm $tempfile' 0 - -if ! dig "$catalog" axfr @"$server" +noall +answer >"$tempfile"; then - printf >&2 '%s: query failed\n' "$0" - exit 1 -fi - -# Make sure the result has an SOA, otherwise the query failed. -if ! awk <"$tempfile" " -BEGIN { - exitcode=1 -} - -\$1 == \"$catalog.\" && \$4 == \"SOA\" { - exitcode=0 -} - -END { - exit exitcode -} -"; then - printf >&2 '%s: no SOA found in zone; transfer failed?\n' "$0" - exit 1 -fi - -awk <"$tempfile" " -\$1 ~ /zones.$catalog/ && \$4 == \"PTR\" { - zone = \$5 - sub(/\\.$/, \"\", zone) - print zone -}" +#! /usr/bin/env python3 +# vim:set noet sw=8 ts=8 sts=8: + +import sys, socket +import dns.query +import dns.zone +import dns.rdatatype + +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(zone, hostname): + addrs = resolve(hostname) + last_exc = None + + for addr in addrs: + try: + return dns.zone.from_xfr(dns.query.xfr(addr, zone)) + except Exception as e: + last_exc = e + raise (Exception(str(last_exc))) + +def print_catalog(zone): + for name, node in zone.nodes.items(): + for rdata in node.rdatasets: + if rdata.rdtype == dns.rdatatype.PTR: + for ptr in rdata: + print(str(ptr.target).rstrip('.')) + + +def main(): + if len(sys.argv) != 3: + print(f"Usage: {sys.argv[0]} <zone> <server>") + 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"Zone transfer failed: {e}") + return 1 + + return 0 + +if __name__ == "__main__": + sys.exit(main()) |
