I'm currently trying to write a script that validates, whether a given record attached to a name is available via all nameservers that are responsible for that name.

E.g. I would like to check whether there is an A record for foo.example.com available at all NS entries for the example.com domain (a.iana-servers.net and b.iana-servers.net)

The script works by first querying the NS records for the given name (or its parents if that fails; e.g. since foo.example.com. doesn't have an NS entry, we try example.com. next and finally .com.), and then checking the A record with all nameservers.

 # get the nameservers for ${name}
 until [ -z "x${sname}" ]; do
    dns=$(dig +short NS "${sname}")
    if [ "x${dns}" != "x" ]; then
# now that we have a list of nameservers in $dns, we query them
for ns in $dns; do
    dig +short A "${name}" @$"{ns}"

This kind of works, unless the name is actually a CNAME. In this case, a dig NS will return the CNAME record (rather than the NS record or no record)

$ dig +noall +answer NS foo.example.com
foo.example.com. 300 IN CNAME bar.example.com.
$ dig +short NS foo.example.com
$ dig A foo.example.com @bar.example.com
;; global options: +cmd
;; connection timed out; no servers could be reached

Instead I would like to have something like:

$ dig +short NS foo.example.com
$ dig +short NS example.com
$ dig +short A foo.example.com @a.iana-servers.net.

So my question is: how can I force dig to only return the NS records, and not some other record which points to a host that is not a nameserver?

One obvious solution is to parse the output of dig +noall +answer to see whether it actually contains an NS record, but this seems rather clumsy and error prone...

  • Although some systems violate the standard, officially there should NEVER be NS records for a name that has a CNAME record, nor any others except for DNSSEC; see en.wikipedia.org/wiki/CNAME_record#Restrictions . If foo.example.com CNAMEs to bar.example.com, you need to find the nameservers and thus A record(s) (or others) for bar.example.com (via its nearest apex). – dave_thompson_085 Dec 21 '16 at 12:10
  • @dave_thompson_085 fine with me; however i'm interested in finding out the nameservers that are responsible for a given name (e.g. foo.example.com), not necessarily the NS record that is attached to that name literally. So I don't think that CNAME-restriction applies (after all, some nameserver must be authoritative to tell that foo.example.com is a CNAME; how do I find out which?) – umläute Dec 21 '16 at 13:10
  • dig has no option to filter specific types of records from the result set. – Andrew B Dec 21 '16 at 16:12
  • Since NS records can't be at the same level as CNAME they must be at a higher level. (This is usually stated as "CNAME cannot be at the [zone] apex" or "The apex cannot be a CNAME".) You already have the logic for this, since it is often true of 'real' names as well. – dave_thompson_085 Dec 25 '16 at 9:54
  • @dave_thompson_085 so how do I detect from the output of dig that I actually queried a CNAME? neither grep -w CNAME nor using some other grep-strip (e.g. to match an IP) sounds particularily compelling or stable. – umläute Dec 26 '16 at 20:14

If you're at all comfortable with Perl, you can save yourself a whole lot of pretty finicky work by writing your test as a plugin to Zonemaster. Its framework already has (correct) code to find the right set of name servers and send a query to all of them.

  • I would encourage using a solution like this as well, simply because the problem can more complicated than is currently being tested for. (glue record mismatch anyone?) – Andrew B Dec 21 '16 at 16:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.