diff options
author | Johan Lundberg <lundberg@nordu.net> | 2013-10-04 14:39:26 +0200 |
---|---|---|
committer | Johan Lundberg <lundberg@nordu.net> | 2013-10-04 14:39:26 +0200 |
commit | e670e1bfb44838c02da92d1cbf4d4859600a60ec (patch) | |
tree | 85d65bcc8894a9f672c20aee0d20a907c1a6abc5 | |
parent | dc0425ff24bd398bb7f0fb6d79b8696365630e60 (diff) |
Now handling more than one NS per zone.
-rw-r--r-- | dnscheck_nsd.py | 100 |
1 files changed, 56 insertions, 44 deletions
diff --git a/dnscheck_nsd.py b/dnscheck_nsd.py index 2444911..b05b53b 100644 --- a/dnscheck_nsd.py +++ b/dnscheck_nsd.py @@ -27,25 +27,28 @@ def get_hostname(addr): return hostname -def get_resolver(nameserver=None, lifetime=30): +def get_resolver(nameservers=None, lifetime=30): resolver = dns.resolver.Resolver() resolver.lifetime = lifetime - if nameserver: - try: - resolver.nameservers = [gethostbyname(nameserver)] - except gaierror: + if nameservers: + resolver.nameservers = [] + for nameserver in nameservers: try: - resolver.nameservers = [nameserver] # It is an IP address + resolver.nameservers.append(gethostbyname(nameserver)) except gaierror: - logger.error('Could not find nameserver: %s' % nameserver) - sys.exit(1) - logger.debug('Resolver instance with nameserver %s.' % resolver.nameservers[0]) + try: + resolver.nameservers.append(nameserver) # It is an IP address + except gaierror: + logger.error('Could not find nameserver: %s' % nameserver) + sys.exit(1) + logger.debug('Resolver instance with nameserver %s.' % resolver.nameservers) return resolver def compare_soa(zone, resolvers): answers = [] for resolver in resolvers: + answer = None try: answer = resolver.query(zone, 'SOA')[0] if VERBOSE: @@ -53,21 +56,21 @@ def compare_soa(zone, resolvers): logger.info('NS %s: %s' % (resolver.nameservers[0], answer)) else: try: - logger.info('NS %s: %s' % (get_hostname(resolver.nameservers[0]), answer)) + logger.info('NS %s (%s): %s' % (get_hostname(resolver.nameservers[0]), + resolver.nameservers[0], answer)) except herror: logger.info('NS %s: %s' % (resolver.nameservers[0], answer)) except dns.exception.Timeout: - logger.error('%s timed out. SOA request for %s failed.' % (get_hostname(resolver.nameservers[0]), zone)) - return 'timeout' + logger.error('%s (%s) timed out. SOA request for %s failed.' % (get_hostname(resolver.nameservers[0]), + resolver.nameservers[0], zone)) except dns.resolver.NoAnswer: - logger.error('%s returned no answer for %s.' % (get_hostname(resolver.nameservers[0]), zone)) - return None + logger.error('%s (%s) returned no answer for %s.' % (get_hostname(resolver.nameservers[0]), + resolver.nameservers[0], zone)) except dns.resolver.NXDOMAIN: - logger.error('NS %s responded domain not found (NXDOMAIN) for %s.' % (get_hostname(resolver.nameservers[0]), zone)) - return None + logger.error('NS %s (%s) responded domain not found (NXDOMAIN) for %s.' % (get_hostname(resolver.nameservers[0]), + resolver.nameservers[0], zone)) except dns.resolver.NoNameservers: logger.error('No non-broken nameservers are available to answer the query for %s.' % zone) - return None if answer: answers.append(answer) if len(set(answers)) == 1: @@ -84,11 +87,14 @@ def print_soa(zone, resolvers): else: print 'NS %s: %s' % (get_hostname(resolver.nameservers[0]), answer) except dns.exception.Timeout: - print '%s timed out. SOA request for %s failed.' % (get_hostname(resolver.nameservers[0]), zone) + logger.error('%s (%s) timed out. SOA request for %s failed.' % (get_hostname(resolver.nameservers[0]), + resolver.nameservers[0], zone)) except dns.resolver.NoAnswer: - logger.error('%s returned no answer for %s.' % (get_hostname(resolver.nameservers[0]), zone)) + logger.error('%s (%s) returned no answer for %s.' % (get_hostname(resolver.nameservers[0]), + resolver.nameservers[0], zone)) except dns.resolver.NXDOMAIN: - logger.error('NS %s responded domain not found (NXDOMAIN) for %s.' % (get_hostname(resolver.nameservers[0]), zone)) + logger.error('NS %s (%s) responded domain not found (NXDOMAIN) for %s.' % (get_hostname(resolver.nameservers[0]), + resolver.nameservers[0], zone)) except dns.resolver.NoNameservers: logger.error('No non-broken nameservers are available to answer the query for %s.' % zone) @@ -106,13 +112,16 @@ def check_auth(zone, resolver): logger.info('NS %s is authoritative for %s...' % (nameserver, zone)) return True except dns.exception.Timeout: - logger.error('%s timed out. NS request for %s failed.' % (get_hostname(resolver.nameservers[0]), zone)) + logger.error('%s timed out. NS request for %s (%s) failed.' % (get_hostname(resolver.nameservers[0]), + resolver.nameservers[0], zone)) return None except dns.resolver.NoAnswer: - logger.error('%s returned no answer for %s.' % (get_hostname(resolver.nameservers[0]), zone)) + logger.error('%s (%s) returned no answer for %s.' % (get_hostname(resolver.nameservers[0]), + resolver.nameservers[0], zone)) return None except dns.resolver.NXDOMAIN: - logger.error('NS %s responded domain not found (NXDOMAIN) for %s.' % (get_hostname(resolver.nameservers[0]), zone)) + logger.error('NS %s (%s) responded domain not found (NXDOMAIN) for %s.' % (get_hostname(resolver.nameservers[0]), + resolver.nameservers[0], zone)) return None except dns.resolver.NoNameservers: logger.error('No non-broken nameservers are available to answer the query for %s.' % zone) @@ -127,34 +136,37 @@ def check_auth(zone, resolver): def parse_file(f): result = [] - in_zone, domain, ns_address = False, '', '' + in_zone, domain, ns_addresses = False, '', [] for line in f: if not line.startswith('#'): + if line.strip() == '': + if in_zone and domain and ns_addresses: + result.append({ + 'domain': domain.strip('"'), + 'ns_addresses': ns_addresses + }) + logger.debug('Added %s to zones that should be checked.' % result[-1]) + in_zone, domain, ns_addresses = False, '', [] if line.startswith('zone'): + if in_zone: # Zones should be separated by a blank line + if domain: + logger.error('Misconfigured zone: %s in %s.' % (domain, f.name)) + if ns_addresses: + logger.error('Misconfigured zone with NS address: %s in %s.' % (ns_addresses, f.name)) + in_zone, domain, ns_addresses = False, '', [] in_zone = True if in_zone and line.find('name') != -1: domain = line.split()[1] if in_zone and line.find('request-xfr') != -1: - ns_address = line.split()[1] - if not line.strip(): # Blank line - if domain: - logger.error('Misconfigured zone: %s in %s.' % (domain, f.name)) - if ns_address: - logger.error('Misconfigured zone with NS address: %s in %s.' % (ns_address, f.name)) - in_zone, domain, ns_address = False, '', '' - if in_zone and domain and ns_address: - result.append({ - 'domain': domain.strip('"'), - 'ns_address': ns_address - }) - in_zone, domain, ns_address = False, '', '' + ns_addresses.append(line.split()[1]) return result def main(): # User friendly usage output parser = argparse.ArgumentParser() - parser.add_argument('--nameserver', '-ns', default=None, help="IP address or hostname of reference NS, default localhosts resolver") + parser.add_argument('--nameserver', '-ns', default=None, + help="IP address or hostname of reference NS, default localhosts resolver") parser.add_argument('--timeout', '-t', type=float, default=5, help="timeout in seconds, default 5") parser.add_argument('--nochecksoa', action='store_true', default=False) parser.add_argument('--nocheckauth', action='store_true', default=False) @@ -187,22 +199,22 @@ def main(): print '-- Exclude List --' else: exclude_list = [] - ref_resolver = get_resolver(nameserver=args.nameserver, lifetime=args.timeout) + ref_resolver = get_resolver(nameservers=[args.nameserver], lifetime=args.timeout) try: for item in parse_file(args.file): if not item['domain'] in exclude_list: if not args.nochecksoa: - resolver = get_resolver(nameserver=item['ns_address'], lifetime=args.timeout) - soa_result = compare_soa(item['domain'], [ref_resolver, resolver]) + resolvers = [ref_resolver] + for address in item['ns_addresses']: + resolvers.append(get_resolver(nameservers=[address], lifetime=args.timeout)) + soa_result = compare_soa(item['domain'], resolvers) if soa_result == 'match' and VERBOSE: print 'SOA check complete for zone %s.\n' % item['domain'] elif not soa_result: print 'SOA check for zone %s failed.\n' % item['domain'] - elif soa_result == 'timeout': - print 'SOA check for zone %s timed out.\n' % item['domain'] elif soa_result == 'no match': print 'SOA did not match:' - print_soa(item['domain'], [ref_resolver, resolver]) + print_soa(item['domain'], resolvers) print '' if not args.nocheckauth: auth_result = check_auth(item['domain'], ref_resolver) |