summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Wu <peter@lekensteyn.nl>2015-03-11 01:42:00 +0100
committerPeter Wu <peter@lekensteyn.nl>2015-03-11 01:42:00 +0100
commitb367416f1b65564675a3a9093137cbd20291b5c3 (patch)
tree5c13004025257a6197939ba9881bdc0c6272b9d2
parent6c3a8cc2a5d0fdfce02b2fc37f80687991a443b0 (diff)
downloadscripts-b367416f1b65564675a3a9093137cbd20291b5c3.tar.gz
dnscheck.py: checks for the existence of DNS names
-rwxr-xr-xdnscheck.py95
1 files changed, 95 insertions, 0 deletions
diff --git a/dnscheck.py b/dnscheck.py
new file mode 100755
index 0000000..efaf99e
--- /dev/null
+++ b/dnscheck.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python
+# Checks a bulk of DNS names for their existence (based on the SOA record).
+#
+# Copyright 2015 Peter Wu <peter@lekensteyn.nl>
+import datetime
+import dns.resolver, dns.exception
+from itertools import product
+import sys
+
+def crange(begin, end):
+ """Generates a range of ascii characters."""
+ return [chr(i) for i in range(ord(begin), ord(end) + 1)]
+
+def parse_pattern(pattern):
+ """Parses a pattern with character classes into a list of character sets."""
+ components = []
+ class_chars = None
+ range_begin = None
+ for c in pattern:
+ if class_chars is not None:
+ if c == ']':
+ if range_begin is not None:
+ # Matches '[X-]'
+ class_chars += [range_begin, '-']
+ range_begin = None
+ components.append(sorted(set(class_chars)))
+ class_chars = None
+ elif range_begin is not None:
+ # Detected 'X-Y'
+ class_chars += crange(range_begin, c)
+ range_begin = None
+ else:
+ if c == '-' and class_chars:
+ # Detected 'X-' (at least one prev. char in char class).
+ range_begin = class_chars.pop()
+ else:
+ # Detected 'X' or '-'
+ class_chars.append(c)
+ else:
+ if c == '[':
+ class_chars = []
+ else:
+ components.append(c)
+ assert range_begin is None
+ assert class_chars is None, "Character class must end with ]"
+ return components
+
+def get_input(patterns):
+ """
+ Accepts patterns such as:
+ - [0-9].tld
+ - [0a-z].tld
+ """
+ for pattern in patterns:
+ format = parse_pattern(pattern)
+ for item in product(*format):
+ yield ''.join(item)
+
+def resolve(domain):
+ # May throw dns.exception.DNSException
+ answer = dns.resolver.query(domain, 'SOA')
+
+ # May throw if malformed... hopefully it does not
+ return answer[0].to_text()
+
+def resolve_inputs(inputs):
+ for line in inputs:
+ domain = line.strip()
+ try:
+ name = resolve(domain)
+ yield "{}: {}".format(line, repr(name))
+ except dns.exception.DNSException as e:
+ yield "{}! {}".format(line, type(e).__name__)
+
+def main(argv):
+ if len(argv) < 3:
+ sys.stderr.write('Usage: {} resolved-names.txt pattern...\n')
+ sys.stderr.write('Usage: {} "" pattern... (to print patterns)\n')
+ return 1
+
+ if argv[1] == '':
+ for key in get_input(argv[2:]):
+ print(key)
+ return 0
+
+ with open(argv[1], 'a') as outf:
+ for result in resolve_inputs(get_input(sys.argv[2:])):
+ now = datetime.datetime.now()
+ sys.stderr.write('{} '.format(now.time()))
+ sys.stderr.flush()
+ print(result)
+ outf.write(result + "\n")
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))