Endpoint
| Method | Path | Permission | Description |
|---|---|---|---|
GET | /api/query/explain?name=&type=&client=&protocol=&dnssec=&ask_upstreams= | logs.read or logs.server | The path one query takes through the server, and its answer |
POST | /api/capture | logs.read (with division_id) or logs.server | Live capture: the queries matching keywords as server-sent events (see Live capture) |
| Parameter | |
|---|---|
name | The name. With type=PTR, an IP address is turned into its reverse name |
type | The record type, A when left out |
client | The client’s IP address |
protocol | udp (default), tcp, dot, doh or doq |
dnssec | true to ask with the DO bit |
ask_upstreams | true to ask the upstreams on a cache miss. Their answer isn’t cached, but their latency stats count it |
logs.server, can
explain any client. Other users and API tokens need
logs.read in the division whose client network holds client. Explaining is read-only and isn’t written to the
audit log.
curl -s "https://dnz.example.com/api/query/explain?name=www.example.com&type=A&client=192.168.1.20" \
-H "Authorization: Bearer $DNZ_TOKEN"
{
"name": "www.example.com.", "type": "A", "client": "192.168.1.20", "protocol": "udp",
"steps": [
{ "stage": "client", "summary": "Client 192.168.1.20",
"details": ["No split-horizon view: the default records",
"Client network 192.168.1.0/24 of division Office: its blocklists apply, then the server-wide ones"] },
{ "stage": "policy", "summary": "Rate limits, DNS cookies and response rate limiting are skipped for explained queries",
"details": ["Over UDP, answers larger than 1232 bytes are truncated (TC) so the client retries over TCP"] },
{ "stage": "local", "summary": "Local zone example.com holds it (as www)",
"details": ["CNAME www.example.com. → example.com (record #2, TTL 300), followed",
"example.com. is in local zone example.com",
"1 A record at example.com.: 192.0.2.1 (record #1, TTL 300)"] }
],
"source": "local",
"response": {
"rcode": "NOERROR", "flags": ["qr", "aa", "rd"],
"answers": ["www.example.com. 300 IN CNAME example.com.", "example.com. 300 IN A 192.0.2.1"],
"authorities": [], "additionals": [], "size": 75
},
"resolved": true, "asked_upstreams": false, "duration_ms": 0.35
}
| Field | |
|---|---|
steps[].stage | client, policy, local, filter, rpz, forward, cache, upstream, alias, dns64, steering or dnssec |
source | Where the answer came from, as the query log names it (local, cache, upstream, conditional, blocked, rpz, safe_search…); null for replies the query log doesn’t record and when nothing is sent |
response | The reply as the client would get it; null when none is sent (an RPZ drop) |
resolved | false when the answer depends on upstreams that weren’t asked; response is then the SERVFAIL a failed lookup would give, not the real answer |
duration_ms | How long explaining took, upstream questions included |