I was interested in how a recursive DNS server resolves DNS queries in detail. That is, not only the mere AAAA or A record, but also DNSSEC keys and signatures, the authority and additional section when testing with
dig, and so on. For this I made two simple DNS queries to my recursive DNS server which resulted in more than 100 DNS packets at all. Wow.
In the following I am publishing a downloadable pcap so that you can analyse it by yourself. Furthermore I am showing some listings and screenshots to get an idea of the DNS resolution process.
Test Setup
Of course such tests heavily depend on the queried names. I chose the following two:
- atlas.ripe.net <- quite simple and only one CNAME behind it, DNSSEC signed
- www.netflix.com <- quite complex with geo load-balancing, no DNSSEC
For both queries I used dig to ask my recursive DNS server BIND (with a cleared cache!) for the A record. Since this server has DNSSEC validation enabled, it looked for DNSKEY/DS records as well. All DNS sessions are either sent via IPv6 or legacy IP, and over UDP or TCP. (I cut off the TCP overheads completely to only have the DNS related packets. Note the different colors in Wireshark or look at the udp/tcp.stream columns.)
PCAP Download
Feel free to use this capture file (zipped, 10 KB) and open it with Wireshark:
Some Details: atlas.ripe.net
The first query for the A record of atlas.ripe.net generated 14 DNS packets. Beside the query for the A record and the corresponding CNAME record (both with RRSIGs included), BIND also queried the DNSKEY (from the authoritative name server) and DS records (from the parent zone) in order to completely validate the answers via DNSSEC. The query looked like this. Note the “ad” flag since the reply is DNSSEC validated:
weberjoh@nb15-lx:~$ dig atlas.ripe.net ; <<>> DiG 9.10.3-P4-Ubuntu <<>> atlas.ripe.net ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41063 ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 2, AUTHORITY: 7, ADDITIONAL: 13 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;atlas.ripe.net. IN A ;; ANSWER SECTION: atlas.ripe.net. 21600 IN CNAME atlas-ui.ripe.net. atlas-ui.ripe.net. 21600 IN A 193.0.6.158 ;; AUTHORITY SECTION: ripe.net. 3600 IN NS a2.verisigndns.com. ripe.net. 3600 IN NS a3.verisigndns.com. ripe.net. 3600 IN NS manus.authdns.ripe.net. ripe.net. 3600 IN NS sns-pb.isc.org. ripe.net. 3600 IN NS a1.verisigndns.com. ripe.net. 3600 IN NS ns4.apnic.net. ripe.net. 3600 IN NS tinnie.arin.net. ;; ADDITIONAL SECTION: a1.verisigndns.com. 156744 IN A 209.112.113.33 a1.verisigndns.com. 156744 IN AAAA 2001:500:7967::2:33 a2.verisigndns.com. 156744 IN A 209.112.114.33 a2.verisigndns.com. 156744 IN AAAA 2620:74:19::33 a3.verisigndns.com. 156744 IN A 69.36.145.33 a3.verisigndns.com. 156744 IN AAAA 2001:502:cbe4::33 ns4.apnic.net. 156733 IN A 202.12.31.53 ns4.apnic.net. 156733 IN AAAA 2001:dd8:12::53 manus.authdns.ripe.net. 60142 IN A 193.0.9.7 manus.authdns.ripe.net. 60142 IN AAAA 2001:67c:e0::7 tinnie.arin.net. 156733 IN A 199.212.0.53 tinnie.arin.net. 156733 IN AAAA 2001:500:13::c7d4:35 ;; Query time: 370 msec ;; SERVER: 2003:de:2016:120::a08:53#53(2003:de:2016:120::a08:53) ;; WHEN: Tue Aug 21 09:32:49 CEST 2018 ;; MSG SIZE rcvd: 518 weberjoh@nb15-lx:~$
For Wireshark I used a couple of custom columns to display the TCP and UDP stream indices as well as the DNS query and DNS type. The first and last packet shown in the screenshot is the query from my Linux machine to the recursive DNS server, while all other packets are generated by this server itself (plus the answers):
As you can see in the background color for each line, some sessions used UDP while others used TCP. Answers with RRSIGs that do not match into single DNS packets used TCP:
Some Details: www.netflix.net
The single query for www.netflix.net produced about 110 DNS packets! (Not counting the TCP overhead here, only DNS. With TCP it’s even more.) This was the dig request:
weberjoh@nb15-lx:~$ dig www.netflix.com ; <<>> DiG 9.10.3-P4-Ubuntu <<>> www.netflix.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 64210 ;; flags: qr rd ra; QUERY: 1, ANSWER: 10, AUTHORITY: 4, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 4096 ;; QUESTION SECTION: ;www.netflix.com. IN A ;; ANSWER SECTION: www.netflix.com. 1800 IN CNAME www.geo.netflix.com. www.geo.netflix.com. 1800 IN CNAME www.eu-west-1.prodaa.netflix.com. www.eu-west-1.prodaa.netflix.com. 60 IN A 34.253.36.84 www.eu-west-1.prodaa.netflix.com. 60 IN A 52.208.174.58 www.eu-west-1.prodaa.netflix.com. 60 IN A 54.229.85.178 www.eu-west-1.prodaa.netflix.com. 60 IN A 54.194.103.216 www.eu-west-1.prodaa.netflix.com. 60 IN A 54.154.12.178 www.eu-west-1.prodaa.netflix.com. 60 IN A 54.194.216.197 www.eu-west-1.prodaa.netflix.com. 60 IN A 54.77.199.154 www.eu-west-1.prodaa.netflix.com. 60 IN A 34.252.114.84 ;; AUTHORITY SECTION: prodaa.netflix.com. 86400 IN NS ns-1489.awsdns-58.org. prodaa.netflix.com. 86400 IN NS ns-1606.awsdns-08.co.uk. prodaa.netflix.com. 86400 IN NS ns-749.awsdns-29.net. prodaa.netflix.com. 86400 IN NS ns-375.awsdns-46.com. ;; Query time: 287 msec ;; SERVER: 2003:de:2016:120::a08:53#53(2003:de:2016:120::a08:53) ;; WHEN: Tue Aug 21 09:33:18 CEST 2018 ;; MSG SIZE rcvd: 366 weberjoh@nb15-lx:~$
While in Wireshark it looks like this. Many of those packets are related to the authority and additional section of dig/BIND that even asked for the A/AAAA records for name servers:
For this single query Wireshark lists 14 TCP and 42 UDP conversations, while 12 took place over legacy IP and 10 over IPv6. Not that bad, isn’t it? ;)
Since Netflix does not sign their zone via DNSSEC, the answer for the DS record is signed with NSEC3 – kind of NXDOMAIN for DNSSEC:
And since Netflix (among other big players) uses some kind of distributed DNS servers and geo-based load-balancing the overall picture looks quite confusing, for example when looking at the DNSViz graph for www.netflix.com.
Conclusion
Have you ever thought of “one DNS query – one DNS answer”? Well … no. Possibly hundreds of packets. That’s the reason why we are using recursive and caching DNS servers. For example, the DNSSEC related resource records for the root zone and the TLDs have quite long TTLs. Hence caching servers really have an advantage here.
But keep in mind that you should NOT use public DNS resolvers such as 8.8.8.8 if you’re interested in your privacy. Have a look at this paper. It’s not that hard to run Unbound or BIND at your own home/company.
I was mostly interested in how the DNS server validates DNSSEC. This can be seen in both queries. While the first one used the DNSKEYs and DS records to validate the signature, the second one simply verified that DNSSEC is not used for this zone (signed NSEC3 from the root server that the DS does not exist).
For further reading have a look at some articles from Geoff Huston such as Measuring DNSSEC Performance or The Cost of DNSSEC.
Featured image “Schutz vor … / Protection against …” by Frank Lindecke west is licensed under CC BY-ND 2.0.