Created
May 3, 2018 20:50
-
-
Save yzguy/e648209d332520956ecabe6e64db24cb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import sys | |
import dns.query | |
import dns.zone | |
import dns.name | |
from dns.exception import DNSException | |
from dns.rdatatype import SOA | |
config = { | |
'masters': { | |
'provider1': '10.10.10.10', | |
'provider2': '20.20.20.20' | |
}, | |
'domains': [ | |
'domain.com', | |
'domain.net' | |
] | |
} | |
# Zone Transfer | |
def get_zone(domain, master): | |
try: | |
zone = dns.zone.from_xfr(dns.query.xfr(master, domain, relativize=False), relativize=False) | |
except DNSException as e: | |
return None, e | |
return zone, None | |
# Compare a zone against another, return data | |
def compare_zones(z1, z2): | |
data = { | |
'totals': [ | |
get_zone_total(z1), | |
get_zone_total(z2) | |
], | |
'missing': {}, | |
'matches': [], | |
'mismatches': {} | |
} | |
# Loop through all the name to rdataset pairs | |
for (name, z1_rdataset) in z1.iterate_rdatasets(): | |
# Skip SOA records (different between providers) | |
if z1_rdataset.rdtype == SOA: | |
continue | |
# Find same record in second zone | |
try: | |
z2_node = z2.find_node(name) | |
z2_rdataset = z2_node.find_rdataset(z1_rdataset.rdclass, z1_rdataset.rdtype) | |
except KeyError: | |
data['missing'][name] = z1_rdataset | |
continue | |
# Compare rdatasets | |
if z1_rdataset == z2_rdataset: | |
if z1_rdataset.ttl == z2_rdataset.ttl: | |
data['matches'].append(name) | |
else: | |
data['mismatches'][name] = [z1_rdataset, z2_rdataset] | |
else: | |
data['mismatches'][name] = [z1_rdataset, z2_rdataset] | |
return data | |
# Get Total Number of Records | |
def get_zone_total(zone): | |
return sum([len(val) for val in zone.values()]) - 1 | |
if __name__ == '__main__': | |
error = False | |
for domain in config['domains']: | |
print '----------- {} -----------'.format(domain) | |
# Perform zone transfer against Provider1 | |
p1, err = get_zone(domain=domain, master=config['masters']['provider1']) | |
if err is not None: | |
print 'ERROR: Unable to perform zone transfer against Provider1 for {} ({})'.format(domain, err) | |
error = True | |
continue | |
# Perform zone transfer against Provider2 | |
p2, err = get_zone(domain=domain, master=config['masters']['provider2']) | |
if err is not None: | |
print 'ERROR: Unable to perform zone transfer against Provider1 for {} ({})'.format(domain, err) | |
error = True | |
continue | |
# Compare zones to each other | |
results = compare_zones(p1, p2) | |
p1_total = results['totals'][0] | |
p2_total = results['totals'][1] | |
# Provider1 total is more than Provider2 | |
if p1_total > p2_total: | |
# Provider2 is missing records | |
print 'ERROR: Records missing from Provider2' | |
for name, rdataset in results['missing'].iteritems(): | |
print '{} {}'.format(name, rdataset) | |
error = True | |
# Provider1 total is less than Provider2 | |
elif p1_total < p2_total: | |
# Compare zones, switching order | |
results = compare_zones(p2, p1) | |
p2_total = results['totals'][0] | |
p1_total = results['totals'][1] | |
# Provider2 total is more, Provider1 is missing records | |
print 'ERROR: Records missing from Provider1' | |
for name, rdataset in results['missing'].iteritems(): | |
print '{} {}'.format(name, rdataset) | |
error = True | |
# Provider1 and Provider2 totals are the same | |
else: | |
# Totals are the same, but records are mismatched | |
if len(results['mismatches']) != 0: | |
print 'ERROR: Records out of sync' | |
for name, rdataset_list in results['mismatches'].iteritems(): | |
print "Provider1:\t {} {}".format(name, rdataset_list[0]) | |
print "Provider2:\t {} {}".format(name, rdataset_list[1]) | |
error = True | |
# Totals match, but a record is missing | |
elif len(results['matches']) != p1_total: | |
print 'ERROR: Records missing from Provider2' | |
for name, rdataset in results['missing'].iteritems(): | |
print '{} {}'.format(name, rdataset) | |
error = True | |
# Print report | |
print "\nResults" | |
print "Provider1 Total:\t", p1_total | |
print "Provider2 Total:\t", p2_total | |
print "Missing:\t", len(results['missing']) | |
print "Matches:\t", len(results['matches']) | |
print "Mis-matches:\t", len(results['mismatches']) | |
# If any error raised, exit | |
if error: | |
sys.exit(1) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment