finding authoritative nameservers
Ronald F. Guilmette
rfg at tristatelogic.com
Mon May 19 18:38:41 UTC 2008
In message <48312BB9.2010704 at cohtech.com>,
Howard Wilkinson <howard at cohtech.com> wrote:
>Ronald F. Guilmette wrote:
>> I'd just like to know if there is any "sure fire" (or mostly sure fire)
>> way of getting a list of the real, true, and actual authoritative name
>> servers for one or both of:
>> (*) A fully-qualified domain name, which is believed to be
>> associated with at least one A record, or...
>> (*) some proper sort of ...in-addr.arpa name that is believed to
>> be associated with at least one PTR record.
>I have recently been writing some code to cover this problem and I think
>my approach works. But I do not claim it is the best and especially the
>What I do is query down from the root servers following the delegations
>given by each server queried. By querying for the NS servers of the
>target domain at each level in the hierarchy you eventually get a parent
>response. The algorithm is applied recursively to find the parent's
>parents by stripping one (or more) of the prefixes from the domain target.
>As the algorithm only accepts non-recursive answers from delegated
>parents the list of name servers retrieved are the only servers that can
>be authoritative (rather than claim to be authoritative) The final step
>is to query each of these name servers for their known name server list.
>They SHOULD all respond authoritatively with a list of name servers the
>same as the parents if everything is set up right. If not the
>intersection of what the parent delegates and what the zone servers that
>responded authoritatively are the best you are going to do.
>By using non-recursive lookups and crawling down the tree you SHOULD get
>a valid answer. However, if you have a set of interceptors in the way
>then the bets are off. Load balancers are an example that will defeat
>this if they are in your path but not everybody elses.
>Hope this makes sense (and is right!)
Thanks for your response. It is comforting to know that I'm not the only
one who has been groping around, looking for a solution to this problem.
Since I posted my eariler question, I totally re-wrote my code... for about
the fourth time... to use a totally new strategy, because I realized that
the strategy I described in my prior posting was utterly lame, and was WAY
Briefly, here's my new approach:
1) If looking for info about an IPv4 address, first convert that IPv4
address into its equivalent ...in-addr.arpa name. Otherwise, just
use the FQDN as given.
2) Perform an ordinary DNS query for the FQDN obtained in step (1).
The qtype for the query should be SOA.
3) If you DO NOT get a valid, non-corrupted response packet corresponding
to the query in (2), then die, otherwise proced to step (4).
4) Search the ANSWER section of the response packet for the preceeding
SOA query. Look specifically for an RR that (a) is an SOA record,
and that also (b) has a name field exactly corresponding (case
insensitive) to the name we asked about in our SOA query. If there
is one, then swell. In that case, proced to step 6. Otherwise
proceed to step 5.
5) Search the AUTHORITY section the response packet for the preceeding
SOA query. Look specifically for *any* SOA RR. Glom on to the
first one you find in the AUTHORITY section. If there are no SOA
records in the AUTHORITY section then die, else proceed to step 6.
(Note: We don't try to do the same kind of name matching in this
case as in step 4 above, because that can fail in cases involving
classless in-addr.arpa delegation... or so it seems anyway.)
6) Take the SOA record obtained in either step (5) or step (6) above
and fish the value of the "mname" (primary nameserver) field out of
7) Construct a new query having type ANY and with a "name" value equal
to the original FQDN that we wanted info about (i.e. the one we
accepted or created in step (1) above. Send this ANY query directly
and only to the *primary nameserver* for the thing of interest, as
obtained in either step (5) or (6) above. IMPORTANT!! For this query,
and this query only, be sure to *disable* recursion, i.e. by clearing
the RD bit in the header of the query packet before sending it. (We
do this because we only want to know what the alleged primary name
server knows. We DO NOT want it to ask anybody else for any info in
8) If you DO NOT get back a valid, non-corrupted response to the type
`ANY' query that was sent (to just the primary nameserver) in step (7)
above, then die. Otherwise, continue to step 9.
9) Search the RRs of the ANSWER section of the response packet correspon-
ding to the ANY query that we sent in step (7) above. Look specifically
for *any* ANSWER section RR whose name field corresponds to the thing
we asked about. If there are -zero- such RRs in the answer section,
then die. In this case, the *purported* primary name server for the
thing we were actually interested in doesn't know *anything* about it,
so maybe somebody lied in the mname field of the SOA we obtained
eariler, or something else weird has gone wrong. In any case, this
alleged primary name server doesn't know anything about the FQDN
that we were seeking a list of nameservers for, so just give up now
and declare defeat. Otherwise, if the ANSWER section DOES contain
one or more RRs whose name field is exactly equal to the thing we
asked about, then procced to step 10.
10) Search the AUTHORITY section of response packet corresponding to the
query we sent (to the alleged primary nameserver) in step (7) above.
fish out any type NS records you find. Add the nameserver names that
you obtaine from all of those to the name of the primary nameserver,
which you already have.
Volia! You now have a full(?) list of authoritative nameservers.
I haven't thought about it deeply, but I do think that your approach will
also yield correct and useful answers. But obviously, as you already know,
it is a royal pain in the ass to have to perform all your own recursion steps
"manually". A lot of coding there!
As you can see, in the procedure I've described above I simply allow my own
local nameserver(s) to handle all of that annoying recursion work for me.
I just ask it to give me an SOA record for the thing of interest, and it
does all of the hard work to find one of those for me. (And if it gets
that SOA records, directly or indirect, from somebody who has it cached,
that's perfectly OK. No big deal. As long as the "mname" field hasn't
been tampered with, then that's all I ned.)
Once I have a valid copy of an SOA records that relates to the thing of
interest, then things get real simple. At that point I can, in effect,
just ask the primary nameserver for the thing of interest (as identified in
the mname field fo the SOA record) for the whole list of nameservers for the
thing of interest, and then I'm done. (Actually, of course, you ask the
primary for the full list of nameservers for the thing of interest by
sending it an ANY query for the thing of interest... with the RD...
Recursion Desired... bit turned off and then fishing the name server list
out of the AUTHORITY section of any response you get to that ANY query.)
So anyway, even though I've described it verbosely above, the approach I've
dscribed definitely would seem to be programatically simpler than the
one you decribed... a lot simpler. That's the good news. The bad news
is that for a variety of reasons, it may in some cases produce results
that aren't as comprehensive as the ones you will get with your method.
I suspect that glue records in various base zones might cause the actual
DNS to find & consult nameservers for the thing of interest that my method
won't find. Also, your method may find secondaries that, for whatever
reasons, the primary knows nothing about. But my method seems to work
adequately well for _my limited purposes_, which is to try (but not
necessarily Really Hard) to find out who is providing name service to
whom. (This information may have applications in spammer tracking and/or
assignment of partial blame/responsibility to entities that are supporting
spammers by providing them with DNS and/or rDNS.)
More information about the bind-users