Before DNS, the internet ran on trust and a text file.
It was called HOSTS.TXT, and it lived on a single machine at the Stanford Research Institute’s Network Information Centre – SRI-NIC. Every host on the ARPANET had an entry in this file: a name and an address, one per line. If you wanted to connect to a machine by name, your computer needed a copy of HOSTS.TXT. You got that copy by using FTP to download it from SRI-NIC. Regularly. Manually. Or, if you were organised, via a cron job.
In the early days, this worked. The ARPANET had a few hundred hosts, and the file changed slowly enough that a weekly download was fine. But by the early 1980s, the network was growing fast. Hundreds of hosts became thousands. Every new machine meant an update to HOSTS.TXT, and every update meant every other machine needed to download the new version. The traffic to SRI-NIC was becoming a problem in itself. Name collisions were becoming common – there was no authority structure, no namespacing, just a flat list. And the single point of failure was obvious: if SRI-NIC went down, nobody could resolve names. (Mockapetris himself described these scaling problems in “Development of the Domain Name System”, his 1988 retrospective.)
Something had to change. And in November 1983, a researcher at the University of Southern California’s Information Sciences Institute published a pair of documents that would quietly reshape how the entire internet works.
Paul Mockapetris and the birth of DNS
Paul Mockapetris wasn’t trying to build a monument. He was trying to solve a practical problem: how do you map names to addresses in a network that’s growing faster than any single file can keep up with?
His answer, published as RFC 882 and RFC 883 in November 1983, was the Domain Name System (RFC 882 and RFC 883). The core insight was elegant: instead of one file on one machine, distribute the data. Break the namespace into a hierarchy of zones, let different organisations manage their own zones, and build a protocol that lets any machine on the network find any name by asking the right sequence of questions.
It took a few years to get right. The original RFCs were superseded in 1987 by RFC 1034 and RFC 1035, which remain the foundational documents of DNS to this day. The system they describe has been extended, patched, argued about, and occasionally abused over the past four decades, but the basic architecture hasn’t changed. It’s still a distributed hierarchical database. It still uses the same query protocol. And it still works, which is remarkable for something designed when the internet had fewer users than a mid-sized Perth suburb.
The hierarchy: dots all the way down
The Domain Name System is a tree. At the top is the root, represented by a single dot that almost nobody types but that technically exists at the end of every domain name. When you write www.example.com, the fully qualified domain name (FQDN) is actually www.example.com. – with a trailing dot. That dot is the root of the DNS tree.
Below the root are the top-level domains (TLDs): .com, .org, .net, .au, .uk, and around 1,500 others. Below each TLD are second-level domains – the names that organisations register: example.com, barkingiguana.com, bom.gov.au. Below those, you can have subdomains: www.example.com, mail.example.com, api.staging.internal.example.com. There’s no practical limit to how deep you can go, though sanity usually intervenes around three or four levels.
This hierarchy is the key to DNS’s scalability. No single server needs to know everything. The root servers know about TLDs. The TLD servers know about second-level domains. The authoritative servers for each domain know about their own subdomains. Authority flows downward through delegation – each level in the hierarchy points to the servers responsible for the level below it. The root says “for .com, ask these servers.” The .com servers say “for example.com, ask those servers.” And the example.com servers know the actual answers.
This is conceptually similar to how postal addresses work. Australia Post doesn’t need to know the layout of every building in Perth. It knows that mail addressed to WA goes to the Western Australian distribution centre. That centre knows which suburb to route it to. The local post office knows which street. Each level handles its own piece of the problem.
The thirteen root servers
At the very top of the DNS hierarchy sit the root servers, and there are exactly thirteen of them – or, more precisely, thirteen root server addresses, labelled A through M: a.root-servers.net through m.root-servers.net.
Why thirteen? It comes down to a practical constraint from the early 1990s. DNS responses needed to fit inside a single UDP packet, which was limited to 512 bytes. The thirteen root server names and their IPv4 addresses fit neatly within that limit. Thirteen was the maximum you could squeeze in. Add a fourteenth and the response wouldn’t fit, forcing a switch to TCP, which is slower.
But thirteen addresses doesn’t mean thirteen physical machines. Through a technique called anycast – where the same IP address is announced from multiple locations around the world, and network routing delivers your query to the nearest one – each root server letter actually represents dozens or hundreds of instances spread across the globe. As of 2024, there are over 1,700 root server instances worldwide. When you query a.root-servers.net from Perth, you’re probably hitting an instance in Sydney or Singapore, not a machine in Virginia.
The thirteen root server letters are operated by twelve different organisations, a mix that reflects the internet’s history as a collaborative, largely American, academic and government project:
| Letter | Operator |
|---|---|
| A | Verisign |
| B | USC Information Sciences Institute |
| C | Cogent Communications |
| D | University of Maryland |
| E | NASA Ames Research Centre |
| F | Internet Systems Consortium |
| G | US Defence Information Systems Agency |
| H | US Army Research Lab |
| I | Netnod (Sweden) |
| J | Verisign |
| K | RIPE NCC (Netherlands) |
| L | ICANN |
| M | WIDE Project (Japan) |
Two are run by Verisign. One by NASA. One by the US Army. One by a Swedish non-profit. One by a Japanese research consortium. It’s a peculiar arrangement that nobody would design from scratch today, but it works because the root servers have an extraordinarily simple job: they just point you to the right TLD servers. The data they serve barely changes and fits comfortably in memory. The hard part is keeping them available, and anycast handles that admirably.
IANA, Jon Postel, and ICANN
If DNS is the phone book, someone has to maintain the master copy. For the first two decades of the internet, that someone was essentially one person.
Jon Postel was a computer scientist at USC’s Information Sciences Institute who, from the early 1970s until his death in 1998, served as the editor of the RFC series and the administrator of what became known as the Internet Assigned Numbers Authority (IANA). IANA is responsible for three things: managing the DNS root zone (the list of TLDs and which servers handle them), allocating IP address blocks to regional registries, and maintaining the registries of protocol parameters (port numbers, protocol numbers, and similar technical identifiers).
For years, IANA was Jon Postel. Not a building, not a committee – a person. He managed the root zone from his office at USC under a contract with the US government. He decided which TLDs to add. He assigned IP address blocks. He edited the RFCs that defined how the internet worked. It’s difficult to overstate how much of the early internet’s governance rested on the trust that the community placed in a single, quiet, bearded computer scientist in Marina del Rey, California.
When Postel died of heart complications in October 1998, he was 55. The internet community mourned him, and then had to reckon with the fact that one person’s judgement had been holding together critical infrastructure for a global network. The transition from “Jon does it” to “an organisation does it” was already underway before his death, driven by the Clinton administration’s desire to privatise DNS governance.
The result was ICANN – the Internet Corporation for Assigned Names and Numbers, incorporated in 1998 as a California non-profit (articles of incorporation). ICANN took over the IANA functions: managing the root zone, coordinating IP address allocation (through regional registries like APNIC in the Asia-Pacific), and overseeing the domain name system’s technical operations.
For years, ICANN operated under a contract with the US Department of Commerce, which gave the US government a unique oversight role over global internet governance. This was controversial, to put it mildly. Other countries objected to one nation having a veto over the internet’s address book. The debate rumbled on for nearly two decades until, in October 2016, the IANA stewardship transition was completed: the US government relinquished its oversight role, and ICANN became a fully independent, multi-stakeholder organisation (the IANA stewardship transition). The root zone is now managed through a collaborative process involving ICANN, Verisign (which operates the root zone maintainer function), and the root server operators.
It’s a strange thing to contemplate: the system that lets you type a domain name and reach a website, the system that underpins essentially all internet communication, was managed by one person for two decades and is now governed by a California non-profit through a multi-stakeholder process that most internet users have never heard of.
Name servers: authoritative and recursive
When people say “DNS server”, they usually mean one of two very different things.
Authoritative name servers are the source of truth. They hold the actual DNS records for a domain and answer queries about that domain with authority. If you own example.com, your authoritative name servers are the ones that know the IP address of www.example.com, the mail server for example.com, and everything else about your domain. When an authoritative server answers a query, it sets a flag in the response that says “I am authoritative for this data” – it’s not guessing, it knows.
Recursive resolvers (also called recursive name servers or simply resolvers) are the intermediaries. They don’t hold authoritative data for any domain (other than perhaps some local zones). Instead, when they receive a query, they go and find the answer by working their way through the DNS hierarchy, starting at the root and following delegations until they reach the authoritative server that has the answer. Then they cache the result and return it to the client.
Your computer almost certainly doesn’t talk to authoritative servers directly. It talks to a recursive resolver. On a home network in Australia, that’s typically a resolver run by your ISP – Telstra, Optus, or whoever provides your internet. Or you might have configured a public resolver like Google’s 8.8.8.8, Cloudflare’s 1.1.1.1, or Quad9’s 9.9.9.9.
There’s actually a third player: the stub resolver, which is the DNS client built into your operating system. When your browser needs to look up www.example.com, it doesn’t do the full resolution itself. It asks the stub resolver, which sends a single query to the configured recursive resolver and waits for the answer. The stub resolver is intentionally simple – it just knows how to ask someone else.
There’s also the concept of a forwarder – a DNS server that, instead of doing the full recursive resolution itself, forwards queries to another recursive resolver. Corporate networks often use forwarders: the internal DNS server handles queries for internal domains directly but forwards everything else to an upstream resolver. This simplifies the internal server’s job and lets the upstream resolver do the heavy lifting and caching.
The resolution process: following the trail
Let’s walk through what actually happens when you type www.bom.gov.au into your browser – the Bureau of Meteorology, because you’re in Perth and you want to know if it’s going to rain this weekend. (Spoiler: in April, probably not.)
Step 1: The stub resolver. Your browser asks the operating system to resolve www.bom.gov.au. The OS checks its local cache – maybe it looked this up recently and the answer is still fresh. If so, it returns the cached answer immediately and the process is done. If not, it sends a DNS query to the recursive resolver configured on your system.
Step 2: The recursive resolver. Your ISP’s recursive resolver receives the query. It also checks its cache. If it has a fresh answer, it returns it. If not, it needs to go looking. But it doesn’t start from scratch every time – it almost certainly has the addresses of the .au TLD servers cached from recent queries. If it does, it can skip straight to step 4. Let’s assume a cold cache for the full picture.
Step 3: The root. The resolver sends a query to one of the root servers: “Where can I find www.bom.gov.au?” The root server doesn’t know the answer, but it knows who handles .au. It responds with a referral: “I don’t know, but here are the authoritative servers for the .au zone.” This is an iterative response – the root server doesn’t go and find the answer for you, it just points you to the next server in the chain.
Step 4: The TLD. The resolver follows the referral and queries an .au TLD server: “Where can I find www.bom.gov.au?” The .au server doesn’t know the final answer either, but it knows who handles gov.au. Another referral.
Step 5: The gov.au delegation. The resolver queries a gov.au server: “Where can I find www.bom.gov.au?” This server knows who handles bom.gov.au and sends a referral to those authoritative name servers.
Step 6: The authoritative answer. The resolver queries the authoritative name server for bom.gov.au: “What is the A record for www.bom.gov.au?” The authoritative server knows this answer. It responds with the IP address, and sets the “authoritative answer” flag. It also includes a TTL (time to live) value – say, 300 seconds – telling the resolver how long it can cache this answer.
Step 7: The response. The resolver caches the answer and returns it to your stub resolver, which passes it to the browser. The browser opens a TCP connection to the IP address and starts loading the forecast page.
The whole process, when the cache is cold, might involve four or five round trips across the internet. But it happens in milliseconds. And most of the time, the resolver’s cache is warm – it’s already looked up .au and gov.au recently for other users – so it can skip straight to step 6 or return a cached final answer without any network traffic at all.
There’s a subtlety here that matters for privacy. In the traditional resolution process, the resolver sends the full domain name at every step: it asks the root server for www.bom.gov.au, even though the root only needs to know about .au. This means the root server operator can see every domain name that’s being queried. QNAME minimisation, defined in RFC 7816 (2016), fixes this: the resolver only sends the minimum information needed at each step. It asks the root “where is .au?”, the .au server “where is gov.au?”, and so on. Each server only sees the part of the name it needs to answer. Most modern resolvers now implement QNAME minimisation by default.
Zone files: the source of truth
The actual DNS data for a domain lives in a zone file – a text file on the authoritative name server. Zone files have a specific format defined in RFC 1035, and they look like this:
$ORIGIN example.com.
$TTL 3600
@ IN SOA ns1.example.com. admin.example.com. (
2026042201 ; serial
7200 ; refresh (2 hours)
3600 ; retry (1 hour)
1209600 ; expire (2 weeks)
300 ; minimum TTL (5 minutes)
)
IN NS ns1.example.com.
IN NS ns2.example.com.
IN A 203.0.113.10
IN AAAA 2001:db8::10
IN MX 10 mail.example.com.
IN MX 20 backup-mail.example.com.
IN TXT "v=spf1 mx -all"
www IN A 203.0.113.10
www IN AAAA 2001:db8::10
mail IN A 203.0.113.20
The $ORIGIN directive sets the base domain – any name that doesn’t end with a dot is treated as relative to this origin. The $TTL sets the default time to live for records that don’t specify their own. The @ symbol is shorthand for the origin itself.
A zone is a unit of administrative delegation. It’s the chunk of the DNS namespace that a particular set of authoritative servers is responsible for. The zone for example.com might include www.example.com, mail.example.com, and the domain itself, but not subdomain.example.com if that’s been delegated to its own servers. The boundary between zones is wherever delegation happens.
SOA records: the zone’s metadata
Every zone has exactly one SOA (Start of Authority) record, and it’s the most information-dense record type in DNS. Let’s break it down field by field:
example.com. IN SOA ns1.example.com. admin.example.com. (
2026042201 ; serial
7200 ; refresh
3600 ; retry
1209600 ; expire
300 ; minimum
)
MNAME (ns1.example.com.) – the primary name server for the zone. This is the server that holds the master copy of the zone data.
RNAME (admin.example.com.) – the email address of the zone administrator, written in a peculiar way: the @ is replaced with a dot. So admin.example.com. means admin@example.com. If the local part of the email address contains a literal dot, it needs to be escaped with a backslash: first\.last.example.com. means first.last@example.com. It’s awkward, but DNS records can’t contain @ because that symbol has a different meaning in zone files.
Serial (2026042201) – a version number for the zone. Secondary name servers use this to determine whether their copy of the zone is out of date. The convention is YYYYMMDDnn, where nn is a sequence number for changes within the same day. So 2026042201 means the first change on 22 April 2026. If you make another change that day, you’d bump it to 2026042202. This convention isn’t enforced by the protocol – the serial is just an unsigned 32-bit integer – but it’s universally followed because it makes zone versions human-readable.
Refresh (7200 – 2 hours) – how often secondary servers should check whether the zone has been updated.
Retry (3600 – 1 hour) – if a refresh attempt fails, how long to wait before trying again.
Expire (1209600 – 2 weeks) – if a secondary server can’t reach the primary for this long, it should stop serving the zone entirely. The assumption is that if you’ve been unable to refresh for two weeks, your data is too stale to trust.
Minimum (300 – 5 minutes) – in modern DNS, this field is used as the negative caching TTL: how long resolvers should cache the fact that a name doesn’t exist (an NXDOMAIN response). This was clarified by RFC 2308.
Record types: the vocabulary of DNS
DNS records come in many types, each serving a different purpose. Here are the ones you’ll encounter most often, and a few exotic ones for good measure.
A and AAAA
The most fundamental records. An A record maps a name to an IPv4 address (32 bits, written as four decimal numbers: 203.0.113.10). An AAAA record (pronounced “quad-A”) maps a name to an IPv6 address (128 bits, written in hexadecimal groups: 2001:db8::10). The name “AAAA” comes from the fact that an IPv6 address is four times the size of an IPv4 address – four A’s.
www.example.com. IN A 203.0.113.10
www.example.com. IN AAAA 2001:db8::10
A domain can have multiple A records, and clients will typically try them in some order – this is a simple form of load balancing. The same name can also have both A and AAAA records, and modern clients will prefer IPv6 (AAAA) through a mechanism called Happy Eyeballs (RFC 8305), which races IPv4 and IPv6 connections and uses whichever completes first.
CNAME
A CNAME (canonical name) record creates an alias. It says “this name is actually another name – go look up that one instead.”
blog.example.com. IN CNAME example.github.io.
When a resolver looks up blog.example.com and gets a CNAME response, it restarts the lookup for example.github.io. instead. This is useful when you want one name to point wherever another name points, without having to maintain duplicate A records.
There’s an important restriction: you cannot place a CNAME at the zone apex (the bare domain, like example.com). The reason is technical and frustrating. RFC 1034 states that a CNAME record cannot coexist with any other record type for the same name. But the zone apex must have SOA and NS records. Therefore, a CNAME at the apex would be a contradiction. This means you can’t CNAME example.com to your hosting provider’s load balancer – you have to use an A record with a specific IP address. Many DNS providers work around this with proprietary extensions (Cloudflare calls theirs CNAME flattening; Route 53 uses ALIAS records), but there’s no standard solution yet.
MX
MX (mail exchange) records tell the world where to deliver email for a domain. Each MX record has a preference value (lower is higher priority) and a target mail server name:
example.com. IN MX 10 mail.example.com.
example.com. IN MX 20 backup.example.com.
When someone sends email to user@example.com, their mail server looks up the MX records for example.com, tries the lowest-preference server first (mail.example.com, preference 10), and falls back to higher-preference servers if the primary is unreachable. This is how email routing has worked since the 1980s, and it’s one of the reasons email is so resilient – even if your primary mail server is down, a backup can hold your messages until it recovers.
NS
NS (name server) records define which servers are authoritative for a zone. They’re the mechanism of delegation – the glue that connects each level of the DNS hierarchy to the next.
example.com. IN NS ns1.example.com.
example.com. IN NS ns2.example.com.
You’ll always see at least two NS records for any zone, because DNS requires redundancy. If one name server is unreachable, the other can still answer queries.
TXT
TXT records were originally intended for human-readable notes, but they’ve become the kitchen-sink record of DNS – used for all sorts of machine-readable data that doesn’t fit into other record types.
example.com. IN TXT "v=spf1 mx ip4:203.0.113.0/24 -all"
example.com. IN TXT "google-site-verification=abc123..."
The most common uses:
- SPF (Sender Policy Framework) – declares which servers are allowed to send email on behalf of your domain. Receiving mail servers check SPF records to detect forged sender addresses.
- DKIM (DomainKeys Identified Mail) – publishes the public key used to verify cryptographic signatures on outgoing email. The actual DKIM records are published under a specific subdomain like
selector._domainkey.example.com. - Domain verification – services like Google, Microsoft, and various certificate authorities ask you to prove you own a domain by adding a specific TXT record. Since only someone with control of the DNS can add records, the presence of the record proves ownership.
TXT records have become so overloaded that there’s an ongoing debate about whether this is a good idea. The answer is probably “no, but it’s too convenient to stop.”
SRV
SRV (service) records provide a generalised mechanism for service discovery – finding the server that handles a particular service for a domain.
_sip._tcp.example.com. IN SRV 10 60 5060 sip.example.com.
The fields are: priority (like MX preference), weight (for load balancing among equal-priority records), port number, and target hostname. The name format follows a convention: _service._protocol.domain. SRV records are used by SIP (Voice over IP), XMPP (chat), LDAP, and various other protocols. The web doesn’t use them (HTTP has its own discovery mechanisms), but they’re essential in enterprise environments.
PTR
PTR (pointer) records are used for reverse DNS – looking up the name associated with an IP address, the opposite of what A records do.
Reverse lookups use a special domain: in-addr.arpa for IPv4 and ip6.arpa for IPv6. The IP address is written backwards (to align with DNS’s right-to-left hierarchy), and each octet becomes a label. So to find the name for 203.0.113.10, you query 10.113.0.203.in-addr.arpa:
10.113.0.203.in-addr.arpa. IN PTR www.example.com.
Reverse DNS is used for diagnostics, logging, and email anti-spam checks. Many mail servers will reject or flag messages from IP addresses that don’t have valid reverse DNS entries, on the theory that legitimate mail servers should be properly configured.
CAA
CAA (Certificate Authority Authorisation) records let domain owners specify which certificate authorities (CAs) are permitted to issue TLS certificates for their domain.
example.com. IN CAA 0 issue "letsencrypt.org"
example.com. IN CAA 0 issuewild ";"
The first record says “only Let’s Encrypt may issue certificates for this domain.” The second says “no CA may issue wildcard certificates.” CAs are required to check CAA records before issuing a certificate, so this provides a layer of protection against certificate mis-issuance – if someone tricks a CA into issuing a fraudulent certificate for your domain, the CAA check should catch it (assuming the CA is compliant).
The exotic ones
A few record types you’ll encounter less often but should know exist:
DNAME – like CNAME but for an entire subtree. A DNAME record at old.example.com pointing to new.example.com will redirect all names under old.example.com to the equivalent name under new.example.com. Useful for renaming a delegation without changing every individual record.
SSHFP – publishes the fingerprint of an SSH host key in DNS, so SSH clients can verify they’re connecting to the right server without asking the user to manually confirm the fingerprint. Requires DNSSEC to be meaningful, since otherwise an attacker could forge the record.
TLSA – part of the DANE (DNS-based Authentication of Named Entities) protocol, which uses DNSSEC to associate TLS certificates with domain names, bypassing the traditional certificate authority system entirely. Elegant in theory, rarely deployed in practice because it requires DNSSEC, which brings its own complications.
NAPTR – Name Authority Pointer records, used in ENUM (telephone number to URI mapping) and SIP routing. They’re essentially regular expressions stored in DNS, which tells you everything you need to know about their complexity.
Glue records: solving the chicken-and-egg problem
Here’s a puzzle: if the authoritative name servers for example.com are ns1.example.com and ns2.example.com, how does anyone find them?
Think about it. To look up ns1.example.com, you need to query the authoritative servers for example.com. But those authoritative servers are ns1.example.com and ns2.example.com. You need to know the answer to ask the question.
This is the glue record problem, and it’s solved at the parent zone level. When the .com registry delegates example.com to ns1.example.com, it doesn’t just store the NS record – it also stores the A record for ns1.example.com right there in the .com zone. These extra A records are called glue records, because they glue the delegation together.
; In the .com zone:
example.com. IN NS ns1.example.com.
example.com. IN NS ns2.example.com.
ns1.example.com. IN A 198.51.100.1 ; glue!
ns2.example.com. IN A 198.51.100.2 ; glue!
Glue records are required when the name server’s name falls within the zone it serves (as in this example – ns1.example.com is within example.com). They’re optional (and generally omitted) when the name server is in a different domain. If your name servers are ns1.hosting-provider.com, there’s no chicken-and-egg problem – the resolver can look up ns1.hosting-provider.com through the normal process without needing to resolve example.com first.
TTL, caching, and why “just lower the TTL” doesn’t always work
TTL (time to live) is a value, in seconds, attached to every DNS record. It tells resolvers how long they’re allowed to cache the record before they must re-query the authoritative server. A TTL of 3600 means “cache this for one hour.” A TTL of 60 means “cache this for one minute.”
The trade-off is straightforward: high TTLs mean better performance (fewer queries, faster responses for users) but less flexibility (if you change the record, old cached values persist until they expire). Low TTLs mean you can change records quickly, but resolvers query your servers more often, and users experience more latency.
There’s a common practice before DNS migrations: lower the TTL well in advance. If you’re moving a website to a new server next Saturday, you might lower the TTL from 3600 to 60 on Monday, wait for the old high-TTL records to expire (up to one hour), and then make the change on Saturday knowing that everyone will pick up the new address within a minute.
This usually works. But sometimes it doesn’t, and the reasons are instructive.
First, not all resolvers honour TTLs faithfully. Some ISP resolvers enforce a minimum TTL, clamping anything below (say) 300 seconds up to 300 seconds, regardless of what the authoritative server specifies. They do this to reduce their query load, but it means your carefully planned 60-second TTL might actually be 5 minutes for some users.
Second, the old TTL is itself cached. If a resolver looked up your record on Sunday (when the TTL was 3600), it cached both the record and the TTL. It won’t re-query until that 3600 seconds has passed. Only then will it discover the new, lower TTL. So if you lower the TTL on Monday, resolvers that already have a cached copy from Sunday won’t see the change until Sunday’s TTL expires. This is why you need to lower the TTL at least one old-TTL-period before the migration.
Third, there’s negative caching. If someone queries a name that doesn’t exist, the resolver caches the NXDOMAIN response for the duration of the SOA record’s minimum TTL (as defined by RFC 2308). If you’re creating a new DNS record for a name that previously didn’t exist, anyone who recently got an NXDOMAIN response will continue to see “doesn’t exist” until the negative cache expires.
Split-horizon DNS: different answers for different people
Sometimes you want the same domain name to resolve to different addresses depending on who’s asking. Your company’s intranet.corp.example.com might resolve to an internal IP (say, 10.1.2.3) when queried from inside the corporate network, and to a public IP (say, 203.0.113.50) – or not resolve at all – when queried from the public internet.
This is split-horizon DNS (also called split DNS or split-view DNS), and it’s common in corporate networks, VPN setups, and cloud environments.
The simplest implementation uses views in the DNS server software. BIND, the most widely deployed DNS server (Cricket Liu also wrote a companion volume for Microsoft DNS environments), supports a view directive that lets you define different sets of zone data based on the source IP address of the query:
view "internal" {
match-clients { 10.0.0.0/8; 192.168.0.0/16; };
zone "example.com" {
type master;
file "db.example.com.internal";
};
};
view "external" {
match-clients { any; };
zone "example.com" {
type master;
file "db.example.com.external";
};
};
Internal users see the internal zone file with private IP addresses. Everyone else sees the external zone file with public addresses.
Split-horizon DNS is useful, but it creates operational headaches. Debugging becomes harder – “it works for me” takes on a whole new dimension when two people can query the same name and get different answers. Tools like dig and nslookup won’t show you the internal view unless you run them from an internal network. DNSSEC (which we’ll get to shortly) is more complicated because you need separate signing for each view. And if you’re not careful with your internal zones, you can leak internal infrastructure details to external queries, or worse, accidentally serve internal addresses to external clients who can’t reach them.
DNS security: a history of creative destruction
DNS was designed in the 1980s, when the internet was a small, trusted academic network. Authentication was not a design goal. The protocol has no built-in way to verify that the answer you received actually came from the server you asked, or that it wasn’t tampered with in transit. This has led to some spectacular attacks.
Cache poisoning and the Kaminsky attack
Cache poisoning is the art of tricking a recursive resolver into storing a false DNS record. If an attacker can inject a bogus answer into a resolver’s cache, every user of that resolver will be directed to the wrong IP address – an attacker-controlled server that could serve a perfect copy of your bank’s website while quietly harvesting your credentials.
In July 2008, security researcher Dan Kaminsky revealed a devastating refinement of cache poisoning that could compromise any DNS resolver on the internet.
The attack exploited a fundamental weakness in how DNS queries work. When a resolver sends a query, it includes a 16-bit transaction ID – a number between 0 and 65,535. The resolver expects the response to include the same transaction ID. This is the primary mechanism for matching responses to queries and preventing spoofed answers.
The problem: 65,536 possible values isn’t very many. An attacker can simply flood the resolver with forged responses, each with a different guessed transaction ID, hoping one matches. Previous cache poisoning attacks had been limited by the fact that you could only try this when the resolver was actively looking up a specific name, and if you failed, you had to wait for the cached record to expire before trying again.
Kaminsky’s insight was that you didn’t need to wait. Instead of trying to poison the answer for www.example.com directly, the attacker would query the resolver for a random subdomain – something like asdfjkl.example.com – that definitely wasn’t in the cache. This forced the resolver to go looking for an answer, giving the attacker a window to inject a forged response. And the forged response wouldn’t just contain a fake answer for asdfjkl.example.com – it would include a malicious additional section claiming that the authoritative server for all of example.com was now evil-server.attacker.com. If the forgery was accepted, the attacker would own the entire domain in that resolver’s cache.
The beauty (for the attacker) was that each attempt was independent. If the first try failed, you just query for a different random subdomain – qwerty123.example.com – and try again. No waiting for cache expiry. You could make hundreds of attempts per second. With only 65,536 possible transaction IDs, success was essentially inevitable given enough attempts. Kaminsky estimated that most resolvers could be compromised in under 10 seconds.
The response was a massive, coordinated effort. Software vendors issued patches that added source port randomisation – instead of sending all queries from a fixed port, resolvers would use a random source port for each query, adding another ~16 bits of entropy that an attacker would need to guess correctly. This was a band-aid, not a cure, but it raised the bar from “trivially exploitable” to “very difficult” (RFC 5452).
The real fix, everyone agreed, was DNSSEC. But that’s a longer story.
DNS amplification and reflection DDoS
DNS can be weaponised for distributed denial-of-service attacks, and the technique is elegant in its simplicity.
A DNS query is small – perhaps 50 bytes. But the response can be much larger, especially for types like ANY (which returns all records for a name) or DNSSEC-signed responses, which can exceed 4,000 bytes. That’s an amplification factor of up to 80x: for every byte the attacker sends, 80 bytes hit the target.
The attack works because DNS typically uses UDP, which doesn’t require a handshake. The attacker sends DNS queries to open resolvers with a forged source IP address – the IP address of the victim. The resolvers helpfully send their large responses to the victim’s IP address, overwhelming it with traffic. The attacker’s actual bandwidth is amplified manyfold, and the victim sees traffic coming from thousands of legitimate DNS servers, making it difficult to filter.
The mitigation is straightforward in principle: DNS resolvers should not answer queries from arbitrary sources. A resolver that only answers queries from its own users can’t be used as an amplifier. But millions of misconfigured open resolvers persist on the internet, and they continue to be exploited.
DNS tunnelling
DNS is one of the few protocols that almost always makes it through firewalls and network filters. Even heavily restricted networks usually allow DNS queries, because without DNS, nothing works. This makes DNS an attractive channel for data exfiltration – smuggling data out of a network by encoding it in DNS queries.
The technique works like this: the attacker controls a domain (say, tunnel.attacker.com) and its authoritative name server. Software on the compromised machine inside the target network encodes stolen data as subdomain labels: aGVsbG8gd29ybGQ.tunnel.attacker.com. The query travels through the normal DNS infrastructure and arrives at the attacker’s name server, which decodes the data from the subdomain. Responses from the attacker’s server (encoded in TXT records, for example) can send commands back.
It’s slow – you can move maybe a few kilobytes per second – and it’s detectable if you’re looking for it (unusually long subdomain labels, high query volumes to a single domain). But it works, and it’s been used in real-world breaches.
NXDOMAIN attacks
A brute-force attack on authoritative servers: the attacker queries massive numbers of non-existent subdomains (random1.example.com, random2.example.com, and so on), generating a flood of NXDOMAIN responses. This wastes the authoritative server’s resources and can fill resolver caches with negative entries. It’s a blunt instrument, but it can be effective against domains with limited server capacity.
Domain hijacking
Perhaps the most dangerous attack doesn’t target the DNS protocol at all – it targets the registrar. If an attacker can compromise your account at the domain registrar (through credential theft, social engineering, or exploiting the registrar’s systems), they can change the NS records for your domain, redirecting all traffic to servers they control. No cryptographic verification will help if the attacker has administrative access to the delegation itself.
Several high-profile domain hijacks have occurred over the years. In 2013, the Syrian Electronic Army hijacked domains belonging to the New York Times and Twitter by compromising the Australian registrar Melbourne IT. Registry lock – a feature that requires manual, out-of-band verification before delegation changes can be made – is the primary defence, but many domain owners don’t enable it.
DNSSEC: signing the phone book
DNSSEC (DNS Security Extensions), defined in RFCs 4033, 4034, and 4035 (2005), adds cryptographic authentication to DNS. It doesn’t encrypt queries or responses – it signs them, so you can verify that the data you received actually came from the authoritative source and wasn’t tampered with.
The mechanism is a chain of trust, anchored at the root zone:
-
The root zone is signed with a root key (the Root Zone Signing Key, or Root KSK). The public portion of this key is distributed as a trust anchor – it’s built into validating resolvers, so they don’t need to look it up.
-
Each TLD’s zone is signed with its own key, and a DS (Delegation Signer) record in the root zone links the TLD’s key to the root’s signature. A resolver can verify the TLD’s key by checking the DS record’s signature against the root key.
-
Each second-level domain is signed with its own key, linked to its parent TLD via another DS record. The chain continues downward through the hierarchy.
-
Individual DNS records (A, AAAA, MX, etc.) are signed with RRSIG (Resource Record Signature) records. A resolver can verify any individual record by following the chain of trust up to the root.
In theory, this solves cache poisoning entirely. A forged response won’t have a valid signature, and a DNSSEC-validating resolver will reject it.
In practice, DNSSEC adoption has been slow and painful. The reasons are numerous: it’s complex to deploy and maintain (key management, key rollovers, and signing zone files are operationally burdensome). It increases DNS response sizes, which can cause problems with firewalls and middleboxes that assume DNS responses are small. The consequences of misconfiguration are severe – a broken DNSSEC chain causes complete resolution failure, which is worse than the insecure case. And it doesn’t encrypt anything, so it doesn’t address the privacy concerns that many people care about most.
As of 2024, roughly 40% of TLDs are signed with DNSSEC, but validation rates vary enormously by country and ISP. The .au zone is signed. The .com zone is signed. But many individual domains within those zones are not, and many resolvers don’t validate even when signatures are available. It’s one of those technologies that everyone agrees is a good idea in principle but that the practical difficulties have kept from achieving universal deployment.
DNS over HTTPS and DNS over TLS: encrypting the question
DNSSEC authenticates answers. But it doesn’t hide the question. Traditional DNS queries are sent in plaintext UDP, which means anyone on the network path – your ISP, a coffee shop WiFi operator, a government surveillance system – can see every domain name you look up.
DNS over TLS (DoT), defined in RFC 7858 (2016), wraps DNS queries in a TLS connection, encrypting them so they can’t be read or tampered with in transit. It uses a dedicated port (853), which makes it easy to identify and block – a fact that hasn’t escaped the notice of censors.
DNS over HTTPS (DoH), defined in RFC 8484 (2018), takes a different approach: it tunnels DNS queries inside regular HTTPS traffic on port 443. This makes DoH queries indistinguishable from normal web traffic, which is the entire point – it’s much harder to selectively block DNS encryption when it’s mixed in with everything else.
Both protocols have been controversial. Supporters argue they’re essential for privacy. Critics raise legitimate concerns about centralisation: if everyone uses DoH to send their DNS queries to Cloudflare or Google, those companies gain a comprehensive view of the browsing habits of millions of users. The traditional DNS system is decentralised by design – your ISP’s resolver sees your queries, but no single entity sees everyone’s. DoH risks concentrating that visibility in a handful of large tech companies.
There’s also a network administration concern. Organisations that use DNS monitoring and filtering – whether for security (blocking known malicious domains), compliance, or parental controls – lose visibility when clients encrypt their DNS traffic and send it to an external resolver. This is particularly contentious in enterprise environments, where IT departments have legitimate reasons to monitor DNS traffic.
The debate continues. The technical community hasn’t reached consensus, and the deployment picture is fragmented: some browsers default to DoH, some operating systems support DoT, and many networks still use traditional unencrypted DNS.
IDN homograph attacks: when domains lie
DNS can only handle ASCII – the letters a-z, digits 0-9, and the hyphen. But the world doesn’t run on ASCII alone, so a system called Internationalised Domain Names (IDN) was created to allow domain names in non-Latin scripts. Under the hood, IDN uses an encoding called Punycode to convert Unicode domain names into ASCII-safe strings. The domain “muenchen.de” becomes “xn–mnchen-3ya.de”. The “xn–” prefix marks it as a Punycode-encoded name.
This creates a security problem. Characters from different scripts can look identical – the Latin “a” (U+0061) and the Cyrillic “a” (U+0430) are visually indistinguishable in most typefaces. An attacker can register a domain using Cyrillic letters that look identical to Latin ones and use it for phishing. The Punycode representation will be completely different, but browsers display the pretty Unicode version to users. This is called an IDN homograph attack, first described by Evgeniy Gabrilovich and Alex Gontmakher in 2002.
Browsers now defend against homograph attacks by detecting suspicious script mixing and displaying the Punycode version instead. But the fundamental tension remains: a system designed for 37 characters (a-z, 0-9, and hyphen) is being asked to represent a Unicode world of over 154,000 characters, many of which look alike to human eyes.
The invisible backbone
DNS is the sort of infrastructure that only becomes visible when it breaks. The rest of the time, it does its job in milliseconds, translating the names humans understand into the addresses that networks need, billions of times a day, across a distributed system that spans every country on Earth.
It was designed in 1983 to solve the problem of a text file that couldn’t keep up with a growing network. Forty years later, it routes traffic for billions of devices. The hierarchy that Mockapetris sketched out – root servers, TLDs, authoritative servers, resolvers – still works. The protocol defined in RFC 1035 is still the foundation. The extensions (DNSSEC, DoH, DoT, QNAME minimisation) are patches on an architecture that has proven remarkably durable.
It’s tempting to take it for granted. You type a name, you get a page. But between the name and the page, a quiet system of delegation and caching, trust and verification, is doing something rather extraordinary: maintaining a coherent, globally consistent, hierarchically distributed mapping of human-readable names to machine-readable addresses, and doing it fast enough that you never notice it’s there.
That’s the best kind of infrastructure. The kind you only appreciate when you learn how it works. Jon Postel managed it from a single office. HOSTS.TXT held every answer in a single file. Now over 1,700 root server instances span the globe, and the query you just sent to check Perth’s weekend weather was answered before you finished reading this sentence.