isitdns? wiki/Zones/Forward zones
Zones

➡️ Forward zones

Asks the server a forward zone would send the query to, directly.

 dig @9.9.9.9 example.isitdns.net A
; <<>> DiG 9.20.11-0ubuntu0.2-Ubuntu <<>> @9.9.9.9 example.isitdns.net A
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 38499
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; 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: 40 msec
;; SERVER: 9.9.9.9#53(9.9.9.9) (UDP)
;; WHEN: Mon Sep 14 17:42:32 CDT 2026
;; MSG SIZE rcvd: 64

GO NOERROR and the answer the forwarder would have returned

NO GO a timeout, which means the forward target is silent from here

run this query in the dig tool →

what each part of this output means →

What it is#

A forward zone is a conditional pointer. When a query arrives matching the zone's name, the local resolver:

  1. Notices the match
  2. Forwards the query, recursion desired (rd=1), to the configured forwarders (one or more upstream IPs)
  3. Waits for the answer
  4. Returns it to the client and caches it locally

Because the forwarded query asks for recursion, the forwarder must itself be a recursive resolver, or be authoritative for the zone. Pointing a forward zone at an authoritative-only server that does not host the zone gets you REFUSED, RCODE 5, a policy refusal (RFC 1035 §4.1.1).

The response carries aa=0 because the local server is not authoritative: it acted as a proxy. The aa bit is reserved for servers that are an authority for the queried name (same section).

This differs from a delegation (you publish NS pointing downstream: resolvers follow the referral there directly) and from an auth zone (you have the data yourself).

When to use it#

  • A partner's internal namespace: your resolver should chase internal.partner.example to their DNS, never to public roots.
  • Service discovery domains: *.consul, *.cluster.local: forward to the discovery resolver.
  • Reverse zones for an upstream's IP space: when a partner delegates a /26 to you over a VPN, forward the matching .in-addr.arpa zone to their DNS.
  • Migration windows: temporarily forward an old zone to its new authoritative location during a cutover.
  • split-horizon namespaces: return different answers to internal vs external clients by forwarding the internal view to a private resolver.

When not to use it#

  • When you own the records: use auth.
  • When you want clients to land directly on the target without going through your resolver: use delegations.
  • When you want only NS-record caching for faster referrals: use stub.
  • When you need encrypted transport to the upstream resolver: see dot-doh for DoT and DoH forwarder options.

Gotchas#

  • Loop hazard. Forward A to B to A is a recursion loop. Resolvers return SERVFAIL after retry, but you will see latency spikes and log noise first. Audit chains.
  • Fallback to root disagrees by implementation. BIND defaults to forward first: query the forwarders, and if that fails, resolve it yourself from root (BIND 9 ARM, Forwarding). Unbound defaults the other way, forward-first: no, so a failed forward stays failed (unbound.conf(5)). For an internal namespace, root fallback is usually wrong: you want SERVFAIL, not a cached NXDOMAIN from root claiming the name does not exist. Set "forwarders only" explicitly (BIND: forward only;; Unbound: leave forward-first at its default no).
  • TLS-aware forwarders. Forwarding to a DoT-capable upstream, most resolvers support TLS on the forwarder entry itself (BIND: a tls transport on the forwarder address; Unbound: forward-tls-upstream: yes). Plain UDP/53 is the default.
  • The forwarder list is redundancy, not load-balancing. Selection is implementation-specific: some servers walk the list in order, others prefer whichever forwarder answered fastest. Treat multiple forwarders as failover, not as a load balancer.
  • Wildcards are not supported. You forward an entire zone: *.internal.partner.example is not a valid forward zone name. Forward internal.partner.example and everything under it follows.
  • DNSSEC validation, two distinct failure modes. A signed forwarded zone needs a DNSSEC-aware forwarder that returns RRSIG records; one that strips them turns every answer SERVFAIL. A private, unsigned namespace like consul. or cluster.local. fails differently: the signed public tree proves those names do not exist, so a validating resolver judges the forwarded answer bogus. Carve the name out of validation for that zone only (BIND: validate-except; Unbound: domain-insecure). See dnssec and dnssec-troubleshooting.

See also#