cat posts/2018-04-17-how-dns-resolution-works.md

How DNS resolution works, step by step

· 7 min read · networking dns privacy security

Quick question: who knows which websites you visited today?

Your browser, obviously. The sites themselves. But also, almost certainly, your ISP, or whoever runs the DNS resolver your laptop uses, because every one of those visits started with your machine asking, in plain text, “what’s the address for this name?” Most developers I work with can tell you that DNS “turns names into IP addresses” and not much past that, which is fine right up until you’re debugging a migration at 2am and the old IP just won’t go away.

Cloudflare launched a public resolver at 1.1.1.1 on April 1st (four-one, one-one-one-one, the date was the joke), pitched mostly on privacy, and I’ve had three people ask me since whether they should switch. Answering that properly means walking through what actually happens when you type a name, so here it is.

The cast

There are four kinds of things involved, and they get confused with each other all the time.

The stub resolver is the bit of your OS that your programs call. When code calls getaddrinfo() or Dns.GetHostEntry(), the stub doesn’t do the work, it just forwards the question to a configured server and waits. On Windows that’s the DNS Client service, on a Mac it’s mDNSResponder, on newer Ubuntu boxes it’s systemd-resolved listening on 127.0.0.53, which confused me the first time I looked at /etc/resolv.conf and found that address there.

The recursive resolver does the actual work. It’s usually your ISP’s, handed out by DHCP along with your IP address, or your office’s, or a public one like Google’s 8.8.8.8 or now 1.1.1.1. It takes your question, chases down the answer, caches it and hands it back.

The root servers are the top of the tree. There are 13 named root server identities, a.root-servers.net through m.root-servers.net, run by a dozen different organizations, and each one is really hundreds of machines around the world sharing one address via anycast. The roots don’t know where www.example.com is. They only know who’s in charge of .com.

The authoritative servers are the ones that actually hold the records for a zone. The .com TLD servers (run by Verisign) are authoritative for .com itself, which means they know who’s in charge of example.com. And example.com’s own name servers, wherever its owner hosts DNS, are authoritative for the records inside it.

One lookup, cold cache

Here’s what happens when you look up www.example.com and nothing is cached anywhere:

your laptop stub resolver recursive resolver ISP, 8.8.8.8, 1.1.1.1 + cache root server "ask the .com servers" .com TLD server "ask example.com's NS" example.com NS "93.184.216.34" 1 5 2 3 4
The stub asks once (1) and gets one answer (5). The recursive resolver does the walking (2–4) and caches every step.
  1. Your stub sends “A record for www.example.com?” to the recursive resolver, usually over UDP port 53.
  2. The resolver doesn’t know, so it asks a root server. Every resolver ships with the root servers’ addresses built in (the “root hints” file), because otherwise it’d have nobody to ask first. The root replies with a referral: I don’t know, but here are the servers for .com.
  3. It asks one of the .com servers. Another referral: here are the name servers for example.com.
  4. It asks one of example.com’s name servers, which actually knows, and answers with an address and a TTL.
  5. The resolver caches everything it learned along the way and hands the answer back to you.

You can watch this happen with dig +trace www.example.com, which does the walk itself from the root and prints each referral. Do it once, it’s worth five minutes.

The thing that makes this whole system work is the caching in step 5. Every record has a TTL, a number of seconds it may be cached for. The .com referral has a long TTL (two days), so a busy resolver almost never needs to ask the roots about .com. The answer for a popular name is probably already sitting in the cache, so the full walk is rare. Most lookups your laptop does are one round trip to the resolver and back.

The flip side is that the TTL is how long the world may keep using an old answer after you change it, which is the 2am migration problem. Years ago, well before we standardized our TTLs, we moved an API endpoint to a new load balancer and forgot that its record had a TTL of 86,400 seconds, a full day, set by someone who didn’t want “unnecessary DNS traffic”. The other direction hurts too: when Dyn went down in 2016, our 60-second TTLs meant resolvers forgot us within a minute. We settled on an hour for most records, lowered deliberately a day ahead of a planned change, because the old TTL is the one everyone cached.

(A short history aside, since I find it funny: before DNS, every machine on the ARPANET used a single HOSTS.TXT file maintained centrally at SRI and downloaded by everyone. DNS was designed in 1983 by Paul Mockapetris because that file had become unmanageable. The hosts file is still there in C:\Windows\System32\drivers\etc and /etc/hosts, still checked first, and still the fastest way to break a coworker’s machine as a prank.)

Who sees what

Now the privacy part. Classic DNS is unencrypted and unauthenticated. Everything above is readable by anyone on the network path, and different parties see different slices:

Who What they see
Anyone on your Wi-Fi or network path Every name you look up, in plain text
Your recursive resolver Every name you look up, and your IP address
Root servers Traditionally the full name (more below), but only the resolver’s IP
.com servers The full name, and the resolver’s IP
example.com’s name servers The name, the resolver’s IP, and sometimes part of yours

The recursive resolver is the one that matters. It sees everything, tied to you, and with the default setup that’s your ISP. In the US, ISPs don’t need your opt-in to use that kind of browsing data for advertising, since Congress repealed the FCC’s broadband privacy rules last year before they took effect. That’s a big part of why a third-party resolver suddenly sounds appealing to a lot of people.

The roots and TLD servers seeing the full name is a historical accident. A resolver traditionally sends the whole question, www.example.com, to every server in the chain, even though the root only needs to know you want .com. QNAME minimization (RFC 7816, from 2016) fixes that by only sending each server the part it needs. Cloudflare says 1.1.1.1 does this. Not many resolvers do yet.

The “sometimes part of yours” in the last row is EDNS Client Subnet, an extension where the resolver passes along a chunk of your IP address so that a CDN’s authoritative server can give you an answer near you. It helps performance and hurts privacy. Cloudflare says it doesn’t send it, which may occasionally get you a slightly less local answer from a CDN.

Encrypting it

There are now two standards-track ways to encrypt the hop between you and your resolver. DNS over TLS (RFC 7858) is just DNS inside a TLS connection on port 853. DNS over HTTPS is still an IETF draft, and it does what it says, DNS queries as HTTPS requests. That makes it look like any other web traffic, which is either the point or the problem, depending on whether you’re the user or the network admin. 1.1.1.1 supports both, which is the most interesting thing about it to me. Very little software on your machine speaks either one out of the box yet, so for now that means running a local proxy, or a router that supports it.

People sometimes bring up DNSSEC here. DNSSEC signs records so you can tell an answer hasn’t been forged, and it does nothing for confidentiality. Everyone can still read the queries, they just can’t fake the answers. It’s worth having, and it’s a different problem.

So, should you switch?

My honest answer to the three people who asked is that switching moves your trust somewhere else. Using 1.1.1.1 means Cloudflare sees all your lookups instead of your ISP. They’ve promised never to write the querying IP address to disk, to wipe the logs within 24 hours, and to have KPMG audit them on it. I’m inclined to believe them, partly because their business is selling CDN and security services, not ads, and partly because a public promise with an auditor attached is more than I’ve ever gotten from an ISP. But it’s still a promise.

And DNS is only one of the leaks. Even with encrypted DNS, your ISP still sees the IP addresses you connect to, and in most HTTPS connections the hostname is sent in plain text anyway, in the SNI field of the TLS handshake, so the server knows which certificate to present. Hiding your DNS while the next packet announces the hostname is privacy theater for anyone watching the wire. It’s still a real improvement against an ISP that logs and sells resolver data, since that’s a lot easier than doing deep packet inspection on every connection.

One more practical warning. A lot of networks and network gear have been treating 1.1.1.1 as if it were unused for years, as a placeholder address on captive portals and in internal configs, so it doesn’t work everywhere. There’s 1.0.0.1 as a secondary for that reason, and if 1.1.1.1 doesn’t respond on some hotel Wi-Fi, that’s probably why.

At home I switched the router over on the 2nd and I haven’t noticed anything except lookups being a few milliseconds faster. At work our servers use the cloud provider’s resolver, because that’s the one that knows about our private zones, and that’s not changing.