add -v switch

This commit is contained in:
2021-08-18 01:08:41 +02:00
parent 329747db1b
commit 3ccf5c11e8

View File

@@ -1,76 +1,116 @@
#!/bin/env python #!/usr/bin/env python
# author: Philipp Gassmann <gassmann@puzzle.ch>
''' # check if domains configured with octodns are configured to use our nameservers
Check whether the authoritative nameservers returned for all puzzle managed # Usage: ./dnsverify.py 2> /dev/null
domains belong to the list of pitc_nameservers and fail if one does not.
'''
import sys import sys
import yaml import yaml
from pprint import pprint
from dns import resolver import dns.query
import dns.resolver
from dns.exception import DNSException
# list of puzzle authoritative name servers def puzzle_nameservers():
pitc_nameservers = [ dnspool = [
'ns1.dnsimple.com.', "ns1.dnsimple.com.",
'ns2.dnsimple.com.', "ns2.dnsimple.com.",
'ns3.dnsimple.com.', "ns3.dnsimple.com.",
'ns4.dnsimple.com.', "ns4.dnsimple.com.",
'ns5.dnsmadeeasy.com.', "ns5.dnsmadeeasy.com.",
'ns6.dnsmadeeasy.com.', "ns6.dnsmadeeasy.com.",
'ns7.dnsmadeeasy.com.' "ns7.dnsmadeeasy.com." ]
] return dnspool
# list of puzzle managed zone files # query_authoritative_ns() based on https://stackoverflow.com/questions/4066614/how-can-i-find-the-authoritative-dns-server-for-a-domain-using-dnspython
pitc_domains = [ 'puzzle.ch.yaml', 'puzzle.yaml', 'nonpuzzle.yaml' ] def query_authoritative_ns(domain, log=lambda msg: None):
# configure opendns resolver #default_resolver = dns.resolver.get_default_resolver()
resolver = resolver.Resolver() my_resolver = dns.resolver.Resolver()
resolver.nameservers = ['208.67.222.222','208.67.220.220'] my_resolver.nameservers = ['8.8.8.8']
def get_authoritative_ns(domains): nameserver = my_resolver.nameservers[0]
'''
dsc: Query the domains and return the authoritative name server. n = domain.split('.')
arg: [list], domain to query
ret: [str], nameserver for i in range(len(n), 0, -1):
''' sub = '.'.join(n[i-1:])
for domain in domains:
answers = resolver.resolve(domain,'NS') log('Looking up %s on %s' % (sub, nameserver))
for server in answers: query = dns.message.make_query(sub, dns.rdatatype.NS)
if not verify_authoritative_ns(str(server)): response = dns.query.tcp(query, nameserver)
print("ERROR: {} got answer from {}, not managed by puzzle".format(domain, server), file=sys.stderr)
return False rcode = response.rcode()
if rcode != dns.rcode.NOERROR:
if rcode == dns.rcode.NXDOMAIN:
raise Exception('%s does not exist.' % (sub))
else: else:
#print("{} got answer from {}".format(domain, server)) raise Exception('Error %s' % (dns.rcode.to_text(rcode)))
pass
return True
def get_domains(filenames): if len(response.authority) > 0:
''' rrsets = response.authority
dsc: Loads domain names from a list of yaml files. elif len(response.additional) > 0:
arg: [list], filenames rrsets = [response.additional]
ret: [list], arbitrary list of domain names else:
''' rrsets = response.answer
domains = []
for file in filenames: # Handle all RRsets, not just the first one
with open(file, 'r') as zone_file: for rrset in rrsets:
yaml_data = yaml.safe_load(zone_file) for rr in rrset:
yaml_list = list(yaml_data.get('zones')) if rr.rdtype == dns.rdatatype.SOA:
domains.extend(yaml_list) log('Same server is authoritative for %s' % (sub))
elif rr.rdtype == dns.rdatatype.A:
ns = rr.items[0].address
log('Glue record for %s: %s' % (rr.name, ns))
elif rr.rdtype == dns.rdatatype.NS:
authority = rr.target
nameserver = my_resolver.query(authority).rrset[0].to_text()
log('%s [%s] is authoritative for %s; ttl %i' %
(authority, nameserver, sub, rrset.ttl))
result = rrset
else:
# IPv6 glue records etc
#log('Ignoring %s' % (rr))
pass
return result
def log (msg):
sys.stderr.write(msg + u'\n')
def domains_from_config(filename):
filecontent = open(filename, 'r')
config_domains = yaml.load(filecontent, Loader=yaml.FullLoader)
domains = config_domains['zones'].keys()
return domains return domains
def verify_authoritative_ns(nameserver): def verify_whois(domain):
''' domain = domain.strip('.')
dsc: Verifies if the authoritative NS belongs to the puzzle managed NS. result = query_authoritative_ns(domain, log)
arg: [str], nameserver for entry in result:
ret: [boolean], true if ok; false if nok. nameserver = entry.target.to_text()
''' if not nameserver in puzzle_nameservers():
if nameserver in pitc_nameservers: print('Domain %s has authoritative NS %s which is not in puzzle_nameservers' % (domain, nameserver))
return True
return False return False
log('Domain %s is ok' % (domain))
return True
def verify_domains_from_config(filename):
status_success = True
domains = domains_from_config(filename)
for domain in domains:
if not verify_whois(domain):
status_success = False
return status_success
if __name__ == "__main__": if __name__ == "__main__":
dns = get_domains(pitc_domains) global_status_success = True
if not get_authoritative_ns(dns): for domain in [
sys.exit(1) './puzzle.ch.yaml',
sys.exit(0) './puzzle.yaml',
'./nonpuzzle.yaml'
]:
if not verify_domains_from_config(domain):
global_status_success = False
if not global_status_success:
exit(1)