[conspire] Unbound + dnsmasqd on openwrt

Rick Moen rick at linuxmafia.com
Wed Apr 5 22:18:00 PDT 2017


Quoting Ivan Sergio Borgonovo (mail at webthatworks.it):

> Current 30Mbit/3Mbit contract costs the same as a 1Gbit contract now.
> I'm planning to change contract just for that and if I'll succeed to
> get a public IP I may consider to maintain my zone on my LAN DNS.
> It depends on what I'm able to get.

Whatever is reliable and convenient, I'd say.  And, on reflection,
reliable isn't actually particularly important, for reasons I'll
explain.  The main thing to realise is that DNS traffic, like server
load from DNS, will be light compared to other Internet services.  
So, it's both an absolutely vital service and one that requires only
small crumbs of machine and bandwidth resources.

The reason is massive redundancy and caching.

If you look at my authoritative DNS for my two personal domains,
linuxmafia.com and unixmercenary.net, I spread it across five widely
dispersed nameservers.  One often speaks of 'geographical diversity', 
in describing the desired situation, but that's strictly speaking 
inaccurate.  One actually wants to avoid SPoFs; the fact that the 
result looks like geographical diversity is somewhat coincidental.

Having them not be all behind the same network switches and routers is 
obviously desirable, along with ensuring that even a regional power
outage cannot take them all down.  (E.g., one of my five is a friend's
in Texas.)  Serendipitously, it's worked out that they aren't all
running the same DNS daemon softare, so the same zero-day exploit (in
nameserver software, anyway) cannot take them them all down:
ns1.svlug.org runs NSD, ns1.linuxmafia.com runs BIND9, and I am unsure
what the rest run (probably BIND9).

If one, two, three, or four of the five nameservers all fail for a
couple of days, nothing bad at all happens as long as one or more remain
working.  If all five fail for a couple of days, degradation is slow
because of massive caching of linuxmafia.com / unixmercenary.net query
data by other recursive servers elsewhere that happen to have recently
handled and retained those domains' authoritative DNS information.

Each DNS data item (called an RR = Reference Record) travels the Internet
with an associated expiry time (a number of seconds after which they are
to be regarded as stale and not used).  This is called the TTL = Time to
Live value.  TTLs of 86400 seconds (1 day) or more are quite common.
Ultra-long TTLs would make your published data highly persistent in
other recursive servers' caches, but mean any changes to your records
might take longer getting out to the public (because distant recursive
servers already having the old records in cache don't know they're
obsolete, only that their TTL hasn't expired).  Ultra-short TTLs permit
rapid propagation of changes to your DNS records, but limit the lifetime
(hence benefit) of third-party nameserver caching.

Anyway, my master nameserver for my domains lives on the ratty old
Pentium III in my garage, on slow aDSL to the Internet.  Sometimes the
aDSL suffers an outage, usually because AT&T, the local large carrier,
does something stupid that takes my ISP Raw Bandwidth Communications,
offline.  But I don't worry about my DNS continuity of service, because
my master nameserver is, from a public perspective, just one of five,
and also most queries are satisfied out of some other recursive
nameserver's cache, anyway.

Some years ago, I got a lesson in why it's important to not merely have
the recommended 3-7 authoritative servers (for a domain) but to
periodically reverify that they still exist and are still serving up the
domain:  I had been helping a somewhat haplessly half-assed LUG effort
in Santa Cruz, CA called 'Smaug' (notionally the Santa Cruz Microsoft
Alternative User Group).  ns1.linuxmafia.com was one of the domain's
(scruz.org's) _six_ nameservers.  The other five were the personally
operated nameservers of five other Santa Cruz locals.  One of them, 
mine, was treated as the master, which merely means that the zone
contents are maintained there and the other five periodically refresh
the zone contents from it.  Years passed.

One day, my aDSL line had been down for a few hours because of a
particularly epic AT&T screwup.  I got back online, and Smaug's mailing
list (hosted at svlug.org) was full of complaints that scruz.org
had been out of service, as in unresolvable (except where cached).
Some of these complaints, to my particular irritation when I solved the
problem, were from the other five individuals supposedly providing the
scruz.org authoritative service.

I got out 'dig' and checked out the other five nameservers.  Some of
them no longer existed.  (In one case, the owner had moved it to a new
IP address and never informed me as maintainer of the master
nameserver.)  Another had just be taken out of service entirely without
notice.  And the other three had been manually modified to no longer
serve up scruz.org as authoritative data, but were still serving other
zones -- and, again, their operators has said nothing to me as operator
of the master zone.

So, over a couple of years, all five of these guys had silently reduced
scruz.org's service redundancy from the official six nameservers of
record down to one (mine) -- but simply forgot to mention this fact.
And a bunch of them were now scolding _me_ -- the only guy who hadn't
shot the domain in the foot -- for unreliable nameservice.

The lesson was:  Never assume people will do The Right Thing when the
path of least resistance lies otherwise.  Monitor, monitor, monitor.


Lesson having been learned, I fixed the domain's redundancy _and_ wrote
up a quick-and-dirty weekly cronjob to report specifically to me about
which nameservers were still authoritative and serving up the correct
zonefile S/N (a key subfield of the 'SOA' = Start of Authority RR) this
week.  I no longer have that script (scruz.org is gone), but here's a
similar one that checks my two domains' nameservice:

:r /etc/cron.weekly/mydomains

#!/bin/sh

# mydomains     Cron script to sanity-check my domains' SOA records at
#               all of their authoritative nameservers, as a quick and 
#               dirty way of making sure (1) they're all online and
#               (2) they're all serving up the same data (or at least
#               data with the same zonefile serial number).
#  
#               The script queries all nameservers for their current
#               SOA value, and then uses awk to parse out of that 
#               verbose record just the S/N field, which is field #3.  
#               The point is that you can visually spot offline or 
#               aberrant nameservers by their S/Ns being (respectively) 
#               missing or an out-of-step value.
#
#		Written by Rick Moen (rick at linuxmafia.com)
#		$Id: cron.weekly,v 1.03 2011/05/21 00:35:00 rick
# Copyright (C) Rick Moen, 2011.  Do anything you want with this work.

set -o errexit  #aka "set -e": exit if any line returns non-true value
set -o nounset  #aka "set -u": exit upon finding an uninitialised variable

test -x /usr/bin/mail || exit 0
test -x /usr/bin/whois || exit 0
test -x /usr/bin/awk || exit 0
test -x /bin/grep || exit 0
test -x /usr/bin/dig || exit 0


{
echo "As of 2011-05-21, linuxmafia.com should show five authoritative nameservers:"
echo ""
echo "ns.primate.net. 198.144.194.12, (Aaron T. Porter)"
echo "ns.tx.primate.net. 72.249.38.88 (Aaron T. Porter)"
echo "ns3.linuxmafia.com. 63.193.123.122, aka ns.catwhisker.org (David Wolfskill)"
echo "ns1.thecoop.net. 66.220.20.163, (Drew Bertola)"
echo "ns1.linuxmafia.com. 198.144.195.186 (Rick Moen)"
echo ""
echo "As of 2011-05-21, unixmercenary.net should show five authoritative nameservers:"
echo ""
echo "ns.primate.net. 198.144.194.12, (Aaron T. Porter)"
echo "ns.tx.primate.net. 72.249.38.88 (Aaron T. Porter)"
echo "ns3.linuxmafia.com. 63.193.123.122, aka ns.catwhisker.org (David Wolfskill)"
echo "ns1.thecoop.net. 66.220.20.163, (Drew Bertola)"
echo "ns1.linuxmafia.com. 198.144.195.186 (Rick Moen)"
echo ""
echo "If any is missing from reports below, or produces odd data, something is wrong."
echo ""
echo "Zonefile S/Ns, linuxmafia.com:"
echo ""
dig -t soa linuxmafia.com. @ns.primate.net. +short | awk '{ print $3 " on ns.primate.net." }'
dig -t soa linuxmafia.com. @ns.tx.primate.net. +short | awk '{ print $3 " on ns.tx.primate.net." }'
dig -t soa linuxmafia.com. @ns3.linuxmafia.com. +short | awk '{ print $3 " on ns3.linuxmafia.com." }'
dig -t soa linuxmafia.com. @ns1.thecoop.net. +short | awk '{ print $3 " on ns1.thecoop.net."}'
dig -t soa linuxmafia.com. @ns1.linuxmafia.com. +short | awk '{ print $3 " on ns1.linuxmafia.com."}'
echo ""
echo "Zonefile S/Ns, unixmercenary.net:"
echo ""
dig -t soa unixmercenary.net. @ns.primate.net. +short | awk '{ print $3 " on ns.primate.net." }'
dig -t soa unixmercenary.net. @ns.tx.primate.net. +short | awk '{ print $3 " on ns.tx.primate.net." }'  
dig -t soa unixmercenary.net. @ns3.linuxmafia.com. +short | awk '{ print $3 " on ns3.linuxmafia.com." }'
dig -t soa unixmercenary.net. @ns1.thecoop.net. +short | awk '{ print $3 " on ns1.thecoop.net."}'
dig -t soa unixmercenary.net. @ns1.linuxmafia.com. +short | awk '{ print $3 " on ns1.linuxmafia.com."}' 
echo ""
echo "Authoritative nameservers from whois, linuxmafia.com:"
echo ""
whois linuxmafia.com | grep 'Name Server' | awk -F: '{ print $2 }' | head -n 7
echo ""
echo "Authoritative nameservers from whois, unixmercenary.net:"
echo ""
whois unixmercenary.net | grep 'Name Server' | awk -F: '{ print $2 }' | head -n 7
echo ""
echo "Parent-zone NS records and matching A records (glue), linuxmafia.com:"
echo ""
dig -t ns linuxmafia.com. @$(dig -t ns com. +short | head -n 1) +nocmd +noquestion +nostats +nocomments
echo ""
echo "Parent-zone NS records and matching A records (glue), unixmercenary.net:"
echo ""
dig -t ns unixmercenary.net. @$(dig -t ns net. +short | head -n 1) +nocmd +noquestion +nostats +nocomments
echo ""
echo "In-domain NS records and matching A records, linuxmafia.com:"
echo ""
dig -t ns linuxmafia.com. @$(dig -t ns linuxmafia.com. +short | head -n 1) +nocmd +noquestion +nostats +nocomments
echo ""
echo "In-domain NS records and matching A records, unixmercenary.net:"
echo ""
dig -t ns unixmercenary.net. @$(dig -t ns unixmercenary.net. +short | head -n 1) +nocmd +noquestion +nostats +nocomments

} |
mail -s "Domains linuxmafia.com and unixmercenary.net SOA check" rick at linuxmafia.com


Now, if one of the five silently vanishes, has extended downtime, gets
re-IPed, etc., I hear about it.  Then, the 'Oh, I forgot to tell you' 
excuse-making you hear from your flaky secondary-nameserver admins
becomes less annoying.

That's not a _good_ script for the purpose (ripe for being improved on),
but one of my rules of thumb is that the half-assed job you do beats
the perfect one you haven't gotten around to.


Many people doing authoritative DNS are blissfully unaware of doing it
badly because it's highly robust and forgiving of most ineptitude.
E.g., I tried to help one fellow (SVLUG's VP at the time) by telling him
his nameservice was dangerously thin because he had only two
authoritative nameservers listed for the domain, and one of them,
queried using dig, turned out to be malfunctioning.  He said 'What's the
big deal?  My domain still works.'  He'd evidently been putting up with
that and similar situations for years.  From his perspective, his
Internet presence hadn't failed catastrophically yet, so, so far, so
good.

RFC 1912 recommends minimum three, maximum seven.  Two is the
minimum _permitted_ (RFC 1918 section 2.8:  'You are required to have at
least two nameservers for every domain, though more is preferred), and
domain owners should always set three as the smallest amount of
redundancy to settle for.  I personally go with five as a good middle
value.


I mentioned my peeve about most DNS admins' overuse of the CNAME record
type.  I should perhaps explain what that's about.  A CNAME is an alias
record, which is to regular 'A' = address records, analogously, what a
symlink is to a file.  Let me give you a real-life example:
linuxmafia.com's DNS zonefile includes:

                IN      A       198.144.195.186
uncle-enzo      IN      A       198.144.195.186
enzo            IN      A       198.144.195.186
mail            IN      A       198.144.195.186
www             IN      A       198.144.195.186
ftp             IN      A       198.144.195.186
ns1             IN      A       198.144.195.186

Those are, you perceive all forward-lookup ('A') records pointing to the
same IP address, that of my main server.

Many people would make carefree use of the CNAME record type, instead,
on the theory that every line but the first one (the blank left-side one
that thus is for hostname 'linuxmafia.com') is (semantically) an alias,
so ought to be defined using the alias record-type -- like this:

                IN      A       198.144.195.186
uncle-enzo      IN      CNAME   linuxmafia.com.
enzo            IN      CNAME   linuxmafia.com.
mail            IN      CNAME   linuxmafia.com.
www             IN      CNAME   linuxmafia.com.
ftp             IN      CNAME   linuxmafia.com.
ns1             IN      CNAME   linuxmafia.com.

(Bad!  Don't do the above!)

This latter example works -- for suitably lowered-expectations values of
'works'.  The first (small) problem is lookup efficiency:  As with
symlinks, resolving the record is always going to require _two_ lookups,
the initial CNAME lookup and then coming back and also resolving the 'A'
record for FQDN 'linuxmafia.com.' to which the CNAME (alias) points.

The second problem is that of long-term maintenance:  Again, this is
closely parallel to the problem you get with overuse of symlinks.  One 
day, you happen to eliminate an 'A' record.  Are you going to always,
unfailingly, search the zonefile to also find and either repoint or
delete any CNAME pointed to the 'A' records's FQDN?  Experience suggests
'probably not'.  Using 'A' records rather than CNAME ones averts this
maintenance issue.

The third and most-fatal problem is that CNAME records have inherent
functionality disadvantages that are not visible unless you are on guard
about those problems.  In particular, for rather arcane reasons, it is
not valid DNS to point an MX (mail exchanger) or NS (name server) record
type at a name defined as a CNAME, only to one defined as an 'A' record.

More than once, I've been called in to diagnose a perplexing SMTP
deliverability issue:  Sysadmin reports that his/her SMTP host can
deliver to some remote SMTP destinations but that others mysteriously
refuse delivery.  One of the first things I check is the public DNS, and
sometimes I see:

$TTL 86400
$ORIGIN example.com.
@       IN      SOA     ns1.example.com.
admin.somewhere.com. (
                        2016030200              ; serial
                        7200                    ; refresh 2 hours
                        3600                    ; retry 1 hour
                        2419200                 ; expire 28 days
                        900                     ; negative TTL 15 mins
                        )
;
                IN      NS      ns1.example.com.
                IN      NS      ns2.example.com.
                IN      NS      ns3.example.net.
                IN      A       123.456.123.345
                IN      MX      10       mail
mail            IN      CNAME   george
george          IN      A       123.456.123.345

The 'MX' record says mail is to be dropped off at host 'mail', but
'mail' is defined by a CNAME (alias) record pointing to 'george', which
in turn is (finally) defined by an 'A' (forward lookup) record.  Thus,
the MX record is invalid.

RFC1034 section 3.6.2 says:

   If a CNAME RR is present at a node, no other data should be present;
   this ensures that the data for a canonical name and its aliases cannot
   be different.

http://serverfault.com/questions/91712/dns-using-cnames-breaks-mx-records

So, this is an easily-made bonehead error of DNS administration:  The
record certainly looks valid, the syntax is fine, but the SMTP host in
question will find that any receiving mail server that enforces the RFCs
will refuse its mail.


My own view is that the CNAME record type is best used _only_ for
pointing to an FQDN in a different zone, like this one in
linuxmafia.com's zonefile:

nsa             IN      CNAME   bxa.doc.gov.

In other word, in my opinion, the CNAME record type should be used
_only_ where no other record type can do the job.  Otherwise, always use
the 'A' (forward-lookup) record type.

Some DNS novices will object 'But that means if I need to change an my
host's IP address, I'll need to change it in every "A" record in the
zone that points to it.'  My answer is, 'Yes, and because you should
ideally make all such changes using sed and awk (or equivalent) to avoid
manual editing errors, it's just as easy to change 100 "A" records as it
is one.'  Reducing the number of lines that must be changed is solving
the wrong problem.


> Not to mention that I may lose my IPv6.
> «Porco Giuda» «Devo lavorare con persone idiota!» [1]
[...] 
> [1] Dr. Emilio Lizardo (BTW s/idiota/idiote/)
> Lizardo sounds more as a Spanish surname rather than Italian. Still
> we've been invaded by Spanish. I'd still say his accent is not
> Italian nor Spanish, but fun.

Even with the spelling error, it's still lovely idiomatic Italian
though, isn't it?  

I've never yet learned Italian properly.  My father spoke quite fluent
Italian with a Neapolitan accent, and if he'd lived longer I'd probably
have picked some up from him.  You might think that an eccentric skill
for my Norwegian-born American father to have, but that's the sort of
outcome warfare creates, as that is where Dad was in the 1940s.
(Ambrose Bierce commented, 'War is God's way of teaching Americans
geography.)


There's a lot more in the very bounteous category of 'How to do DNS
_wrong_', such as failing to keep NS records in the parent zone
identical to those in-zone.  Unfortunately, it's a long and detailed
list.  Perhaps one day I'll write a book.





More information about the conspire mailing list