isitdns? wiki/Security/Split-horizon DNS
Security

Split-horizon DNS

A view ties a set of zone data to match criteria. The server checks each configured view in order and answers from the first one the query matches, usually by source IP, sometimes by the arriving interface or a TSIG key (RFC 9499 Section 6, "View"; BIND's view statement works the same way: "the order of the view statements is significant; a client request is resolved in the context of the first matching view"). The matched views share a zone name; records, TTLs and NS sets can differ between them, and nothing keeps them in sync automatically.

Asks the public authority what the outside world sees for a name.

 dig -4 @coleman.ns.cloudflare.com example.isitdns.net A
; <<>> DiG 9.20.11-0ubuntu0.2-Ubuntu <<>> -4 @coleman.ns.cloudflare.com example.isitdns.net A
; (3 servers found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1422
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;example.isitdns.net. IN A
;; ANSWER SECTION:
example.isitdns.net. 300 IN A 192.0.2.1
;; Query time: 32 msec
;; SERVER: 108.162.195.64#53(coleman.ns.cloudflare.com) (UDP)
;; WHEN: Mon Sep 14 17:52:09 CDT 2026
;; MSG SIZE rcvd: 64

GO aa on the flags line and the public answer

NO GO a different answer than your internal view returns, which is the split

what each part of this output means →

Where it gets implemented#

ServerHow it names a view
BINDA view block, matched with match-clients (source IPs and/or TSIG keys) and scoping an authoritative zone to it (view Block Definition and Usage).
Windows ServerDNS Policies: a query-resolution policy picks a zone scope by client subnet or server interface (DNS Policies overview, Microsoft Learn).
Other authoritative servers, DNS appliancesSame match-then-serve mechanism under the vendor's own name; views are "not a standardized part of the DNS, but widely implemented in server software" (RFC 9499 Section 6, "View").

Common gotchas#

1. Records drift between views. Two zone copies, two places to edit. Template both from one source (Ansible, Terraform, a vendor API) before you have ten views.

2. DNSSEC is per-view. Each view is a separate zone copy, signed or not on its own. Once the public delegation publishes a DS record, every validating resolver expects that zone's answers to validate against it; an internal view signed with different keys, or unsigned, is bogus (RFC 4033 §5) and clients get SERVFAIL. Sign both views with the same keys, or give internal resolvers a trust anchor for the internal view's key. See dnssec-troubleshooting.

3. Clients bypass the internal resolver. A laptop with 8.8.8.8 hard-coded never sees the internal view. Push the internal resolver via DHCP and block outbound port 53, and manage DoH/DoT too: encrypted DNS to a public resolver skips the internal view the same way.

4. NS records leak the wrong nameservers. The internal view's NS records must point at internal nameservers, the external view's at external ones. Cross-pollination sends a chasing resolver to the wrong side.

5. Cached answers cross horizons. A laptop caches the internal IP at the office, then fails to connect from home on the same TTL. Low TTLs help; per-view TTLs help more.

Testing each view#

Ask each authoritative server directly; this bypasses recursive caching and forwarder rewriting.

dig -4 @ns-internal.example.com service.example.com A
dig -4 @ns-external.example.com service.example.com A

isitdns.net has one view, so both its authorities return the same address pair (record order rotates between queries):

dig -4 @coleman.ns.cloudflare.com isitdns.net A +short
dig -4 @hera.ns.cloudflare.com isitdns.net A +short
172.67.155.242
104.21.56.211
104.21.56.211
172.67.155.242

On a split zone the internal and external authorities would disagree instead (RFC 9499 section 6); that disagreement is the split working.

ResultDiagnosis
Both authorities return the same answer for a name that should be view-splitView definitions are not matching the way you expect; check match-clients / ACL
Authorities return different answers but a specific client gets the wrong oneThat client is not being directed at the right view: source-IP mismatch, NAT rewriting source, or wrong resolver in resolv.conf
Both authorities return NXDOMAINThe name is not in either view; this is a different bug, not a split-horizon issue

When not to use split-horizon#

Skip it for internal-only names (a separate internal zone on the internal resolver is enough), for hiding a handful of public records (that's an HTTP-layer or authn problem, not DNS), or when a load balancer that routes by source already solves it at L3.

Policy interception isn't split-horizon#

Filtering resolvers and home gateways fake the same "different answer per client" effect by rewriting queries in flight rather than holding a second zone copy: RFC 9499's policy-implementing resolver, "a resolver acting in recursive mode that changes some of the answers that it returns based on policy criteria" (RFC 9499 Section 6). It owns no zone, cannot AXFR/IXFR, and the rewrite applies only inside the network doing it; an upstream authority never sees it.

See also#