Subject: Re: another question about interpretation of the scriptures: cname chains

From: Josh Littlefield <[email-masked]>
Date: Mon, 03 Apr 2006 14:58:55 -0400

Paul Vixie wrote:
> i know that an authority server can emit an incomplete cname chain if it
> leads outside the servers's authority zone(s).  but what should a recursive
> server return if a cname chain from the qname leads to an NXDOMAIN?  my
> intuition says "return NXDOMAIN" since the nonterminal cname chain has no
> value and no meaning to an RD=1 initiator.  but i note with dismay that BIND
> actually emits the nonterminal chain as if it were an answer to the question.
> 

Not sure if you are saying BIND returns NOERROR with a CNAME chain, or 
NXDOMAIN with a CNAME chain.  I assume the latter would not be a 
surprise to you (I think its correct), so I assume you mean the former.

Returning NOERROR with a non-terminal CNAME chain to an RD=1 query might 
be a no-data negative response (depending on the content of the auth 
section), which not exactly true, though without DNSSEC I don't know if 
its all that bad.  Its certainly better that a referral (which is 
useless to a stub-resolver.

RFC 2308 clarified that an NXDOMAIN response may include a CNAME chain 
leading to the non-existent name terminating that chain.  2308 doesn't 
specifically talk about caching such a response (with CNAMEs), but I 
think its reasonable to conclude that since such a response indicates 
that the terminal name does not exist, this non-existence may be cached 
(assuming the answer includes an SOA relevant to the non-existent name).

So I think it seems appropriate for a non-authoritative server to 
provide  this same response from cache, as it would any other negative 
response.  From there, I don't think it's a leap to say that there 
should be no difference in behavior between a server answering from 
cache and a server that has to recurse before answering to discover the 
same information.

-- 
=====================================================================
Josh Littlefield                                  Cisco Systems, Inc.
[email-masked]                             1414 Massachusetts Avenue
tel: 978-936-1379  fax: 978-936-2226       Boxborough, MA  01719-2205

--
to unsubscribe send a message to [email-masked] with
the word 'unsubscribe' in a single line as the message text body.
archive: <http://ops.ietf.org/lists/namedroppers/>

---

From: Alan Barrett <[email-masked]>
Date: Mon, 3 Apr 2006 21:03:38 +0200

On Mon, 03 Apr 2006, Paul Vixie wrote:
> i know that an authority server can emit an incomplete cname chain if
> it leads outside the servers's authority zone(s). but what should a
> recursive server return if a cname chain from the qname leads to an
> NXDOMAIN? my intuition says "return NXDOMAIN" since the nonterminal
> cname chain has no value and no meaning to an RD=1 initiator. but i
> note with dismay that BIND actually emits the nonterminal chain as if
> it were an answer to the question.

My intuition says: NXDOMAIN means that the node does not exist in the
graph, and that's clearly not the case when a node exists and has a
CNAME record.  The dangling CNAME *is* an answer to the question.

My intuition also says: RD=1 queries should be processed exacly like
RD=0 queries until the point where you know whether or not you have an
answer.  At that point, if you don't have an answer, then RD=0 queries
return an error or referral, whle RD=1 queries recurse; but if you have
an answer (even if it's a dangling CNAME), then you return that answer,
regardless of RD=0 or RD=1.

--apb (Alan Barrett)

---

From: bert hubert <[email-masked]>
Date: Mon, 3 Apr 2006 21:14:52 +0200

> value and no meaning to an RD=1 initiator.  but i note with dismay that BIND

Which is what the PowerDNS recursor does, although I thought I'd implemented
it to return SERVFAIL. So far for my memory.

This happens because PowerDNS basically restarts the query as if the target
of the CNAME had been the query, which causes a NXDOMAIN.

Output:

;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 32827
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 0
;; QUESTION SECTION:
;dangle.ds9a.nl.                        IN      A

;; ANSWER SECTION:
dangle.ds9a.nl.         3600    IN      CNAME   bestanie.nowhere.

;; AUTHORITY SECTION:
.                       86400   IN      SOA     A.ROOT-SERVERS.NET.
NSTLD.VERISIGN-GRS.COM. 2006040200 1800 900 604800 86400

Trace:

question for 'dangle.ds9a.nl|A' from 127.0.0.1
dangle.ds9a.nl: Looking for CNAME cache hit of 'dangle.ds9a.nl|CNAME'
dangle.ds9a.nl: No CNAME cache hit of 'dangle.ds9a.nl|CNAME' found
dangle.ds9a.nl: Looking for direct cache hit of 'dangle.ds9a.nl|A', negative cached: 0
dangle.ds9a.nl: No cache hit for 'dangle.ds9a.nl|A', trying to find an appropriate NS record
dangle.ds9a.nl: Checking if we have NS in cache for 'dangle.ds9a.nl'
dangle.ds9a.nl: Checking if we have NS in cache for 'ds9a.nl'
dangle.ds9a.nl: NS (with ip, or non-glue) in cache for 'ds9a.nl' -> 'ns1.pine.nl'
dangle.ds9a.nl: within bailiwick: 0, not in cache
dangle.ds9a.nl: NS (with ip, or non-glue) in cache for 'ds9a.nl' -> 'ns2.pine.nl'
dangle.ds9a.nl: within bailiwick: 0, not in cache
dangle.ds9a.nl: We have NS in cache for 'ds9a.nl'
dangle.ds9a.nl: Cache consultations done, have 2 NS to contact
dangle.ds9a.nl: Nameservers: ns2.pine.nl(0ms), ns1.pine.nl(6ms)
dangle.ds9a.nl: Trying to resolve NS ns2.pine.nl (1/2)
  ns2.pine.nl: Looking for CNAME cache hit of 'ns2.pine.nl|CNAME'
  ns2.pine.nl: No CNAME cache hit of 'ns2.pine.nl|CNAME' found
  ns2.pine.nl: Looking for direct cache hit of 'ns2.pine.nl|A', negative cached: 0
  ns2.pine.nl: Found cache hit for A: 217.114.101.235[ttl=86399] 
dangle.ds9a.nl: Resolved 'ds9a.nl' NS ns2.pine.nl to 217.114.101.235, asking 'dangle.ds9a.nl|A'
dangle.ds9a.nl: Got 27 answers from ns2.pine.nl (217.114.101.235), rcode=0, in 14ms
dangle.ds9a.nl: accept answer 'dangle.ds9a.nl|CNAME|bestanie.nowhere.' from 'ds9a.nl' nameservers? YES!
dangle.ds9a.nl: accept answer '|NS|a.root-servers.net.' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer '|NS|h.root-servers.net.' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer '|NS|c.root-servers.net.' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer '|NS|g.root-servers.net.' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer '|NS|f.root-servers.net.' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer '|NS|b.root-servers.net.' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer '|NS|j.root-servers.net.' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer '|NS|k.root-servers.net.' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer '|NS|l.root-servers.net.' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer '|NS|m.root-servers.net.' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer '|NS|i.root-servers.net.' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer '|NS|e.root-servers.net.' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer '|NS|d.root-servers.net.' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer 'a.root-servers.net|A|198.41.0.4' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer 'h.root-servers.net|A|128.63.2.53' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer 'c.root-servers.net|A|192.33.4.12' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer 'g.root-servers.net|A|192.112.36.4' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer 'f.root-servers.net|A|192.5.5.241' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer 'b.root-servers.net|A|192.228.79.201' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer 'j.root-servers.net|A|192.58.128.30' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer 'k.root-servers.net|A|193.0.14.129' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer 'l.root-servers.net|A|198.32.64.12' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer 'm.root-servers.net|A|202.12.27.33' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer 'i.root-servers.net|A|192.36.148.17' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer 'e.root-servers.net|A|192.203.230.10' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: accept answer 'd.root-servers.net|A|128.8.10.90' from 'ds9a.nl' nameservers? NO!
dangle.ds9a.nl: determining status after receiving this packet
dangle.ds9a.nl: got upwards/level NS record '' -> 'a.root-servers.net.', had 'ds9a.nl'
dangle.ds9a.nl: got upwards/level NS record '' -> 'h.root-servers.net.', had 'ds9a.nl'
dangle.ds9a.nl: got upwards/level NS record '' -> 'c.root-servers.net.', had 'ds9a.nl'
dangle.ds9a.nl: got upwards/level NS record '' -> 'g.root-servers.net.', had 'ds9a.nl'
dangle.ds9a.nl: got upwards/level NS record '' -> 'f.root-servers.net.', had 'ds9a.nl'
dangle.ds9a.nl: got upwards/level NS record '' -> 'b.root-servers.net.', had 'ds9a.nl'
dangle.ds9a.nl: got upwards/level NS record '' -> 'j.root-servers.net.', had 'ds9a.nl'
dangle.ds9a.nl: got upwards/level NS record '' -> 'k.root-servers.net.', had 'ds9a.nl'
dangle.ds9a.nl: got upwards/level NS record '' -> 'l.root-servers.net.', had 'ds9a.nl'
dangle.ds9a.nl: got upwards/level NS record '' -> 'm.root-servers.net.', had 'ds9a.nl'
dangle.ds9a.nl: got upwards/level NS record '' -> 'i.root-servers.net.', had 'ds9a.nl'
dangle.ds9a.nl: got upwards/level NS record '' -> 'e.root-servers.net.', had 'ds9a.nl'
dangle.ds9a.nl: got upwards/level NS record '' -> 'd.root-servers.net.', had 'ds9a.nl'
dangle.ds9a.nl: status=got a CNAME referral, starting over with bestanie.nowhere
bestanie.nowhere: Looking for CNAME cache hit of 'bestanie.nowhere|CNAME'
bestanie.nowhere: No CNAME cache hit of 'bestanie.nowhere|CNAME' found
bestanie.nowhere: Looking for direct cache hit of 'bestanie.nowhere|A', negative cached: 0
bestanie.nowhere: No cache hit for 'bestanie.nowhere|A', trying to find an appropriate NS record
bestanie.nowhere: Checking if we have NS in cache for 'bestanie.nowhere'
bestanie.nowhere: Checking if we have NS in cache for 'nowhere'
bestanie.nowhere: Checking if we have NS in cache for ''
bestanie.nowhere: NS (with ip, or non-glue) in cache for '' -> 'a.root-servers.net'
bestanie.nowhere: within bailiwick: 1, in cache, ttl=3599994
bestanie.nowhere: NS (with ip, or non-glue) in cache for '' -> 'b.root-servers.net'
bestanie.nowhere: within bailiwick: 1, in cache, ttl=3599994
bestanie.nowhere: NS (with ip, or non-glue) in cache for '' -> 'c.root-servers.net'
bestanie.nowhere: within bailiwick: 1, in cache, ttl=3599994
bestanie.nowhere: NS (with ip, or non-glue) in cache for '' -> 'd.root-servers.net'
bestanie.nowhere: within bailiwick: 1, in cache, ttl=3599994
bestanie.nowhere: NS (with ip, or non-glue) in cache for '' -> 'e.root-servers.net'
bestanie.nowhere: within bailiwick: 1, in cache, ttl=3599994
bestanie.nowhere: NS (with ip, or non-glue) in cache for '' -> 'f.root-servers.net'
bestanie.nowhere: within bailiwick: 1, in cache, ttl=3599994
bestanie.nowhere: NS (with ip, or non-glue) in cache for '' -> 'g.root-servers.net'
bestanie.nowhere: within bailiwick: 1, in cache, ttl=3599994
bestanie.nowhere: NS (with ip, or non-glue) in cache for '' -> 'h.root-servers.net'
bestanie.nowhere: within bailiwick: 1, in cache, ttl=3599994
bestanie.nowhere: NS (with ip, or non-glue) in cache for '' -> 'i.root-servers.net'
bestanie.nowhere: within bailiwick: 1, in cache, ttl=3599994
bestanie.nowhere: NS (with ip, or non-glue) in cache for '' -> 'j.root-servers.net'
bestanie.nowhere: within bailiwick: 1, in cache, ttl=3599994
bestanie.nowhere: NS (with ip, or non-glue) in cache for '' -> 'k.root-servers.net'
bestanie.nowhere: within bailiwick: 1, in cache, ttl=3599994
bestanie.nowhere: NS (with ip, or non-glue) in cache for '' -> 'l.root-servers.net'
bestanie.nowhere: within bailiwick: 1, in cache, ttl=3599994
bestanie.nowhere: NS (with ip, or non-glue) in cache for '' -> 'm.root-servers.net'
bestanie.nowhere: within bailiwick: 1, in cache, ttl=3599994
bestanie.nowhere: We have NS in cache for ''
bestanie.nowhere: Cache consultations done, have 13 NS to contact
bestanie.nowhere: Nameservers: l.root-servers.net(0ms), k.root-servers.net(0ms), g.root-servers.net(0ms), d.root-servers.net(0ms), 
bestanie.nowhere:              b.root-servers.net(0ms), e.root-servers.net(0ms), m.root-servers.net(0ms), a.root-servers.net(0ms), 
bestanie.nowhere:              f.root-servers.net(0ms), h.root-servers.net(0ms), c.root-servers.net(0ms), i.root-servers.net(8ms), 
bestanie.nowhere:              j.root-servers.net(93ms)
bestanie.nowhere: Trying to resolve NS l.root-servers.net (1/13)
  l.root-servers.net: Looking for CNAME cache hit of 'l.root-servers.net|CNAME'
  l.root-servers.net: No CNAME cache hit of 'l.root-servers.net|CNAME' found
  l.root-servers.net: Looking for direct cache hit of 'l.root-servers.net|A', negative cached: 0
  l.root-servers.net: Found cache hit for A: 198.32.64.12[ttl=3599994] 
bestanie.nowhere: Resolved '' NS l.root-servers.net to 198.32.64.12, asking 'bestanie.nowhere|A'
bestanie.nowhere: Got 1 answers from l.root-servers.net (198.32.64.12), rcode=3, in 181ms
bestanie.nowhere: accept answer '|SOA|A.ROOT-SERVERS.NET. NSTLD.VERISIGN-GRS.COM. 2006040200 1800 900 604800 86400' from '' nameservers? YES!
bestanie.nowhere: determining status after receiving this packet
bestanie.nowhere: got negative caching indication for RECORD 'bestanie.nowhere'
bestanie.nowhere: status=NXDOMAIN, we are done (have negative SOA)
bestanie.nowhere: failed
dangle.ds9a.nl: failed
answer to question 'dangle.ds9a.nl|A': 1 answers, 0 additional, took 2 packets, 0 throttled, 0 timeouts, 0 tcp connections, rcode=3

-- 
http://www.PowerDNS.com      Open source, database driven DNS Software 
http://netherlabs.nl              Open and Closed source services

---

From: Florian Weimer <[email-masked]>
Date: Tue, 04 Apr 2006 14:01:38 +0200

> actually emits the nonterminal chain as if it were an answer to the question.

The BIND behavior probably looks like NODATA.

I don't know what most clients do when confronted with CNAME records
(as there is no standard DNS processing library *sigh*).  They
probably just look at the answer section and snarf the records of the
type they requested, leading to a NODATA behavior in this case.  This
behavior makes sense to me, more than the NXDOMAIN behavior (after
all, there is some RR at the requested domain name, but none of the
requested type).

Just my .02 EUR.

---

From: [email-masked] (Andreas Gustafsson)
Date: Tue, 4 Apr 2006 15:19:27 +0300

> actually emits the nonterminal chain as if it were an answer to the question.

I'm confused as to what you think is a problem here.  I checked what
BIND 9.3.1 does, and it does return NXDOMAIN as expected.  The
response also has a CNAME chain, but that's not "the answer" - 
the NXDOMAIN is.

As for the CNAME chain having "no value and no meaning to an RD=1
initiator", you could equally well make that statement about positive
answers containing a CNAME chain and an answer RRset.  Why should
NXDOMAINs be treated any differently?

See also RFC1034 section 4.3.1:

  If recursive service is requested and available, the recursive response
  to a query will be one of the following:

     - The answer to the query, possibly preface by one or more CNAME
       RRs that specify aliases encountered on the way to an answer.

     - A name error indicating that the name does not exist.  This
       may include CNAME RRs that indicate that the original query
       name was an alias for a name which does not exist.

-- 
Andreas Gustafsson, [email-masked]

---

From: Edward Lewis <[email-masked]>
Date: Tue, 4 Apr 2006 08:37:36 -0700

>actually emits the nonterminal chain as if it were an answer to the question.

This is a dilemma for the same reason why the query count can't be 
more than 1.  There's only one RCODE field, that's the problem.

Let's say there's "first CNAME second", with first in the authority 
of the server and second not, further, not even existent.

If the RCODE is for the first, then it ought to be "NO ERROR" as 
you've found the name ("name error" means the name lookup failed). 
There's no RCODE for "PARTIAL ANSWER" which is most appropriate when 
just a CNAME set is returned but not asked for.  If the RCODE is for 
the second, then "NAME ERROR" is appropriate.

Hmm, what's a server to do?

First question, is this a real problem, is it begging to be solved?

Second question, does it matter?  Won't resolvers be smart enough, if 
properly implemented, to deal with the two responses?  I mean, 
coherency doesn't mean consistency.

Up to me, using a 30 seconds-of-thought heuristic, I would say that 
the server use the RCODE for first if there is a problem with second. 
Let the resolver discover the problem (too), force the work back on 
them.  Yes, that means the recursive work goes unused - but that's 
operational slop.

-- 
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Edward Lewis                                                +1-571-434-5468
NeuStar

Nothin' more exciting than going to the printer to watch the toner drain...