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
if len(response.authority) > 0:
rrsets = response.authority
elif len(response.additional) > 0:
rrsets = [response.additional]
else:
rrsets = response.answer
# Handle all RRsets, not just the first one
for rrset in rrsets:
for rr in rrset:
if rr.rdtype == dns.rdatatype.SOA:
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
def verify_whois(domain):
domain = domain.strip('.')
result = query_authoritative_ns(domain, log)
for entry in result:
nameserver = entry.target.to_text()
if not nameserver in puzzle_nameservers():
print('Domain %s has authoritative NS %s which is not in puzzle_nameservers' % (domain, nameserver))
return False
log('Domain %s is ok' % (domain))
return True return True
def get_domains(filenames): def verify_domains_from_config(filename):
''' status_success = True
dsc: Loads domain names from a list of yaml files. domains = domains_from_config(filename)
arg: [list], filenames for domain in domains:
ret: [list], arbitrary list of domain names if not verify_whois(domain):
''' status_success = False
domains = [] return status_success
for file in filenames:
with open(file, 'r') as zone_file:
yaml_data = yaml.safe_load(zone_file)
yaml_list = list(yaml_data.get('zones'))
domains.extend(yaml_list)
return domains
def verify_authoritative_ns(nameserver):
'''
dsc: Verifies if the authoritative NS belongs to the puzzle managed NS.
arg: [str], nameserver
ret: [boolean], true if ok; false if nok.
'''
if nameserver in pitc_nameservers:
return True
return False
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)