DNS ... CNAME records ... to CNAMES? How long a chain? Loops? ...
So, sometimes the question comes up, can you do a CNAME to a CNAME? Yes, ... but not recommended. What about CNAME to CNAME to CNAME ...? Again, not recommended, but within reason, it will still work. Up to? Probably 8, ... maybe 16 ... more than that? Hypothetically, but mostly not. What about a CNAME loop? That should cleanly fail ... but that doesn't mean it always does.
I set up some CNAME "test" records again ... if folks wanted to poke at such a bit and see how it behaves. First teensy primer on number bases >10 and >16 ... just continue the character sequence so ... I use some base36 - characters go from 0 through 9 then a through z. I did that to make the coding/interpretation of such fairly easy to be able to go up to 36 with a single character. Anyway, set up temporarily (goes away # at -l | fgrep root 71 Sat Nov 12 09:52:00 2022 a root ) fair number of CNAME records one can poke at, notably a chain, and several loops. So, the chain ... eventually resolves to working IPs ..., we have: cc-0-tmp.balug.org. IN CNAME www.balug.org. cc-1-tmp.balug.org. IN CNAME cc-0-tmp.balug.org. cc-2-tmp.balug.org. IN CNAME cc-1-tmp.balug.org. cc-3-tmp.balug.org. IN CNAME cc-2-tmp.balug.org. ... cc-h-tmp.balug.org. IN CNAME cc-g-tmp.balug.org. cc-i-tmp.balug.org. IN CNAME cc-h-tmp.balug.org. cc-j-tmp.balug.org. IN CNAME cc-i-tmp.balug.org. (cc - think Cname Chain) so, a chain of 20 (0 through j, base36) CNAME records. Feel free to, e.g. try resolving, doing some use of dig(1) to lookup the DNS data, etc. Oh, and yes, works as a web site ... cert even matches those names ... but since those CNAMES aren't canonical names for that site, the website is configured to redirect to a canonical name for the web site. Loops! Yes, also set up CNAME loops of various sizes one can poke at: cl-0-tmp.balug.org. IN CNAME cl-0-tmp.balug.org. cl-01-tmp.balug.org. IN CNAME cl-10-tmp.balug.org. cl-10-tmp.balug.org. IN CNAME cl-01-tmp.balug.org. cl-012-tmp.balug.org. IN CNAME cl-201-tmp.balug.org. cl-120-tmp.balug.org. IN CNAME cl-012-tmp.balug.org. cl-201-tmp.balug.org. IN CNAME cl-120-tmp.balug.org. ... cl-0123456789abcdef-tmp.balug.org. IN CNAME cl-f0123456789abcde-tmp.balug.org. ... cl-0123456789abcdefg-tmp.balug.org. IN CNAME cl-g0123456789abcdef-tmp.balug.org. ... cl-0123456789abcdefgh-tmp.balug.org. IN CNAME cl-h0123456789abcdefg-tmp.balug.org. So cl (think Cname Loop), loops from 1 to 18 CNAME records in each loop. If we use > to represent our link, we have these loops - showing the portion that varies in each name: 0>0 01>10>01 012>201>120>012 ... 0123456789abcdefgh>h0123456789abcdefg>...>0123456789abcdefgh
Also, RFC 1034 (look for "loop" within) we have: The recommended priorities for the resolver designer are:
1. Bound the amount of work (packets sent, parallel processes started) so that a request can't get into an infinite loop or start off a chain reaction of requests or queries with other implementations EVEN IF SOMEONE HAS INCORRECTLY CONFIGURED SOME DATA.
domain software should not fail when presented with CNAME chains or loops; CNAME chains should be followed and CNAME loops signaled as an error.
Multiple levels of aliases should be avoided due to their lack of efficiency, but should not be signaled as an error. Alias loops and aliases which point to non-existent names should be caught and an error condition passed back to the client.
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.
And ... was pretty easy to write little program to create the records ... and get rid of same records. Yes, Dynamic DNS (DDNS) also makes it quite nice 'n easy, and also at(1) to later do the removals: #!/bin/sh
# add/del CNAME chain / loop(s)
set -e
suffix=-tmp.balug.org. ttl=300 b="$(basename "$0")" case "$b" in add|CNAMEadd) adddel=add ;; del|CNAMEdel) adddel=del ;; *) echo "$0: expecting to be invoked as add, CNAMEadd, del, or" \ "CNAMEdel, aborting" 1>&2 exit 1 ;; esac
# our base36 digits: seq=0123456789abcdefghijklmnopqrstuvwxyz # max 36
{ # CNAME chain prefix=cc- # Cname Chain c0=www.balug.org. # Chain 0 to (anchor) max=20 # integer between 2 and 36, this is count, not value set -- \ $( echo "$seq" | sed -ne ' s/^(.{'"$max"'}).*$/\1/ s/./& /gp ' ) o="$1"; shift echo "update $adddel $prefix$o$suffix $ttl IN CNAME $c0" while : do case "$1" in ?):;;*)break;;esac # break if < 1 arg echo "update $adddel $prefix$1$suffix $ttl IN CNAME" \ "$prefix$o$suffix" o="$1"; shift done
# CNAME loops prefix=cl- # Cname Loop max=18 # integer between 1 and 36 n="$max" while [ "$n" -ge 1 ] do a=$( echo "$seq" | sed -ne 's/^(.{'"$n"'}).*$/\1/p' ) while : do b=$( echo "$a" | sed -ne 's/^(.*)(.)$/\2\1/p' ) echo "update $adddel $prefix$a$suffix $ttl IN CNAME" \ "$prefix$b$suffix" case "$b" in 0*) break;; esac # last one a="$b" done n="$(expr "$n" - 1)" done
echo send } | nsupdate -l
Quoting Michael Paoli (Michael.Paoli@cal.berkeley.edu):
DNS ... CNAME records ... to CNAMES? How long a chain? Loops? ...
Or: Just don't.
Over a very large number of years of doing authoritive DNS, including for some large Internet concerns, I eventually came up with a guideline: Use a CNAME _only_ when an A (and/or AAAA) record cannot do the job -- and that basically means a cross-domain name reference.
All other uses of CNAME create risk of errors, one or more of:
1. CNAME breaks because you renamed the thing it used to point to, but forgot to update the CNAME record. (In fairness, this is also a risk with cross-domain name references, but nothing fixes that.) This error mode is analogous to the "dangling symlink" problem that teaches all sysadmins "don't use a symlink unless a hard link cannot do the job".
2. You absent-mindedly pointed one of the record types at the CNAME for which that reference is invalid (MX, NS), and had puzzling problems until you figured that out.
Both of these failure-modes go away automatically if you use, instead, A or AAAA records pointing directly to the IP in question.
There is a standard objection one hears _every_ time this is discussed, so I'll quote it and point out why it is dumb. "But, if I do that, then any time I re-IP the underlying host, I'll need to change all the A or AAAA records to match, whereas if n-1 of the records are symlinks, I need update only _one_ record."
That is true, but dumb -- because a single sed statement can change n lines citing an IP exactly as easily as it can one.
And, believe me, you really need to learn to use scripted editing to do DNS maintenance, anyway. It not only prevents most errors, but makes any you commit much easier to find. Also, it makes rollback trivial and fast, no matter how many lines are affected.
Version B of the dumb objection is: "But, because the zone is built out of multiple include files, I'd need to make any IP change in a bunch of separate files, whereas if n-1 of the records are symlinks, I need update only _one_ record."
That is true, but dumb -- because a single one-liner with find, exec, and sed can change n lines citing an IP across a group of include files exactly as easily as it can one.
Let's see, do I follow my own rule?
:r! grep CNAME /etc/bind/linuxmafia.com.zone [censored] IN CNAME gv-[censored].dv.googlehosted.com.
Yep. That's the a record you can voluntarily add to your domain if you want to use some of Google's services and let Google verify that the domain is yours, like Google's webmaster tools. https://webmasters.stackexchange.com/questions/54527/why-is-googlehosted-com... (now called Google Search Console, https://search.google.com/search-console/about )
Everything else in linuxmafia.com that _most_ people would use CNAMEs for, I use A records -- because that works and makes the possibility of whole classes of problem go away.
On 2022-10-13 00:48, Rick Moen wrote:
Quoting Michael Paoli (Michael.Paoli@cal.berkeley.edu):
DNS ... CNAME records ... to CNAMES? How long a chain? Loops? ...
Or: Just don't.
Yup, that's generally best approach - at least as feasible.
I tend to, e.g. see o a CNAME record and think, uhm, yeah, not optimal - at least generally, and certainly never optimal for performance. o a CNAME to a CNAME ... will typically elicit a groan. o a CNAME to a CNAME to a CNAME ... in production, generally a WTF, a double take, a double check, a shaking of the head and quite the look of disapproval. o etc. o And ... possibly excepting if it's merely for temporary test / / demonstration / educational purposes ... and has really or essentially no production impacts. So, yeah, those temporary ones I dropped in ... those fit that category.
And yes, temporary, they do go away soon(ish): # at -l | grep '^71'; at -c 71 | sed -ne "/^echo '/{s/$/\n.../p};/^send'/,$p" 71 Sat Nov 12 09:52:00 2022 a root echo 'update del cc-0-tmp.balug.org. 300 IN CNAME www.balug.org. ... send' | nspdate -l :
#
Over a very large number of years of doing authoritive DNS, including for some large Internet concerns, I eventually came up with a guideline: Use a CNAME _only_ when an A (and/or AAAA) record cannot do the job -- and that basically means a cross-domain name reference.
All other uses of CNAME create risk of errors, one or more of:
Yes, many things that can go wrong - not to mention always sub-optimal performance (at the very least, additional data getting dragged along, and that's "best" case).
And all kinds of nastiness can happen if NS and CNAME records interact, again, yeah, just don't.
And, believe me, you really need to learn to use scripted editing to do DNS maintenance, anyway. It not only prevents most errors, but makes any you commit much easier to find. Also, it makes rollback trivial and fast, no matter how many lines are affected.
Absolutely! E.g. those test CNAME records I have in place ... yeah, 191 such records ... easily and programmatically added. And likewise they also go away when their time has come ... and don't even need to remember, as at(1) will be handling that for me.
Sysadmin laziness^UDevOps efficiency - notably automation, is a good thing!
That is true, but dumb -- because a single one-liner with find, exec, and sed can change n lines citing an IP across a group of include files exactly as easily as it can one.
Yes, very much so ... and there are many other possible approaches that can similarly update all the relevant, quickly, easily, and with negligible probability of introducing errors.
Let's see, do I follow my own rule?
:r! grep CNAME /etc/bind/linuxmafia.com.zone [censored] IN CNAME gv-[censored].dv.googlehosted.com.
Yep. That's the a record you can voluntarily add to your domain if you want to use some of Google's services and let Google verify that the domain is yours, like Google's webmaster tools.
Hmmm, I thought they offered some other record type(s) (TXT?) ... but I haven't looked at that in a while. Yeah, peeking, have some older TXT records in balug.org. domain for same or similar with Google ... though I'm not 100% sure they're still fully functional. And they may not cover all the current relevant.
Everything else in linuxmafia.com that _most_ people would use CNAMEs for, I use A records -- because that works and makes the possibility of whole classes of problem go away.
And, checking for all CNAME records across all the LUG and related domains that, at least I cover the primary master for: balug.org. e.9.1.0.5.0.f.1.0.7.4.0.1.0.0.2.ip6.arpa. sf-lug.org. sf-lug.com. sflug.org. sflug.com. sflug.net. sf-lug.net. berkeleylug.com. if I exclude the 191 test CNAME records (easy to do since I did a very nice regular naming convention on them), after removing those, total count of CNAME records remaining across all those domains is: 0 Yep, one big fat goose egg. :-) So ... around 2022-11-12T09:52:00Z ... well plus TTL of 300s, so: 2022-11-12T09:57:00Z - I'm expecting that total all inclusive CNAME count (unless something else gets added before then) to again be back to lovely zero ... the origin from which we all count. ;-)