From b367416f1b65564675a3a9093137cbd20291b5c3 Mon Sep 17 00:00:00 2001 From: Peter Wu Date: Wed, 11 Mar 2015 01:42:00 +0100 Subject: dnscheck.py: checks for the existence of DNS names --- dnscheck.py | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100755 dnscheck.py 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 +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)) -- cgit v1.2.1