aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README1
-rwxr-xr-xbin/get_catalog95
2 files changed, 55 insertions, 41 deletions
diff --git a/README b/README
index 0bd4dff..c7914d3 100644
--- a/README
+++ b/README
@@ -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())