๐ IP address spaces: public, private, documentation
Three categories of IP address show up in DNS conversations: public (routable on the Internet, identifies you), private (RFC 1918 / ULA, routable only inside your network), and documentation (RFC 5737 / 3849, reserved so authors can write examples that don't accidentally point at someone's real network). Knowing which is which keeps you from leaking infrastructure or breaking examples.
TL;DR#
| Category | What it is | Where you see it | Safe to publish? |
|---|---|---|---|
| Public | Real, routable, ISP-assigned or RIR-allocated | The address your traffic leaves your network with | โ identifies your network |
| Private | Reserved for internal networks only, never routes on the Internet | RFC 1918 for IPv4, ULA (fd00::/8) for IPv6 | โ harmless (everyone uses the same numbers) |
| Documentation | Reserved so authors have something to put in tutorials without pointing at real IPs | RFC 5737, RFC 3849, RFC 2606 domain names | โ guaranteed not to route |
Public addresses#
Real, routable, identifying. These are the addresses your ISP hands you (IPv4 WAN, IPv6 delegated prefix), the addresses cloud providers assign to your VMs, the addresses you'd put in DNS for a service you want the world to reach.
| Allocation | Examples |
|---|---|
| ISP-issued IPv4 WAN | Whatever your home/business gateway picked up via DHCP from the ISP |
| ISP-delegated IPv6 prefix | Typically a /56 or /60 from the ISP, fingerprintable to subscriber, region, and carrier |
| Cloud provider allocations | EC2 elastic IPs, GCP external IPs, etc. |
| BYOIP / RIR-allocated | Your own AS, ARIN/RIPE-allocated address space |
Two important properties:
- They identify you. An IPv6 prefix is unique to your subscriber line; the first 24โ32 bits identify the carrier (publicly looked up in WHOIS), the next chunk narrows it to a region or subscriber pool. An IPv4 WAN is less precise but trivially geo-located.
- They appear in DNS PTR records. Reverse DNS for public IPs is delegated by the RIR/ISP; you usually can't set your own PTR unless you have a static allocation and your ISP gives you delegation control.
Private addresses#
Reserved for use inside your network. They are guaranteed to not route on the public Internet. Two devices anywhere in the world can both use 192.168.0.10 without conflict, those packets stay on their respective LANs.
IPv4: RFC 1918#
| Range | Size | Typical use |
|---|---|---|
10.0.0.0/8 | 16,777,216 addresses | Large enterprises, cloud VPCs |
172.16.0.0/12 | 1,048,576 addresses | Mid-size networks; Docker's default bridge sits here (172.17.0.0/16) |
192.168.0.0/16 | 65,536 addresses | Home networks, small offices, every consumer router on the planet |
IPv6: RFC 4193 Unique Local Addresses (ULA)#
| Range | Notes |
|---|---|
fc00::/7 (in practice fd00::/8) | The IPv6 equivalent of RFC 1918. Generate the next 40 bits randomly (per the RFC) to avoid collisions when networks merge. |
Other reserved-but-not-RFC-1918 spaces you'll meet#
| Range | RFC | What it is |
|---|---|---|
127.0.0.0/8 and ::1 | RFC 6890, RFC 4291 | Loopback |
169.254.0.0/16 and fe80::/10 | RFC 3927, RFC 4291 | Link-local. IPv4 self-assigns 169.254.x.x when DHCP fails; IPv6 puts an fe80:: address on every interface, always |
100.64.0.0/10 | RFC 6598 | Carrier-grade NAT (the address your ISP NATs you behind when they don't give you a real public IPv4) |
Why this matters for DNS#
- PTR for RFC 1918 space never resolves in the public tree. If you want reverse lookups for your
192.168.0.0/24, you have to stand up your own reverse zone. In the public tree,192.in-addr.arpais administered by ARIN, and ARIN delegates168.192.in-addr.arpato the AS112 project sink servers,blackhole-1.iana.organdblackhole-2.iana.org(RFC 7534). Those servers host the zone as empty: they answer authoritatively withNXDOMAINfor every name inside it. Nobody can get a real delegation for their private space, because RFC 1918 space is not assigned to any single organization. See reverse-dns.
In practice your query rarely even reaches AS112. Watch what a public resolver does with the zone itself:
curl -s -H 'accept: application/dns-json' \
'https://cloudflare-dns.com/dns-query?name=168.192.in-addr.arpa&type=NS'{"Status":3,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"168.192.in-addr.arpa","type":2}]}Status 3 is NXDOMAIN, with no Answer and no Authority section, and 8.8.8.8 returns the same. That answer comes from the resolver itself, not from recursion: ask an AS112 server this exact question directly and it answers NOERROR with the two blackhole-*.iana.org NS records. A resolver that had really walked the tree would have returned those. Both resolvers instead answer RFC 1918 reverse space from their own local zones, which is exactly the behavior RFC 6303 asks for.
RFC 6303 says recursive resolvers SHOULD serve these reverse zones locally instead of leaking the queries upstream. BIND does it by default (
empty-zones-enable yes;); Unbound ships the same zones as built-inlocal-zonedefaults (opt a zone back out withlocal-zone: "168.192.in-addr.arpa." nodefault). Queries that escape anyway land on the AS112 sinks and get NXDOMAIN there.
- A wide-open recursive resolver can leak internal addresses. Queries for
1.1.168.192.in-addr.arpagoing to public resolvers expose your internal IP scheme. Configure your resolver to authoritatively returnNXDOMAINfor unrouted reverse space. Most DNS server implementations have an "empty zones" feature that does this automatically. - Split-horizon DNS (a.k.a. DNS views) often returns RFC 1918 internally and a public IP externally. The authoritative server picks a different record set based on the client's source IP, matched against an ACL. See authoritative zones for the working example.
Documentation addresses#
These ranges are reserved by IANA/RFCs explicitly so authors have something they can put in tutorials, books, and docs without accidentally pointing at someone's real production network. They are guaranteed to not route on the public internet. Safe to publish anywhere.
| RFC | Range | Use |
|---|---|---|
| RFC 5737 | 192.0.2.0/24 (TEST-NET-1) | IPv4 examples |
| RFC 5737 | 198.51.100.0/24 (TEST-NET-2) | IPv4 examples |
| RFC 5737 | 203.0.113.0/24 (TEST-NET-3) | IPv4 examples |
| RFC 3849 | 2001:db8::/32 | IPv6 examples |
| RFC 9542 | 00:00:5E:00:53:00โ00:00:5E:00:53:FF | Unicast MAC examples (a documentation block inside the IANA OUI 00-00-5E) |
| RFC 2606 | example.com, example.net, example.org, .test, .example, .invalid, .localhost | Reserved DNS names, the counterpart to the IP ranges above |
Where you'll see them in DNS#
- In tutorials and RFCs. Every protocol document uses these so reading code or running examples doesn't generate real traffic against unrelated hosts.
- In live example records. A zone can publish a real DNS record that returns a documentation address. The record resolves and
digreturns a normal answer, but the address goes nowhere. This wiki does exactly this:example.isitdns.net(a name that lives inside theisitdns.netzone, not a delegated zone of its own) has an A record returning192.0.2.1and an AAAA record returning2001:db8::1. Both resolve; neither routes.
dig @1.1.1.1 example.isitdns.net A;; QUESTION SECTION:
;example.isitdns.net. IN A
;; ANSWER SECTION:
example.isitdns.net. 300 IN A 192.0.2.1(The record's TTL is 300. You'll see exactly 300 on a fresh fetch; on a cache hit the resolver shows the remaining time, counting down toward 0.)
nslookup example.isitdns.net 1.1.1.1Server: 1.1.1.1
Address: 1.1.1.1#53
Non-authoritative answer:
Name: example.isitdns.net
Address: 192.0.2.1
Name: example.isitdns.net
Address: 2001:db8::1Note that plain nslookup shows both addresses: modern nslookup (BIND 9) queries A and AAAA by default, so one command returns the whole pair.
dig @1.1.1.1 example.isitdns.net AAAA;; QUESTION SECTION:
;example.isitdns.net. IN AAAA
;; ANSWER SECTION:
example.isitdns.net. 300 IN AAAA 2001:db8::1nslookup -type=AAAA example.isitdns.net 1.1.1.1Server: 1.1.1.1
Address: 1.1.1.1#53
Non-authoritative answer:
Name: example.isitdns.net
Address: 2001:db8::1- In TLDs reserved for testing.
.test,.example,.invalid, and.localhostwill never be issued as real TLDs. You can build a test rig underlab.testknowing it will never collide with the public Internet. One trap to avoid:.localis not on that list. It belongs to multicast DNS (RFC 6762), and naming a LAN under.localfights with mDNS on macOS and on any Linux client running an mDNS stack (Avahi/nss-mdns, a desktop default but absent on most headless servers). Use.test(or RFC 8375'shome.arpafor home networks) instead.
Why documentation addresses exist: two reasons#
1. Privacy. An ISP-delegated IPv6 prefix is fingerprintable to a subscriber line. The first 24โ32 bits identify the carrier (publicly resolvable via WHOIS); the next chunk narrows it to a region or a specific subscriber pool. A residential IPv4 WAN address is less precise but trivially geo-located. Documentation ranges give authors something safe to publish that carries no identifying information.
2. Reproducibility. Documentation addresses do not change with your ISP. Someone reading these notes does not have to mentally substitute "your prefix" at every example. They see 2001:db8::/32, recognize it as documentation, and the example stays valid regardless of their own network.
Why mix documentation IPs with real domain names?#
Because it makes hands-on examples runnable. A record like example.isitdns.net A 192.0.2.1 actually resolves, you can dig it, you can see the DNS query in motion, you can practice. But the address doesn't route, so nothing on the other end accidentally receives your packets. Best of both worlds.
Practical hygiene#
If you're editing a doc and you're not sure whether a particular address should be in plaintext:
- Anything inside RFC 5737 / RFC 3849 / RFC 1918 / RFC 4193 / link-local / loopback โ safe to publish.
- Anything that looks like your ISP's WAN address or IPv6 prefix โ treat it as identifying. Don't put it in shared docs.
- Cert files, .p12, .pem, .key โ never in any repo, not even private ones.
- Full MAC addresses โ anonymize unless the doc is specifically teaching Layer 2 / ARP / OUI identification. The RFC 9542 documentation range (
00:00:5E:00:53:xx, inside the IANA OUI) exists for this purpose, the same way RFC 5737 exists for IPv4.
When in doubt: substitute a documentation address. They were created exactly so you don't have to make this call under pressure.
See also#
- Reverse DNS: in-addr.arpa and ip6.arpa, where private vs public addressing changes who's authoritative
- A record ยท AAAA record ยท PTR record, the records that carry these addresses
- split-horizon, how one name resolves differently inside vs outside your network
- Authoritative zones, for how views and ACLs are configured
- query-types, for the full menu of DNS record types
- rfc-index, for the primary references: RFC 1918, RFC 5737, RFC 3849, RFC 4193, RFC 6598, RFC 6303, RFC 7534