Reverse DNS: in-addr.arpa and ip6.arpa
Reverse DNS is the IP-to-name lookup. It's the part of DNS that looks weird the first time you see it, because the zones have names like
53.100.51.198.in-addr.arpainstead ofexample.com. The structure is fine. It's the ergonomics ofip6.arpathat hurt.
Why reverse DNS exists#
Forward DNS asks: "What's the address of example.isitdns.net?": a name in, an address out.
Reverse DNS asks the other direction: "Who lives at 198.51.100.53?": an address in, a name out. Used by:
- mail servers verifying that the connecting IP has matching forward/reverse records (the "FCrDNS check": see ptr for how FCrDNS asymmetry breaks mail delivery)
- SSH log enrichment (
sshdreverse-resolves the connecting client whenUseDNSis enabled; note it defaults tonoin modern OpenSSH, precisely because a slow PTR lookup delays logins) - spam scoring (mail from a host with no PTR is suspicious)
- observability tooling labeling traffic by host name instead of IP
- humans reading
tcpdumpoutput without going cross-eyed
The DNS protocol has exactly one way to do this: define a special domain tree where every IP address is encoded as a name, and resolve it the normal way.
The in-addr.arpa tree (IPv4)#
The IPv4 address 198.51.100.53 becomes the DNS name:
53.100.51.198.in-addr.arpa
| | | | +--------- the reverse-DNS root for IPv4
| | | +------------ most-significant octet
| | +---------------- next octet
| +-------------------- next octet
+------------------------ least-significant octet (the host)Reversing the octets lets the DNS hierarchy walk the same way it does for forward names: most-general on the right, most-specific on the left. The root delegates arpa, which delegates in-addr.arpa, which delegates 198.in-addr.arpa, and so on. For RFC 1918 private space (10/8, 172.16/12, 192.168/16) the public tree dead-ends on purpose: IANA delegates those reverse zones to the AS112 blackhole servers, which serve them as empty zones: SOA and NS at the zone name itself, NXDOMAIN for every address inside it. RFC 6303 tells recursive resolvers to serve the same empty zones out of their own data, so that NXDOMAIN for a name inside the block arrives without anyone being asked. So on a private network you stand up your own reverse zone. You can watch a resolver do this below.
The shorthand form, letting dig handle the name reversal:
dig @1.1.1.1 -x 198.51.100.53What it actually sends on the wire:
dig @1.1.1.1 53.100.51.198.in-addr.arpa PTR
198.51.100.xis one of the three RFC 5737 documentation prefixes (TEST-NET-2). Nobody publishes PTRs in it, and RFC 6303 section 4.2 lists100.51.198.in-addr.arpaas a locally served zone, so a resolver returnsNXDOMAINfor these names out of its own empty zone instead of walking the tree. They are shown here only to illustrate the name format. For a live working example, see the Quick check section below.
The shorthand form for nslookup:
nslookup 198.51.100.53 1.1.1.1What it actually sends on the wire:
nslookup -type=PTR 53.100.51.198.in-addr.arpa 1.1.1.1Both forms send a PTR query and return a PTR record. Every reverse zone also requires an SOA at the apex and NS records, just like any other zone. For classless sub-range delegations (RFC 2317), the parent /24 zone also uses CNAME records to redirect individual host queries to the delegated sub-zone.
The ip6.arpa tree (IPv6)#
Same idea, with twice as much pain. Each IPv6 address is 128 bits = 32 hex nibbles, and reverse DNS encodes one nibble per label, in reverse order. The address 2001:db8::1 becomes:
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpaYes really. Thirty-two single-character labels. Plus ip6.arpa. That's the lookup name for 2001:db8::1.
Ouch, my eyes. This is why every reverse-DNS tool on the planet has a built-in formatter. You will never type these by hand.
dig -xdoes it for you.
The shorthand form (using the RFC 3849 documentation prefix to illustrate the format):
dig @1.1.1.1 -x 2001:db8::1What hits the wire:
dig @1.1.1.1 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa PTR
2001:db8::is the RFC 3849 documentation prefix. It has no reverse zone, so both commands returnNXDOMAIN. These are shown to illustrate the nibble format, not as live lookups. For a working IPv6 PTR example, see the ptr page.
The shorthand form for nslookup:
nslookup 2001:db8::1 1.1.1.1What hits the wire:
nslookup -type=PTR 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa 1.1.1.1The two principles to remember:
- One nibble per label. Not one hex-byte (two nibbles) per label. One nibble.
- Reversed nibble order. Most-significant nibble of the original address ends up on the right.
That's it. The verbosity is the price of using the same delegation machinery as forward DNS.
Delegation: who's authoritative for what#
For IPv4:
| Range | Authoritative for the reverse zone |
|---|---|
| Public, allocated to your ISP | Usually the ISP: call them if you want a custom PTR for your static IP |
| Public, allocated to you (BYOIP) | You: your RIR (or the ISP/LIR you got the block through) delegated the relevant /24 (or smaller, via RFC 2317 classless delegation) |
RFC1918 (10/8, 172.16/12, 192.168/16) | You. The public zones (168.192.in-addr.arpa etc.) are delegated to the AS112 blackhole servers (blackhole-1.iana.org, blackhole-2.iana.org), which answer NOERROR with their own NS at the zone name and NXDOMAIN for every address inside it, and most resolvers short-circuit them locally per RFC 6303. Stand up your own. |
Link-local (169.254/16) | No one usable: 254.169.in-addr.arpa points at the same blackhole servers, so these addresses never get real global reverse DNS |
For IPv6 the analogous split applies. ULA space (fc00::/7) is yours to host; public allocations are usually delegated by your RIR.
The categorization of public, private, and documentation addresses is summarized at the addresses you'll meet.
Watch a resolver answer private space itself#
Ask a public resolver who serves the reverse zone for 192.168.0.0/16:
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, aa set (measured 2026-09-04 against blackhole-1.iana.org from a network with no port-53 interception). A resolver that had really walked the tree would have returned those.
Keep two things apart here, because they do not say the same thing. RFC 6303 section 3 asks a resolver for name errors on queries within the locally served zones, "with the obvious exception of queries for the zone name itself where SOA, NS, and 'no data' responses will be returned as appropriate to the query type". BIND implements that literally: its built-in empty zones are "for SOA and NS records only" (BIND 9 ARM), so 168.192.in-addr.arpa NS gets NOERROR and an NS record from a stock BIND, and only a name below the apex gets NXDOMAIN. 1.1.1.1 and 8.8.8.8 are stricter than the RFC and return NXDOMAIN at the zone name too. Ask for a name inside the block and everyone agrees:
curl -s -H 'accept: application/dns-json' \
'https://cloudflare-dns.com/dns-query?name=1.1.168.192.in-addr.arpa&type=PTR'{"Status":3,"TC":false,"RD":true,"RA":true,"AD":false,"CD":false,"Question":[{"name":"1.1.168.192.in-addr.arpa","type":12}]}Unbound ships the same zones as built-in local-zone defaults.
RFC 2317: classless reverse delegation#
If your ISP delegates a /26 to you, the classful reverse zone (x.y.z.in-addr.arpa: a /24) doesn't line up. RFC 2317 defines a CNAME-based trick to delegate a sub-range. You don't need this for RFC 1918 space; you do need it if you're getting a small public allocation. The pattern shows up in customer environments more than home labs.
PTR records inside any reverse zone are documented on the PTR page, including the FCrDNS gotchas that trip up mail delivery.
Quick check that reverse is working#
Pick an IP you know has a PTR record. Cloudflare's 1.1.1.2 works reliably, and unlike 1.1.1.1 its reversal is visible (1.1.1.2 becomes 2.1.1.1.in-addr.arpa):
dig @1.1.1.1 -x 1.1.1.2 +shortsecurity.cloudflare-dns.com.With nslookup:
nslookup 1.1.1.2 1.1.1.12.1.1.1.in-addr.arpa name = security.cloudflare-dns.com.
Authoritative answers can be found from:Exact framing varies by nslookup build: current BIND 9.18 nslookup prints just the answer for the by-IP form, while other builds add a
Server:banner and aNon-authoritative answer:line first, as in the next example. The answer line is the part that matters.
Or query the reverse name directly:
dig @1.1.1.1 2.1.1.1.in-addr.arpa PTR +shortsecurity.cloudflare-dns.com.nslookup -type=PTR 2.1.1.1.in-addr.arpa 1.1.1.1Server: 1.1.1.1
Address: 1.1.1.1#53
Non-authoritative answer:
2.1.1.1.in-addr.arpa name = security.cloudflare-dns.com.
Authoritative answers can be found from:Failure modes to distinguish:
NXDOMAIN: the reverse zone exists and is authoritative, but no PTR is provisioned for that IP. (Also what you get for RFC 1918 and documentation addresses, per the delegation table above.)SERVFAIL: the reverse zone delegation is broken (missing or misconfigured NS/glue), DNSSEC validation failed, or the resolver gave up trying to reach the authoritative servers.- Timeout: your query never got any answer at all, which points at the path between you and the resolver, not the authoritative side. Start at the L3 path to the resolver.
See also#
- PTR records: what lives inside a reverse zone
- All record types: the cheat sheet
- Anatomy of a DNS query: including reverse lookups
- The OSI model: including the public, private, and documentation address ranges
- Query types: what record types mean
- DNS delegations and zone cuts
- nslookup and dig: the two tools you will actually use
- SOA: the zone authority record
- CNAME: canonical names and aliases