How DNS works with Lattice

A laptop is a stub. It asks DHCP option 6. It does not discover lattice-dns.

This is the education page for how a laptop finds a nameserver. How to mint credentials and wire adapters (keytab, TSIG, PowerDNS API): integrations. Zone modes and the lattice-dns binary: dns. Adapters: bind-ddns, ad-ddns, powerdns. Admin path: manuals/admin.

Lattice does two DNS jobs and never mixes them in one process:

  1. Update names after a lease — the worker writes A/PTR (and deletes them) via an adapter. dhcpd does not talk DNS on Ack.
  2. Answer for zones Lattice ownslattice-dns is an authoritative server for those zones only. Recursion is off.

Most sites only need (1). (2) is optional. Neither job makes Lattice the resolver the laptop uses for google.com or for the AD forest.


1. The laptop is a stub

A Windows / macOS / Linux DHCP client is a stub resolver. After Ack it has a list of DNS server IPs from DHCP option 6. Every lookup — printer-01.office.example.com, dc01.ad.example.com, google.com — is sent to that list.

The stub does not:

  • Walk NS records from the root
  • Read the NS you set on a Lattice zone
  • Discover lattice-dns by itself
  • Fail over to AD because Lattice REFUSED google.com

NS records tell other nameservers where a zone lives. They do not tell a workstation “use this as my DNS server.” Option 6 does that (or a static NIC config).

Lattice does not fill option 6 when you enable DDNS or embedded. You set it as a subnet DHCP option (code 6, payload {"addresses":["10.0.0.1","10.0.0.2"]}), or the machine is configured by hand. Mask, router, and lease-time are built-in from the subnet row. DNS servers are not.

DHCP option 15 (domain name) and search lists only change which suffix the stub appends. They do not choose the server.

  laptop (stub)
       |
       |  every name
       v
  whatever option 6 said
  (AD, Unbound, BIND, or — rarely — lattice-dns)

2. The recursive resolver is someone else

Unbound, BIND as a cache, or AD DNS (many forests use the DCs as both authoritative and recursive) is a recursive resolver. It:

  • Accepts the stub’s query
  • Follows NS / forwards stub zones / uses slave zones
  • Caches
  • Talks to lattice-dns or a DC on the client’s behalf

That is why the production-shaped picture is:

  laptop  --option 6-->  Unbound or AD or BIND
                              |
                              +--> lattice-dns   only for office.example.com
                              +--> DCs           ad.example.com, _msdcs
                              +--> the internet  everything else

lattice-dns is the box in the middle of one zone, not the box the laptop points at.


3. Pick one mode per zone

Do not set embedded and bind_tsig / ad_gsstsig / powerdns_http on the same zone. Split brain: two writers, two answers.

ModeWhat the laptop asks (option 6)Who talks to lattice-dnsHow names get into DNS
Keep AD / BIND / PowerDNSUnchanged (DCs or existing BIND)Nobody on the query pathWorker RFC 2136 / HTTP after Ack
Hidden primaryBIND (or Unbound in front of BIND)BIND secondaries, AXFR from Latticeembedded bumps serial; secondaries transfer
Published lattice-dnslattice-dns VIP — only if that zone is all they will queryThe laptop itselfSnapshot from leases + static

Ack never waits. A dead BIND or a slow AXFR delays names, not leases. outbox / Overview lag.

Keep AD or BIND (usual day one)

Workstations already query the DCs. You do not change option 6.

  laptop --option 6--> DC / BIND
  dhcpd --SQL--> Postgres
  worker --RFC 2136 / GSS-TSIG / HTTP--> DC / BIND / PowerDNS
  lattice-dns                         (idle for this zone)

Use this for ad.example.com and _msdcs. Lattice must not host the forest.

Hidden primary (usual if Lattice owns the DHCP zone)

Laptops still do not point at Lattice. BIND is type secondary (older configs: type slave); the primary is the lattice-dns VIP. Parent NS at the registrar or internal parent is BIND, not Lattice. Syntax: BIND ARM — zone types.

  laptop --option 6--> BIND (or Unbound → BIND)
  BIND  --AXFR/IXFR--> lattice-dns VIP :53
  worker --embedded--> Postgres serial bump + NOTIFY

lattice-dns is doing the job: compiling leases and static records into a zone and serving it to secondaries. Clients never configured it.

Published lattice-dns (a dedicated internal zone only)

You choose to put the lattice-dns address in option 6. Then the stub sends every name there. Off-zone → REFUSED. google.com fails. dc01.ad.example.com fails.

That is correct only when clients in that zone never look up anything else (office.example.com only). It is wrong as the site resolver.

If you want laptops to use Lattice names and the internet / AD, put Unbound (or BIND as a cache) in option 6, and conditional-forward only our zones:

# Unbound — sketch, not a shipped file
forward-zone:
  name: "office.example.com."
  forward-addr: 10.0.0.10@53        # lattice-dns VIP

forward-zone:
  name: "20.20.10.in-addr.arpa."
  forward-addr: 10.0.0.10@53

Leave AD on the DCs (another stub-zone / forward). Do not forward the forest at Lattice.


4. What lattice-dns is doing when you use it

Authoritative only (RecursionAvailable=0). In-memory snapshot from Postgres:

  • SOA/NS from dns_zone
  • A/AAAA/PTR from leased rows and static_record
  • MX/SRV/CAA from static records

The embedded adapter does not send RFC 2136 to lattice-dns. It bumps dns_zone.serial and NOTIFY. lattice-dns reloads. Off-zone REFUSED; missing name NXDOMAIN; name in zone wrong type NODATA.

AXFR is TCP (ACL + optional TSIG). IXFR only from the previous compiled snapshot; process restart → next transfer is AXFR.

Listen on :53 on the node or the HA VIP. Binary notes: dns.


5. Why Lattice is not Unbound

Recursive lookup, forwarding, RPZ, public DNS, DNSSEC, and hosting the AD forest are v1 non-goals (01-VISION.md). Unbound already does recursion. AD already does the forest. Principle: adapter, don’t colonize — day one does not mean “repoint every workstation.”

A Lattice recursive forwarder would own “the internet is down,” cache, _msdcs, and Infoblox-shaped DNS security. The product is IPAM + scale-out DHCP + updates (and optional authoritative for our zones). Option 6 still points at AD, Unbound, or BIND.


6. Checklist

  • One adapter per zone
  • Forest / _msdcs stays on the DCs (adapter-only, never embedded)
  • Option 6 is set on purpose (DHCP option code 6). Enabling embedded did not set it
  • Option 6 is not the lattice-dns VIP unless that zone is all clients query, or Unbound sits in front
  • Hidden primary: parent NS = BIND; allow_transfer / also_notify = slave IPs
  • Published + real site: Unbound in option 6; forward only Lattice zones
  • After Ack, missing names → Overview outbox lag, not a DHCP failure