DNS
How the Domain Name System turns names into addresses: the hierarchy, resolvers, record types and caching.
Why names
Computers address each other by number: 192.0.2.10, or 2001:db8::10. People are bad at remembering numbers and good at remembering names. There is a second, more technical reason: an address belongs to a place in the network, and it changes when a service moves to another data center or cloud provider. A name can stay the same while the address behind it changes.
The Domain Name System (DNS) connects the two. It is a distributed, hierarchical database, run by thousands of organizations, that translates names into IP addresses and other information, such as which server receives email for a domain. Almost every connection starts with a DNS lookup, which is why a DNS failure looks like "everything is down".
Before DNS, every host on the early Internet had a copy of one text file, HOSTS.TXT, with every name and address. That did not scale. DNS (defined in RFC 1034 and RFC 1035, 1987) replaced it by giving each organization control over its own part of the namespace.
The DNS hierarchy
DNS names form a tree. A domain name is a name in that tree: a sequence of labels separated by dots, read from the most specific label on the left to the most general on the right. Each label may be up to 63 characters, and a whole name up to 253.
- Root. The top of the tree, an empty label written as a single dot. The root zone is served by 13 named root server identities (a.root-servers.net to m.root-servers.net), which together run as well over a thousand server instances worldwide using anycast.
- Top-level domains (TLDs). Generic TLDs such as .com, .org and .net, and country-code TLDs such as .nl, .de and .uk. Each is run by a registry.
- Second-level domains such as example.com, which organizations register and then manage themselves.
- Subdomains such as www.example.com or eu.shop.example.com, created freely by the domain's owner.
The tree is divided into zones: parts of the namespace that one party manages. The .com zone does not contain www.example.com; it only contains a delegation, a note that says which name servers are responsible for example.com. That delegation is what lets DNS scale.
Fully qualified domain names
A fully qualified domain name (FQDN) is
a complete name that specifies every label up to the root, such as
www.example.com. — with a trailing dot for the root. In
everyday use the final dot is left out and assumed, but in zone
files and in the output of dig it matters: a name
without the trailing dot is relative, and software may append a
search domain to it. On a laptop with search domain
corp.example.com, typing intranet makes
the resolver try intranet.corp.example.com..
How a name is resolved
Resolution involves several kinds of servers, each with its own role.
- The stub resolver is the small DNS client built into the operating system. Applications ask it; it asks a configured DNS server and waits for a final answer.
- A DNS resolver (recursive resolver) is a server that accepts queries from clients and does the full work of finding the answer, by asking other servers in turn, and caches what it learns. In a company it is usually the internal DNS server; at home, the router or the provider's resolver; or a public resolver.
- An authoritative name server holds the actual records of a zone and gives definitive answers for it. It does not look anything up elsewhere. The root servers and TLD servers are authoritative for their own zones.
- An application asks the stub resolver for www.example.com. It checks its own cache and the hosts file, then sends a query to the configured DNS resolver.
- The resolver, with nothing cached, asks a root server. It knows the root server addresses from a built-in list, the root hints.
- The root server does not know the answer, but refers the resolver to the name servers for .com.
- The resolver asks a .com TLD server.
- The TLD server refers it to the name servers for example.com, such as ns1.example.com.
- The resolver asks ns1.example.com.
- ns1.example.com is authoritative for example.com and answers: 192.0.2.10.
- The resolver caches the answer (and the referrals along the way) and returns it to the stub resolver, which also caches it.
Recursive and iterative queries
The diagram shows two styles of query. A recursive query says "give me the final answer, or an error": the stub resolver sends one, and the resolver takes on all the work. An iterative query says "give me the best answer you have": the root and TLD servers reply with a referral to servers closer to the answer, and the resolver follows the chain itself. Root and TLD servers only answer iteratively; doing recursion for the whole Internet would overload them.
Record types
A zone is a collection of resource records. Each record has a name,
a TTL, a class (practically always IN, Internet), a
type and data. The type decides what the data means:
| Type | Holds | Example data |
|---|---|---|
A |
An A record maps a name to an IPv4 address. | 192.0.2.10 |
AAAA |
An AAAA record ("quad A") maps a name to an IPv6 address. | 2001:db8::10 |
CNAME |
A CNAME record (canonical name) makes a name an alias of another name; the resolver then looks up the target. | www.example.com. |
MX |
An MX record (mail exchanger) names a server that accepts email for the domain, with a preference; the lowest number is tried first. | 10 mail.example.com. |
NS |
A name server that is authoritative for the zone; also used for delegation from the parent zone. | ns1.example.com. |
PTR |
A pointer from an address back to a name (reverse DNS). | www.example.com. |
TXT |
Free text, used for email policies such as the Sender Policy Framework (SPF) and for proving domain ownership. | "v=spf1 mx -all" |
SOA |
Start of authority: one per zone, with the primary name server, the administrator's mailbox, a serial number and timers. | (see the zone file below) |
SRV |
The host and port of a service, with priority and weight; Active Directory uses it to let clients find domain controllers. | 0 100 389 dc1.example.com. |
In a zone file, the text format many DNS servers read, the records of a small example.com zone look like this (TTL in seconds):
example.com. 3600 IN SOA ns1.example.com. hostmaster.example.com. (
2026093001 ; serial
7200 ; refresh
3600 ; retry
1209600 ; expire
3600 ) ; negative-caching TTL
example.com. 86400 IN NS ns1.example.com.
example.com. 86400 IN NS ns2.example.net.
example.com. 3600 IN MX 10 mail.example.com.
example.com. 3600 IN TXT "v=spf1 mx -all"
www.example.com. 3600 IN A 192.0.2.10
www.example.com. 3600 IN AAAA 2001:db8::10
shop.example.com. 3600 IN CNAME www.example.com.
mail.example.com. 3600 IN A 192.0.2.25
_ldap._tcp.example.com. 3600 IN SRV 0 100 389 dc1.example.com.
Reverse DNS
Normal (forward) DNS turns a name into an address. Reverse DNS goes
the other way, and it uses the same tree: addresses are written as
names under a special domain. For IPv4 the four octets are reversed
and in-addr.arpa is appended, because DNS names run
from specific to general while addresses run from general to
specific. A PTR record (pointer)
under that name holds the host name. IPv6 uses
ip6.arpa with one label per hexadecimal digit. Python's
ipaddress module builds these names for you:
import ipaddress
for text in ["192.0.2.10", "2001:db8::10"]:
print(ipaddress.ip_address(text).reverse_pointer)
10.2.0.192.in-addr.arpa 0.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa
Reverse zones are managed by whoever holds the address block, not by the domain owner. Reverse DNS makes logs and traceroute output readable, and mail servers often reject mail from addresses without a matching PTR record.
TTL and caching
Without caching, every lookup would go all the way to the root. Instead, every resolver and every client caches answers for as long as the record's time to live (TTL) allows: a number of seconds, chosen by the zone's owner, that travels with each record. When the TTL runs out, the entry is dropped and the next query goes out again. Failed lookups are cached too (negative caching), for the time set in the zone's SOA record.
This simulation resolves one name three times, at 0, 600 and 4000 seconds, with a TTL of 3600:
# Simulated name servers: each one only knows its own part of the tree
SERVERS = {
"a root server": ("referral", "a .com TLD server"),
"a .com TLD server": ("referral", "ns1.example.com"),
"ns1.example.com": ("answer", "192.0.2.10"),
}
TTL = 3600 # seconds, chosen by whoever manages the example.com zone
cache = {} # name -> (address, expires at)
def resolve(name, now):
if name in cache and cache[name][1] > now:
address, expires = cache[name]
print(f"t={now:>4} cache hit: {address} (valid {expires - now} s more)")
return address
reason = "expired" if name in cache else "not cached"
print(f"t={now:>4} {reason}, resolving {name} iteratively:")
server = "a root server"
while True:
kind, value = SERVERS[server]
print(f" ask {server}: {kind} -> {value}")
if kind == "answer":
cache[name] = (value, now + TTL)
return value
server = value
for now in [0, 600, 4000]:
resolve("www.example.com.", now)
t= 0 not cached, resolving www.example.com. iteratively:
ask a root server: referral -> a .com TLD server
ask a .com TLD server: referral -> ns1.example.com
ask ns1.example.com: answer -> 192.0.2.10
t= 600 cache hit: 192.0.2.10 (valid 3000 s more)
t=4000 expired, resolving www.example.com. iteratively:
ask a root server: referral -> a .com TLD server
ask a .com TLD server: referral -> ns1.example.com
ask ns1.example.com: answer -> 192.0.2.10
A real resolver would also have cached the referrals, whose TTLs are typically a day or two, so its second full lookup would go straight to ns1.example.com.
The consequence for operations: when you change a record, clients may keep using the old value until their cached copy expires. With a TTL of 86400, that can be a full day. The usual practice before a planned change, such as moving a website to a new address, is to lower the TTL (for example to 300 seconds) at least one old TTL in advance, make the change, and raise it again afterward.
Tools: nslookup, dig and the hosts file
The output below is illustrative: it uses documentation addresses, so the real example.com returns different ones.
nslookup
nslookup is available on Windows, Linux and macOS, and
is the tool you will most often see in Windows tickets:
nslookup www.example.com
Server: UnKnown
Address: 192.168.1.1
Non-authoritative answer:
Name: www.example.com
Addresses: 2001:db8::10
192.0.2.10
Server and Address show which DNS server
answered; "UnKnown" only means that server's own address has no PTR
record. "Non-authoritative answer" means the answer came from a
resolver (often from its cache), not from the zone's authoritative
server. To ask for another type, or ask a specific server, add
options: nslookup -type=mx example.com 192.0.2.53.
dig
dig (domain information groper, from the Berkeley
Internet Name Domain (BIND) tools) is the standard on Linux and
shows the full DNS message:
dig www.example.com A
; <<>> DiG 9.18.28 <<>> www.example.com A ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 41286 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 ;; OPT PSEUDOSECTION: ; EDNS: version: 0, flags:; udp: 65494 ;; QUESTION SECTION: ;www.example.com. IN A ;; ANSWER SECTION: www.example.com. 3600 IN A 192.0.2.10 ;; Query time: 24 msec ;; SERVER: 127.0.0.53#53(127.0.0.53) (UDP) ;; WHEN: Wed Sep 30 10:15:42 CEST 2026 ;; MSG SIZE rcvd: 60
-
status: NOERROR— the name exists. Other statuses:NXDOMAIN(the name does not exist) andSERVFAIL(the server could not get an answer). -
flags: qr rd ra— this is a response (qr), recursion was desired (rd) and is available (ra). Anaaflag would mean an authoritative answer. - The ANSWER SECTION shows the record with its remaining TTL: repeat the query and you see it count down from the cache.
-
SERVERis the resolver that answered, here the local stub of systemd-resolved, and the transport used (UDP).
Useful variations: +short for just the data,
-x for a reverse lookup, @server to ask a
specific server, and +trace to follow the whole chain
from the root yourself.
dig +short example.com MX
dig +short -x 192.0.2.10
10 mail.example.com. www.example.com.
The hosts file
Before asking DNS, operating systems check a local text file:
/etc/hosts on Linux and macOS, and
C:\Windows\System32\drivers\etc\hosts on Windows. An
entry there overrides DNS for that machine only:
127.0.0.1 localhost ::1 localhost 192.168.1.40 intranet.example.com intranet
It is handy for testing a new server before changing DNS. It is also
a classic cause of "it works on every machine except this one", and
malware has been known to edit it to redirect sites. On Linux, the
order of sources is set in
/etc/nsswitch.conf, usually
hosts: files dns (files first).
DNS on a Cisco device
Routers and switches can resolve names too. On a Cisco device, a mistyped command is treated as a host name to connect to, and the device tries to resolve it — which hangs the console for several seconds when no DNS server is reachable:
R1# shwo run
Translating "shwo"...domain server (255.255.255.255)
% Unknown command or computer name, or unable to find computer address
R1# configure terminal
R1(config)# no ip domain-lookup
no ip domain-lookup turns name lookups off, the usual
choice in labs. On devices that should resolve names, keep lookups
enabled and configure a server with
ip name-server 192.168.1.53, so that commands such as
ping accept names.
Try it: a DNS lookup
Enter a host name or an IP address to see which records a lookup
asks for, the reverse lookup name of an address, and the
nslookup and dig commands to run yourself.
All of that is worked out in your browser. Only if you choose
Look it up live, and confirm, is the name sent to an
outside resolver.
Transport, encryption and split-horizon
UDP and TCP port 53
Most DNS queries and answers travel over the User Datagram Protocol (UDP) on port 53: one small datagram each way, no connection setup. DNS also uses the Transmission Control Protocol (TCP) on port 53:
- when an answer does not fit in a UDP response. The server sets the truncated (TC) flag and the client repeats the query over TCP. Classic DNS limited UDP answers to 512 bytes; the Extension Mechanisms for DNS (EDNS) allow larger ones, but large answers such as those with DNS Security Extensions (DNSSEC) signatures can still fall back to TCP;
- for zone transfers (full transfers, AXFR, and incremental ones, IXFR), in which a secondary server copies a zone from the primary.
A firewall rule that allows only UDP 53 therefore breaks some lookups in a way that is hard to spot: small answers work, large ones time out.
DNS over TLS and DNS over HTTPS
Classic DNS is unencrypted: anyone on the path can see and alter which names you look up. Two standards encrypt the connection from client to resolver with Transport Layer Security (TLS):
- DNS over TLS (DoT) uses its own port, TCP 853, which makes it easy to recognize and to allow or block.
- DNS over HTTPS (DoH) sends DNS messages inside HTTP Secure (HTTPS, the encrypted form of the Hypertext Transfer Protocol, HTTP) on port 443, where it blends in with web traffic. Browsers can use it independently of the operating system's DNS settings.
For privacy this is an improvement. For a company it is a mixed blessing: a browser that uses DoH to an outside resolver bypasses internal DNS, its filtering and its internal names. Many organizations therefore manage DoH settings centrally.
Internal and public DNS, split-horizon
Organizations usually run two kinds of DNS. Public DNS holds the records the world may see, such as the website and mail servers. Internal DNS — in Windows networks typically the Active Directory DNS servers — resolves internal names, such as file servers and printers, and forwards everything else to the Internet.
Split-horizon (split-brain) DNS gives different
answers to the same name depending on who asks. Inside the office,
portal.example.com may resolve to the private address
10.1.20.15; from outside, to the public address 203.0.113.15. That
is useful, but it causes confusing tickets: the same name works on
the virtual private network (VPN) and fails off it, or the other way
round. When a user's answer differs from yours, first check which
DNS server each of you is using.
Common problems: "it's always DNS"
"It's always DNS" is a running joke among network engineers, and it has reasons. Nearly every service depends on names, so a DNS fault shows up as an application fault; DNS is spread over many servers and caches that each can be wrong; and caching makes problems appear and disappear with a delay. The usual suspects:
-
Wrong or unreachable DNS server. A wrong Dynamic
Host Configuration Protocol (DHCP) option, a static setting left
over, a VPN client that replaced the server. Check with
ipconfig /allorresolvectl status. -
Stale cache. A record was changed, but clients
still use the old one until the TTL expires. Clear the local cache
with
ipconfig /flushdns(Windows) orresolvectl flush-caches(Linux with systemd-resolved); caches on the resolvers remain. -
Missing or wrong record. A typo in a record, a
forgotten trailing dot in a zone file (so
www.example.combecomeswww.example.com.example.com.), or a missing PTR record. - A hosts file entry that overrides DNS on one machine.
- Split-horizon differences between internal and public answers.
- Firewall rules that block port 53, or allow UDP but not TCP.
A quick test separates DNS from everything else: if
ping 192.0.2.10 works but
ping www.example.com fails with "could not find host",
the network is fine and the problem is name resolution. See
Troubleshooting Tools and Method.