DNS zonefiles for the `cosi.clarkson.edu`, `cslabs.clarkson.edu`, and `csprojects.clarkson.edu` subdomains
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

168 lines
4.7 KiB

#!/usr/bin/env python3
import re
'db.cslabs': 'cslabs.clarkson.edu',
'db.cosi': 'cosi.clarkson.edu',
#'db.csprojects': 'csprojects.clarkson.edu',
#'db.cslabs.rvs': ?,
'db.cslabs.rvs.144': '128.153.144.',
'db.cslabs.rvs.145': '128.153.145.',
'db.cslabs.rvs.146': '128.153.146.',
'db.cslabs.rvs.c051': '2605:6480:c051:',
RECPAT = re.compile(r'''
''', re.X)
class Record(object):
__slots__ = ['name', 'cls', 'tp', 'value']
def __init__(self, name, cls, tp, value):
self.name = name
self.cls = cls
self.tp = tp
self.value = value
def from_match(cls, match):
return cls(
*match.group('name', 'class', 'type', 'value')
def __repr__(self):
return f'Record(name={self.name!r}, cls={self.cls!r}, tp={self.tp!r}, value={self.value!r})'
def __hash__(self):
return hash((self.name, self.cls, self.tp, self.value))
def __eq__(self, other):
if not isinstance(other, Record):
return False
return (self.name, self.cls, self.tp, self.value) == (other.name, other.cls, other.tp, other.value)
FWD = {} # zonefile -> [record]
RVS = {} # id
def get_recs_from_file(f):
rv = []
for line in open(fn):
match = RECPAT.match(line)
if not match:
print(f'rejected line: {line!r}')
rec = Record.from_match(match)
return rv
def expand_ip6(s):
groups = s.split(':')
zs = 8 - len(list(filter(None, groups)))
if zs > 0:
fi = groups.index('')
groups = groups[:fi] + ['0000'] * zs + groups[fi+1:]
return ':'.join(i.rjust(4, '0') for i in groups)
def into_digits(addr):
return [c for c in addr if c != ':']
def canon_ip6(digits):
groups = [''.join(digits[i*4:(i+1)*4]) for i in range(8)]
fz, lz = None, None
fz = groups.index('0000')
except ValueError:
lz = len(groups) - list(reversed(groups)).index('0000')
groups = [i.lstrip('0') for i in groups]
if fz is not None:
return ':'.join(groups[:fz]) + '::' + ':'.join(groups[lz:])
return ':'.join(groups)
def cons_addr(rec, org):
if rec.tp != 'PTR':
raise ValueError(rec)
if '.' in org:
parts = '.'.join(reversed(rec.name.split('.')))
return org + parts
elif ':' in org:
digits = list(reversed(rec.name.split('.')))
digits = [i for i in org if i != ':'] + digits
return canon_ip6(digits)
for fn, zone in ORIGINS.items():
FWD[fn] = get_recs_from_file(open(fn))
for fn, rv in REVERSE.items():
RVS[fn] = get_recs_from_file(open(fn))
for za in ORIGINS.keys():
for zb in ORIGINS.keys():
if za <= zb:
print('Comparison between', za, 'and', zb)
sa = set(FWD[za])
sb = set(FWD[zb])
ma = sb - sa
mb = sa - sb
print(f'Missing from {za}:')
for i in ma:
print('\t', i)
print(f'Missing from {zb}:')
for i in mb:
print('\t', i)
mrvs = {} # canonaddr -> rec
seen_addrs = {} # addr -> oldname
seen_names = {} # name -> firstaddr
for z in ORIGINS.keys():
for rec in FWD[z]:
if rec.tp == 'A':
mrvs[rec.value] = rec
elif rec.tp == 'AAAA':
mrvs[canon_ip6(into_digits(expand_ip6(rec.value)))] = rec
print('Reverse records:')
for r, addr in REVERSE.items():
for rec in RVS[r]:
if rec.tp != 'PTR':
a = cons_addr(rec, addr)
if a in seen_addrs:
print(f'\t- Rvs {a} (for {rec.value}) has already been seen as {seen_addrs[a]}')
del mrvs[a]
except KeyError:
print(f'\t- Rvs {a} (supposedly {rec.value}) doesn\'t correspond to any forward record')
seen_addrs[a] = rec.value
if rec.value in seen_names:
print(f'\t- Name {rec.value} (for {a}) has already been seen as {seen_names[rec.value]}')
seen_names[rec.value] = a
for addr, rec in mrvs.items():
print(f'\t- No rvs for {addr} (in {rec!r})')
#for fn, recs in FWD.items():
# for rec in recs:
# print(fn, ':', rec)
# if rec.tp == 'AAAA':
# print(canon_ip6(into_digits(expand_ip6(rec.value))))
#for fn, recs in RVS.items():
# for rec in recs:
# print(fn, ':', rec)
# if rec.tp == 'PTR':
# print(cons_addr(rec, REVERSE[fn]))