summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohan Lundberg <lundberg@nordu.net>2013-10-04 14:39:26 +0200
committerJohan Lundberg <lundberg@nordu.net>2013-10-04 14:39:26 +0200
commite670e1bfb44838c02da92d1cbf4d4859600a60ec (patch)
tree85d65bcc8894a9f672c20aee0d20a907c1a6abc5
parentdc0425ff24bd398bb7f0fb6d79b8696365630e60 (diff)
Now handling more than one NS per zone.
-rw-r--r--dnscheck_nsd.py100
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)