In my last post in this series, I mentioned a kind of resolver known as a recursive resolver. In this post, I will explain what a recursive resolver is and how they work.
What is a recursive resolver?
To simply put it: A recursive resolver is a DNS resolver that resolves a DNS query by going through hierarchical sets of authoritative nameservers until it gets an answer to the query.
Breaking down a query
This is not a great definition since I used a term I haven’t explained yet, authoritative nameservers. The details of authoritative nameservers will be in the next post in this series but for now let me allow to demonstrate a recursive DNS query with an example.
% dig +trace +nodnssec nullrouted.space @149.112.121.10 ; <<>> DiG 9.10.6 <<>> +trace +nodnssec nullrouted.space @149.112.121.10 ;; global options: +cmd . 435655 IN NS f.root-servers.net. . 435655 IN NS k.root-servers.net. . 435655 IN NS i.root-servers.net. . 435655 IN NS g.root-servers.net. . 435655 IN NS m.root-servers.net. . 435655 IN NS c.root-servers.net. . 435655 IN NS a.root-servers.net. . 435655 IN NS e.root-servers.net. . 435655 IN NS j.root-servers.net. . 435655 IN NS b.root-servers.net. . 435655 IN NS h.root-servers.net. . 435655 IN NS l.root-servers.net. . 435655 IN NS d.root-servers.net. ;; Received 811 bytes from 149.112.121.10#53(149.112.121.10) in 27 ms com. 172800 IN NS e.gtld-servers.net. com. 172800 IN NS h.gtld-servers.net. com. 172800 IN NS l.gtld-servers.net. com. 172800 IN NS f.gtld-servers.net. com. 172800 IN NS k.gtld-servers.net. com. 172800 IN NS b.gtld-servers.net. com. 172800 IN NS j.gtld-servers.net. com. 172800 IN NS d.gtld-servers.net. com. 172800 IN NS a.gtld-servers.net. com. 172800 IN NS c.gtld-servers.net. com. 172800 IN NS i.gtld-servers.net. com. 172800 IN NS g.gtld-servers.net. com. 172800 IN NS m.gtld-servers.net. ;; Received 840 bytes from 192.36.148.17#53(i.root-servers.net) in 158 ms nullrouted.space. 172800 IN NS pns31.cloudns.net. nullrouted.space. 172800 IN NS pns32.cloudns.net. nullrouted.space. 172800 IN NS pns33.cloudns.net. nullrouted.space. 172800 IN NS pns34.cloudns.net. ;; Received 135 bytes from 192.31.80.30#53(d.gtld-servers.net) in 35 ms nullrouted.space. 86400 IN A 45.79.184.143 nullrouted.space. 86400 IN NS pns32.cloudns.net. nullrouted.space. 86400 IN NS pns34.cloudns.net. nullrouted.space. 86400 IN NS pns31.cloudns.net. nullrouted.space. 86400 IN NS pns33.cloudns.net. ;; Received 151 bytes from 2a06:fb00:1::1:66#53(pns31.cloudns.net) in 967 ms
Whoa, that’s a lot of terminal output that I just dropped on you. Let’s break it down step by step.
Firstly, this terminal output is coming from a terminal utility known as dig which stands for DNS Information Groper. It is a utility for interrogating DNS name servers. We will come back to this tool often. I am running this tool from a macOS system which has dig built in, so if you are running macOS just launch Terminal and use dig from there. For Windows users, you can get it via WSL or if you are familiar with virtual machines, I would recommend setting up a Ubuntu server virtual machine and installing the dnsutils package to get dig. Linux users of other distributions, please look up relevant instructions for your distribution to get dig installed.
Next let’s break down the actual command I ran:
dig +trace +nodnssec nullrouted.space @149.112.121.10
- +trace – this tells dig to perform a iterative query, this lets us demonstrate the entire process of resolving a name from start to finish
- +nodnssec – I used this to disable DNSSEC validation/fetching for the query. DNSSEC records add a lot of noise to the output which is not important to us right now.
- nullrouted.space – this is the DNS name we are making a query for. We haven’t specified a DNS record type for the query so dig performs a query for the A record for that name. We will get into record types in a later post but for now, all we need to know is that an A record value means the IPv4 address for a DNS name.
- @149.112.121.10 – lastly, we use this to define a server to make the first step of the query. In this specific example, I used the CIRA public resolver service. If you don’t specify this, dig will use the values defined in /etc/resolv.conf which is on *nix systems is where DNS resolver values get stored.
Now, let us break down the steps of the query itself.
To resolve ‘nullrouted.space.’ our recursive resolver needs to resolve four things, in order to get the final result.
The first step is resolving for “.” or the root. Recursive nameserver software come with a list of root servers compiled in. This is known as the “root hints” file, every recursive nameserver needs this to bootstrap itself.
Operators who manage a DNS recursive resolver typically need to configure a “root hints file”. This file contains the names and IP addresses of the authoritative name servers for the root zone, so the software can bootstrap the DNS resolution process. For many pieces of software, this list comes built into the software.
This is from the IANA root files page. You can download the root hints file itself and see what it contains. The Wikipedia page for root name server is a good place to get started if you want to learn more about how they work and are operated.
Now let us look at the first section of the dig output from earlier:
. 435655 IN NS f.root-servers.net. . 435655 IN NS k.root-servers.net. . 435655 IN NS i.root-servers.net. . 435655 IN NS g.root-servers.net. . 435655 IN NS m.root-servers.net. . 435655 IN NS c.root-servers.net. . 435655 IN NS a.root-servers.net. . 435655 IN NS e.root-servers.net. . 435655 IN NS j.root-servers.net. . 435655 IN NS b.root-servers.net. . 435655 IN NS h.root-servers.net. . 435655 IN NS l.root-servers.net. . 435655 IN NS d.root-servers.net.
;; Received 811 bytes from 149.112.121.10#53(149.112.121.10) in 27 ms
In our example, we ask the CIRA recursive resolver to give us a list of root servers so we can proceed with the next step of the query.
The second step of the query is asking the root nameservers about the nameservers for the TLD (Top Level Domain) part of our DNS name. In our example that would be .com. Every root nameserver has a root zone file that contains the nameserver names for every TLD and their corresponding IP addresses. Like the root hints file, you can download the root zone file and have a look at it yourself.
com. 172800 IN NS e.gtld-servers.net. com. 172800 IN NS h.gtld-servers.net. com. 172800 IN NS l.gtld-servers.net. com. 172800 IN NS f.gtld-servers.net. com. 172800 IN NS k.gtld-servers.net. com. 172800 IN NS b.gtld-servers.net. com. 172800 IN NS j.gtld-servers.net. com. 172800 IN NS d.gtld-servers.net. com. 172800 IN NS a.gtld-servers.net. com. 172800 IN NS c.gtld-servers.net. com. 172800 IN NS i.gtld-servers.net. com. 172800 IN NS g.gtld-servers.net. com. 172800 IN NS m.gtld-servers.net. ;; Received 840 bytes from 192.36.148.17#53(i.root-servers.net) in 158 ms
This is from the second part of the dig query. We get a list of nameservers for the com. TLD from i.root-servers.net which dig can then use to proceed with the next step of the query process.
The third step of the query is asking the com. TLD nameservers what the nameservers for nullrouted.space are. These are the nameserver values that get modified whenever you change your nameservers at your domain registrar.
nullrouted.space. 172800 IN NS pns31.cloudns.net. nullrouted.space. 172800 IN NS pns32.cloudns.net. nullrouted.space. 172800 IN NS pns33.cloudns.net. nullrouted.space. 172800 IN NS pns34.cloudns.net.
;; Received 135 bytes from 192.31.80.30#53(d.gtld-servers.net) in 35 ms
This is from the third part of the dig output. The dig utility now has a set of four nameservers for nullrouted.space from one of the TLD nameservers for com., in our example that would be d.gtld-servers.net.
The fourth step of the query is asking one of the four nameservers we got from our TLD nameservers what the A record value is for nullrouted.space. But hold up! How does dig know where pns31.cloudns.net and the other three nameservers are? Well, it has to then resolve for cloudns.net the way we iterated through for nullrouted.space. Once dig knows where pns31 through pns34 are, it can then ask those for the A record for nullrouted.space. dig doesn’t show that particular query in its output but if you want to see it, you can just replace “nullrouted.space” in the command with “pns31.cloudns.net”.
nullrouted.space. 86400 IN A 45.79.184.143 nullrouted.space. 86400 IN NS pns32.cloudns.net. nullrouted.space. 86400 IN NS pns34.cloudns.net. nullrouted.space. 86400 IN NS pns31.cloudns.net. nullrouted.space. 86400 IN NS pns33.cloudns.net.
;; Received 151 bytes from 2a06:fb00:1::1:66#53(pns31.cloudns.net) in 967 ms
This is from the fourth and final part of the dig output. We have a A record value for nullrouted.space! Huzzah! pns31.cloudns.net has kindly let us know that the A record value for nullrouted.space which is 45.79.184.143 along with the TTL (Time to Live) value for the record which is 86400 seconds or 24 hours. TTLs will be the topic of yet another post!
Sidebar about glue
You may find yourself wondering what would happen if the nameservers for nullrouted.space were *inside* the domain rather than being under a different domain.
What happens if the nameservers for nullrouted.space are ns1 and ns2.nullrouted.space? Well, if you guessed a “catch 22” situation you would be right! A recursive resolver that needs to know where nullrouted.space is needs to know where ns1/2.nullrouted.space are first but since ns1/2 are under nullrouted.space we have a catch-22 situation. Fortunately, there is a way to solve this! This problem is solved by adding what is known as a “glue” record at your domain registrar. A glue record tells the TLD nameservers what the IP addresses for ns1 and ns2 are so it can send that information along to a recursive resolver and it can then resolve the name.
Your domain registrar may call glue, “registering nameservers’ or “private nameservers”. Adding glue nameservers is a somewhat advanced concept and if you are just getting started with domain names and the DNS you are most likely not going to need to make use of glue records but now you know what they are!
Conclusions
So to conclude this particular post, let’s recap what we’ve learned in a simpler format.
A recursive nameserver does this in order to resolve a name:
Ask root server for TLD nameservers -> Ask TLD nameservers for domain’s nameservers -> Ask domain’s nameservers for the record you queried -> Return answer to the query sender
Now we used a dig trace query to demonstrate this process in its entirety for educational purposes, in the real world recursive nameservers don’t perform the entire process every time in its entirety. For example, if a recursive nameserver has resolved a .com domain name once, it does not need to ask the root servers for the .com TLD nameservers again because the recursive nameservers will have cached the results of that first query in memory and therefore can just use that instead of reaching out to the root nameservers again. Caching and TTLs will be a separate post in this series so don’t worry if you don’t already know/understand what those are.
See y’all next time where we get into what it means to be an authoritative nameserver.