Every visit to a website starts with a question your device asks out loud: what is the address of this name? For most of the internet's life that question crossed the network in plain text, readable by the café Wi-Fi, your provider and anyone else on the path. This chapter is about who can read it, how DNS over TLS, HTTPS and QUIC seal it, and what they still leave in the open. If tunnels and encryption on the wire are new to you, start with networks · VPNs, tunnels & overlays; if you need a refresher on what a resolver is and how your device gets one, read networks · DHCP & DNS.
Common mix-up: encrypted DNS is not DNSSEC. Encryption protects the conversation between your device and one resolver, so nobody on that stretch of wire can read or change it. DNSSEC protects the data, so you can check that an answer really came from the zone's owner, however many hands it passed through. They solve different problems, and you can have either one without the other. Chapter 11 is about DNSSEC.
Look at it from the point of view of a single question. You type www.shop.example into a browser on a café's Wi-Fi. Before anything else happens, your device's stub resolver writes a small DNS query, perhaps 40 bytes, and sends it as one UDP packet to port 53 on the resolver it was given. The query contains the name, the record type and nothing else that is secret, but that is already a lot: the name of every site you visit, every app that phones home, every mail server your laptop checks, in order and with timestamps.
The DNS data itself is public. Anyone can look up www.shop.example, and the answer is the same for everyone. What is private is the fact that you asked, and when. RFC 9076, the IETF's survey of DNS privacy (it replaced the earlier RFC 7626 in 2021), sorts the people who can learn that fact into three groups, and the rest of this chapter is organized around them.
The cheapest fix for the third group needs no encryption at all. QNAME minimisation (RFC 9156) has the resolver tell each authoritative server only as much of the name as that server needs to give a referral: the root is asked about example, the example servers about shop.example, and only the zone that actually holds the record hears www.shop.example. Chapter 3 walks through how that works step by step. The first two groups need cryptography, and that is where DoT, DoH and DoQ come in.
| Observer | With classic DNS (Do53) | With DoT, DoH or DoQ to your resolver | What else helps |
|---|---|---|---|
| Wi-Fi, ISP, transit | Every name, type and answer, your IP, timing; can forge replies | Your IP, the resolver's IP, timing and sizes; cannot read or forge | Padding (sizes), ECH (the later TLS connection) |
| Your resolver | Every name, your IP | Every name, your IP (unchanged) | Choosing whom to trust; Oblivious DoH |
| Root and TLD servers | The full name, the resolver's IP | Unchanged: that hop is a separate conversation | QNAME minimisation; resolver-to-authoritative encryption |
| The zone's own servers | The full name, the resolver's IP | Unchanged | Nothing: it has to know what you asked to answer it |
RFC 9076 is careful to list leaks that are easy to miss. The timing of queries is a fingerprint: a news site triggers a burst of lookups for its ad and analytics hosts in a recognizable order. The source port and query ID of a stub can make one device stand out behind a shared address. Some resolvers forward part of your IP address to authoritative servers in an EDNS Client Subnet option so that a CDN can pick a nearby server for you (chapter 9), which hands a slice of your location to parties you never chose.
There is also cache snooping: anyone who can query a shared resolver can ask, with recursion turned off, whether a name is already in its cache, and so learn whether someone nearby looked it up recently. Resolvers that serve the public usually blunt this. RFC 8932 collects recommended practices for privacy-respecting resolver operators, including how long to keep logs and what to publish in a privacy policy.
Pick a transport and switch the other protections on and off. The diagram shows each stretch of the path as readable (dashed) or encrypted (solid), and the cards below list, in words, exactly what each party learns about one lookup of www.shop.example from a laptop at 198.51.100.23. All names and addresses are simulated documentation values. The model assumes the resolver's cache is empty; on a cache hit the authoritative servers learn nothing at all.
The first standard answer, DNS over TLS or DoT (RFC 7858, May 2016), is the most direct one. Take the DNS-over-TCP that has existed since the 1980s, where each message is preceded by a two-byte length, and run it inside TLS, the same encryption that protects HTTPS. Give it its own well-known port, TCP 853, so that a client knows to start TLS immediately instead of guessing. Nothing about the DNS message changes. The resolver unwraps the TLS layer and sees exactly the bytes chapter 2 takes apart.
TLS buys two things. Confidentiality: an observer sees a TLS session to port 853 and the sizes and timing of the records inside it, but not the questions. Integrity and authentication: if the client checks the server's certificate, a box in the middle can no longer slip in a forged answer, because it cannot produce valid TLS records for that session. That second half only works if the client actually checks, and that turns out to be the hard part.
A stub resolver usually learns its resolver as a bare IP address, from DHCP or router advertisements. A certificate is issued to a name. So what should the client check the certificate against? RFC 8310 (March 2018) answers with two usage profiles:
dns.example.net, or a key pin, and refuses to send any query unless the server proves it holds that name. If it cannot, resolution fails. That is safe and unforgiving: a captive portal at a hotel can break name resolution until you sign in another way.Android's "Private DNS" setting is the most widely seen example of this split: give it a hostname and it runs strict DoT to that name; leave it on automatic and it tries the network's resolver over TLS opportunistically.
Three round trips for the first answer would be painful if every query paid them. RFC 7858 therefore expects clients to keep the connection open and send many queries down it, and to pipeline them: send the next query before the previous answer arrives, and match answers by ID, since the server may answer out of order. TLS session resumption lets a client that reconnects later skip most of the handshake. In practice a DoT stub keeps one long-lived connection to its resolver, and after the first lookup each query costs a single round trip, like classic UDP.
There was also a datagram variant, DNS over DTLS (RFC 8094, experimental), meant to keep DNS on UDP. It saw almost no deployment and has been overtaken by DNS over QUIC, which does the same job better.
A dedicated port has a weakness: it is easy to see, and easy to block. A network that wants to force everyone onto its own resolver can drop TCP 853 and most opportunistic clients will quietly fall back to plain text. DNS over HTTPS, DoH (RFC 8484, October 2018), takes the opposite approach. It sends each DNS message as an ordinary HTTPS request to a URL such as https://doh.example/dns-query. On the wire that is TLS to port 443, the same as every web page. A network can still block a well-known DoH server by its address, but it cannot block DoH as a protocol without blocking the web.
The message itself is still the binary DNS message, unchanged, labeled with the media type application/dns-message. There are two ways to send it:
- and _ in place of + and /, and no trailing =) and placed in a URL parameter called dns. That makes the whole question part of the URL, so an ordinary HTTP cache can store the answer and hand it to the next person who asks the same question.For GET caching to work, two identical questions have to produce identical URLs. That is why RFC 8484 says a DoH client SHOULD set the DNS message ID to 0: the ID was there to match a UDP answer to its question, and HTTP already does that job. The answer's cache lifetime comes from the smallest TTL in it, carried in the HTTP freshness headers. The DNS header carries the type; the HTTP layer carries everything else.
Because it is just HTTPS, DoH slots into software that already speaks HTTP. A browser can resolve names over the same HTTP/2 or HTTP/3 connection machinery it uses for pages, without asking the operating system. That is the source of both its popularity and its controversy, which the trade-offs section below comes back to. RFC 8484 recommends HTTP/2 as the minimum version, so many queries share one connection without waiting on each other.
Type a name and choose a type. The builder writes the real DNS query bytes (the header, the question, and optionally an EDNS OPT record), encodes them with base64url, and shows both the GET URL and the POST request a DoH client would send. Turn on padding and the message grows to the next multiple of 128 bytes, as RFC 8467 recommends for queries, so that the length no longer hints at the name. With the defaults, the output matches the example printed in RFC 8484. Nothing is sent anywhere: doh.example is a reserved name and the page makes no network requests.
DoT and DoH both ride on TCP, and TCP has two costs that classic DNS never paid. The first is set-up: a TCP handshake, then a TLS handshake, before the first question can go. The second is head-of-line blocking: TCP delivers bytes strictly in order, so if one packet is lost, every answer queued behind it waits for the retransmission, even answers that have nothing to do with the lost one.
QUIC (RFC 9000) is a transport built on UDP that fixes both. It combines the transport and TLS 1.3 handshakes into a single round trip, and it carries many independent streams in one connection, each delivered in order on its own, so a loss on one stream does not stall the others. HTTP/3 runs on it. DNS over QUIC, DoQ (RFC 9250, May 2022), puts DNS directly on QUIC on UDP port 853, with each query and its answer on a stream of their own. As with DoH, the DNS message ID must be 0, since the stream already pairs question and answer.
DoQ is also designed for more than the stub-to-resolver hop. The RFC explicitly covers resolver-to-authoritative traffic and zone transfers, places where a long-lived, low-latency encrypted connection with no head-of-line blocking is attractive. A client that has talked to the server before can use QUIC's 0-RTT resumption to send its first query in the very first packet, at the cost of some replay and privacy caveats the RFC spells out.
| Transport | RFC | Carried over | Port | Message ID | Status |
|---|---|---|---|---|---|
| Do53 | 1035 | UDP, TCP for large answers | 53 | random | Classic DNS; plain text |
| DoT | 7858, 8310 | TLS over TCP | TCP 853 | random | Standards Track |
| DoH | 8484 | HTTPS (HTTP/2 or later recommended) | TCP or UDP 443 | 0 (SHOULD) | Standards Track |
| DoQ | 9250 | QUIC | UDP 853 | 0 (MUST) | Standards Track |
| ODoH | 9230 | HTTPS through a proxy, sealed with HPKE | 443 | 0 | Experimental |
This is a round-trip model, not a measurement. Set the round-trip time to your resolver and the number of lookups a page needs. The model counts handshakes and query round trips for a fresh connection, then charges one round trip for every later query on the kept-open connection. Turn on resumption to see what TLS 1.3 early data and QUIC 0-RTT save on a reconnect. Each bar is labeled with its arithmetic below; packet loss, server time and congestion are left out.
Kinder: a lost packet in the TCP handshake costs a retransmission timeout, often a second or more, and with TCP every later answer waits behind any lost segment. Classic UDP DNS has its own version of this, a client retry timer, usually a second or more. QUIC recovers loss per stream. None of that is in the bars.
Harsher: real clients rarely pay the full handshake. A DoH client usually keeps its connection to the resolver warm for minutes, and a browser may resolve over a connection it already has open to the same provider. After that the cost of encrypted DNS is one round trip per uncached question, the same as UDP, plus a few dozen bytes of framing and encryption overhead per message.
Encryption to the resolver moves your trust; it doesn't remove it. Your resolver still learns your address and every name you look up. You can choose a resolver whose privacy policy you like, but you have to take the policy on faith. Oblivious DNS over HTTPS, ODoH (RFC 9230, June 2022, published as Experimental), arranges things so that no single party has to be trusted with both facts.
There are two servers, run by different organizations. The client looks up the target resolver's public key and seals its DNS query for that key using HPKE, hybrid public-key encryption. It then sends the sealed query, over ordinary HTTPS, to an oblivious proxy, with the media type application/oblivious-dns-message. The proxy can see the client's IP address but only a sealed blob; it forwards the blob to the target. The target opens it, resolves the name and seals the answer with a key only that client can use, but it only ever sees the proxy's address.
The guarantee depends on the two operators not colluding, which is a policy assumption rather than a mathematical one, and on enough clients sharing the proxy that a single user cannot be picked out by timing. The cost is an extra hop on every query. The same split-trust idea, generalised to any HTTP request, became Oblivious HTTP (RFC 9458).
Encryption is useless if the client doesn't know that its resolver supports it, or under which name to authenticate it. For years the only answers were manual configuration or hard-coded lists in browsers and operating systems. Two standards from November 2023 let a network advertise its encrypted resolver properly.
Discovery of Designated Resolvers, DDR (RFC 9462), works from the resolver the client already has. The client asks that resolver, over plain DNS, for the SVCB records at the special name _dns.resolver.arpa. The answer lists the encrypted endpoints the resolver operator designates: their names, ALPN protocols (dot, h2, h3, doq), ports, and for DoH the URI path. In verified discovery, the client then connects to the designated name and requires that the TLS certificate cover the original resolver's IP address too, which proves that whoever runs the advertised server also controls the unencrypted one. If the original resolver is at a private address, no public certificate can cover it, so only opportunistic discovery is possible, and only when the designated resolver has that same IP address.
;; DDR: a client asks its plain resolver for its designated encrypted resolvers (simulated) ;; QUESTION SECTION: ;_dns.resolver.arpa. IN SVCB ;; ANSWER SECTION: _dns.resolver.arpa. 7200 IN SVCB 1 dns.example.net. alpn="h2,h3" port=443 dohpath="/dns-query{?dns}" _dns.resolver.arpa. 7200 IN SVCB 2 dns.example.net. alpn="dot" port=853 _dns.resolver.arpa. 7200 IN SVCB 3 dns.example.net. alpn="doq" port=853 ;; ADDITIONAL SECTION: dns.example.net. 7200 IN A 192.0.2.53 ;; verified discovery: the TLS certificate of dns.example.net must also list 192.0.2.53
Discovery of Network-designated Resolvers, DNR (RFC 9463), carries the same information in the network's own configuration messages: new DHCPv4, DHCPv6 and IPv6 Router Advertisement options that hand the client an authentication name, protocol list and addresses at the moment it joins. That removes the first plain-text query DDR needs, but it trusts the local network's configuration channel, which is no stronger than the network itself.
The last stretch is the one from the resolver up to the authoritative servers. It is still almost entirely plain UDP, which matters less than the first hop because the resolver aggregates many users, but it is not nothing. RFC 9539 (February 2024, Experimental) describes how a resolver can, without any coordination, try DoT or DoQ to an authoritative server's address, remember which servers answered encrypted, and fall back silently when they don't. It defends against passive monitoring only; an active attacker can force the fallback. It is a deliberately modest first step, because authenticating authoritative servers at scale is an open problem.
The awkward fact behind all of this is that DHCP and router advertisements hand out resolvers as addresses, and TLS authenticates names. Public resolver operators solved it for themselves by getting certificates that list their well-known anycast addresses as IP subject names, so a client configured with an address can still check a certificate. That is what makes DDR's verified mode possible for them. A home router at a private address can't do the same, which is why DNR exists and why so many devices still run opportunistic DoT, or nothing, on home networks.
Browsers took a third route: a built-in list of resolvers known to support DoH, and an upgrade to the matching DoH endpoint when the system resolver's address is on the list. DDR standardized that idea so that it no longer needs a hand-maintained list.
Encrypted DNS closes one window. Several others stay open, and it helps to name them, because the most common overclaim about DoH is that it hides which sites you visit. It does not, on its own.
a.example and one with a 60-character label produce visibly different packet sizes. EDNS padding (RFC 7830 defines the option, RFC 8467 the policy) rounds queries up to a multiple of 128 bytes and answers to a multiple of 468, which blurs that signal. Timing patterns remain.RFC 8467 weighed several policies and recommended block-length padding: clients pad each query to the closest multiple of 128 octets, and servers pad each answer to a multiple of 468. The query size was chosen because nearly all queries fit in one 128-byte block, so they all look the same. The 468 figure was chosen so that three blocks, 1,404 bytes, still fit in a typical 1,500-byte Ethernet packet after IP, UDP or TCP and encryption overhead. Padding only makes sense on an encrypted transport; in plain text it just wastes bytes, and the RFC says not to do it there.
Padding costs bandwidth and helps only against size analysis. It doesn't hide how many queries you made or when. The padding option itself is EDNS option code 12, filled with zero bytes, which Instrument 2 builds.
Plain DNS had an accidental property: whoever ran the network could see and steer it. Encrypted DNS removes that property, and some people relied on it on purpose.
intranet.corp.example, only from their internal resolvers, and some names resolve differently inside and out (chapter 10). A device that sends everything to a public resolver gets the outside view, or an NXDOMAIN, and internal sites stop working. Browsers handle this with fallback rules and enterprise policies; that is fragile, which is another argument for discovering the local resolver rather than bypassing it.Platforms expose this as a setting. Firefox, for example, documents several DoH protection levels, from off through a default that can fall back to the system resolver, to a strict mode that never does, and it turns DoH off by default on networks that signal they filter, using a "canary" domain the network can make fail. Mozilla's support page describes the current levels and exceptions. Public resolvers such as Cloudflare's 1.1.1.1 and Google Public DNS publish their DoH and DoT endpoints and privacy commitments in their documentation (sources below).
| Concern | DoT (port 853) | DoH (port 443) | DoQ (UDP 853) |
|---|---|---|---|
| Easy for a network to spot | Yes: its own port | Hard: looks like web traffic | Yes: its own port |
| Fits in the OS stub resolver | Natural fit | Common, but often app-level | Natural fit; newer |
| Head-of-line blocking on loss | Yes (TCP) | Yes on HTTP/2; no on HTTP/3 | No |
| Answers cacheable by HTTP caches | No | Yes, with GET and ID 0 | No |
| Resolver-to-authoritative use | Yes (RFC 9539) | Rare | Yes (RFC 9250, 9539) |
Modern versions of dig can speak DoT and DoH directly, which is the quickest way to see that a resolver answers over an encrypted transport. The commands and trimmed output below are illustrative, against a simulated resolver; substitute the name your provider documents. The output is the same DNS message you would get on port 53. Only the transport changed, and dig tells you which one it used on the SERVER line.
$ dig +tls @dns.example.net www.example.com A ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 0 ;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1 www.example.com. 300 IN A 203.0.113.80 ;; SERVER: 192.0.2.53#853(dns.example.net) (TLS) $ dig +https @dns.example.net www.example.com A www.example.com. 300 IN A 203.0.113.80 ;; SERVER: 192.0.2.53#443(dns.example.net) (HTTPS) $ dig +tls @192.0.2.99 www.example.com A ;; Connection to 192.0.2.99#853(192.0.2.99) for www.example.com failed: connection refused. ;; a strict client stops here; an opportunistic one would retry on port 53
Two details are worth noticing. The ID is 0 in the DoH case, as RFC 8484 recommends, and the port changed from 853 to 443 without anything else in the answer changing. And the failed case is the strict-versus-opportunistic decision of RFC 8310 in miniature: what your client does next is a policy choice, not a protocol one.