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