What We’re Testing
MagicDNS lets machines resolve each other by hostname instead of tailnet IP. When enabled, the Go client starts a local DNS resolver (package pkg/dns, file resolver.go) that intercepts queries for tailnet hostnames and resolves them from the local peer list. Non-tailnet queries are forwarded upstream via DNS-over-TLS (Quad9: 9.9.9.9:853, 149.112.112.112:853).
Key facts from source code:
- Backend endpoint:
POST /api/dns-managementwithaction: "get_settings"returns the current MagicDNS state, nameservers, and auto-generated DNS records from online machines (dns-management.tslines 23-46) - Backend endpoint:
POST /api/dns-managementwithaction: "update_settings"togglesmagic_dns_enabled(requires org admin,dns-management.tslines 49-66) - DNS domain format:
{org_slug}.zt.net— each machine gets{machine_name}.{org_slug}.zt.netas an A record pointing to its tailnet IP - Local resolver listen address:
127.0.0.53:53(falls back to port15353if 53 is unavailable —resolver.golines 176-189) - Default search domain:
"ztna"— used whenDNSSearchDomainin client config is empty (resolver.goline 94,cmd_dns.goline 45) - CLI subcommands:
ztna dns statusshows resolver state;ztna dns query <hostname>resolves a hostname via the control plane (cmd_dns.go) - Config fields:
dns_enabled(bool) anddns_search_domain(string) in the client config file (config.golines 107-108)
Your Test Setup
| Machine | Role |
|---|---|
| ⊞ Win-A | Dashboard admin — enable MagicDNS, verify settings |
| 🐧 Linux-C | CLI machine — verify local DNS resolver starts and resolves peers |
ST1 — Enable MagicDNS via Dashboard
What it verifies: An org admin can enable MagicDNS and the backend persists the setting.
Steps:
- On ⊞ Win-A , open
https://login.quickztna.com/dns. - Find the MagicDNS toggle (it controls
magic_dns_enabled). - Enable MagicDNS.
- The page should save the setting automatically or provide a Save button.
Verify via API:
TOKEN="YOUR_ACCESS_TOKEN"
curl -s -X POST "https://login.quickztna.com/api/dns-management" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"get_settings","org_id":"YOUR_ORG_ID"}' | python3 -m json.tool
Expected response shape:
{
"success": true,
"data": {
"settings": {
"magic_dns_enabled": true,
"search_domains": "[]"
},
"nameservers": [],
"dns_records": [
{
"name": "Win-A.yourorg.zt.net",
"type": "A",
"value": "100.64.0.1"
}
],
"domain": "yourorg.zt.net"
}
}
Pass: magic_dns_enabled is true. The dns_records array contains an A record for each online machine in the org, with {machine_name}.{org_slug}.zt.net as the name and the tailnet IP as the value.
Fail / Common issues:
FORBIDDENerror — you must be an org admin to update DNS settings.dns_recordsis empty — no machines are registered with a tailnet IP, or machines have status other thanonlineoroffline(the query filters onstatus IN ('online', 'offline')).
ST2 — Verify DNS Records Are Generated from Machines
What it verifies: The get_settings action auto-generates A records from the machines table (not a separate static DNS records table).
Steps:
- On ⊞ Win-A , with MagicDNS enabled, call the API:
curl -s -X POST "https://login.quickztna.com/api/dns-management" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"get_settings","org_id":"YOUR_ORG_ID"}' | python3 -c "
import sys, json
data = json.load(sys.stdin)['data']
print('Domain:', data['domain'])
print('Records:')
for r in data['dns_records']:
print(f\" {r['name']} -> {r['value']} ({r['type']})\")
"
Expected: One A record per registered machine that has a tailnet IP and status online or offline. The domain follows the pattern {org_slug}.zt.net.
- Check the org slug matches your org:
curl -s "https://login.quickztna.com/api/db/organizations?id=eq.YOUR_ORG_ID" \
-H "Authorization: Bearer $TOKEN" | python3 -c "
import sys, json
orgs = json.load(sys.stdin)['data']
if orgs: print('Slug:', orgs[0].get('slug', '(none)'))
"
Pass: The domain prefix matches your org’s slug. Each online/offline machine appears as a DNS record.
Fail / Common issues:
- Domain shows
ztna.zt.netinstead of your org slug — the org may not have aslugfield set. The backend falls back to"ztna"whenorg.slugis null. - Missing machines — machines with status
pendingorquarantinedare excluded from DNS records.
ST3 — Check DNS Status on CLI
What it verifies: ztna dns status reads the local client config and reports whether MagicDNS is enabled and what search domain is configured.
Steps:
- On 🐧 Linux-C , ensure the machine is connected:
ztna status
- Check DNS status:
ztna dns status
Expected output:
MagicDNS: enabled
Search domain: ztna
Resolution: <hostname>.ztna -> tailnet IP
The Search domain line shows the value of dns_search_domain from the client config. If not set, it defaults to ztna.
Pass: Output shows MagicDNS: enabled and a search domain. The resolution pattern shows how hostnames map to tailnet IPs.
Fail / Common issues:
MagicDNS: disabled— the client config file hasdns_enabled: false. This is the local client-side setting and may not match the server-side org setting. The client must have DNS enabled locally for the resolver to start.error loading config— the machine is not authenticated. Runztna loginfirst.
ST4 — Resolve a Peer Hostname via CLI
What it verifies: ztna dns query calls the backend’s resolve action and returns the tailnet IP for a known machine name.
Steps:
- On 🐧 Linux-C , resolve ⊞ Win-A by name:
ztna dns query Win-A
Expected output:
Win-A.yourorg.zt.net -> 100.64.0.1
The CLI first tries the hostname as-is against the backend. If the response returns no IP and the hostname has no dots, it retries with the search domain appended (Win-A.ztna). The backend’s resolve action (dns-management.ts lines 92-138) performs three lookups in order:
-
FQDN match: hostname ending with
.{org_slug}.zt.net -
Short hostname match: first label before any dot, case-insensitive lookup in
machinestable -
Custom DNS record match: user-created records in
dns_recordstable -
Try a hostname that does not exist:
ztna dns query nonexistent-machine
Expected output:
nonexistent-machine -> (not found)
Pass: Known machine name resolves to its tailnet IP. Unknown machine name shows (not found).
Fail / Common issues:
not authenticated. Run 'ztna login' first— the client config has noorg_id. You must be logged in.DNS resolution failed— network error reaching the control plane. Check connectivity tologin.quickztna.com.- Machine resolves but with wrong IP — the machine may have been re-registered and received a new tailnet IP.
ST5 — Verify MagicDNS Can Be Disabled
What it verifies: Disabling MagicDNS via the API removes the DNS records from the settings response.
Steps:
- On ⊞ Win-A , disable MagicDNS via the dashboard DNS page toggle, or via API:
curl -s -X POST "https://login.quickztna.com/api/dns-management" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"update_settings","org_id":"YOUR_ORG_ID","magic_dns_enabled":false}'
Expected response:
{
"success": true,
"data": { "updated": true }
}
- Fetch settings again:
curl -s -X POST "https://login.quickztna.com/api/dns-management" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"get_settings","org_id":"YOUR_ORG_ID"}' | python3 -c "
import sys, json
data = json.load(sys.stdin)['data']
print('MagicDNS enabled:', data['settings']['magic_dns_enabled'])
print('DNS records count:', len(data['dns_records']))
"
Expected: magic_dns_enabled is false. Note that dns_records may still be populated (the backend always builds them from machines) — the magic_dns_enabled flag is what the client uses to decide whether to start the local resolver.
- On 🐧 Linux-C ,
ztna dns querystill works because it calls the backend’sresolveaction directly (it does not depend on the local resolver). The local resolver is what handles system-level DNS interception.
Pass: Setting toggled to false successfully. The update_settings action returns updated: true.
Fail / Common issues:
FORBIDDEN— only org admins can update DNS settings.
Cleanup: Re-enable MagicDNS for subsequent DNS tests:
curl -s -X POST "https://login.quickztna.com/api/dns-management" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"action":"update_settings","org_id":"YOUR_ORG_ID","magic_dns_enabled":true}'
Summary
| Sub-test | What it proves | Pass condition |
|---|---|---|
| ST1 | MagicDNS enable toggle | magic_dns_enabled is true, DNS records generated for online machines |
| ST2 | Auto-generated DNS records | Each machine with tailnet IP appears as {name}.{slug}.zt.net A record |
| ST3 | CLI dns status | ztna dns status shows enabled state and search domain |
| ST4 | Hostname resolution via CLI | ztna dns query resolves known peers, returns (not found) for unknown |
| ST5 | MagicDNS disable | Setting toggled to false, re-enabled for subsequent tests |