Discussion:
axfr bringing my dns config error to light
Jeremy Kister
2010-04-06 20:38:07 UTC
Permalink
i have 204.9.96.4 & 204.9.96.5 answering authoritatively for:
example.com
sub.example.com

(literally). 204.9.96.4 allows all internet hosts to axfr
example.com/sub.example.com.

when i AXFR example.com, i get the A record(s) (et. al.) inside
sub.example.com, which i wouldnt expect.

what have i done wrong [in my data file] ?


# grep example.com /etc/tinydns/root/data
Zexample.com:a.ns.example.com:hostmaster.example.com
&example.com::a.ns.example.com:3600
&example.com::b.ns.example.com:3600
Zsub.example.com:a.ns.example.com:hostmaster.example.com
&sub.example.com::a.ns.example.com:3600
&sub.example.com::b.ns.example.com:3600
+a.ns.example.com:204.9.96.4:3600
+b.ns.example.com:204.9.96.5:3600
+examtest1.example.com:10.0.0.1:3600
+subtest1.sub.example.com:10.0.0.2:3600
#
--
Jeremy Kister
http://jeremy.kister.net./
Matthew Dempsky
2010-04-06 21:19:13 UTC
Permalink
On Tue, Apr 6, 2010 at 1:38 PM, Jeremy Kister
Post by Jeremy Kister
when i AXFR example.com, i get the A record(s) (et. al.) inside
sub.example.com, which i wouldnt expect.
It's the intended behavior according to the documentation at least;
see http://cr.yp.to/djbdns/axfrdns.html:

axfrdns provides every record it can find inside the target domain.
This may include records in child zones. Some of these records (such as
glue inside a child zone) are essential; others are not. It is up to
the client to decide which out-of-zone records to keep.
Post by Jeremy Kister
what have i done wrong [in my data file] ?
Nothing.
Jeremy Kister
2010-04-07 01:02:40 UTC
Permalink
Post by Matthew Dempsky
It's the intended behavior according to the documentation at least;
any ideas on how to differentiate 'essential' records from not ?

i suppose to differentiate 'x' from a host and a domain, i can look to
see if x.example.com has ns record(s) and/or it's own SOA; if so, it's a
domain and further records under x.example.com could be ignored ?

ick. this might be the first djbehavior i don't like! :D

i just trolled tinydns.org; anyone have a patch or an idea on what to
change to modify the behavior that i'd expect ?
--
Jeremy Kister
http://jeremy.kister.net./
Matthew Dempsky
2010-04-07 04:27:00 UTC
Permalink
On Tue, Apr 6, 2010 at 6:02 PM, Jeremy Kister
Post by Jeremy Kister
any ideas on how to differentiate 'essential' records from not ?
Are the extra records actually problematic for you?

But assuming they are, you could pipe the resulting file through a
script like the Python script I wrote below. It's really only
flexible enough to handle the output of axfr-get, but the general idea
is how I'd tackle it. Also, if you want to support DNSSEC, you'll
need to tweak the 'keep' function to keep DS records at zone cuts (and
their RRSIGs).


import sys

def inzone(n1, n2):
return n1[-(1 + len(n2)):] == '.' + n2

zone = None
nsrecords = dict()

# First pass through the zone file just to collect the NS records (and
# the SOA record to determine what zone we're looking at).
for line in sys.stdin:
line = line.rstrip(' \t\n')
if line == '': continue
if line[0] not in 'Z&': continue
fields = line[1:].split(':')
if line[0] == 'Z':
zone = fields[0]
else:
nsrecords.setdefault(fields[0], set()).add(fields[2].rstrip('.'))

if not zone:
print 'No SOA record?'
sys.exit(1)

# Don't worry about NS records for the zone itself.
if zone in nsrecords:
del nsrecords[zone]

zonecuts = set()
gluenames = set()

# Go through NS records and discard grandchildren records. E.g., if
# we're processing example.com and there are NS records for both
# foo.example.com and bar.foo.example.com, we only want
# foo.example.com.
for n1, ns in nsrecords.items():
for n2 in nsrecords.keys():
if inzone(n1, n2):
break
else:
zonecuts.add(n1)
gluenames.update(ns)


def keep(name, rtype):
# Keep A and AAAA records for names used in NS records.
if name in gluenames and rtype in ['+', 28]: return True

for zone in zonecuts:
# If a name is at a zone cut, only keep it if it's an NS record.
if name == zone: return rtype == '&'

# Discard any other records within the zone cut.
if inzone(name, zone): return False

# Keep everything else.
return True

sys.stdin.seek(0)

# Loop through the file a second time, only printing out records for
# names that we've decided to keep.
for line in sys.stdin:
line = line.rstrip(' \t\n')
if line == '': continue
if line[0] in '-#':
print line
continue
fields = line[1:].split(':')
if keep(fields[0], line[0] == ':' and int(fields[1]) or line[0]):
print line

Loading...