← Safis

Computing

How DNS Turns a Name into an Address

What happens in the few milliseconds between typing a name like example.com and your computer knowing which address to connect to, and why the answer is usually already waiting in a cache.

  • The internet delivers packets to numbers, not names. DNS turns a name into a number by asking a chain of servers, each responsible for one part of the name.
  • Your computer hands the question to a recursive resolver, which walks from the root to the top-level domain to the domain's own servers: a few round trips of tens of milliseconds each.
  • Every answer carries a lifetime, its TTL, and is cached for that long at every step, so most lookups take one short round trip or none. "Propagation" is old copies expiring.
  • The questions travel in small UDP packets that can be lost, forged, or too big, and DNS failures (timeouts, SERVFAIL, NXDOMAIN) come from that plumbing.

Type example.com into a browser and press Enter. Before the browser can ask for the page, it needs a number. The internet delivers packets to addresses like 192.0.2.10, not to names, and the step that turns the name into that number is the Domain Name System, DNS. It usually finishes before the page has started to load.

In outline, the conversation goes like this. Your computer asks a resolver, and the resolver asks three servers in turn, each of which knows a little more of the answer:

The messages in one lookup that starts from nothing. Only the last server knows the address; the others say where to ask next.

Here is the same lookup live, slowed down 20 times. Each arrow is a packet, and time runs down the page, so the slope of an arrow is the time it spends in flight. Watch it from nothing, then switch to the case where :

From nothing, the answer takes 90 ms: four round trips, each waiting for the one before, because each answer says where to ask next. When , it takes 16 ms. When , no packet leaves at all. I picked these times by hand at a typical size; real ones depend on where everyone is, and a later section has some I measured. The rest of the page takes this diagram apart: why four servers, what each one knows, how long anyone may remember an answer, and what goes wrong.

Names and numbers

Routers forward packets by number: an IPv4 address is 32 bits, written like 192.0.2.10, and an IPv6 address is 128 bits, written like 2001:db8::10. Names are for people, and a name can stay put when the site behind it moves to new machines.

The first link between the two was a list. Until the mid-1980s, every computer on the ARPANET kept a copy of one file, HOSTS.TXT, with a line per host, edited by the Network Information Center at SRI and downloaded from there. Slide the number of hosts and watch what the copying costs:

Double the hosts and both the file and the number of copies double, so the traffic grows four times. At 1,024 hosts, a daily copy for everyone is 63 MB. At , the count at the end of 1987 , it would be 48 GB, more than 80 of the network's 50 kbit/s lines running flat out. The DNS specification names exactly this square law as its reason for being , along with a human one: every new machine waited for one office to edit the file.

The replacement, designed by Paul Mockapetris in 1983, splits the list into a tree and hands each branch to its owner. Pick a name and read it from right to left, starting at the root:

Each dot is a step down the tree, and the final dot, usually left off, is the root. Now . Each shaded region is a zone, a part of the tree looked after by one set of servers. The root zone, edited by IANA, lists only the top-level domains, about 1,400 of them , and the servers for each. The com zone, run by Verisign, lists every name under com and its servers. It doesn't know example.com's address, only who does. Handing a branch down this way is delegation, and it's why the owner of example.com can add mail.example.com without asking anyone.

Inside your computer

The lookup starts at home. A browser asks the operating system with a library call (getaddrinfo on most systems), which goes to the stub resolver, a stub because it never walks the tree itself. Before anything leaves the machine, the answer may already be in one of three places. Switch them on and off and watch where the question stops:

The hosts file is HOSTS.TXT's descendant, still on every computer (/etc/hosts on Linux and macOS). An entry there usually beats DNS, which is how developers point a name at a test machine. The two caches hold recent answers for as long as each answer allows. The order varies between systems, and some browsers skip the operating system entirelyChrome has its own built-in DNS client, and browsers with encrypted DNS switched on (the last "going deeper" section) send their queries directly to the resolver they're set up to use., but the idea is the same: look locally, then ask.

When everything local misses, a packet goes to a recursive resolver, which does the whole walk. The network you join picks one, usually your provider's, often relayed through your router, unless you choose a public one such as 1.1.1.1 or 8.8.8.8. Either way it serves thousands or millions of people, so someone has usually asked your question a moment ago.

Walking the tree

A resolver that has just started knows only one thing: the addresses of the root servers, shipped with its software in a short file called the root hints. So it starts at the top. Step through the replies to its question about example.com, one server at a time:

The root server doesn't know example.com's address and doesn't guess. Its reply is a referral: the answer section is empty, the authority section names the servers for com, and the additional section gives their addresses so the resolver can reach them. The com server does the same one level down. Only example.com's own server fills the answer section, and it marks the reply authoritative: this comes from the zone's owner, not from someone's cache. Each line carries a TTL in seconds. The referrals say 172,800, two days, and the resolver keeps them that long.

Here is the same first step for real: the question as I sent it to a.root-servers.net with dig, a command-line DNS tool, and the start of the reply. The real com zone has 13 servers, a.gtld-servers.net to m.gtld-servers.net, each with an IPv4 and an IPv6 address:

dig +norecurse @a.root-servers.net example.com A
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 65455
;; flags: qr; QUERY: 1, ANSWER: 0, AUTHORITY: 13, ADDITIONAL: 27

;; QUESTION SECTION:
;example.com.                 IN      A

;; AUTHORITY SECTION:
com.                    172800  IN      NS      l.gtld-servers.net.
com.                    172800  IN      NS      j.gtld-servers.net.
com.                    172800  IN      NS      h.gtld-servers.net.
; (10 more NS records)

;; ADDITIONAL SECTION:
l.gtld-servers.net.     172800  IN      A       192.41.162.30
l.gtld-servers.net.     172800  IN      AAAA    2001:500:d937::30
; (25 more address records)

That changes the next lookup. Here is one resolver handling six questions a minute apart, all sharing one cache, with what it knows listed on the right. Step through them:

The first lookup pays for the full walk. The second, the IPv6 address of the same name, goes straight to example.com's server, because the resolver already knows where it is; so does mail.example.com. The , a name under .net, needs the root again, because nothing so far has said who runs .net. By the the answer itself is cached and nothing is sent. A busy resolver almost never asks a root server anything: it learned where every popular top-level domain lives within minutes of starting, and that knowledge lasts two days.

There's a puzzle hiding in the com server's referral. It says example.com's servers are ns1.example.com and ns2.example.com. To reach ns1.example.com the resolver needs its address, but that address lives inside example.com, which it can only ask ns1.example.com about. The com zone breaks the loop by including the addresses, in the additional section. These are glue records. Take them away and see what the resolver does:

Without glue, the resolver asks com for ns1.example.com and gets the same referral back, around and around, until it gives up and reports SERVFAIL, a server failure. That's why a registrar asks for addresses when you name your own servers inside your own domain. Servers named in , like a hosting company's ns1.dnshost.net, need no glue: the resolver looks that name up on the side, through .net, then carries on. It costs three extra round trips the first time, and after that the answer is cached like any other.

What the answers say

So far every question has asked for an address. A zone holds other kinds of record too, each a line with a name, a TTL, a type, and some data. Here is the whole of example.com. Pick a name and a type and see which lines answer:

A records hold IPv4 addresses and AAAA records IPv6 ones, four times as long, hence the four A's. A browser usually asks for both and uses whichever connects first. MX names the domain's mail servers, with a number saying which to try first. TXT holds free text, these days mostly email rules and proofs that you control the domain. NS lists the zone's own servers, repeating what the parent said. Ask for and the reply is an empty answer, not an error: the name exists, the record doesn't. And answers every question the same way, with a CNAME.

A CNAME says this name is an alias for another one, and the resolver has to start over with the other name. Here www.example.com points at edge.example.net, a name in a different zone, with servers of its own. Compare what the resolver has to do depending on what it already knows:

From an empty cache the alias doubles the work. After example.com's server answers with the alias, the resolver goes back to the root to find out who runs .net, then on to example.net's server: six queries. With , it's two. The is the everyday one. The alias has a TTL of an hour, the address at the end of it only 60 seconds, so the resolver usually still holds the first and refetches the second. Short TTLs like that are how a content delivery network steers each visitor to a nearby server and changes its answer minute by minute.

One rule follows from how aliases work: a name with a CNAME can't have any other records, since every question about it is redirected. The bare example.com must have NS and SOA records, so it can never be an alias.

How long an answer lasts

Every record carries a TTL, its time to live: the number of seconds anyone may keep a copy before asking again. The zone's owner sets it. Here is one name at one resolver over six hours. Each tick is a lookup by one of its users; set how often people ask and how long the answer may be kept:

A green tick is a miss: the cache was empty or expired, so the resolver asked example.com's server and started a fresh copy, the blue bar, which lasts exactly one TTL. Every lookup inside the bar is answered from it. The TTL counts down while the copy sits there, so a user who asks 20 minutes into a one-hour copy is told it has 40 minutes left, and their own computer's copy runs out at the same moment as the resolver's. Compare , which misses almost every time, with .

So how well caching works depends on both numbers together. Before looking, a guess:

A resolver's users look up a name 1,000 times an hour, and the name's TTL is only 60 seconds. What share of those lookups does the resolver answer from its cache?

In each 60-second copy's life about 17 more lookups arrive, all answered from the copy, so only one lookup in 18 goes to the server: 94% from the cache.

Here is that share against the TTL, for names of four popularities:

Each copy lives for one TTL, \green{T}, and in that time a name asked \blue{\lambda} times a second collects \blue{\lambda}\green{T} more lookups, all of them answered from the copy. Out of every 1 + \blue{\lambda}\green{T} lookups, one goes to the server:

\text{share from cache} = \frac{\blue{\lambda}\green{T}}{1 + \blue{\lambda}\green{T}}

A name asked a thousand times an hour is answered from the cache 94% of the time even with a one-minute TTL. A name asked once an hour barely benefits from anything shorter than a few hours. That's why big sites can afford short TTLs, and why a short TTL costs a small site very few extra queries: its name was rarely cached anyway.

The same arithmetic, applied to referrals, explains how a few root servers can serve the whole internet. Here is a simulated resolver handling 20,000 lookups an hour for 50,000 domains, a few very popular and most rarely asked, starting with an empty cache. Slide through its first two days:

In its first minutes the resolver asks the root about every top-level domain it meets, 50 here, and then not at all until those two-day referrals expire. The TLD servers hear from it when a domain turns up that it hasn't met, less and less as the long tail of rare names gets used up. Most of the remaining work lands on the domains' own servers, and about three lookups in five never leave the resolver. The mix of names is made up, but the shape is what real resolvers see: the higher a server sits in the tree, the less it hears from any one resolverReal root servers still answer billions of queries a day, mostly for names that don't exist. In 2020 Verisign found that close to half of them came from one browser feature: Chromium testing random made-up names to detect networks that rewrite failed lookups ..

Changing an address

Caching bites when a record changes. Suppose I move example.com to a new machine and change its A record to 203.0.113.99. Its own server gives the new address at once, but every resolver holding the old one keeps handing that out until its copy expires. People call the wait propagation, as if the change spread outward across the world. Guess first:

The old record's TTL is one hour. Which resolvers start giving out the new address first?

Nothing is pushed out from the server. Each resolver asks again only when its own copy expires, and copies were fetched at scattered moments, so the switches come in random places at a steady rate.

Here are 60 resolvers around the world, each holding the old address with a one-hour TTL, fetched at some moment in the hour before the change. Slide the time since the change:

There's no wave. Each resolver switches the moment its own copy runs out, and because the copies were fetched at scattered times, the green dots appear in random places at a steady rate until, , all of them have the new address. Distance from the server plays no part. Propagation is old copies expiring, and its limit is the TTL in force before the change. Lowering the TTL at the same moment as changing the address doesn't help, because the old copies still carry the old TTLSome resolvers also impose their own minimum or maximum on TTLs, and some apps keep addresses longer than they should, which is where stories of changes taking days come from..

The fix is to lower the TTL well before the change. Say example.com's address normally has a TTL of one day. Ahead of the move, I drop it to five minutes; later, I change the address. Each row below is one resolver's copies over time, gray for the old address and green for the new, with the share still on the old address plotted beneath. Slide how far ahead the TTL was lowered:

Lowered , it does nothing: copies with up to a day left keep the old address that long. Lowered 12 hours ahead, about half the resolvers already hold short copies and switch within minutes, while the rest drag on for up to 12 hours. Lowered , every long copy has expired before the change, and everyone switches within five minutes. Then the TTL can go back up; the short TTL's only cost is a few hours of extra queries.

On the wire

Each question and each answer is a single small packet, usually sent over UDP, the internet's simplest way to send a message: no connection, no delivery promise, just a packet addressed to port 53. Here are the actual bytes your computer sends for one question, one cell per byte. Point at a byte to see what it's for:

The first row, 12 bytes, is the header: an ID, a pair of bytes of flags, and four counts. The name follows as labels, each led by a byte giving its length: 3, then w-w-w, 7, then e-x-a-m-p-l-e, and so on. The dots are never sent, and the name ends in a zero byte, the root. Two bytes ask for type A and two for class IN, the internet: 33 bytes in all. Resolvers usually add , 11 more bytes saying how large a reply this end can take, and that number matters once answers get big.

Replies repeat the question and then add records, and the original rules capped a UDP reply at 512 bytes. Add addresses to an answer and watch it fill up:

An IPv4 address adds 16 bytes and an IPv6 one 28, so 30 IPv4 addresses fit in 512 bytes but only 17 IPv6 ones, and takes more than half the space. EDNS lets each side say it can take more; since 2020 the agreed default is 1,232 bytes , because bigger UDP packets get split into fragments that many networks drop. A reply that still doesn't fit is sent cut short with a TC flag, and the resolver asks again over TCP, at the cost of two more round trips, one wasted and one for TCP's handshake .

UDP's other property is that nothing checks delivery. If the question or the answer is lost, the stub hears nothing, and all it can do is wait and ask again. Set how many packets are lost and how long the stub waits, and look at how long 4,000 lookups take:

With 2% of packets lost each way, about 4% of lookups lose one, and each of those costs a full wait: a second or more instead of a few tens of milliseconds. The median doesn't move, but the slow end is nearly all retries. The usual Linux C library waits and tries twice per server ; resolvers do better, timing each server and waiting only a little longer than usual.

No connection also means no proof of who sent a reply. The resolver accepts the first reply that matches its question, its 16-bit ID, and the port it sent from. An attacker who can't see the question can still guess: send a burst of forged replies, each with a different ID, hoping one lands before the real answer. Say each race allows 100 guesses. Slide the number of races:

Checking only the ID, 100 guesses win one race in 655, so an attacker has even odds after . In 2008 Dan Kaminsky showed how to start races at will, by asking about made-up names like 123.example.com, and how a forged referral could take over a whole domain . The fix shipped that summer: a random source port on every question, which pushes even odds out to . Signed answers, at the end of the page, are the real cure.

One address, many places

The round trips in the first figure were set by hand. Real ones are set by distance: light in fiber covers about 200 km each millisecond, and cables rarely run straight. Yet there are only 13 root server names, each with one address, and resolvers on every continent reach one in a few milliseconds. The trick is anycast: many machines in many cities share one address, and routing delivers each packet to the nearest copy. Drag yourself around the map, and switch anycast off:

From São Paulo, with anycast, the root and .com copies are in the same city and answer in about a millisecond; nearly all of the cold lookup is the trip to example.com's servers, which sit in one place. , the root is in Los Angeles and .com in Washington, adding a few hundred milliseconds. The roots run about 2,000 copies between them , and the .com servers and big public resolvers such as 1.1.1.1 use the same trick. But "nearest" means nearest along the routes networks agree to carry, not on the map.

I timed all 13 root servers from the computer I wrote this page on, three times each, and asked each one which copy had answered (a root server reports its copy's name when asked for hostname.bind). The bars are the median round trips. Press play to watch a resolver learn which to use:

Seven letters answered in 40 to 63 ms, most from Mumbai. The other six took 100 to 290 ms, from Singapore, Tokyo, Los Angeles, London, and one copy whose name doesn't say: some letters have few copies, and others have copies this network's routes don't reach. The resolver doesn't need to know any of this. It keeps a running average of each server's speed, sends most questions to the quickest, and lets the others' averages fade so it retries them now and then. After a few hundred queries, more than four in five go to the six 40 ms copies, and the average wait settles near 63 ms, under half of what picking at random would cost.

When it fails

Not every lookup ends with an address. Each reply carries a response code, and besides success there are three outcomes worth telling apart. Try each one:

means the name doesn't exist, and it's an answer, not a failure: the .com server has never heard of exmaple.com, and that's final. An means the name exists but has no record of the type asked. is the real failure: example.com's servers don't reply, and after waiting on both, the resolver gives up. Only that one might go away if you try again.

A "no" is cached too, for the smaller of the SOA record's TTL and its last field : 15 minutes for unregistered names under .com, 5 minutes for missing names under example.com. Look up a name before creating it, and you may wait that long to see it work.

The worst failure is a domain's own servers going silent for everyone at once. On 4 October 2021 the routes to Facebook's DNS servers vanished from the internet, and within minutes resolvers everywhere returned SERVFAIL for facebook.com . What keeps a site reachable in such an outage is the cache. Set the TTL and see what share of resolvers can still answer for a popular name after its servers disappear:

With a , the name disappears for nearly everyone within five minutes. With , three-quarters of resolvers still answer six hours in, as long as the addresses they hold still work. Resolvers that go further: when a domain's servers can't be reached, they keep handing out the expired record, for up to a few days . Failure also makes noise. Apps that got SERVFAIL for facebook.com retried again and again, and Cloudflare's resolver saw 30 times its usual load ; experiments with attacks on DNS servers found the same pattern, with caches and retries carrying many users through at the price of up to eight times the normal traffic .

Back to the address bar

Put it together for the name people actually type, www.example.com, an alias. From an empty resolver it takes six queries across two branches of the tree (). But a busy resolver is rarely empty: the referrals last two days, the alias an hour, and usually only the 60-second address at the end has to be fetched again, one query to one server. Often even that was fetched a moment ago for someone else, and the answer comes back in one short round trip, or from your own computer with no packet at all, the fast cases of .

DNS was drawn up in 1983 for a few hundred machines and has grown to billions mostly by not being asked. Every answer may be remembered for a while, a resolver's users share what it remembers, and the top of the tree hears from each resolver about once every two days. What it never had built in was proof or privacy; both were added later, and both are below.

Signed answers: DNSSEC 3 min

DNSSEC, standardized in 2005 , adds signatures. Each zone publishes a public key in a DNSKEY record and signs each set of records with the matching private key; the signatures travel in RRSIG records beside the data. A validating resolver checks the signature on example.com's answer with example.com's key. To trust that key, it checks a DS record, a fingerprint of the key published and signed by the parent zone, .com; the .com key in turn has a DS record signed by the root. The chain ends at the root's key, which validating resolvers carry built in, like the root hints. The root zone was first signed in July 2010.

A forged reply like the ones in the race above can't carry a valid signature without example.com's private key, so a validating resolver throws it away and returns SERVFAIL rather than a wrong address. The costs are bigger replies (the signature in is about 300 bytes), new ways to break a domain by mishandling its keys, and the fact that only a minority of domains are signed. DNSSEC proves an answer is genuine. It doesn't hide it.

Private questions: DNS over TLS and HTTPS 2 min

Plain DNS travels unencrypted, so anyone on the path, a café's Wi-Fi or an internet provider, can read every name you look up, and some networks rewrite the answers. DNS over TLS (DoT) wraps the conversation between your computer and its resolver in the same encryption web pages use, on its own port, 853 . DNS over HTTPS (DoH) sends the questions as ordinary HTTPS requests on port 443 , so they look like any other web traffic. Browsers can switch DoH on by themselves, which is one reason they sometimes skip the operating system.

Encryption hides the questions from the path, not from the resolver, which still sees everything you ask. Between the resolver and the root, TLD, and authoritative servers, most traffic is still plain UDP. A separate change limits what those servers learn: with query name minimisation , a resolver asks the root only about com and the .com server only about example.com, instead of sending the full name to every server on the way.

References

  1. P. Mockapetris, “Domain names: concepts and facilities”, RFC 1034, IETF, November 1987. Section 2.1 gives the history of HOSTS.TXT.
  2. Robert H. Zakon, “Hobbes' Internet Timeline”, zakon.org. Host counts from 1981 to 1989.
  3. IANA, “Root Zone Database”, iana.org/domains/root/db. A copy of the root zone I downloaded in October 2026 delegated 1,437 top-level domains.
  4. Matthew Thomas and Duane Wessels, “Chromium's impact on root DNS traffic”, Verisign blog, August 2020.
  5. J. Damas, M. Graff, and P. Vixie, “Extension Mechanisms for DNS (EDNS(0))”, RFC 6891, IETF, April 2013. It replaced RFC 2671, from 1999.
  6. DNS Flag Day 2020, dnsflagday.net/2020. The recommendation of a 1,232-byte EDNS buffer and of retrying truncated replies over TCP.
  7. J. Dickinson, S. Dickinson, R. Bellis, A. Mankin, and D. Wessels, “DNS Transport over TCP: Implementation Requirements”, RFC 7766, IETF, March 2016.
  8. resolv.conf(5), Linux man-pages, man7.org. The defaults for timeout (5 seconds) and attempts (2).
  9. CERT/CC, “Multiple DNS implementations vulnerable to cache poisoning”, Vulnerability Note VU#800113, July 2008.
  10. Root Server Technical Operations Association, root-servers.org. The 13 root server identities, their 12 operators, and their instances around the world.
  11. M. Andrews, “Negative Caching of DNS Queries (DNS NCACHE)”, RFC 2308, IETF, March 1998.
  12. Celso Martinho and Tom Strickx, “Understanding how Facebook disappeared from the Internet”, Cloudflare blog, 4 October 2021.
  13. D. Lawrence, W. Kumari, and P. Sood, “Serving Stale Data to Improve DNS Resiliency”, RFC 8767, IETF, March 2020.
  14. Giovane C. M. Moura, John Heidemann, Moritz Müller, Ricardo de O. Schmidt, and Marco Davids, “When the Dike Breaks: Dissecting DNS Defenses During DDoS”, ACM Internet Measurement Conference (IMC), 2018.
  15. R. Arends, R. Austein, M. Larson, D. Massey, and S. Rose, “DNS Security Introduction and Requirements”, RFC 4033, IETF, March 2005.
  16. Z. Hu, L. Zhu, J. Heidemann, A. Mankin, D. Wessels, and P. Hoffman, “Specification for DNS over Transport Layer Security (TLS)”, RFC 7858, IETF, May 2016.
  17. P. Hoffman and P. McManus, “DNS Queries over HTTPS (DoH)”, RFC 8484, IETF, October 2018.
  18. S. Bortzmeyer, R. Dolmans, and P. Hoffman, “DNS Query Name Minimisation to Improve Privacy”, RFC 9156, IETF, November 2021.